Skip to main content

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_number progressivo
  • Le righe di tipo is_header raggruppano altre righe
  • Le righe is_sub_total contengono 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:

  1. Trasforma i dati nel formato richiesto dal provider
  2. Invia la richiesta all'API del provider
  3. Restituisce InvSdiResponseDto con UUID e stato

3. Salvataggio identificatori

$sdiService->updateSdiIdentifier($response);

Viene creato/aggiornato il record InvSdiDriverIdentifier:

  • driver_uuid: UUID assegnato dal provider
  • driver_type: classe del driver utilizzato
  • sdi_status: stato iniziale (tipicamente INV)
  • 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

BadgeDescrizione
FTFattura normale
FTSFattura stornata
NCNota di credito

Stato completamento

StatoDescrizione
draftBozza, in fase di compilazione
incompleteDati mancanti o non validi
completePronta per l'invio

Stato pagamento

StatoDescrizione
PENDINGIn attesa di pagamento
COMPLETEDPagamento completato
PARTIALPagamento parziale
NOT_DUEPagamento non dovuto
AUTHORIZEDPagamento 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;
}