Schema DB inv
π― Cosa faβ
Definisce il persistence layer della fatturazione: 11 tabelle e 1 funzione
nel schema inv del progetto TrainingHub.Database. Deploy tramite
DACPAC via pipeline Azure.
πΊοΈ Tabelleβ
| Tabella | Ruolo |
|---|---|
inv.issuers | Emittente fattura (cedente/prestatore) con credenziali Aruba |
inv.invoices | Intestazione fattura |
inv.invoiceLines | Righe di dettaglio di una fattura |
inv.invoicePayments | Piano rate di una fattura |
inv.invoiceAppointments | Associazione N:N fattura β appuntamenti formativi |
inv.invoiceStatusHistory | Storico cambi di stato di una fattura |
inv.bankAccounts | Anagrafica conti bancari per emittente |
inv.vatCodes | Codici IVA riutilizzabili (aliquota + natura) |
inv.paymentMethods | Lookup codici metodo di pagamento SDI (MP01βMP23) |
inv.documentTypes | Lookup codici tipo documento SDI (TD01βTD28) |
inv.conventions | Convenzioni commerciali (sconto per categoria corso) |
inv.companyConventions | Associazione N:N azienda β convenzione |
π Relazioniβ
Referenze esterne: reg.companies, reg.organizers, edu.categories,
edu.appointments.
ποΈ Dettaglio tabelleβ
inv.issuersβ
Emittente fattura. Una ragione sociale 3SD con credenziali Aruba dedicate.
- PK:
id(GUID, defaultnewid()) - FK:
organizerSlug β reg.organizers(slug) - Campi chiave:
companyName,vatCode,fiscalCode,address,city,zipCode,province,country(default'IT') β anagrafica legalepec,reaOffice,reaNumber,shareCapitalβ extra FatturaPAarubaUsername,arubaPassword(in chiaro),arubaEnvironment('demo'|'production', default'demo')
- Check:
CHK_issuers_arubaEnvironmentsuarubaEnvironment
inv.invoicesβ
Intestazione fattura.
- PK:
id - FK:
issuerId β inv.issuers(id),companyId β reg.companies(id),documentTypeCode β inv.documentTypes(code) - Campi chiave:
documentTypeCode(NVARCHAR(8), default'TD01') β codice SDI tipo documento (FatturaPA), es.TD01fattura,TD04nota di creditocode(es.A/2026/1),invoiceNumber(progressivo),invoiceYearissueDate,status(string, non enum DB β mappato aInvoiceStatuslato C#)taxableAmount,vatAmount,totalAmountnotes- Aruba:
arubaTransmissionId,sdiProtocolNumber,arubaStatus,arubaLastCheckAt,arubaNotificationXml,sentXmlContent - Audit:
createdAt(defaultgetdate()),updatedAt
- Unique:
UQ_invoices_number(issuerId, invoiceYear, invoiceNumber)β garantisce unicitΓ progressivo per emittente/anno
inv.invoiceLinesβ
Righe di dettaglio fattura.
- PK:
id - FK:
invoiceId β inv.invoices(id) ON DELETE CASCADE,vatCodeId β inv.vatCodes(id) - Campi chiave:
lineNumber(progressivo da 1)productServiceCode(opzionale),description,quantity,unitOfMeasure,unitPrice,discountPercentagetotalAmount(calcolato lato app:quantity * unitPrice * (1 β discount/100))
- Cascade: elimina riga se fattura eliminata
inv.invoicePaymentsβ
Piano rate di pagamento.
- PK:
id - FK:
invoiceId β inv.invoices(id) ON DELETE CASCADE,paymentMethodCode β inv.paymentMethods(code),bankAccountId β inv.bankAccounts(id)(nullable) - Campi chiave:
lineNumber,paymentMethodCode(codice SDI),paymentDueDate,paymentDate(data ricezione, nullable),bankAccountId(nullable; obbligatorio solo sepaymentMethods.ibanRequired = 1)percentage(somma rate = 100%),amount(calcolato:totalAmount * percentage / 100)
inv.invoiceAppointmentsβ
Associazione N:N tra fattura e appuntamenti formativi.
- PK composita:
(invoiceId, appointmentId) - FK:
invoiceId β inv.invoices(id) ON DELETE CASCADE,appointmentId β edu.appointments(id)
inv.invoiceStatusHistoryβ
Storico cambi di stato di una fattura.
- PK:
id - FK:
invoiceId β inv.invoices(id)(no cascade β audit trail) - Campi chiave:
status,arubaStatus(nullable),notes,createdAt(defaultgetdate()),createdBy
inv.bankAccountsβ
Anagrafica conti bancari per emittente. Riferita da
inv.invoicePayments.bankAccountId per il rendering del nodo
<IBAN> nell'XML FatturaPA.
- PK:
id - FK:
issuerId β inv.issuers(id) - Campi chiave:
label(etichetta breve),iban(NVARCHAR(64), formato SEPA/IT validato lato C# da[ItalianIban]),bankName,bic(NVARCHAR(11)),accountHolderactive(bit, default1) β soft-delete: se0il conto non Γ¨ selezionabile in nuove rate ma resta legato ai pagamenti storici
- Indice:
IX_bankAccounts_issuerId
inv.vatCodesβ
Codici IVA riutilizzabili.
- PK:
id - Campi chiave:
label,vatRate,vatNature(se aliquota = 0)
inv.paymentMethodsβ
Lookup dei codici metodo di pagamento SDI (FatturaPA, MP01βMP23).
Riferito da inv.invoicePayments.paymentMethodCode.
- PK:
code(NVARCHAR(8), es.MP05) - Campi chiave:
label(es. Bonifico),descriptionibanRequired(bit) β se1, l'IBAN diventa obbligatorio sulla rata che usa questo metodoactive(bit, default1) β flag soft-delete
- Seed:
Scripts/seed-inv-paymentMethods.sql(MERGE idempotente)
inv.documentTypesβ
Lookup dei codici tipo documento SDI (FatturaPA, TD01βTD28).
Riferito da inv.invoices.documentTypeCode.
- PK:
code(NVARCHAR(8), es.TD01) - Campi chiave:
label(es. Fattura, Nota di credito),descriptionactive(bit, default1) β flag soft-delete; i tipi non attivi non sono selezionabili in nuove fatture
- Seed:
Scripts/seed-inv-documentTypes.sql(MERGE idempotente)
inv.conventionsβ
Convenzioni commerciali.
- PK:
id - FK:
categoryId β edu.categories(id),organizerSlug β reg.organizers(slug)(entrambe nullable) - Campi chiave:
label,discountPercentagevalidFrom(default'1900-01-01'),validTo(nullable = illimitata)
inv.companyConventionsβ
Associazione N:N azienda β convenzione, con override validitΓ opzionale.
- PK:
id - FK:
companyId β reg.companies(id),conventionId β inv.conventions(id) - Unique:
UQ_companyConventions(companyId, conventionId) - Campi chiave:
validFrom,validTo(entrambi nullable;NULL= usa le date della convenzione)
π§ Funzioniβ
inv.fn_activeConventions(@companyId, @issueDate)β
TVF che restituisce le convenzioni attive per un'azienda a una data data. Verifica entrambe le validitΓ (convenzione e associazione):
SELECT c.id AS conventionId, c.categoryId, c.discountPercentage
FROM inv.conventions c
INNER JOIN inv.companyConventions cc ON cc.conventionId = c.id
WHERE cc.companyId = @companyId
AND @issueDate >= c.validFrom
AND (c.validTo IS NULL OR @issueDate <= c.validTo)
AND (cc.validFrom IS NULL OR @issueDate >= cc.validFrom)
AND (cc.validTo IS NULL OR @issueDate <= cc.validTo);
Usata da InvoiceService / wizard fattura per applicare lo sconto in
automatico.
π File chiaveβ
TrainingHub.Database/inv/Tables/*.sqlβ tabelleTrainingHub.Database/inv/Functions/fn_activeConventions.sqlβ funzione TVFTrainingHub.Database/TrainingHub.Database.sqlprojβ progetto SQL
β οΈ Debito tecnicoβ
-
invoices.statuscome stringa anzichΓ© FK a una lookup oCHECKesplicito: oggi validato solo lato C# conEnum.Parse. Valori errati scritti in DB via altri path non sono bloccati. Valutare check constraint o tabella di lookup. -
arubaPasswordin chiaro. Decisione esplicita a design (back- office interno con accesso controllato), ma da rivedere per compliance. - Indici espliciti minimi. Esiste unique su
invoices.number,companyConventions(companyId, conventionId)e index subankAccounts.issuerId. Valutare indici aggiuntivi su FK frequentemente usate in join (es.invoiceLines.invoiceId,invoicePayments.invoiceId,invoiceStatusHistory.invoiceId) se query lente emergono in profilo.