Add RRO, portal section perms, dislocation presets, and hiring intern flow.

Ship cash-register registry, section-based portal access, configurable dislocation columns, and trial-hire intern accounts with credentials PDF.
This commit is contained in:
2026-08-09 14:58:17 +03:00
parent 237275abd0
commit ae5c1f1848
63 changed files with 5987 additions and 2217 deletions
+103
View File
@@ -0,0 +1,103 @@
{% load i18n %}
<div class="page-content">
<div style="margin-bottom:1.5rem;">
<h1 style="font-size:1.25rem; font-weight:500; color:var(--color-foreground);">{% trans "РРО / ПРРО" %}</h1>
<p style="font-size:0.875rem; color:var(--color-muted-foreground); margin-top:0.25rem;">
{% if is_staff %}{% trans "Реестр кассовых аппаратов по аптекам" %}{% else %}{% trans "Кассовые аппараты вашей аптеки" %}{% endif %}
</p>
</div>
<form method="get" hx-get="/rro/" hx-target="#main-content" hx-push-url="true" hx-indicator="#loader"
style="display:flex; align-items:center; gap:0.5rem; margin-bottom:1rem; flex-wrap:wrap;">
<input type="text" name="q" value="{{ filter_q }}" class="input" style="width:14rem;"
placeholder="{% trans 'ФН, серийник, модель…' %}">
{% if is_staff %}
<select name="organization" class="input" style="width:auto;" onchange="this.form.requestSubmit()">
<option value="">{% trans "Все организации" %}</option>
{% for org in organizations %}
<option value="{{ org.pk }}" {% if filter_org == org.pk|stringformat:"s" %}selected{% endif %}>{{ org.name }}</option>
{% endfor %}
</select>
<select name="pharmacy" class="input" style="width:auto;" onchange="this.form.requestSubmit()">
<option value="">{% trans "Все аптеки" %}</option>
{% for p in all_pharmacies %}
<option value="{{ p.pk }}" {% if filter_pharmacy == p.pk|stringformat:"s" %}selected{% endif %}>{{ p.organization.name }} №{{ p.pharmacy_number }}</option>
{% endfor %}
</select>
{% endif %}
<select name="kind" class="input" style="width:auto;" onchange="this.form.requestSubmit()">
<option value="">{% trans "Все типы" %}</option>
{% for value, label in kind_choices %}
<option value="{{ value }}" {% if filter_kind == value %}selected{% endif %}>{{ label }}</option>
{% endfor %}
</select>
<select name="status" class="input" style="width:auto;" onchange="this.form.requestSubmit()">
<option value="">{% trans "Все статусы" %}</option>
{% for s in statuses %}
<option value="{{ s.pk }}" {% if filter_status == s.pk|stringformat:"s" %}selected{% endif %}>{{ s.name }}</option>
{% endfor %}
</select>
<button type="submit" class="btn btn-secondary" style="font-size:0.8125rem;">{% trans "Найти" %}</button>
{% if is_staff %}
<a href="/admin/rro/cashregister/add/" target="_blank" class="btn btn-primary" style="font-size:0.8125rem; text-decoration:none; margin-left:auto;">{% trans "Добавить в админке" %}</a>
{% endif %}
</form>
<div style="background:var(--color-card); border:1px solid var(--color-border); border-radius:0.75rem; overflow:hidden; box-shadow:0 1px 2px rgb(0 0 0/0.05);">
<div style="overflow-x:auto;">
<table style="width:100%; border-collapse:collapse; font-size:0.8125rem;">
<thead>
<tr style="border-bottom:1px solid var(--color-border); text-align:left;">
<th style="padding:0.75rem 1rem; color:var(--color-muted-foreground); font-weight:500;">{% trans "Аптека" %}</th>
<th style="padding:0.75rem 1rem; color:var(--color-muted-foreground); font-weight:500;">{% trans "Тип" %}</th>
<th style="padding:0.75rem 1rem; color:var(--color-muted-foreground); font-weight:500;">{% trans "Фискальный номер" %}</th>
<th style="padding:0.75rem 1rem; color:var(--color-muted-foreground); font-weight:500;">{% trans "Модель" %}</th>
<th style="padding:0.75rem 1rem; color:var(--color-muted-foreground); font-weight:500;">{% trans "Статус" %}</th>
<th style="padding:0.75rem 1rem; color:var(--color-muted-foreground); font-weight:500;">{% trans "Сертификат до" %}</th>
<th style="padding:0.75rem 1rem; color:var(--color-muted-foreground); font-weight:500;"></th>
</tr>
</thead>
<tbody>
{% for reg in registers %}
<tr style="border-bottom:1px solid var(--color-border);">
<td style="padding:0.75rem 1rem;">
<a href="/pharmacies/{{ reg.pharmacy_id }}/" hx-get="/pharmacies/{{ reg.pharmacy_id }}/" hx-target="#main-content" hx-push-url="/pharmacies/{{ reg.pharmacy_id }}/" hx-indicator="#loader"
style="color:var(--color-foreground); text-decoration:none; font-weight:500;">
{{ reg.pharmacy.organization.name }} №{{ reg.pharmacy.pharmacy_number }}
</a>
{% if reg.is_primary %}<span class="badge badge-info" style="margin-left:0.35rem;">{% trans "осн." %}</span>{% endif %}
</td>
<td style="padding:0.75rem 1rem;">{{ reg.get_kind_display }}</td>
<td style="padding:0.75rem 1rem; font-family:ui-monospace,monospace;">{{ reg.fiscal_number }}</td>
<td style="padding:0.75rem 1rem; color:var(--color-muted-foreground);">
{% if reg.vendor %}{{ reg.vendor.name }} {% endif %}{{ reg.model_name|default:"—" }}
</td>
<td style="padding:0.75rem 1rem;">
{% if reg.status.code == 'active' %}<span class="badge badge-success">{{ reg.status.name }}</span>
{% elif reg.status.code == 'repair' %}<span class="badge badge-warning">{{ reg.status.name }}</span>
{% elif reg.status.code == 'decommissioned' %}<span class="badge badge-danger">{{ reg.status.name }}</span>
{% else %}<span class="badge badge-muted">{{ reg.status.name }}</span>{% endif %}
</td>
<td style="padding:0.75rem 1rem; color:var(--color-muted-foreground);">
{% if reg.cert_expires_at %}{{ reg.cert_expires_at|date:"d.m.Y" }}{% else %}—{% endif %}
</td>
<td style="padding:0.75rem 1rem; text-align:right;">
{% if is_staff %}
<a href="/admin/rro/cashregister/{{ reg.pk }}/change/" target="_blank"
style="font-size:0.75rem; color:var(--color-primary); text-decoration:none;">{% trans "Изменить" %}</a>
{% endif %}
</td>
</tr>
{% empty %}
<tr>
<td colspan="7" style="padding:2rem; text-align:center; color:var(--color-muted-foreground);">
{% trans "Кассовые аппараты не найдены" %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>