feat(v2): verbale istruttoria PDF con tranche N/M + custom_checks + 5 voci Cecilia + storico
B6 routers/verbale.py:
- _build_context arricchito con custom_checks_merged (schema+values da RemissionCustomCheckValue)
- previous_tranches: elenco tranche APPROVED precedenti con cumulative progressivo
- max_tranches_snapshot letto dallo schema_snapshot.gate_rules.max_tranches
- filename include _t{sequence_number}.pdf
B6 templates_jinja/verbale_istruttoria.html:
- Header: 'Tranche N/M' + period_label dopo numero pratica
- Meta-grid: riga 'Tranche / fase' quando max_tranches > 1
- Nuova sezione 'Controlli aggiuntivi' (dopo verifica documenti):
tabella label, obbligatorio, dichiarato SI/NO, doc allegato SI/NO, validazione, note
- Sezione 'Storico tranches precedenti' (solo se sequence > 1):
tabella con cumulativo progressivo
- Box totali riscritto con **5 VOCI UFFICIALI CECILIA**:
(1) Importo massimo ammissibile (cap globale) + gia approvato tranche precedenti
(2) Richiesto pre-controllo = pre_check_admissible
(3) Ammesso post-controllo = remission_due
(4) Importo finanziamento erogato + tranches count/max
(5) Residuo da restituire = erogato - approvato_prec - ammesso
- Box 'REMISSIONE APPROVATA PER QUESTA TRANCHE' evidenziato quando APPROVED
Test E2E: verbale T1 APPROVED 29.3KB con tutte sezioni presenti.
Verbale T2 simulata con storico T1 e cap tranche 2 correttamente calcolato.
This commit is contained in:
@@ -182,7 +182,8 @@
|
||||
<div class="hdr__right">
|
||||
<div><strong>Verbale di istruttoria</strong></div>
|
||||
<div>Rendicontazione bando</div>
|
||||
<div>Pratica n. {{ practice.application_id }}</div>
|
||||
<div>Pratica n. {{ practice.application_id }}{% if max_tranches_snapshot > 1 or practice.sequence_number > 1 %} — Tranche {{ practice.sequence_number }}/{{ max_tranches_snapshot }}{% endif %}</div>
|
||||
{% if practice.period_label %}<div><small>{{ practice.period_label }}</small></div>{% endif %}
|
||||
</div>
|
||||
<div>
|
||||
<span class="hdr__logo">GEPAFIN</span>
|
||||
@@ -237,6 +238,15 @@
|
||||
{% else %}—{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% if max_tranches_snapshot > 1 %}
|
||||
<div class="row">
|
||||
<div class="cell label">Tranche / fase</div>
|
||||
<div class="cell val">
|
||||
<strong>Tranche {{ practice.sequence_number }} di {{ max_tranches_snapshot }}</strong>
|
||||
{% if practice.period_label %} — {{ practice.period_label }}{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="row">
|
||||
<div class="cell label">Data presentazione</div>
|
||||
<div class="cell val">{{ practice.submitted_at|datetimefmt if practice.submitted_at else '—' }}</div>
|
||||
@@ -387,6 +397,45 @@
|
||||
<p class="text-secondary">Nessun documento richiesto dallo schema del bando.</p>
|
||||
{% endif %}
|
||||
|
||||
{# ============ CONTROLLI AGGIUNTIVI ============ #}
|
||||
{% if custom_checks_merged %}
|
||||
<h2>Controlli aggiuntivi (dichiarazioni beneficiario)</h2>
|
||||
<table class="data">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="width:32%">Controllo</th>
|
||||
<th style="width:12%">Obbligatorio</th>
|
||||
<th style="width:10%">Dichiarato</th>
|
||||
<th style="width:11%">Doc. allegato</th>
|
||||
<th style="width:11%">Validazione</th>
|
||||
<th style="width:24%">Note istruttore</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for cc in custom_checks_merged %}
|
||||
{% set stat = cc.verification_status or 'PENDING' %}
|
||||
{% set cls = 'rejected' if stat == 'NON_VALIDO' else '' %}
|
||||
{% set missing = cc.required and not cc.beneficiary_declared %}
|
||||
<tr class="{{ 'rejected' if missing else cls }}">
|
||||
<td>
|
||||
<strong>{{ cc.label or cc.code }}</strong>
|
||||
{% if cc.description %}<br><small>{{ cc.description|truncate(180) }}</small>{% endif %}
|
||||
</td>
|
||||
<td>{% if cc.required %}<span class="ko">SÌ</span>{% else %}<small class="text-secondary">opzionale</small>{% endif %}</td>
|
||||
<td>{% if cc.beneficiary_declared %}<span class="ok">SÌ</span>{% else %}<span class="ko">NO</span>{% endif %}</td>
|
||||
<td>
|
||||
{% if cc.requires_document %}
|
||||
{% if cc.has_document %}<span class="ok">SÌ</span>{% else %}<span class="ko">NO</span>{% endif %}
|
||||
{% else %}<small class="text-secondary">non richiesto</small>{% endif %}
|
||||
</td>
|
||||
<td><span class="status-inline status-{{ stat }}">{{ stat }}</span></td>
|
||||
<td>{{ cc.verification_notes or '—' }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
{% endif %}
|
||||
|
||||
{# ============ SOCCORSI ============ #}
|
||||
{% if amendments %}
|
||||
<h2>Soccorso istruttorio</h2>
|
||||
@@ -406,43 +455,94 @@
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
{# ============ TOTALI ============ #}
|
||||
<h2>Riepilogo finanziario</h2>
|
||||
{# ============ STORICO TRANCHES PRECEDENTI ============ #}
|
||||
{% if previous_tranches %}
|
||||
<h2>Storico tranches precedenti</h2>
|
||||
<table class="data">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="width:8%">#</th>
|
||||
<th style="width:35%">Periodo / fase</th>
|
||||
<th style="width:17%">Data approvazione</th>
|
||||
<th style="width:20%" class="num">Importo ammesso</th>
|
||||
<th style="width:20%" class="num">Cumulativo</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for t in previous_tranches %}
|
||||
<tr>
|
||||
<td><strong>T{{ t.sequence_number }}</strong></td>
|
||||
<td>{{ t.period_label or '—' }}</td>
|
||||
<td>{{ t.reviewed_at|datefmt }}</td>
|
||||
<td class="num">{{ t.approved_remission|euro }}</td>
|
||||
<td class="num"><strong>{{ t.cumulative|euro }}</strong></td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
{% endif %}
|
||||
|
||||
{# ============ 5 VOCI UFFICIALI CECILIA ============ #}
|
||||
<h2>Riepilogo finanziario (cap tranche {{ practice.sequence_number }})</h2>
|
||||
|
||||
<div class="totals-summary">
|
||||
<div class="row">
|
||||
<div class="cell">
|
||||
<div class="lbl">Totale dichiarato</div>
|
||||
<div class="val">{{ totals.grand_total_declared|euro }}</div>
|
||||
<div class="cell" style="width:50%">
|
||||
<div class="lbl">(1) Importo massimo ammissibile (cap globale)</div>
|
||||
<div class="val">{{ totals.max_remission_global|euro }}</div>
|
||||
{% if totals.already_approved_previous_tranches > 0 %}
|
||||
<div class="lbl" style="margin-top:4pt">già approvato nelle tranche precedenti</div>
|
||||
<div style="font-size:10pt; font-weight:700; color:#744210">− {{ totals.already_approved_previous_tranches|euro }}</div>
|
||||
<div class="lbl" style="margin-top:4pt">max. disponibile per questa tranche</div>
|
||||
<div style="font-size:11pt; font-weight:700; color:#2b6cb0">= {{ totals.max_remission_this_tranche|euro }}</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="cell">
|
||||
<div class="lbl">Totale ammesso</div>
|
||||
<div class="val">{{ totals.grand_total_verified|euro }}</div>
|
||||
</div>
|
||||
<div class="cell">
|
||||
<div class="lbl">Cap remissione</div>
|
||||
<div class="val">{{ totals.max_remission|euro }}</div>
|
||||
</div>
|
||||
<div class="cell">
|
||||
<div class="lbl">Remissione spettante</div>
|
||||
<div class="val final">{{ totals.remission_due|euro }}</div>
|
||||
<div class="cell" style="width:50%">
|
||||
<div class="lbl">(4) Importo finanziamento erogato</div>
|
||||
<div class="val">{{ totals.amount_erogato|euro }}</div>
|
||||
<div class="lbl" style="margin-top:6pt">tranches complessive</div>
|
||||
<div style="font-size:10pt">{{ totals.tranches_count }} / {{ totals.tranches_max }}</div>
|
||||
</div>
|
||||
</div>
|
||||
{% if practice.status == 'APPROVED' %}
|
||||
<div class="row">
|
||||
<div class="cell" style="background: #f0fff4;">
|
||||
<div class="lbl">Remissione approvata</div>
|
||||
<div class="val" style="color: #22543d;">{{ practice.approved_remission|euro }}</div>
|
||||
</div>
|
||||
<div class="cell" style="background: #fff5f5;">
|
||||
<div class="lbl">Residuo da restituire</div>
|
||||
<div class="val residuo">{{ (practice.amount_erogato - (practice.approved_remission or 0))|euro }}</div>
|
||||
</div>
|
||||
<div class="cell" colspan="2"></div>
|
||||
<div class="cell"></div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<div class="totals-summary" style="margin-top:8pt">
|
||||
<div class="row">
|
||||
<div class="cell" style="width:33%">
|
||||
<div class="lbl">(2) Richiesto pre-controllo (ammissibile)</div>
|
||||
<div class="val">{{ totals.pre_check_admissible|euro }}</div>
|
||||
<div class="lbl" style="margin-top:4pt">dichiarato tranche</div>
|
||||
<div style="font-size:9pt">{{ totals.grand_total_declared|euro }}</div>
|
||||
</div>
|
||||
<div class="cell" style="width:33%">
|
||||
<div class="lbl">(3) Ammesso post-controllo istruttore</div>
|
||||
<div class="val final">{{ totals.remission_due|euro }}</div>
|
||||
{% if totals.any_verified %}
|
||||
<div class="lbl" style="margin-top:4pt">verificato tranche</div>
|
||||
<div style="font-size:9pt">{{ totals.grand_total_verified|euro }}</div>
|
||||
{% else %}
|
||||
<div class="lbl" style="margin-top:4pt"><em>in attesa di verifica istruttore</em></div>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="cell" style="width:34%; background:#fff5f5">
|
||||
<div class="lbl">(5) Residuo da restituire</div>
|
||||
<div class="val residuo">{{ totals.residuo_da_restituire|euro }}</div>
|
||||
<div class="lbl" style="margin-top:4pt">= erogato − approvato precedente − ammesso tranche</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% if practice.status == 'APPROVED' %}
|
||||
<div class="totals-summary" style="margin-top:8pt; background:#f0fff4; border-color:#68d391">
|
||||
<div class="row">
|
||||
<div class="cell" style="width:100%">
|
||||
<div class="lbl">REMISSIONE APPROVATA PER QUESTA TRANCHE</div>
|
||||
<div class="val" style="color:#22543d; font-size:18pt">{{ practice.approved_remission|euro }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{# ============ CHECKLIST + NOTE ============ #}
|
||||
{% set checklist = practice.instructor_checklist or {} %}
|
||||
{% if checklist %}
|
||||
|
||||
Reference in New Issue
Block a user