netgescon-day0/resources/views/filament/pages/contabilita/fattura-elettronica-scheda.blade.php

451 lines
28 KiB
PHP

<x-filament-panels::page>
<div class="mx-auto max-w-7xl space-y-4" x-data="{ openDocumentoModal: false }">
<x-filament.components.page-breadcrumbs
:breadcrumbs="collect($this->getBreadcrumbs())->map(fn ($url, $label) => ['label' => $label, 'url' => $url])->values()->all()"
:back-url="$this->getBackUrl()"
/>
<div class="grid grid-cols-1 gap-4 lg:grid-cols-3">
<div class="rounded-xl border border-gray-200 bg-white p-4 dark:border-gray-800 dark:bg-gray-900">
<div class="text-sm text-gray-500 dark:text-gray-400">Fattura</div>
<div class="mt-1 text-xl font-semibold">
{{ $fattura->numero_fattura }}
</div>
<dl class="mt-4 space-y-2 text-sm">
<div class="flex justify-between gap-4">
<dt class="text-gray-500 dark:text-gray-400">Data</dt>
<dd class="font-medium">{{ optional($fattura->data_fattura)->format('d/m/Y') }}</dd>
</div>
<div class="flex justify-between gap-4">
<dt class="text-gray-500 dark:text-gray-400">Scadenza</dt>
<dd class="font-medium">{{ optional($fattura->data_scadenza)->format('d/m/Y') ?: '—' }}</dd>
</div>
<div class="flex justify-between gap-4">
<dt class="text-gray-500 dark:text-gray-400">Stato</dt>
<dd class="font-medium">{{ $fattura->stato }}</dd>
</div>
@php
$modalitaLabel = $this->getPagamentoModalitaXsdLabel();
@endphp
@if(is_string($fattura->pagamento_modalita) && trim($fattura->pagamento_modalita) !== '')
<div class="flex justify-between gap-4">
<dt class="text-gray-500 dark:text-gray-400">Modalità pagamento</dt>
<dd class="font-medium text-right">
<div>{{ trim($fattura->pagamento_modalita) }}</div>
@if($modalitaLabel)
<div class="text-xs text-gray-500 dark:text-gray-400">{{ $modalitaLabel }}</div>
@endif
@if(auth()->user()?->hasRole('super-admin'))
<div class="text-xs">
<a class="underline" href="{{ \App\Filament\Pages\SuperAdmin\CodiciFatturaElettronicaXsd::getUrl(panel: 'admin-filament') }}?domain={{ urlencode('ModalitaPagamentoType') }}" target="_blank" rel="noopener">Vedi codici</a>
</div>
@endif
</dd>
</div>
@endif
@if(!empty($fattura->consumo_valore) || (is_string($fattura->consumo_riferimento) && trim($fattura->consumo_riferimento) !== ''))
<div class="flex justify-between gap-4">
<dt class="text-gray-500 dark:text-gray-400">Consumo (acqua)</dt>
<dd class="font-medium text-right">
<div>
{{ $fattura->consumo_valore !== null ? number_format((float) $fattura->consumo_valore, 3, ',', '.') : '—' }}
{{ $fattura->consumo_unita ?: 'mc' }}
</div>
@if(is_string($fattura->consumo_riferimento) && trim($fattura->consumo_riferimento) !== '')
<div class="text-xs text-gray-500 dark:text-gray-400">{{ trim($fattura->consumo_riferimento) }}</div>
@endif
</dd>
</div>
@endif
</dl>
</div>
<div class="rounded-xl border border-gray-200 bg-white p-4 dark:border-gray-800 dark:bg-gray-900">
<div class="text-sm text-gray-500 dark:text-gray-400">Fornitore (da XML)</div>
<div class="mt-1 text-lg font-semibold">
{{ $fattura->fornitore_denominazione }}
</div>
<dl class="mt-4 space-y-2 text-sm">
<div class="flex justify-between gap-4">
<dt class="text-gray-500 dark:text-gray-400">P.IVA</dt>
<dd class="font-medium">{{ $fattura->fornitore_piva ?: '—' }}</dd>
</div>
<div class="flex justify-between gap-4">
<dt class="text-gray-500 dark:text-gray-400">C.F.</dt>
<dd class="font-medium">{{ $fattura->fornitore_cf ?: '—' }}</dd>
</div>
<div class="flex justify-between gap-4">
<dt class="text-gray-500 dark:text-gray-400">Fornitore agganciato</dt>
<dd class="font-medium">{{ $this->getFornitoreAgganciatoLabel() ?: '—' }}</dd>
</div>
</dl>
@php
$xmlOk = is_string($fattura->xml_content ?? null) ? trim((string) $fattura->xml_content) !== '' : false;
$pdfOk = (is_string($fattura->allegato_pdf_path ?? null) && trim((string) $fattura->allegato_pdf_path) !== '')
|| (is_string($fattura->allegato_pdf_hash ?? null) && trim((string) $fattura->allegato_pdf_hash) !== '')
|| (isset($this->documento) && $this->documento);
@endphp
<div class="mt-4 flex flex-wrap gap-3 text-sm">
@if($pdfOk)
<a class="underline" href="{{ route('admin.fatture-elettroniche.download-pdf', ['fattura' => $fattura->id]) }}" target="_blank" rel="noopener">Scarica PDF</a>
@endif
@if($xmlOk)
<a class="underline" href="{{ route('admin.fatture-elettroniche.download-xml', ['fattura' => $fattura->id]) }}" target="_blank" rel="noopener">Scarica FE XML</a>
@endif
</div>
</div>
<div class="rounded-xl border border-gray-200 bg-white p-4 dark:border-gray-800 dark:bg-gray-900">
<div class="text-sm text-gray-500 dark:text-gray-400">Importi</div>
<dl class="mt-4 space-y-2 text-sm">
<div class="flex justify-between gap-4">
<dt class="text-gray-500 dark:text-gray-400">Imponibile</dt>
<dd class="font-medium"> {{ number_format((float) $fattura->imponibile, 2, ',', '.') }}</dd>
</div>
<div class="flex justify-between gap-4">
<dt class="text-gray-500 dark:text-gray-400">IVA</dt>
<dd class="font-medium"> {{ number_format((float) $fattura->iva, 2, ',', '.') }}</dd>
</div>
<div class="flex justify-between gap-4">
<dt class="text-gray-500 dark:text-gray-400">Totale</dt>
<dd class="text-base font-semibold"> {{ number_format((float) $fattura->totale, 2, ',', '.') }}</dd>
</div>
@php
$ritenuta = is_array($xmlDetails['ritenuta'] ?? null) ? $xmlDetails['ritenuta'] : [];
$ritenutaImporto = (float) ($ritenuta['importo'] ?? 0);
$ritenutaAliquota = $ritenuta['aliquota'] ?? null;
$ritenutaTipo = $ritenuta['tipo'] ?? null;
$ritenutaCausale = $ritenuta['causale'] ?? null;
$nettoDaPagare = round(((float) $fattura->totale) - $ritenutaImporto, 2);
$scadenzaVersamento = null;
if ($ritenutaImporto > 0 && $fattura->data_fattura) {
$scadenzaVersamento = optional($fattura->data_fattura)->copy()->addMonthNoOverflow()->day(16);
}
@endphp
@if($ritenutaImporto > 0)
<div class="pt-2">
<div class="text-xs text-gray-500 dark:text-gray-400">Ritenuta d'acconto</div>
<div class="mt-1 space-y-2">
<div class="flex justify-between gap-4">
<dt class="text-gray-500 dark:text-gray-400">Importo</dt>
<dd class="font-medium">€ {{ number_format($ritenutaImporto, 2, ',', '.') }}</dd>
</div>
<div class="flex justify-between gap-4">
<dt class="text-gray-500 dark:text-gray-400">Aliquota</dt>
<dd class="font-medium">{{ $ritenutaAliquota !== null ? number_format((float) $ritenutaAliquota, 2, ',', '.') . '%' : '' }}</dd>
</div>
<div class="flex justify-between gap-4">
<dt class="text-gray-500 dark:text-gray-400">Tipo</dt>
<dd class="font-medium">{{ $ritenutaTipo ?: '' }}</dd>
</div>
<div class="flex justify-between gap-4">
<dt class="text-gray-500 dark:text-gray-400">Causale</dt>
<dd class="font-medium">{{ $ritenutaCausale ?: '' }}</dd>
</div>
<div class="flex justify-between gap-4">
<dt class="text-gray-500 dark:text-gray-400">Netto da pagare</dt>
<dd class="font-medium">€ {{ number_format($nettoDaPagare, 2, ',', '.') }}</dd>
</div>
<div class="flex justify-between gap-4">
<dt class="text-gray-500 dark:text-gray-400">Versamento (indicativo)</dt>
<dd class="font-medium">{{ $scadenzaVersamento ? $scadenzaVersamento->format('d/m/Y') : '' }}</dd>
</div>
</div>
</div>
@endif
</dl>
</div>
</div>
<div class="rounded-xl border border-gray-200 bg-white p-4 dark:border-gray-800 dark:bg-gray-900">
<div class="flex items-center justify-between gap-3">
<div>
<div class="text-sm font-medium">Documento</div>
<div class="text-xs text-gray-500 dark:text-gray-400">PDF allegato (se presente) oppure prospetto generato</div>
@if($this->documento)
<div class="mt-1 text-xs text-gray-500 dark:text-gray-400">
Protocollo: <span class="font-medium">{{ $this->documento->numero_protocollo }}</span>
·
<button
type="button"
class="underline"
x-on:click="openDocumentoModal = true"
>Apri Documento</button>
</div>
@php
$ocr = is_string($this->documento->contenuto_ocr ?? null)
? trim((string) $this->documento->contenuto_ocr)
: '';
@endphp
@if($ocr !== '')
<div class="mt-1 text-xs text-gray-500 dark:text-gray-400">
Testo PDF estratto: <span class="font-medium">presente</span> ({{ number_format(mb_strlen($ocr), 0, ',', '.') }} caratteri)
</div>
@endif
@else
<div class="mt-1 text-xs text-gray-500 dark:text-gray-400">Nessun Documento collegato</div>
@endif
</div>
</div>
@php
$pdfPath = is_string($fattura->allegato_pdf_path) ? trim($fattura->allegato_pdf_path) : '';
$pdfHash = is_string($fattura->allegato_pdf_hash ?? null) ? trim((string) $fattura->allegato_pdf_hash) : '';
$hasXml = is_string($fattura->xml_content ?? null) ? trim((string) $fattura->xml_content) !== '' : false;
$docPdfPath = '';
if ($this->documento) {
$docPdfPath = is_string($this->documento->percorso_file) ? trim($this->documento->percorso_file) : '';
if ($docPdfPath === '') {
$docPdfPath = is_string($this->documento->path_file) ? trim($this->documento->path_file) : '';
}
}
// Se abbiamo un riferimento (path/hash) o l'XML, proviamo comunque a mostrare l'iframe:
// l'endpoint download-pdf fa auto-repair/rigenerazione se lo storage è stato pulito.
// Evita di mostrare l'iframe quando non c'è alcun PDF agganciato: in quel caso la rotta scarica-pdf andrà in 404.
$pdfOk = ($pdfPath !== '' || $docPdfPath !== '' || $pdfHash !== '');
$righe = is_array($xmlDetails['righe'] ?? null) ? $xmlDetails['righe'] : [];
$escludiRigheFe = (bool) ($fattura->fornitore?->escludi_righe_fe ?? false);
@endphp
@if($pdfOk)
<div class="mt-3 overflow-hidden rounded-lg border border-gray-200 dark:border-gray-800">
<iframe
title="PDF fattura"
class="h-[60vh] w-full"
src="{{ route('admin.fatture-elettroniche.download-pdf', ['fattura' => $fattura->id]) }}?inline=1"
></iframe>
</div>
@else
<div class="mt-3 rounded-lg border border-gray-200 bg-white p-4 text-sm dark:border-gray-800 dark:bg-gray-900">
<div class="text-sm text-gray-600 dark:text-gray-300">
PDF non disponibile (mancante o non ancora spostato nel percorso corretto). Usa “Completa” per riparare/aggiornare.
</div>
</div>
@endif
@if($this->documento)
<div
x-cloak
x-show="openDocumentoModal"
class="fixed inset-0 z-[70]"
x-on:keydown.escape.window="openDocumentoModal = false"
>
<div class="absolute inset-0 bg-black/70" x-on:click="openDocumentoModal = false"></div>
<div class="relative mx-auto mt-6 h-[92vh] w-[96vw] max-w-7xl overflow-hidden rounded-xl bg-white shadow-2xl dark:bg-gray-900">
<div class="flex items-center justify-between border-b border-gray-200 px-4 py-3 dark:border-gray-800">
<div class="text-sm font-semibold">Documento protocollato (PDF)</div>
<button
type="button"
class="rounded-md px-2 py-1 text-sm text-gray-600 hover:bg-gray-100 dark:text-gray-300 dark:hover:bg-gray-800"
x-on:click="openDocumentoModal = false"
>Chiudi</button>
</div>
<iframe
title="Documento protocollato"
class="h-[calc(92vh-56px)] w-full"
src="{{ route('filament.documenti.download', ['documento' => $this->documento->id]) }}?inline=1"
></iframe>
</div>
</div>
@endif
<div class="mt-3 rounded-lg border border-gray-200 bg-white p-4 text-sm dark:border-gray-800 dark:bg-gray-900">
<div class="flex items-start justify-between gap-4">
<div>
<div class="text-xs text-gray-500 dark:text-gray-400">Fornitore</div>
<div class="text-base font-semibold">{{ $fattura->fornitore_denominazione }}</div>
<div class="mt-1 text-xs text-gray-500 dark:text-gray-400">P.IVA {{ $fattura->fornitore_piva ?: '—' }} · CF {{ $fattura->fornitore_cf ?: '—' }}</div>
</div>
<div class="text-right">
<div class="text-xs text-gray-500 dark:text-gray-400">Fattura</div>
<div class="text-base font-semibold">{{ $fattura->numero_fattura }}</div>
<div class="mt-1 text-xs text-gray-500 dark:text-gray-400">{{ optional($fattura->data_fattura)->format('d/m/Y') }}</div>
</div>
</div>
@if($escludiRigheFe)
<div class="mt-3 text-xs text-gray-500 dark:text-gray-400">
Righe FE non visualizzate: il fornitore ha attiva l'opzione “Escludi righe FE”.
</div>
@elseif(count($righe) > 0)
<div class="mt-4 overflow-auto">
<table class="min-w-full text-left text-xs">
<thead class="text-gray-500 dark:text-gray-400">
<tr>
<th class="py-2 pr-3">Riga</th>
<th class="py-2 pr-3">Descrizione</th>
<th class="py-2 pr-3">Q.tà</th>
<th class="py-2 pr-3">Totale</th>
<th class="py-2 pr-3">IVA%</th>
<th class="py-2">RA</th>
</tr>
</thead>
<tbody class="divide-y divide-gray-100 dark:divide-gray-800">
@foreach($righe as $r)
<tr>
<td class="py-2 pr-3 align-top">{{ $r['numero_linea'] ?? '' }}</td>
<td class="py-2 pr-3 align-top">{{ $r['descrizione'] ?? '' }}</td>
<td class="py-2 pr-3 align-top">{{ isset($r['quantita']) ? number_format((float) $r['quantita'], 2, ',', '.') : '' }}</td>
<td class="py-2 pr-3 align-top">€ {{ isset($r['prezzo_totale']) ? number_format((float) $r['prezzo_totale'], 2, ',', '.') : '' }}</td>
<td class="py-2 pr-3 align-top">{{ isset($r['aliquota_iva']) ? number_format((float) $r['aliquota_iva'], 2, ',', '.') : '' }}</td>
<td class="py-2 align-top">{{ ($r['ritenuta'] ?? false) ? 'SI' : '' }}</td>
</tr>
@endforeach
</tbody>
</table>
</div>
@endif
<div class="mt-4 flex justify-end">
<div class="text-right">
<div class="text-xs text-gray-500 dark:text-gray-400">Totale documento</div>
<div class="text-base font-semibold">€ {{ number_format((float) $fattura->totale, 2, ',', '.') }}</div>
</div>
</div>
</div>
</div>
<div class="rounded-xl border border-gray-200 bg-white p-4 dark:border-gray-800 dark:bg-gray-900">
<div class="flex items-center justify-between gap-3">
<div>
<div class="text-sm font-medium">Dati destinatario</div>
<div class="text-xs text-gray-500 dark:text-gray-400">Da XML (DatiTrasmissione / CessionarioCommittente) + riferimenti stabile</div>
</div>
</div>
@php
$cfStabileNorm = strtoupper(str_replace(' ', '', (string) ($fattura->stabile?->codice_fiscale ?? '')));
$cfDestNorm = strtoupper(str_replace(' ', '', (string) ($fattura->destinatario_cf ?? '')));
$cfOk = ($cfStabileNorm !== '' && $cfDestNorm !== '' && $cfStabileNorm === $cfDestNorm);
@endphp
<div class="mt-3 rounded-lg border px-3 py-2 text-xs {{ $cfOk ? 'border-emerald-200 bg-emerald-50 text-emerald-800 dark:border-emerald-900/50 dark:bg-emerald-950/40 dark:text-emerald-200' : 'border-amber-200 bg-amber-50 text-amber-800 dark:border-amber-900/50 dark:bg-amber-950/40 dark:text-amber-200' }}">
@if($cfOk)
Filtro CF stabile: OK. Questa FE e coerente con lo stabile attivo.
@else
Filtro CF stabile: non allineato. La lettura guidata PDF acqua viene bloccata finche CF stabile e CF destinatario FE non coincidono.
@endif
</div>
<dl class="mt-4 grid grid-cols-1 gap-3 text-sm sm:grid-cols-2">
<div class="flex justify-between gap-4">
<dt class="text-gray-500 dark:text-gray-400">Stabile</dt>
<dd class="font-medium">{{ $fattura->stabile?->codice_stabile ? ($fattura->stabile->codice_stabile . ' - ' . $fattura->stabile->denominazione) : '' }}</dd>
</div>
<div class="flex justify-between gap-4">
<dt class="text-gray-500 dark:text-gray-400">CF stabile</dt>
<dd class="font-medium">{{ $fattura->stabile?->codice_fiscale ?: '' }}</dd>
</div>
<div class="flex justify-between gap-4">
<dt class="text-gray-500 dark:text-gray-400">CF destinatario</dt>
<dd class="font-medium">{{ $fattura->destinatario_cf ?: '' }}</dd>
</div>
<div class="flex justify-between gap-4">
<dt class="text-gray-500 dark:text-gray-400">Destinatario</dt>
<dd class="font-medium">{{ $fattura->destinatario_denominazione ?: '' }}</dd>
</div>
<div class="flex justify-between gap-4">
<dt class="text-gray-500 dark:text-gray-400">Codice destinatario</dt>
<dd class="font-medium">{{ $fattura->codice_destinatario ?: '' }}</dd>
</div>
<div class="flex justify-between gap-4">
<dt class="text-gray-500 dark:text-gray-400">PEC destinatario</dt>
<dd class="font-medium">{{ $fattura->pec_destinatario ?: '' }}</dd>
</div>
<div class="flex justify-between gap-4">
<dt class="text-gray-500 dark:text-gray-400">SDI stabile</dt>
<dd class="font-medium">{{ $fattura->stabile?->codice_destinatario_sdi ?: '' }}</dd>
</div>
<div class="flex justify-between gap-4">
<dt class="text-gray-500 dark:text-gray-400">PEC stabile</dt>
<dd class="font-medium">{{ $fattura->stabile?->pec_condominio ?: ($fattura->stabile?->pec_amministratore ?: '') }}</dd>
</div>
@php
$tx = is_array($xmlDetails['trasmissione'] ?? null) ? $xmlDetails['trasmissione'] : [];
$idPaese = $tx['id_paese'] ?? null;
$idCodice = $tx['id_codice'] ?? null;
$progressivo = $tx['progressivo_invio'] ?? null;
$formato = $tx['formato_trasmissione'] ?? null;
@endphp
<div class="flex justify-between gap-4">
<dt class="text-gray-500 dark:text-gray-400">IdTrasmittente</dt>
<dd class="font-medium">{{ ($idPaese && $idCodice) ? ($idPaese . $idCodice) : '' }}</dd>
</div>
<div class="flex justify-between gap-4">
<dt class="text-gray-500 dark:text-gray-400">Progressivo invio</dt>
<dd class="font-medium">{{ $progressivo ?: '' }}</dd>
</div>
<div class="flex justify-between gap-4">
<dt class="text-gray-500 dark:text-gray-400">Formato trasmissione</dt>
<dd class="font-medium">{{ $formato ?: '' }}</dd>
</div>
</dl>
</div>
@if(!empty($fattura->xml_content))
<div class="rounded-xl border border-gray-200 bg-white p-4 dark:border-gray-800 dark:bg-gray-900">
<details>
<summary class="cursor-pointer text-sm font-medium">XML importato</summary>
<pre class="mt-3 overflow-auto rounded-lg bg-gray-50 p-3 text-xs dark:bg-gray-950">{{ $fattura->xml_content }}</pre>
</details>
</div>
@endif
@php
$preview = is_array($acquaPdfPreview ?? null) ? $acquaPdfPreview : [];
$rawText = is_string($preview['raw_text'] ?? null) ? $preview['raw_text'] : '';
$parsed = is_array($preview['parsed'] ?? null) ? $preview['parsed'] : [];
@endphp
@if($preview !== [])
<div class="rounded-xl border border-blue-200 bg-white p-4 dark:border-blue-900/50 dark:bg-gray-900">
<div class="flex items-center justify-between gap-3">
<div>
<div class="text-sm font-medium">Lettura PDF Acqua (Guidata)</div>
<div class="text-xs text-gray-500 dark:text-gray-400">Anteprima dati estratti dalla FE #{{ $preview['fattura_id'] ?? $fattura->id }} del {{ $preview['generated_at'] ?? '' }}</div>
</div>
<div class="text-xs text-gray-500 dark:text-gray-400">
CF stabile: <span class="font-medium">{{ $preview['stabile_cf'] ?? '' }}</span>
· CF destinatario FE: <span class="font-medium">{{ $preview['destinatario_cf'] ?? '' }}</span>
</div>
</div>
<div class="mt-3 space-y-4">
<div>
<div class="text-xs font-medium text-gray-600 dark:text-gray-300">JSON parser acqua (ordinato)</div>
<pre class="mt-1 max-h-[45vh] overflow-auto whitespace-pre-wrap break-words rounded-lg bg-gray-50 p-3 text-xs dark:bg-gray-950">{{ json_encode($parsed, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) }}</pre>
</div>
<div>
<div class="text-xs font-medium text-gray-600 dark:text-gray-300">Testo OCR PDF estratto (completo anteprima)</div>
<div class="mt-1 text-[11px] text-gray-500 dark:text-gray-400">
Caratteri: {{ number_format((int) ($preview['chars'] ?? 0), 0, ',', '.') }}
@if(($preview['truncated'] ?? false) === true)
· mostrati i primi {{ number_format(mb_strlen($rawText), 0, ',', '.') }}
@endif
</div>
<pre class="mt-1 max-h-[70vh] overflow-auto whitespace-pre-wrap break-words rounded-lg bg-gray-50 p-3 text-xs dark:bg-gray-950">{{ $rawText }}</pre>
</div>
</div>
</div>
@endif
</div>
</x-filament-panels::page>