Passa al contenuto principale

Dominio inv β€” Panoramica sviluppatore

🎯 Cosa fa​

Il dominio inv gestisce la fatturazione elettronica FatturaPA: emissione, trasmissione via Aruba al Sistema di Interscambio, tracciamento stati, piano rate e convenzioni commerciali.

πŸ—ΊοΈ Mappa moduli​

Database β€” TrainingHub.Database/inv/​

FileRuolo
Tables/issuers.sqlEmittenti (cedente/prestatore + credenziali Aruba)
Tables/bankAccounts.sqlAnagrafica conti bancari per emittente
Tables/invoices.sqlIntestazione fattura
Tables/invoiceLines.sqlRighe di dettaglio
Tables/invoicePayments.sqlPiano rate
Tables/invoiceAppointments.sqlAssociazione N:N fattura ↔ appuntamenti formativi
Tables/invoiceStatusHistory.sqlStorico cambi di stato
Tables/conventions.sqlConvenzioni (sconto per categoria corso)
Tables/companyConventions.sqlAssociazione N:N azienda ↔ convenzione
Tables/vatCodes.sqlCodici IVA riutilizzabili
Tables/paymentMethods.sqlLookup codici metodo pagamento SDI (MP01–MP23)
Tables/documentTypes.sqlLookup codici tipo documento SDI (TD01–TD28)
Tables/invoiceCounters.sqlNumerazioni progressive per (issuerId, documentTypeCode, year)
Tables/invoiceDocuments.sqlAllegati della fattura
Tables/reminders.sqlPromemoria fatturabili (sorgente di riga)
Tables/companyPaymentTerms.sqlPiani di pagamento per azienda, con default globale (companyId IS NULL)
Functions/fn_activeConventions.sqlTVF: convenzioni attive per (companyId, issueDate)
Views/vw_invoicesData.sqlVista dati fatture (CRUD generato)
Views/vw_billableItems.sql, vw_billableAppointments.sql, vw_billableReminders.sqlIl fatturabile, con pagine dedicate

In tutto: 16 tabelle, 4 viste e 1 funzione.

Service layer β€” TrainingHub.BackOffice/Services/Invoicing/​

23 file. I principali:

FileRuolo
IInvoiceService.cs / InvoiceService.csOrchestrazione fattura + integrazione Aruba
IInvoiceBillingService.cs / InvoiceBillingService.csRighe da appuntamenti e promemoria
IArubaSdiService.cs / ArubaSdiService.csHTTP verso Aruba, con retry
IFatturaPaXmlGenerator.cs / FatturaPaXmlGenerator.csXML FatturaPA 1.2
PaymentTermsService.cs + PaymentTermsCalculator.csPiani di pagamento
InvoiceCourtesyCopyService.csCopia di cortesia
InvoiceStatusRefreshWorker.csRefresh stati ogni 10 minuti

Elenco completo in Servizi.

UI CRUD β€” TrainingHub.BackOffice/Components/CRUD/inv/​

19 pagine CRUD auto-generate. Pattern per ciascuna:

  • <Entity>.razor + .razor.tt.cs (grid autogenerata)
  • <Entity>.razor.cs (code-behind custom)
  • Forms/<Entity>Form.razor + .razor.cs + .razor.tt.cs
  • FormPopups/<Entity>FormPopup.razor + .razor.cs + .razor.tt.cs

EntitΓ  presenti:

  • Invoice (con wizard a 5 step in FormPopups/InvoiceFormPopup.razor + i partial InvoiceFormPopup.razor.Step*.cs)
  • InvoiceLine, InvoicePayment, InvoiceAppointment, InvoiceStatusHistory, InvoiceDocument, InvoiceCounter
  • Reminder, CompanyPaymentTerm
  • Issuer, VatCode, PaymentMethod, DocumentType
  • BankAccount
  • Convention, CompanyConvention
  • Generati su vista: InvoicesData, BillableItem, BillableAppointment, BillableReminder

