0da9c13192
Иерархия рамочных/дочерних договоров и платежей, интернет-биллинг, месячные IT-отчёты (импорт, DOCX/PDF, шаблоны выводов). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
155 lines
12 KiB
HTML
155 lines
12 KiB
HTML
{% load i18n %}
|
||
<div id="internet-billing-panel">
|
||
|
||
{% if billing_form_message %}
|
||
<div style="margin-bottom:1rem; padding:0.75rem 1rem; border-radius:0.5rem; border:1px solid hsl(152 40% 70%); background:color-mix(in srgb, var(--color-success) 12%, var(--color-card)); color:var(--color-foreground); font-size:0.875rem;">
|
||
{{ billing_form_message }}
|
||
</div>
|
||
{% endif %}
|
||
{% if billing_form_error %}
|
||
<div style="margin-bottom:1rem; padding:0.75rem 1rem; border-radius:0.5rem; background:hsl(0 70% 96%); border:1px solid hsl(0 70% 85%); color:hsl(0 55% 35%); font-size:0.8125rem;">
|
||
{{ billing_form_error }}
|
||
</div>
|
||
{% endif %}
|
||
|
||
<div style="display:flex; align-items:center; justify-content:space-between; margin-bottom:1rem; flex-wrap:wrap; gap:0.75rem;">
|
||
<div style="display:flex; align-items:center; gap:0.5rem;">
|
||
<a href="#" class="btn btn-ghost btn-icon"
|
||
{% if accounting_embed %}hx-get="{{ accounting_base_url }}&month={{ billing_prev_month }}{% if billing_filter_provider %}&provider={{ billing_filter_provider }}{% endif %}"
|
||
{% else %}hx-get="/accounting/?tab=internet&month={{ billing_prev_month }}"{% endif %}
|
||
hx-target="#main-content" hx-push-url="true" hx-indicator="#loader">
|
||
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="15 18 9 12 15 6"/></svg>
|
||
</a>
|
||
<span style="font-size:0.9375rem; font-weight:500; color:var(--color-foreground); min-width:9rem; text-align:center;">{{ billing_period_label }}</span>
|
||
<a href="#" class="btn btn-ghost btn-icon"
|
||
{% if accounting_embed %}hx-get="{{ accounting_base_url }}&month={{ billing_next_month }}{% if billing_filter_provider %}&provider={{ billing_filter_provider }}{% endif %}"
|
||
{% else %}hx-get="/accounting/?tab=internet&month={{ billing_next_month }}"{% endif %}
|
||
hx-target="#main-content" hx-push-url="true" hx-indicator="#loader">
|
||
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="9 18 15 12 9 6"/></svg>
|
||
</a>
|
||
</div>
|
||
<form method="get"
|
||
{% if accounting_embed %}hx-get="{{ accounting_base_url }}"{% else %}hx-get="/accounting/?tab=internet"{% endif %}
|
||
hx-target="#main-content" hx-push-url="true" hx-indicator="#loader"
|
||
style="display:flex; align-items:center; gap:0.5rem;">
|
||
<input type="hidden" name="tab" value="internet">
|
||
<input type="hidden" name="month" value="{{ billing_period }}">
|
||
<select name="provider" class="input" style="min-width:14rem;" onchange="this.form.requestSubmit()">
|
||
<option value="">{% trans "Все провайдеры" %}</option>
|
||
{% for p in billing_providers %}
|
||
<option value="{{ p.pk }}" {% if billing_filter_provider == p.pk|stringformat:"s" %}selected{% endif %}>{{ p.name }}</option>
|
||
{% endfor %}
|
||
</select>
|
||
</form>
|
||
</div>
|
||
|
||
<div style="display:grid; grid-template-columns:repeat(3,minmax(0,1fr)); gap:0.75rem; margin-bottom:1.25rem;">
|
||
<div class="stat-card" style="padding:1rem 1.25rem;">
|
||
<div style="font-size:0.6875rem; color:var(--color-muted-foreground); text-transform:uppercase; letter-spacing:0.05em; margin-bottom:0.375rem;">{% trans "К оплате" %}</div>
|
||
<div style="font-size:1.375rem; font-weight:600; color:var(--color-foreground);">{{ billing_total_amount|default:"0" }} {% trans "грн" %}</div>
|
||
<div style="font-size:0.75rem; color:var(--color-muted-foreground); margin-top:0.25rem;">{{ billing_contract_count }} {% trans "договоров" %}</div>
|
||
</div>
|
||
<div class="stat-card" style="padding:1rem 1.25rem;">
|
||
<div style="font-size:0.6875rem; color:var(--color-muted-foreground); text-transform:uppercase; letter-spacing:0.05em; margin-bottom:0.375rem;">{% trans "Оплачено" %}</div>
|
||
<div style="font-size:1.375rem; font-weight:600; color:var(--color-success);">{{ billing_paid_amount|default:"0" }} {% trans "грн" %}</div>
|
||
<div style="font-size:0.75rem; color:var(--color-muted-foreground); margin-top:0.25rem;">{{ billing_paid_count }} {% trans "договоров" %}</div>
|
||
</div>
|
||
<div class="stat-card" style="padding:1rem 1.25rem;">
|
||
<div style="font-size:0.6875rem; color:var(--color-muted-foreground); text-transform:uppercase; letter-spacing:0.05em; margin-bottom:0.375rem;">{% trans "Не оплачено" %}</div>
|
||
<div style="font-size:1.375rem; font-weight:600; color:{% if billing_unpaid_count %}var(--color-destructive){% else %}var(--color-foreground){% endif %};">{{ billing_unpaid_count }}</div>
|
||
<div style="font-size:0.75rem; color:var(--color-muted-foreground); margin-top:0.25rem;">{% trans "договоров" %}</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div style="background:var(--color-card); border-radius:0.75rem; border:1px solid var(--color-border); box-shadow:0 1px 2px rgb(0 0 0/0.05); overflow:hidden;">
|
||
<div style="overflow-x:auto;">
|
||
<table style="width:100%; border-collapse:collapse; font-size:0.875rem;">
|
||
<thead>
|
||
<tr style="border-bottom:1px solid var(--color-border);">
|
||
<th style="padding:0.75rem 1rem; text-align:left; color:var(--color-muted-foreground); font-weight:600; font-size:0.8125rem;">{% trans "Договор / локация" %}</th>
|
||
<th style="padding:0.75rem 1rem; text-align:left; color:var(--color-muted-foreground); font-weight:600; font-size:0.8125rem;">{% trans "Провайдер" %}</th>
|
||
<th style="padding:0.75rem 1rem; text-align:right; color:var(--color-muted-foreground); font-weight:600; font-size:0.8125rem;">{% trans "Сумма" %}</th>
|
||
<th style="padding:0.75rem 1rem; text-align:center; color:var(--color-muted-foreground); font-weight:600; font-size:0.8125rem;">{% trans "Статус" %}</th>
|
||
<th style="padding:0.75rem 1rem; text-align:left; color:var(--color-muted-foreground); font-weight:600; font-size:0.8125rem;">{% trans "Счёт" %}</th>
|
||
<th style="padding:0.75rem 1rem; text-align:right; color:var(--color-muted-foreground); font-weight:600; font-size:0.8125rem;"></th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
{% for row in billing_rows %}
|
||
{% if row.is_provider_header %}
|
||
<tr style="background:color-mix(in srgb, var(--color-muted) 65%, var(--color-card)); border-bottom:1px solid var(--color-border);">
|
||
<td colspan="6" style="padding:0.625rem 1rem; font-size:0.8125rem; font-weight:600; color:var(--color-foreground); letter-spacing:0.02em;">
|
||
{{ row.provider.name }}
|
||
</td>
|
||
</tr>
|
||
{% else %}
|
||
{% with c=row.contract %}
|
||
<tr style="border-bottom:1px solid var(--color-border);{% if row.is_paid %} background:color-mix(in srgb, var(--color-success) 6%, transparent);{% elif row.is_framework %} background:color-mix(in srgb, var(--color-muted) 35%, transparent);{% elif row.indent %} background:color-mix(in srgb, var(--color-muted) 18%, transparent);{% endif %}">
|
||
<td style="padding:0.75rem 1rem; color:var(--color-foreground);">
|
||
<div style="display:flex; align-items:flex-start; gap:0.5rem; padding-left:{{ row.indent_rem }}rem;">
|
||
{% if row.indent %}
|
||
<span style="flex:none; width:1rem; color:var(--color-muted-foreground); font-size:0.875rem; line-height:1.35;">└</span>
|
||
{% elif row.is_framework and row.has_children %}
|
||
<span style="flex:none; width:1rem; color:var(--color-primary); font-size:0.75rem; line-height:1.5;">▾</span>
|
||
{% else %}
|
||
<span style="flex:none; width:1rem;"></span>
|
||
{% endif %}
|
||
<div style="min-width:0;{% if row.indent %} border-left:2px solid color-mix(in srgb, var(--color-border) 80%, var(--color-primary)); padding-left:0.75rem;{% endif %}">
|
||
{% if row.is_framework %}
|
||
<span class="badge badge-info" style="font-size:0.6875rem; margin-right:0.35rem;">{% trans "Общий" %}</span>
|
||
{% endif %}
|
||
<strong>№{{ c.contract_number }}</strong>
|
||
<div style="font-size:0.75rem; color:var(--color-muted-foreground); margin-top:0.125rem;">{{ c.location_display }}</div>
|
||
{% if row.has_children %}
|
||
<div style="font-size:0.6875rem; color:var(--color-muted-foreground); margin-top:0.2rem;">{% trans "группа договоров" %}</div>
|
||
{% endif %}
|
||
</div>
|
||
</div>
|
||
</td>
|
||
<td style="padding:0.75rem 1rem; color:var(--color-muted-foreground);">
|
||
{% if row.indent %}—{% else %}{{ c.provider.name }}{% endif %}
|
||
</td>
|
||
<td style="padding:0.75rem 1rem; text-align:right; color:var(--color-foreground); font-weight:500;">
|
||
{{ row.amount|default:"—" }}{% if row.amount %} {% trans "грн" %}{% endif %}
|
||
</td>
|
||
<td style="padding:0.75rem 1rem; text-align:center;">
|
||
{% if row.is_paid %}
|
||
<span class="badge badge-success">{% trans "Оплачено" %}</span>
|
||
{% if row.payment.paid_at %}
|
||
<div style="font-size:0.6875rem; color:var(--color-muted-foreground); margin-top:0.125rem;">{{ row.payment.paid_at|date:"d.m.Y" }}</div>
|
||
{% endif %}
|
||
{% else %}
|
||
<span class="badge badge-warning">{% trans "Не оплачено" %}</span>
|
||
{% endif %}
|
||
</td>
|
||
<td style="padding:0.75rem 1rem; color:var(--color-muted-foreground); font-size:0.8125rem;">
|
||
{{ row.payment.invoice_number|default:"—" }}
|
||
</td>
|
||
<td style="padding:0.75rem 1rem; text-align:right;">
|
||
<form method="post" action="/accounting/internet-payment/" hx-post="/accounting/internet-payment/" hx-target="#main-content" hx-indicator="#loader" style="display:inline-flex; gap:0.35rem; align-items:center; margin:0;">
|
||
{% csrf_token %}
|
||
<input type="hidden" name="month" value="{{ billing_period }}">
|
||
<input type="hidden" name="contract_id" value="{{ c.pk }}">
|
||
<input type="hidden" name="action" value="{% if row.is_paid %}mark_unpaid{% else %}mark_paid{% endif %}">
|
||
{% if billing_filter_provider %}<input type="hidden" name="provider" value="{{ billing_filter_provider }}">{% endif %}
|
||
<button type="submit" class="btn {% if row.is_paid %}btn-secondary{% else %}btn-primary{% endif %}" style="font-size:0.75rem; padding:0.35rem 0.65rem;">
|
||
{% if row.is_paid %}{% trans "Снять оплату" %}{% else %}{% trans "Отметить оплату" %}{% endif %}
|
||
</button>
|
||
</form>
|
||
</td>
|
||
</tr>
|
||
{% endwith %}
|
||
{% endif %}
|
||
{% empty %}
|
||
<tr>
|
||
<td colspan="6" style="padding:2rem; text-align:center; color:var(--color-muted-foreground);">
|
||
{% trans "Нет активных договоров для учёта оплат." %}
|
||
</td>
|
||
</tr>
|
||
{% endfor %}
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
</div>
|