netgescon-day0/app/Filament/Pages/Contabilita/DebitiPagareHub.php

375 lines
13 KiB
PHP

<?php
namespace App\Filament\Pages\Contabilita;
use App\Models\User;
use App\Models\Stabile;
use App\Support\StabileContext;
use BackedEnum;
use Filament\Pages\Page;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
use UnitEnum;
class DebitiPagareHub extends Page
{
protected static ?string $title = 'Hub Pagamenti (Debiti da Pagare)';
protected static ?string $navigationLabel = 'Hub Pagamenti';
protected static BackedEnum|string|null $navigationIcon = 'heroicon-o-credit-card';
protected static UnitEnum|string|null $navigationGroup = 'Contabilità';
protected static ?int $navigationSort = 12;
protected static ?string $slug = 'contabilita/debiti-da-pagare';
protected string $view = 'filament.pages.contabilita.debiti-pagare-hub';
public string $activeTab = 'debiti'; // 'debiti', 'movimenti', 'stato_debiti'
public ?string $targetDate = null; // Data di riferimento per calcolo debiti residui
/** @var array<int, array{id: int, numero_documento: string, data_documento: string, totale: float, netto_da_pagare: float, fornitore_ragione_sociale: string, iban: ?string, descrizione_bonifico: string}> */
public array $debiti = [];
/** @var array<int, array{id: int, data: string, descrizione: string, importo: float, stato: string, invoice_id: ?int, invoice_number: ?string, fornitore: ?string, advice: string}> */
public array $movimenti = [];
/** @var array<int, array{id: int, numero_documento: string, data_documento: string, totale: float, netto_da_pagare: float, fornitore: string, stato_corrente: string, data_chiusura: string}> */
public array $debitiStorici = [];
public float $totaleDebitiStorici = 0.0;
public static function canAccess(): bool
{
$user = Auth::user();
if (! $user instanceof User) {
return false;
}
if ($user->hasAnyRole(['super-admin', 'admin'])) {
return true;
}
return $user->can('contabilita.prima-nota') || $user->can('contabilita.fatture-fornitori');
}
public function getActiveStabile(): ?Stabile
{
$user = Auth::user();
if (! $user instanceof User) {
return null;
}
return StabileContext::getActiveStabile($user);
}
public function mount(): void
{
$stabile = $this->getActiveStabile();
if ($stabile) {
$gestioneId = $this->resolveActiveGestioneId((int) $stabile->id);
if ($gestioneId) {
$gestione = DB::table('gestioni_contabili')->where('id', $gestioneId)->first();
if ($gestione && $gestione->data_fine) {
$this->targetDate = $gestione->data_fine;
}
}
}
if (! $this->targetDate) {
$this->targetDate = now()->format('Y-12-31');
}
$this->loadTabContent();
}
public function setTab(string $tab): void
{
$this->activeTab = $tab;
$this->loadTabContent();
}
public function updatedTargetDate(): void
{
$this->loadTabContent();
}
public function loadTabContent(): void
{
if ($this->activeTab === 'debiti') {
$this->loadDebiti();
} elseif ($this->activeTab === 'movimenti') {
$this->loadMovimenti();
} elseif ($this->activeTab === 'stato_debiti') {
$this->loadDebitiStorici();
}
}
public function loadDebiti(): void
{
$user = Auth::user();
if (! $user instanceof User) {
return;
}
$stabileId = StabileContext::resolveActiveStabileId($user);
if (! $stabileId || ! Schema::hasTable('contabilita_fatture_fornitori')) {
$this->debiti = [];
return;
}
$select = [
'f.id',
'f.numero_documento',
'f.data_documento',
'f.totale',
'f.netto_da_pagare',
'f.stato',
'f.fornitore_id',
'f.fattura_elettronica_id',
];
$query = DB::table('contabilita_fatture_fornitori as f')
->where('f.stabile_id', $stabileId)
->where(function ($q) {
$q->where('f.stato', '!=', 'pagato')
->orWhereNull('f.stato');
});
if (Schema::hasTable('fornitori')) {
$query->leftJoin('fornitori as forn', 'forn.id', '=', 'f.fornitore_id');
$select[] = 'forn.ragione_sociale as fornitore_ragione_sociale';
$select[] = 'forn.iban as fornitore_iban';
}
if (Schema::hasTable('fatture_elettroniche')) {
$query->leftJoin('fatture_elettroniche as fe', 'fe.id', '=', 'f.fattura_elettronica_id');
$select[] = 'fe.pagamento_iban as fe_pagamento_iban';
}
$dbRows = $query->select($select)
->orderBy('f.data_documento')
->orderBy('f.id')
->get();
$this->debiti = [];
foreach ($dbRows as $row) {
$iban = null;
if (isset($row->fe_pagamento_iban) && $row->fe_pagamento_iban) {
$iban = $row->fe_pagamento_iban;
}
if (! $iban && isset($row->fornitore_iban)) {
$iban = $row->fornitore_iban;
}
$id = (int) $row->id;
$fornitoreName = $row->fornitore_ragione_sociale ?? 'Fornitore Sconosciuto';
$numDoc = $row->numero_documento ?? 'N/D';
$prefix = "FAT-ID:{$id} ";
$suffix = " N.{$numDoc}";
$avail = 140 - strlen($prefix) - strlen($suffix);
$cleanName = substr($fornitoreName, 0, max(0, $avail));
$descrizione = $prefix . $cleanName . $suffix;
$this->debiti[] = [
'id' => $id,
'numero_documento' => $numDoc,
'data_documento' => $row->data_documento ? Carbon::parse($row->data_documento)->format('d/m/Y') : '—',
'totale' => (float) $row->totale,
'netto_da_pagare' => (float) ($row->netto_da_pagare ?? $row->totale),
'fornitore_ragione_sociale' => $fornitoreName,
'iban' => $iban ? strtoupper(str_replace(' ', '', $iban)) : null,
'descrizione_bonifico' => $descrizione,
];
}
}
public function loadMovimenti(): void
{
$user = Auth::user();
if (! $user instanceof User) {
return;
}
$stabileId = StabileContext::resolveActiveStabileId($user);
if (! $stabileId || ! Schema::hasTable('contabilita_movimenti_banca')) {
$this->movimenti = [];
return;
}
$query = DB::table('contabilita_movimenti_banca as m')
->where('m.stabile_id', $stabileId);
if (Schema::hasTable('contabilita_fatture_fornitori')) {
$query->leftJoin('contabilita_fatture_fornitori as f', 'f.movimento_pagamento_id', '=', 'm.id');
}
if (Schema::hasTable('fornitori')) {
$query->leftJoin('fornitori as forn', 'forn.id', '=', 'm.fornitore_id');
}
$select = [
'm.id',
'm.data',
'm.descrizione',
'm.descrizione_estesa',
'm.importo',
'm.registrazione_id',
'm.causale',
];
if (Schema::hasTable('contabilita_fatture_fornitori')) {
$select[] = 'f.id as invoice_id';
$select[] = 'f.numero_documento as invoice_number';
}
if (Schema::hasTable('fornitori')) {
$select[] = 'forn.ragione_sociale as fornitore_ragione_sociale';
}
$rows = $query->select($select)
->orderByDesc('m.data')
->orderByDesc('m.id')
->get();
$this->movimenti = [];
foreach ($rows as $r) {
$invId = isset($r->invoice_id) ? $r->invoice_id : null;
$invNum = isset($r->invoice_number) ? $r->invoice_number : null;
$forn = isset($r->fornitore_ragione_sociale) ? $r->fornitore_ragione_sociale : null;
$isReconciled = ! empty($r->registrazione_id) || ! empty($invId);
$advice = '';
if (! $isReconciled) {
if ((float) $r->importo < 0) {
if (in_array((string) $r->causale, ['198', '219', '048', '208'], true)) {
$advice = 'Spesa bancaria diretta. Configura la regola interbancaria per registrarla in prima nota.';
} else {
$advice = 'Uscita bancaria. Registra la fattura fornitore corrispondente o riconcilia manualmente.';
}
} else {
$advice = 'Entrata/Incasso rate. Riconcilia con le rate o gli incassi del condominio.';
}
}
$this->movimenti[] = [
'id' => (int) $r->id,
'data' => $r->data ? Carbon::parse($r->data)->format('d/m/Y') : '—',
'descrizione' => $r->descrizione ?: 'Movimento banca',
'importo' => (float) $r->importo,
'stato' => $isReconciled ? 'quadrato' : 'da_quadrare',
'invoice_id' => $invId,
'invoice_number' => $invNum,
'fornitore' => $forn,
'advice' => $advice,
];
}
}
public function loadDebitiStorici(): void
{
$user = Auth::user();
if (! $user instanceof User) {
return;
}
$stabileId = StabileContext::resolveActiveStabileId($user);
if (! $stabileId || ! Schema::hasTable('contabilita_fatture_fornitori') || ! $this->targetDate) {
$this->debitiStorici = [];
$this->totaleDebitiStorici = 0.0;
return;
}
$query = DB::table('contabilita_fatture_fornitori as f')
->where('f.stabile_id', $stabileId)
->where('f.data_documento', '<=', $this->targetDate)
->where(function ($q) {
$q->where('f.stato', '!=', 'pagato')
->orWhereNull('f.stato')
->orWhereNull('f.data_pagamento')
->orWhere('f.data_pagamento', '>', $this->targetDate);
});
if (Schema::hasTable('fornitori')) {
$query->leftJoin('fornitori as forn', 'forn.id', '=', 'f.fornitore_id');
}
$select = [
'f.id',
'f.numero_documento',
'f.data_documento',
'f.totale',
'f.netto_da_pagare',
'f.stato',
'f.data_pagamento',
];
if (Schema::hasTable('fornitori')) {
$select[] = 'forn.ragione_sociale as fornitore_ragione_sociale';
}
$rows = $query->select($select)
->orderBy('f.data_documento')
->orderBy('f.id')
->get();
$this->debitiStorici = [];
$this->totaleDebitiStorici = 0.0;
foreach ($rows as $row) {
$tot = (float) $row->totale;
$due = (float) ($row->netto_da_pagare ?? $row->totale);
$this->totaleDebitiStorici += $due;
$chiusoAl = 'Ancora aperto';
if ($row->stato === 'pagato' && $row->data_pagamento) {
$chiusoAl = Carbon::parse($row->data_pagamento)->format('d/m/Y');
}
$this->debitiStorici[] = [
'id' => (int) $row->id,
'numero_documento' => $row->numero_documento ?? 'N/D',
'data_documento' => $row->data_documento ? Carbon::parse($row->data_documento)->format('d/m/Y') : '—',
'totale' => $tot,
'netto_da_pagare' => $due,
'fornitore' => $row->fornitore_ragione_sociale ?? 'Fornitore Sconosciuto',
'stato_corrente' => $row->stato ?? 'N/D',
'data_chiusura' => $chiusoAl,
];
}
}
private function resolveActiveGestioneId(int $stabileId): ?int
{
$anno = \App\Support\AnnoGestioneContext::resolveActiveAnno();
$tipo = \App\Support\GestioneContext::resolveActiveGestione();
$match = DB::table('gestioni_contabili')
->where('stabile_id', $stabileId)
->where('anno_gestione', $anno)
->where('tipo_gestione', $tipo)
->where('stato', 'aperta')
->orderByDesc('gestione_attiva')
->orderByDesc('id')
->first();
if (! $match) {
$match = DB::table('gestioni_contabili')
->where('stabile_id', $stabileId)
->where('stato', 'aperta')
->orderByDesc('gestione_attiva')
->orderByDesc('id')
->first();
}
return $match ? (int) $match->id : null;
}
}