Configurazione CRUD β€” _conf/*.dxgrid.conf.json​

Un file JSON per entitΓ  che guida la generazione. Modificare qui per cambi persistenti; i file .razor e .razor.tt.cs vengono rigenerati dal tool MCP 3sd-generator.

Test β€” TrainingHub.UnitTests/Services/Invoicing/​

21 file di test sull'area. Fra i principali: InvoiceServiceTests.cs (numerazione, invio, storico, piano rate), InvoiceStatusExtensionsTests.cs (mapping notifiche SDI), ArubaSdiServiceRetryTests.cs e ArubaSdiServiceRateLimitTests.cs (retry e 429), PaymentTermsServiceTests.cs, InvoiceCourtesyCopyServiceTests.cs, InvoiceStatusRefreshWorkerTests.cs.

πŸ”§ API pubblica β€” IInvoiceService​

Task<invoice> AssignNumberAsync(Guid invoiceId, CancellationToken ct);
Task<string> GeneratePreviewXmlAsync(Guid invoiceId, CancellationToken ct = default);
Task SendToArubaAsync(Guid invoiceId, CancellationToken ct);
Task RefreshStatusFromArubaAsync(Guid invoiceId, CancellationToken ct);
Task AddStatusHistoryAsync(Guid invoiceId, InvoiceStatus status, string? arubaStatus, string? notes, string? createdBy, CancellationToken ct);
Task<IEnumerable<invoiceStatusHistory>> GetStatusHistoryAsync(Guid invoiceId, CancellationToken ct);
Task<IEnumerable<invoicePayment>> GetPaymentsAsync(Guid invoiceId, CancellationToken ct);
Task SavePaymentsAsync(Guid invoiceId, IEnumerable<invoicePayment> payments, CancellationToken ct);

Registrato in Program.cs nella sezione DI.

🧩 Pattern chiave​

Wizard fattura​

Il form di edit della fattura Γ¨ un wizard a 5 step realizzato in FormPopups/InvoiceFormPopup.razor + .razor.cs, usando Tabiot.Blazor.Wizard.Wizard. Sequenza step e hook OnStepChange:

StepFormIdTitoloHook
1invoice_dataDati fatturaSaveInvoiceDraft
2invoice_linesRighe fatturasorgenti di fatturazione aggiunte da popup (appuntamenti, promemoria)
3paymentsPagamentiSavePayments (valida somma = 100%)
4summaryRiepilogoLoadSummary (totali + storico + pulsanti SDI)
5documentsDocumentiallegati della fattura

Generazione CRUD​

I file .razor e .razor.tt.cs sono rigenerati dal tool MCP 3sd-generator a partire dallo schema DB e dal conf.json. Modifiche dirette in questi file vanno perse alla rigenerazione: per rendere persistenti le modifiche aggiornare il conf.json e rigenerare.

Il code-behind .razor.cs contiene il codice custom e non viene toccato dalla generazione.

Applicazione convenzioni​

Al momento dell'emissione fattura, CreateLinesFromAppointments (in InvoiceFormPopup.razor.cs) usa inv.fn_activeConventions(companyId, issueDate) per recuperare lo sconto attivo e pre-popolare la riga con il discountPercentage corretto.

Numerazione​

La bozza non Γ¨ numerata. All'emissione (SendToArubaAsync), AssignNumberAsync incrementa in transazione il contatore inv.invoiceCounters della serie (issuerId, documentTypeCode, year) β€” serie dedicata al tipo documento se esiste, altrimenti la serie di default (documentTypeCode NULL) condivisa da tutti i tipi. Il code Γ¨ generato con un template Handlebars (templatingExpression, default {{year}}/{{progressive}}); roll-over annuale con terminated, retry su collisione. L'unicitΓ  (issuerId, documentTypeCode, invoiceYear, invoiceNumber) Γ¨ garantita dall'indice filtrato UQ_invoices_number (WHERE invoiceNumber IS NOT NULL).

πŸ“¦ Dipendenze​

  • Brighela.SimpleCRUD.Service.ISimpleCRUDService β€” CRUD di base
  • Oss.Filters β€” filtri su grid
  • Tabiot.Blazor.* β€” wizard, grid, popup, combo
  • DevExpress.Blazor β€” componenti UI
  • Microsoft.Extensions.Localization.IStringLocalizer<T> β€” etichette localizzate
  • Ecosistema 3SD: Scarnas, Brighela, Servel, Ploc, Tabiot, Mulet

⚠️ Domande aperte / debito tecnico​

  • Credenziali Aruba in chiaro. inv.issuers.arubaPassword Γ¨ memorizzata in chiaro. Decisione esplicita a design (back-office interno), ma valutare cifratura simmetrica con chiave da config per compliance futura.
  • Job schedulato di refresh stato fatture inviate. Consegnato. Services/Invoicing/InvoiceStatusRefreshWorker.cs Γ¨ un BackgroundService con Interval = TimeSpan.FromMinutes(10), registrato in Program.cs:133 (AddHostedService<…>()) e governato dal gate di configurazione InvoiceStatusRefresh:Enabled. Il refresh manuale via pulsante resta come scorciatoia.

πŸ”— Vedi anche​