""" Template schemi precompilati per bandi noti. RE-START: il bando del xlsx di Cecilia, base per la prima iterazione. v2 (2026-04-18): schema_version=2, max_tranches, custom_checks[] """ RESTART_TEMPLATE = { "version": "2.0", "schema_version": 2, "template_id": "RESTART_V2", "template_label": "RE-START (fondo prestiti con remissione del debito)", "sections": [ { "type": "static_fields", "id": "general", "label": "Dati generali", "description": "Regime IVA, dati base del beneficiario, periodo di ammissibilità delle spese.", "fields": [ { "id": "period_start_date", "type": "date", "label": "Periodo ammissibilità — Data inizio", "description": "Data minima di emissione/pagamento fatture ammissibili. Di norma: data erogazione del finanziamento.", "editable_by": "superadmin", "required": True }, { "id": "period_end_date", "type": "date", "label": "Periodo ammissibilità — Data fine", "description": "Data massima di emissione/pagamento fatture ammissibili.", "editable_by": "superadmin", "required": True }, { "id": "iva_regime", "type": "select", "label": "Regime IVA", "required": True, "options": [ {"value": "ORDINARIO", "label": "Ordinario — IVA non ammissibile"}, {"value": "FORFETTARIO", "label": "Forfettario — IVA ammissibile"}, {"value": "ESENTE", "label": "Esente"}, ], "help": "Il regime IVA determina se l'IVA delle fatture è rendicontabile. In regime ordinario vale solo l'imponibile.", } ], }, { "type": "category_grid", "id": "expenses", "label": "Spese ammissibili per categoria", "description": "Carica le fatture dentro la categoria appropriata. Totali parziali e complessivo calcolati in tempo reale.", "categories": [ { "code": "B1", "label": "Tecnologie innovative (Industry 4.0, digitale)", "description": "Hardware, software, soluzioni innovative destinate ad attività produttive", "cap_amount": None, }, { "code": "B2", "label": "Incremento ULA (occupazione)", "description": "Costi del personale collegati a incremento di occupazione", "cap_amount": None, }, { "code": "B3", "label": "Formazione", "description": "Corsi, docenze, materiali didattici per il personale", "cap_amount": None, }, ], "invoice_schema": { "required_fields": [ "invoice_number", "invoice_date", "payment_date", "supplier_name", "supplier_vat", "description", "taxable", "vat", "total", "pdf", ], "optional_fields": ["vat_rate", "vat_exempt_reason"], }, }, { "type": "ula_block", "id": "ula", "label": "Calcolo ULA (incremento occupazione)", "description": "Per ogni dipendente: codice fiscale, tipologia contratto, percentuale di tempo, periodo. Allegato di supporto obbligatorio (LUL, estratto gestionale, dichiarazione del consulente del lavoro).", "enabled": True, "threshold": 1.0, "period_start_rule": "erogato_date", "period_end": "2021-12-31", "supporting_doc_required": True, "supporting_doc_types": [ {"code": "LUL", "label": "Libro Unico del Lavoro"}, {"code": "GESTIONALE_PAGHE", "label": "Estratto gestionale paghe"}, {"code": "DICHIARAZIONE_CDL", "label": "Dichiarazione Consulente del Lavoro"}, {"code": "ALTRO", "label": "Altro documento di supporto"}, ], }, { "type": "document_checklist", "id": "docs", "label": "Documenti richiesti", "description": "I documenti già in regola nel repository della Company saranno riutilizzati (semaforo verde). Solo quelli scaduti o mancanti richiedono caricamento.", "required_types": [ {"code": "DURC", "label": "DURC (Documento Unico di Regolarità Contributiva)"}, {"code": "VISURA_CAMERALE", "label": "Visura camerale aggiornata"}, {"code": "BILANCIO", "label": "Bilancio ultimo esercizio"}, {"code": "ANTIRICICLAGGIO", "label": "Dichiarazione antiriciclaggio"}, ], }, ], "custom_checks": [ { "code": "antiriciclaggio", "label": "Dichiarazione antiriciclaggio", "description": "Dichiaro che il beneficiario rispetta la normativa antiriciclaggio (D.Lgs. 231/2007 e s.m.i.) e che i soggetti coinvolti non sono iscritti in liste sanzionatorie.", "requires_document": False, "required": True, }, { "code": "polizza_fidejussoria", "label": "Polizza fidejussoria", "description": "Allegare copia della polizza fidejussoria a garanzia dell'importo erogato (se richiesta da bando).", "requires_document": True, "required": False, }, ], "gate_rules": { "amount_range": {"min": 5000, "max": 25000}, "cap_pct_erogato": 0.5, "cap_absolute": 12500, "iva_ordinario_imponibile_only": True, "period_start_rule": "erogato_date", "period_end": "2021-12-31", "require_at_least_one_invoice_per_nonzero_category": True, "require_ula_above_threshold": True, "require_all_documents_resolved": True, "max_tranches": 2, # v2: superadmin configurabile, default 1 }, } def upgrade_schema_to_v2(schema_json: dict) -> dict: """Upgrade in-place di schema v1 a v2. - Aggiunge schema_version=2 se mancante - Aggiunge gate_rules.max_tranches=1 se mancante - Aggiunge custom_checks=[] se mancante - Assicura ula_section.enabled presente (default True se ula_block esiste) Idempotente: se lo schema e gia v2, no-op. """ if not isinstance(schema_json, dict): return schema_json changed = False if schema_json.get("schema_version", 1) < 2: schema_json["schema_version"] = 2 changed = True gate = schema_json.setdefault("gate_rules", {}) if "max_tranches" not in gate: gate["max_tranches"] = 1 changed = True if "custom_checks" not in schema_json: schema_json["custom_checks"] = [] changed = True # ula_section.enabled esplicito for sec in schema_json.get("sections", []): if sec.get("type") == "ula_block" and "enabled" not in sec: sec["enabled"] = True changed = True return schema_json