Logiche tecniche
Questa sezione descrive come funziona il sistema di fatturazione, dalla creazione della fattura all'invio al Sistema di Interscambio.
🧠 Concetti chiave
Il modulo fatture si basa su un'architettura a servizi con pattern adapter per i driver SDI.
Servizi principali
- InvInvoiceCrudService: operazioni CRUD sulle fatture
- InvInvoiceService: logiche di business (calcoli, validazioni)
- InvSdiService: comunicazione con il Sistema di Interscambio
- InvXmlService: generazione e parsing XML
Driver SDI
Il sistema supporta diversi provider SDI tramite il pattern adapter:
- Ogni driver implementa l'interfaccia
SdiInterface - Il driver attivo è configurato in
config/invoice.php - Acube API è il driver di default
⚙️ Flusso di creazione fattura
1. Creazione base
$invoiceDto = new InvEntityDto([...]);
$invoice = $crudService->store($invoiceDto);
2. Associazione contatti
I contatti (mittente/destinatario) vengono creati come InvoiceContact:
- Possono derivare da entità esistenti (
model_type,model_id) - Contengono tutti i dati fiscali necessari per l'XML
3. Aggiunta righe
Le righe vengono create con InvInvoiceRowCrudService:
- Ogni riga ha un
row_numberprogressivo - Le righe di tipo
is_headerraggruppano altre righe - Le righe
is_sub_totalcontengono subtotali
4. Ricalcolo totali
Dopo ogni modifica vengono ricalcolati automaticamente:
$invoice->recalculateTotals(); // Totali fattura
$invoice->recalculateVatSummary(); // Riepilogo IVA
$invoice->recalculateHeaderTotals(); // Totali intestazioni
🔄 Flusso di invio al SDI
1. Preparazione
Prima dell'invio:
- Verifica
completion_status === 'complete' - Validazione XML contro schema XSD
2. Invio tramite driver
$sdiService = new InvSdiService();
$response = $sdiService->send($invoiceShowDto);
Il driver configurato:
- Trasforma i dati nel formato richiesto dal provider
- Invia la richiesta all'API del provider
- Restituisce
InvSdiResponseDtocon UUID e stato
3. Salvataggio identificatori
$sdiService->updateSdiIdentifier($response);
Viene creato/aggiornato il record InvSdiDriverIdentifier:
driver_uuid: UUID assegnato dal providerdriver_type: classe del driver utilizzatosdi_status: stato iniziale (tipicamenteINV)metadata['log']: array di log delle comunicazioni
4. Ricezione webhook
Il provider notifica gli aggiornamenti di stato:
public function webhook(Request $request): InvSdiResponseDto
{
$this->sdiDriver->authorizeWebhook($request);
return $this->sdiDriver->handleWebhook($request);
}
Il webhook aggiorna lo stato e aggiunge un nuovo log in metadata.
📊 Calcolo totali e riepilogo IVA
Calcolo totali
Il metodo calculateTotal() somma le righe:
public function calculateTotal(Invoice $invoice): array
{
// Esclude header e subtotali
// Calcola: total, totalGross, vatAmount
}
Riepilogo IVA
Il metodo calculateVatSummary() raggruppa per aliquota:
public function calculateVatSummary(Invoice $invoice): array
{
// Per ogni aliquota/natura restituisce:
// - taxableAmount: imponibile
// - vatRate: aliquota
// - vatNature: natura (se aliquota 0)
// - vatAmount: importo IVA
}
Il riepilogo viene salvato in additional_data['vatSummary'].
🔐 Accesso sicuro ai PDF
Il sistema genera chiavi temporanee per l'accesso ai PDF:
Generazione chiave
public function generatePdfKey(Invoice $invoice): string
{
$key = Str::uuid()->toString();
Cache::put($key, $invoice->id, now()->addMinutes(10));
return $key;
}
Verifica chiave
public function checkPdfKey(Invoice $invoice, string $key): bool
{
$invoiceId = Cache::get($key);
return $invoiceId === $invoice->id;
}
La chiave:
- È valida per 10 minuti
- Permette accesso senza autenticazione
- È monouso (viene invalidata dopo l'uso)
🏷️ Gestione badge e stati
Badge fattura
| Badge | Descrizione |
|---|---|
| FT | Fattura normale |
| FTS | Fattura stornata |
| NC | Nota di credito |
Stato completamento
| Stato | Descrizione |
|---|---|
| draft | Bozza, in fase di compilazione |
| incomplete | Dati mancanti o non validi |
| complete | Pronta per l'invio |
Stato pagamento
| Stato | Descrizione |
|---|---|
| PENDING | In attesa di pagamento |
| COMPLETED | Pagamento completato |
| PARTIAL | Pagamento parziale |
| NOT_DUE | Pagamento non dovuto |
| AUTHORIZED | Pagamento autorizzato |
🔧 Configurazione driver SDI
Il driver SDI è configurato in config/invoice.php:
return [
'sdi' => [
'driver' => env('SDI_DRIVER', AcubeSdiDriver::class),
],
];
Implementazione driver
Ogni driver deve implementare SdiInterface:
interface SdiInterface
{
public function send(InvEntityShowDto $invoice): InvSdiResponseDto;
public function status(string $invoiceId): JsonResponse;
public function authorizeWebhook(Request $request): void;
public function handleWebhook(Request $request): InvSdiResponseDto;
}