633 lines
51 KiB
PHP
Executable File
633 lines
51 KiB
PHP
Executable File
<x-filament-panels::page>
|
|
<div class="mx-auto max-w-7xl space-y-6">
|
|
@php
|
|
$selectedMovement = $selectedBankMovementSnapshot['record'] ?? null;
|
|
$selectedAi = $selectedBankMovementSnapshot['ai_review'] ?? [];
|
|
$selectedLedger = $selectedCiLedger ?? [];
|
|
@endphp
|
|
|
|
<div class="bg-white border rounded-md p-4 space-y-4">
|
|
<div class="flex flex-wrap items-start justify-between gap-3">
|
|
<div>
|
|
<div class="text-sm font-semibold text-gray-800">HUB gestione incassi</div>
|
|
<div class="text-xs text-gray-500">Flusso operativo: coda movimenti banca, scelta del C/I, quadratura sulle rate e conferma finale della registrazione.</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="flex flex-wrap gap-2">
|
|
<button type="button" wire:click="$set('workspaceTab', 'gestione')" class="netgescon-btn netgescon-btn-sm {{ $workspaceTab === 'gestione' ? 'netgescon-btn-primary' : 'netgescon-btn-outline-secondary' }}">
|
|
Gestione incassi
|
|
</button>
|
|
<button type="button" wire:click="$set('workspaceTab', 'apprendimento')" class="netgescon-btn netgescon-btn-sm {{ $workspaceTab === 'apprendimento' ? 'netgescon-btn-primary' : 'netgescon-btn-outline-secondary' }}">
|
|
Apprendimento mini AI
|
|
</button>
|
|
<button type="button" wire:click="$set('workspaceTab', 'hub')" class="netgescon-btn netgescon-btn-sm {{ $workspaceTab === 'hub' ? 'netgescon-btn-primary' : 'netgescon-btn-outline-secondary' }}">
|
|
HUB read-only
|
|
</button>
|
|
<button type="button" wire:click="$set('workspaceTab', 'archivio')" class="netgescon-btn netgescon-btn-sm {{ $workspaceTab === 'archivio' ? 'netgescon-btn-primary' : 'netgescon-btn-outline-secondary' }}">
|
|
Archivio
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
@if($workspaceTab === 'gestione')
|
|
<div class="bg-white border rounded-md p-4 space-y-4">
|
|
<div class="flex flex-wrap items-start justify-between gap-3">
|
|
<div>
|
|
<div class="text-sm font-semibold text-gray-800">Scheda operativa incassi</div>
|
|
<div class="text-xs text-gray-500">In coda vedi solo i movimenti banca da associare. La riga sparisce dalla pila quando la riconciliazione viene salvata.</div>
|
|
</div>
|
|
<div class="text-xs text-gray-500">Coda aperta: {{ count($bankIncassiQueue) }}</div>
|
|
</div>
|
|
|
|
<div class="grid gap-4 xl:grid-cols-5">
|
|
<div class="xl:col-span-2 rounded-md border border-gray-200 p-3 space-y-3">
|
|
<div class="text-xs font-semibold text-gray-700">Movimenti banca da gestire</div>
|
|
|
|
@if(empty($bankIncassiQueue))
|
|
<div class="text-sm text-gray-500">Nessun movimento aperto per lo stabile attivo.</div>
|
|
@else
|
|
<div class="space-y-2 max-h-[42rem] overflow-auto pr-1">
|
|
@foreach($bankIncassiQueue as $movement)
|
|
<button
|
|
type="button"
|
|
wire:click="selectBankMovement({{ $movement['id'] }})"
|
|
class="w-full rounded-md border p-3 text-left {{ $movement['selected'] ? 'border-primary-500 bg-primary-50/40' : 'border-gray-200 hover:border-primary-300' }}"
|
|
>
|
|
<div class="flex items-start justify-between gap-2">
|
|
<div class="text-sm font-semibold text-gray-800">#{{ $movement['id'] }} · {{ $movement['importo_label'] }}</div>
|
|
<div class="text-[11px] text-gray-500">{{ $movement['data'] }}</div>
|
|
</div>
|
|
<div class="mt-1 text-xs text-gray-600 line-clamp-3">{{ $movement['descrizione'] }}</div>
|
|
<div class="mt-2 flex flex-wrap gap-2 text-[11px]">
|
|
@if($movement['ai_status'])
|
|
<span class="rounded bg-gray-100 px-2 py-0.5 text-gray-700">AI {{ $movement['ai_status'] }}</span>
|
|
@endif
|
|
@if($movement['ai_action'])
|
|
<span class="rounded bg-blue-50 px-2 py-0.5 text-blue-700">{{ $movement['ai_action'] }}</span>
|
|
@endif
|
|
@if(!is_null($movement['ai_confidence']))
|
|
<span class="rounded bg-emerald-50 px-2 py-0.5 text-emerald-700">conf. {{ number_format($movement['ai_confidence'], 2, ',', '.') }}</span>
|
|
@endif
|
|
</div>
|
|
</button>
|
|
@endforeach
|
|
</div>
|
|
@endif
|
|
</div>
|
|
|
|
<div class="xl:col-span-3 rounded-md border border-gray-200 p-3 space-y-4">
|
|
@if(empty($selectedMovement))
|
|
<div class="text-sm text-gray-500">Seleziona un movimento dalla pila per aprire la lavorazione.</div>
|
|
@else
|
|
<div class="flex flex-wrap items-start justify-between gap-3">
|
|
<div>
|
|
<div class="text-sm font-semibold text-gray-800">Movimento #{{ $selectedBankMovementId }} · {{ $selectedMovement['importo_label'] ?? '—' }}</div>
|
|
<div class="text-xs text-gray-500">
|
|
{{ $selectedMovement['data_pag_label'] ?? '—' }}
|
|
@if(!empty($selectedMovement['nome_condomino']))
|
|
· {{ $selectedMovement['nome_condomino'] }}
|
|
@endif
|
|
@if(!empty($selectedMovement['sc_int']))
|
|
· {{ $selectedMovement['sc_int'] }}
|
|
@endif
|
|
</div>
|
|
</div>
|
|
|
|
<div class="flex flex-wrap gap-2">
|
|
<button type="button" wire:click="sendSelectedMovementToMiniAi" class="netgescon-btn netgescon-btn-primary netgescon-btn-sm">
|
|
Invia a mini AI
|
|
</button>
|
|
@if(!empty($selectedAi['id']))
|
|
<button type="button" wire:click="loadAiRequestForReview({{ $selectedAi['id'] }})" class="netgescon-btn netgescon-btn-outline-secondary netgescon-btn-sm">
|
|
Carica review AI
|
|
</button>
|
|
@endif
|
|
@if(!empty($selectedBankMovementSnapshot['bank_url']))
|
|
<a href="{{ $selectedBankMovementSnapshot['bank_url'] }}" target="_blank" rel="noopener" class="netgescon-btn netgescon-btn-outline-secondary netgescon-btn-sm">
|
|
Vai alla banca
|
|
</a>
|
|
@endif
|
|
@if(!empty($selectedBankMovementSnapshot['estratto_url']))
|
|
<a href="{{ $selectedBankMovementSnapshot['estratto_url'] }}" target="_blank" rel="noopener" class="netgescon-btn netgescon-btn-outline-secondary netgescon-btn-sm">
|
|
Apri estratto conto
|
|
</a>
|
|
@endif
|
|
</div>
|
|
</div>
|
|
|
|
<div class="rounded-md bg-gray-50 p-3 text-sm text-gray-700">
|
|
{{ $selectedMovement['descrizione_aggintiva'] ?? 'Nessuna descrizione banca disponibile.' }}
|
|
</div>
|
|
|
|
<div class="space-y-4">
|
|
<div class="rounded-md border border-gray-200 p-3 space-y-3">
|
|
<div class="text-xs font-semibold text-gray-700">Totali aperti del C/I</div>
|
|
<div class="grid gap-3 md:grid-cols-3">
|
|
@foreach(($selectedLedger['summary']['by_bucket'] ?? []) as $item)
|
|
<div class="rounded-md bg-gray-50 p-3">
|
|
<div class="text-[11px] uppercase tracking-wide text-gray-500">{{ $item['label'] }}</div>
|
|
<div class="mt-1 text-base font-semibold text-gray-900">€ {{ number_format((float) ($item['total'] ?? 0), 2, ',', '.') }}</div>
|
|
<div class="text-xs text-gray-500">{{ (int) ($item['rows'] ?? 0) }} partite</div>
|
|
</div>
|
|
@endforeach
|
|
</div>
|
|
|
|
@if(!empty($selectedLedger['summary']['by_gestione'] ?? []))
|
|
<div class="overflow-auto">
|
|
<table class="min-w-full text-xs border border-gray-200">
|
|
<thead class="bg-gray-50">
|
|
<tr>
|
|
<th class="px-2 py-1 text-left">Gestione</th>
|
|
<th class="px-2 py-1 text-right">Ordinarie</th>
|
|
<th class="px-2 py-1 text-right">Straordinarie</th>
|
|
<th class="px-2 py-1 text-right">Totale dovuto</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
@foreach(($selectedLedger['summary']['by_gestione'] ?? []) as $row)
|
|
<tr class="border-t">
|
|
<td class="px-2 py-1">{{ $row['gestione'] }}</td>
|
|
<td class="px-2 py-1 text-right">€ {{ number_format((float) ($row['ordinary_total'] ?? 0), 2, ',', '.') }}</td>
|
|
<td class="px-2 py-1 text-right">€ {{ number_format((float) ($row['extraordinary_total'] ?? 0), 2, ',', '.') }}</td>
|
|
<td class="px-2 py-1 text-right font-semibold">€ {{ number_format((float) ($row['general_total'] ?? 0), 2, ',', '.') }}</td>
|
|
</tr>
|
|
@endforeach
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
@endif
|
|
</div>
|
|
|
|
<div class="rounded-md border border-gray-200 p-3 space-y-3">
|
|
<div class="text-xs font-semibold text-gray-700">C/I selezionato e gestione di competenza</div>
|
|
<div>
|
|
<div class="text-base font-semibold text-gray-900">{{ $selectedCiIdentity['subject_label'] ?? ($selectedMovement['nome_condomino'] ?? 'C/I da confermare') }}</div>
|
|
<div class="text-xs text-gray-500">{{ $selectedCiIdentity['unit_label'] ?? ($selectedMovement['sc_int'] ?? 'Unità da confermare') }}</div>
|
|
</div>
|
|
|
|
<div class="grid gap-3 lg:grid-cols-[minmax(0,1fr)_18rem]">
|
|
<div class="flex gap-2">
|
|
<input wire:model.defer="debtorSearch" type="text" class="w-full rounded-md border-gray-300 text-sm" placeholder="Cerca per scala/interno, nominativo, codice unità, CF" />
|
|
<button type="button" wire:click="searchCiTargets" class="netgescon-btn netgescon-btn-outline-secondary netgescon-btn-sm">
|
|
Cerca
|
|
</button>
|
|
</div>
|
|
<div>
|
|
<div class="mb-1 text-[11px] font-semibold uppercase tracking-wide text-gray-500">Gestione di competenza</div>
|
|
<div class="flex flex-wrap gap-2">
|
|
@foreach($manualCompetenceOptions as $option)
|
|
<button type="button" wire:click="selectCompetenceLabel('{{ $option['value'] }}')" class="rounded border px-2 py-1 text-xs {{ $manualCompetenceLabel === $option['value'] ? 'border-primary-500 bg-primary-50 text-primary-700' : 'border-gray-200 text-gray-700 hover:border-primary-300' }}">
|
|
{{ $option['label'] }}
|
|
</button>
|
|
@endforeach
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
@if(!empty($debtorSearchResults))
|
|
<div class="max-h-56 overflow-auto rounded-md border border-gray-200">
|
|
@foreach($debtorSearchResults as $result)
|
|
<button type="button" wire:click="selectCiTarget('{{ $result['legacy_cond_id'] }}', {{ $result['soggetto_id'] ?? 'null' }}, {{ $result['unita_id'] ?? 'null' }})" class="block w-full border-b border-gray-100 px-3 py-2 text-left text-xs hover:bg-gray-50">
|
|
<div class="font-semibold text-gray-800">{{ $result['subject_label'] ?: 'Soggetto da confermare' }}</div>
|
|
<div class="text-gray-500">{{ $result['label'] }} @if(!empty($result['subject_cf']))· {{ $result['subject_cf'] }} @endif</div>
|
|
</button>
|
|
@endforeach
|
|
</div>
|
|
@endif
|
|
|
|
<div class="space-y-1 text-xs text-gray-700">
|
|
<div>Legacy cond: {{ $selectedCiIdentity['legacy_cond_id'] ?? ($selectedLegacyCondId ?: ($selectedMovement['id_condomino'] ?? 'n/d')) }}</div>
|
|
<div>Soggetto ID: {{ $selectedCiIdentity['subject_id'] ?? ($selectedSubjectId ?: ($selectedBankMovementSnapshot['subject_id'] ?? 'n/d')) }}</div>
|
|
<div>Unità ID: {{ $selectedCiIdentity['unit_id'] ?? ($selectedUnitId ?: ($selectedBankMovementSnapshot['unit_id'] ?? 'n/d')) }}</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="rounded-md border border-gray-200 p-3 space-y-2">
|
|
<div class="text-xs font-semibold text-gray-700">Riferimenti banca del pagante</div>
|
|
@php($payerReference = $selectedMovement['payer_reference'] ?? [])
|
|
@if(empty($payerReference['holder_name']) && empty($payerReference['holder_iban']) && empty($payerReference['bank_label']))
|
|
<div class="text-sm text-gray-500">Nessun riferimento aggiuntivo estratto dalla descrizione del bonifico.</div>
|
|
@else
|
|
<div class="text-sm text-gray-800"><strong>Pagante:</strong> {{ $payerReference['holder_name'] ?? 'n/d' }}</div>
|
|
<div class="text-xs text-gray-700">IBAN ordinante: {{ $payerReference['holder_iban'] ?? 'n/d' }}</div>
|
|
<div class="text-xs text-gray-700">Banca ordinante: {{ $payerReference['bank_label'] ?? 'n/d' }}</div>
|
|
@if(!empty($payerReference['bic']))
|
|
<div class="text-xs text-gray-700">BIC/SWIFT: {{ $payerReference['bic'] }}</div>
|
|
@endif
|
|
@if(!empty($payerReference['cro']))
|
|
<div class="text-xs text-gray-700">CRO: {{ $payerReference['cro'] }}</div>
|
|
@endif
|
|
<div class="text-xs {{ !empty($payerReference['matched_from_reference']) ? 'text-emerald-700' : 'text-gray-500' }}">
|
|
@if(!empty($payerReference['matched_from_reference']))
|
|
Collegamento risolto anche da riferimento bancario già noto.
|
|
@else
|
|
Il riferimento verrà memorizzato sul soggetto quando chiudi questa riconciliazione.
|
|
@endif
|
|
</div>
|
|
@endif
|
|
</div>
|
|
|
|
<div class="rounded-md border border-gray-200 p-3 space-y-2">
|
|
<div class="text-xs font-semibold text-gray-700">Esito mini AI / ponte</div>
|
|
@if(empty($selectedAi))
|
|
<div class="text-sm text-gray-500">Nessuna proposta mini AI ancora disponibile.</div>
|
|
@else
|
|
<div class="text-xs text-gray-700">
|
|
Stato {{ $selectedAi['status'] ?? 'n/d' }}
|
|
@if(!empty($selectedAi['suggested_action']))
|
|
· azione {{ $selectedAi['suggested_action'] }}
|
|
@endif
|
|
@if(!is_null($selectedAi['confidence'] ?? null))
|
|
· conf. {{ number_format((float) $selectedAi['confidence'], 2, ',', '.') }}
|
|
@endif
|
|
</div>
|
|
@if(!empty($selectedAi['summary']))
|
|
<div class="text-sm text-gray-700"><strong>Summary:</strong> {{ $selectedAi['summary'] }}</div>
|
|
@endif
|
|
@if(!empty($selectedAi['reason']))
|
|
<div class="text-sm text-gray-700"><strong>Motivo:</strong> {{ $selectedAi['reason'] }}</div>
|
|
@endif
|
|
@if(!empty($selectedAi['allocations'] ?? []))
|
|
<div class="rounded-md border border-gray-200 bg-white p-2">
|
|
<div class="text-[11px] font-semibold uppercase tracking-wide text-gray-500">Allocazioni suggerite</div>
|
|
<div class="mt-2 max-h-40 overflow-auto">
|
|
<table class="min-w-full text-xs">
|
|
<thead>
|
|
<tr class="border-b border-gray-200">
|
|
<th class="px-1 py-1 text-left">Rata</th>
|
|
<th class="px-1 py-1 text-left">Descrizione</th>
|
|
<th class="px-1 py-1 text-right">Importo</th>
|
|
<th class="px-1 py-1 text-left">Gestione</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
@foreach($selectedAi['allocations'] as $allocation)
|
|
<tr class="border-b border-gray-100">
|
|
<td class="px-1 py-1">#{{ $allocation['rate_id'] ?? '—' }}</td>
|
|
<td class="px-1 py-1">
|
|
{{ $allocation['descrizione'] ?? '—' }}
|
|
@if(!empty($allocation['ricevuta']))
|
|
<span class="text-gray-500">· ric. {{ $allocation['ricevuta'] }}</span>
|
|
@endif
|
|
</td>
|
|
<td class="px-1 py-1 text-right">€ {{ $allocation['amount_label'] ?? number_format((float) ($allocation['amount'] ?? 0), 2, ',', '.') }}</td>
|
|
<td class="px-1 py-1">{{ ($allocation['ci'] ?? '—') }} {{ !empty($allocation['gestione']) ? '· ' . $allocation['gestione'] : '' }}</td>
|
|
</tr>
|
|
@endforeach
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
@elseif(($selectedAi['suggested_action'] ?? '') === 'link' && (int) ($selectedAi['candidate_rates_count'] ?? 0) > 0)
|
|
<div class="rounded-md border border-amber-200 bg-amber-50 px-3 py-2 text-xs text-amber-800">
|
|
La mini AI ha proposto il collegamento ma non ha indicato le rate da chiudere. Invia di nuovo dopo aver selezionato la gestione corretta oppure imputa manualmente le rate dalla lista sotto.
|
|
</div>
|
|
@endif
|
|
@endif
|
|
<div class="text-xs {{ !empty($miniAiStatus['active']) ? 'text-gray-600' : 'text-amber-700' }}">{{ $miniAiStatus['message'] ?? 'Questa registrazione va chiusa solo a quadratura esatta con l\'importo banca.' }}</div>
|
|
<div class="text-xs text-gray-600">Questa registrazione va chiusa solo a quadratura esatta con l'importo banca.</div>
|
|
@if(!empty($selectedAi['allocations'] ?? []))
|
|
<div class="pt-1">
|
|
<button type="button" wire:click="applySelectedAiAllocations" class="netgescon-btn netgescon-btn-outline-secondary netgescon-btn-sm">
|
|
Applica allocazioni AI alle rate
|
|
</button>
|
|
</div>
|
|
@endif
|
|
</div>
|
|
|
|
<div class="rounded-md border border-gray-200 p-3 space-y-2">
|
|
<div class="text-xs font-semibold text-gray-700">Rate già pagate</div>
|
|
@if(empty($selectedLedger['paid']))
|
|
<div class="text-sm text-gray-500">Nessun pagamento storico disponibile per il C/I selezionato.</div>
|
|
@else
|
|
<div class="max-h-72 overflow-auto">
|
|
<table class="min-w-full text-xs border border-gray-200">
|
|
<thead class="bg-gray-50">
|
|
<tr>
|
|
<th class="px-2 py-1 text-left">Emissione</th>
|
|
<th class="px-2 py-1 text-left">Gestione</th>
|
|
<th class="px-2 py-1 text-left">Descrizione</th>
|
|
<th class="px-2 py-1 text-right">Pagato</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
@foreach($selectedLedger['paid'] as $rate)
|
|
<tr class="border-t">
|
|
<td class="px-2 py-1">{{ !empty($rate['data_emissione']) ? \Illuminate\Support\Carbon::parse($rate['data_emissione'])->format('d/m/Y') : '—' }}</td>
|
|
<td class="px-2 py-1">{{ $rate['gestione'] ?? '—' }}</td>
|
|
<td class="px-2 py-1">{{ $rate['descrizione'] ?? '—' }}</td>
|
|
<td class="px-2 py-1 text-right">€ {{ number_format((float) ($rate['gia_pagato'] ?? 0), 2, ',', '.') }}</td>
|
|
</tr>
|
|
@endforeach
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
@endif
|
|
</div>
|
|
|
|
<div class="rounded-md border border-gray-200 p-3 space-y-2">
|
|
<div class="flex flex-wrap items-center justify-between gap-2">
|
|
<div class="text-xs font-semibold text-gray-700">Rate ordinarie da pagare / da imputare</div>
|
|
@if($manualCompetenceLabel)
|
|
<div class="text-xs text-gray-500">Gestione mostrata: {{ $manualCompetenceLabel }}</div>
|
|
@endif
|
|
</div>
|
|
@if(empty($selectedLedger['due_ordinary'] ?? []))
|
|
<div class="text-sm text-gray-500">Nessuna partita ordinaria aperta disponibile per il C/I selezionato.</div>
|
|
@else
|
|
<div class="max-h-72 overflow-auto">
|
|
<table class="min-w-full text-xs border border-gray-200">
|
|
<thead class="bg-gray-50">
|
|
<tr>
|
|
<th class="px-2 py-1 text-left">Emissione</th>
|
|
<th class="px-2 py-1 text-left">Gestione</th>
|
|
<th class="px-2 py-1 text-left">Descrizione</th>
|
|
<th class="px-2 py-1 text-right">Residuo</th>
|
|
<th class="px-2 py-1 text-right">Da imputare</th>
|
|
<th class="px-2 py-1"></th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
@foreach(($selectedLedger['due_ordinary'] ?? []) as $rate)
|
|
<tr class="border-t">
|
|
<td class="px-2 py-1">{{ !empty($rate['data_emissione']) ? \Illuminate\Support\Carbon::parse($rate['data_emissione'])->format('d/m/Y') : '—' }}</td>
|
|
<td class="px-2 py-1">{{ $rate['gestione'] ?? '—' }}</td>
|
|
<td class="px-2 py-1">{{ $rate['display_description'] ?? ($rate['descrizione'] ?? '—') }}</td>
|
|
<td class="px-2 py-1 text-right">€ {{ number_format((float) ($rate['residuo'] ?? 0), 2, ',', '.') }}</td>
|
|
<td class="px-2 py-1 text-right">
|
|
<input type="text" value="{{ $manualRateInputs[$rate['id']] ?? '' }}" wire:change="setManualAllocationAmount({{ $rate['id'] }}, $event.target.value)" class="w-24 rounded-md border-gray-300 text-right text-xs" placeholder="0,00" />
|
|
</td>
|
|
<td class="px-2 py-1 text-right">
|
|
<button type="button" wire:click="useSuggestedResidualAmount({{ $rate['id'] }})" class="text-[11px] text-primary-600 hover:underline">Usa residuo</button>
|
|
</td>
|
|
</tr>
|
|
@endforeach
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
@endif
|
|
</div>
|
|
|
|
<div class="rounded-md border border-amber-200 bg-amber-50/40 p-3 space-y-2">
|
|
<div class="flex flex-wrap items-center justify-between gap-2">
|
|
<div class="text-xs font-semibold text-amber-800">Spese straordinarie aperte</div>
|
|
@if(!empty($selectedLedger['totals']['due_extraordinary']))
|
|
<div class="text-xs text-amber-700">Residuo straordinarie: € {{ number_format((float) ($selectedLedger['totals']['due_extraordinary'] ?? 0), 2, ',', '.') }}</div>
|
|
@endif
|
|
</div>
|
|
@if(empty($selectedLedger['due_extraordinary'] ?? []))
|
|
<div class="text-sm text-amber-700/80">Nessuna partita straordinaria aperta rilevata per il C/I selezionato.</div>
|
|
@else
|
|
<div class="text-xs text-amber-700">Le straordinarie restano visibili separatamente fino alla loro chiusura effettiva.</div>
|
|
|
|
@if(!empty($selectedLedger['summary']['extraordinary_by_work'] ?? []))
|
|
<div class="overflow-auto">
|
|
<table class="min-w-full text-xs border border-amber-200">
|
|
<thead class="bg-amber-100/70">
|
|
<tr>
|
|
<th class="px-2 py-1 text-left">Tipo straordinaria</th>
|
|
<th class="px-2 py-1 text-left">Gestione</th>
|
|
<th class="px-2 py-1 text-right">Partite</th>
|
|
<th class="px-2 py-1 text-right">Residuo</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
@foreach(($selectedLedger['summary']['extraordinary_by_work'] ?? []) as $item)
|
|
<tr class="border-t border-amber-200">
|
|
<td class="px-2 py-1">{{ $item['label'] }}</td>
|
|
<td class="px-2 py-1">{{ $item['gestione'] }}</td>
|
|
<td class="px-2 py-1 text-right">{{ (int) ($item['rows'] ?? 0) }}</td>
|
|
<td class="px-2 py-1 text-right font-semibold">€ {{ number_format((float) ($item['total'] ?? 0), 2, ',', '.') }}</td>
|
|
</tr>
|
|
@endforeach
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
@endif
|
|
|
|
@if(!empty($selectedLedger['summary']['extraordinary_missing_works'] ?? []))
|
|
<div class="rounded-md border border-rose-200 bg-rose-50 p-3 space-y-1">
|
|
<div class="text-xs font-semibold text-rose-800">Straordinarie attese ma mancanti nel residuo dell'interno</div>
|
|
@foreach(($selectedLedger['summary']['extraordinary_missing_works'] ?? []) as $missing)
|
|
<div class="text-xs text-rose-700">
|
|
{{ $missing['label'] }}
|
|
@if(!empty($missing['numero_straordinaria']))
|
|
({{ $missing['numero_straordinaria'] }}/{{ $missing['gestione'] }})
|
|
@endif
|
|
· {{ $missing['message'] }}
|
|
</div>
|
|
@endforeach
|
|
</div>
|
|
@endif
|
|
|
|
<div class="max-h-72 overflow-auto">
|
|
<table class="min-w-full text-xs border border-amber-200">
|
|
<thead class="bg-amber-100/70">
|
|
<tr>
|
|
<th class="px-2 py-1 text-left">Emissione</th>
|
|
<th class="px-2 py-1 text-left">Gestione</th>
|
|
<th class="px-2 py-1 text-left">Descrizione</th>
|
|
<th class="px-2 py-1 text-right">Residuo</th>
|
|
<th class="px-2 py-1 text-right">Da imputare</th>
|
|
<th class="px-2 py-1"></th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
@foreach(($selectedLedger['due_extraordinary'] ?? []) as $rate)
|
|
<tr class="border-t border-amber-200">
|
|
<td class="px-2 py-1">{{ !empty($rate['data_emissione']) ? \Illuminate\Support\Carbon::parse($rate['data_emissione'])->format('d/m/Y') : '—' }}</td>
|
|
<td class="px-2 py-1">{{ $rate['gestione'] ?? '—' }}</td>
|
|
<td class="px-2 py-1">{{ $rate['display_description'] ?? ($rate['descrizione'] ?? '—') }}</td>
|
|
<td class="px-2 py-1 text-right">€ {{ number_format((float) ($rate['residuo'] ?? 0), 2, ',', '.') }}</td>
|
|
<td class="px-2 py-1 text-right">
|
|
<input type="text" value="{{ $manualRateInputs[$rate['id']] ?? '' }}" wire:change="setManualAllocationAmount({{ $rate['id'] }}, $event.target.value)" class="w-24 rounded-md border-amber-300 text-right text-xs" placeholder="0,00" />
|
|
</td>
|
|
<td class="px-2 py-1 text-right">
|
|
<button type="button" wire:click="useSuggestedResidualAmount({{ $rate['id'] }})" class="text-[11px] text-amber-700 hover:underline">Usa residuo</button>
|
|
</td>
|
|
</tr>
|
|
@endforeach
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
@endif
|
|
</div>
|
|
</div>
|
|
|
|
<div class="rounded-md border border-gray-200 p-3 space-y-3">
|
|
<div class="grid gap-4 lg:grid-cols-4">
|
|
<div>
|
|
<div class="text-xs text-gray-500">Importo banca</div>
|
|
<div class="text-base font-semibold text-gray-800">€ {{ number_format($this->manualBankAmount, 2, ',', '.') }}</div>
|
|
</div>
|
|
<div>
|
|
<div class="text-xs text-gray-500">Totale imputato</div>
|
|
<div class="text-base font-semibold text-gray-800">€ {{ number_format($this->manualAllocationTotal, 2, ',', '.') }}</div>
|
|
</div>
|
|
<div>
|
|
<div class="text-xs text-gray-500">Differenza</div>
|
|
<div class="text-base font-semibold {{ abs($this->manualAllocationDifference) < 0.01 ? 'text-emerald-700' : 'text-rose-700' }}">€ {{ number_format($this->manualAllocationDifference, 2, ',', '.') }}</div>
|
|
</div>
|
|
<div class="flex items-end justify-end gap-2">
|
|
<button type="button" wire:click="clearManualAllocations" class="netgescon-btn netgescon-btn-outline-secondary netgescon-btn-sm">
|
|
Azzera imputazioni
|
|
</button>
|
|
<button type="button" wire:click="saveManualReconciliation" @disabled(!$this->manualCanSave) class="netgescon-btn netgescon-btn-primary netgescon-btn-sm disabled:opacity-50 disabled:cursor-not-allowed">
|
|
Salva riconciliazione
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="grid gap-4 lg:grid-cols-2">
|
|
<label class="text-xs text-gray-600">
|
|
Alias pagante / anagrafica di appoggio
|
|
<input wire:model.defer="manualPayerAlias" type="text" class="mt-1 w-full rounded-md border-gray-300 text-sm" placeholder="Es. Nethome paga per ..." />
|
|
</label>
|
|
<label class="text-xs text-gray-600">
|
|
Note operatore
|
|
<textarea wire:model.defer="manualNote" rows="2" class="mt-1 w-full rounded-md border-gray-300 text-sm" placeholder="Eventuali note sulla chiusura della partita"></textarea>
|
|
</label>
|
|
</div>
|
|
</div>
|
|
@endif
|
|
</div>
|
|
</div>
|
|
</div>
|
|
@elseif($workspaceTab === 'apprendimento')
|
|
<div class="bg-white border rounded-md p-4 space-y-3">
|
|
<div>
|
|
<div class="text-sm font-semibold text-gray-800">Verifica movimenti mini AI</div>
|
|
<div class="text-xs text-gray-500">Sezione separata per la correzione e l'istruzione della mini AI.</div>
|
|
</div>
|
|
|
|
@if(empty($this->miniAiReviewItems))
|
|
<div class="rounded-md border border-amber-200 bg-amber-50 px-3 py-2 text-sm text-amber-800">
|
|
Nessuna risposta mini AI disponibile per lo stabile attivo.
|
|
</div>
|
|
@else
|
|
<div class="space-y-3">
|
|
@foreach($this->miniAiReviewItems as $item)
|
|
<div class="rounded-md border {{ $item['selected'] ? 'border-primary-500 bg-primary-50/30' : 'border-gray-200' }} p-3 space-y-3">
|
|
<div class="flex flex-wrap items-start justify-between gap-3">
|
|
<div class="space-y-1">
|
|
<div class="text-sm font-semibold text-gray-800">Movimento #{{ $item['movimento_id'] ?: 'n/d' }} · {{ $item['nominativo'] }}</div>
|
|
<div class="text-xs text-gray-500">{{ $item['data'] ?: 'data n/d' }} · {{ $item['importo_label'] }}</div>
|
|
</div>
|
|
<div class="text-right text-xs text-gray-600">
|
|
<div>Stato {{ $item['status'] }}</div>
|
|
<div>{{ $item['suggested_action'] }} @if(!is_null($item['confidence']))· conf. {{ number_format($item['confidence'], 2, ',', '.') }} @endif</div>
|
|
</div>
|
|
</div>
|
|
@if($item['summary'] !== '')
|
|
<div class="text-sm text-gray-700"><strong>Summary:</strong> {{ $item['summary'] }}</div>
|
|
@endif
|
|
@if($item['reason'] !== '')
|
|
<div class="text-sm text-gray-700"><strong>Motivo:</strong> {{ $item['reason'] }}</div>
|
|
@endif
|
|
<div class="flex flex-wrap justify-end gap-2">
|
|
<button type="button" wire:click="loadAiRequestForReview({{ $item['id'] }})" class="netgescon-btn netgescon-btn-outline-secondary netgescon-btn-sm">Carica in editor</button>
|
|
<button type="button" wire:click="confirmAiRequestLearning({{ $item['id'] }})" class="netgescon-btn netgescon-btn-primary netgescon-btn-sm">Conferma per apprendimento</button>
|
|
<button type="button" wire:click="rejectAiRequestLearning({{ $item['id'] }})" class="netgescon-btn netgescon-btn-outline-secondary netgescon-btn-sm">Da rivedere</button>
|
|
</div>
|
|
</div>
|
|
@endforeach
|
|
</div>
|
|
@endif
|
|
</div>
|
|
|
|
<div class="bg-white border rounded-md p-4 space-y-3">
|
|
<div class="flex items-center justify-between">
|
|
<div>
|
|
<div class="text-sm font-semibold text-gray-800">Richieste AI</div>
|
|
<div class="text-xs text-gray-500">File: incoming/ai_requests.md</div>
|
|
</div>
|
|
<button type="button" wire:click="$refresh" class="netgescon-btn netgescon-btn-outline-secondary netgescon-btn-sm">Ricarica</button>
|
|
</div>
|
|
<textarea class="w-full text-xs font-mono rounded-md border-gray-300" rows="10" readonly>{{ $aiRequestsText }}</textarea>
|
|
</div>
|
|
|
|
<div class="bg-white border rounded-md p-4 space-y-3">
|
|
<div>
|
|
<div class="text-sm font-semibold text-gray-800">Risposte AI</div>
|
|
<div class="text-xs text-gray-500">Salvato in: incoming/ai_responses.md</div>
|
|
</div>
|
|
@if($selectedAiRequestId)
|
|
<div class="rounded-md border border-primary-200 bg-primary-50 px-3 py-2 text-xs text-primary-800">Richiesta selezionata: #{{ $selectedAiRequestId }}.</div>
|
|
@endif
|
|
<textarea wire:model.defer="aiResponseText" class="w-full text-xs font-mono rounded-md border-gray-300" rows="12"></textarea>
|
|
<div class="flex flex-wrap justify-end gap-2">
|
|
<button type="button" wire:click="saveSelectedAiRequestReview" class="netgescon-btn netgescon-btn-outline-secondary netgescon-btn-sm">Aggiorna richiesta selezionata</button>
|
|
<button type="button" wire:click="saveAiQaToDb" class="netgescon-btn netgescon-btn-outline-secondary netgescon-btn-sm">Registra Q/A in tabella</button>
|
|
<button type="button" wire:click="saveAiResponse" class="netgescon-btn netgescon-btn-primary netgescon-btn-sm">Salva risposta</button>
|
|
</div>
|
|
</div>
|
|
@elseif($workspaceTab === 'hub')
|
|
<div class="bg-white border rounded-md p-4 space-y-4">
|
|
<div class="flex flex-wrap items-start justify-between gap-3">
|
|
<div>
|
|
<div class="text-sm font-semibold text-gray-800">HUB incassi da estratto conto</div>
|
|
<div class="text-xs text-gray-500">
|
|
Fonte: {{ $legacyHubMeta['source_label'] ?? 'nessuna fonte disponibile' }}
|
|
@if(!empty($legacyHubMeta['stabile_label'])) · {{ $legacyHubMeta['stabile_label'] }} @endif
|
|
· righe: {{ $legacyHubMeta['records_count'] ?? 0 }}
|
|
</div>
|
|
</div>
|
|
<button type="button" wire:click="sendLegacyHubToMiniAi" class="netgescon-btn netgescon-btn-primary netgescon-btn-sm">Invia a mini AI</button>
|
|
</div>
|
|
|
|
@if(empty($legacyHubRows))
|
|
<div class="rounded-md border border-amber-200 bg-amber-50 px-3 py-2 text-sm text-amber-800">Nessun dato read-only disponibile.</div>
|
|
@else
|
|
<div>
|
|
<div class="text-xs font-semibold text-gray-700 mb-1">Payload cumulativo</div>
|
|
<textarea class="w-full text-xs font-mono rounded-md border-gray-300" rows="12" readonly>{{ $legacyHubExportText }}</textarea>
|
|
</div>
|
|
@endif
|
|
</div>
|
|
@else
|
|
<div class="bg-white border rounded-md p-4 space-y-3">
|
|
<div>
|
|
<div class="text-sm font-semibold text-gray-800">Storico Q/A (DB)</div>
|
|
<div class="text-xs text-gray-500">Ultimi 50 record dalla tabella ai_requests.</div>
|
|
</div>
|
|
<div class="overflow-x-auto">
|
|
<table class="min-w-full text-xs border border-gray-200">
|
|
<thead class="bg-gray-50">
|
|
<tr>
|
|
<th class="px-2 py-1 text-left">ID</th>
|
|
<th class="px-2 py-1 text-left">Contesto</th>
|
|
<th class="px-2 py-1 text-left">Stato</th>
|
|
<th class="px-2 py-1 text-left">Filtri</th>
|
|
<th class="px-2 py-1 text-left">Richiesta</th>
|
|
<th class="px-2 py-1 text-left">Risposta</th>
|
|
<th class="px-2 py-1 text-left">Data</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
@forelse($this->aiRequestsDb as $row)
|
|
<tr class="border-t">
|
|
<td class="px-2 py-1">{{ $row['id'] }}</td>
|
|
<td class="px-2 py-1">{{ $row['context'] }}</td>
|
|
<td class="px-2 py-1">{{ $row['status'] }}</td>
|
|
<td class="px-2 py-1">{{ json_encode($row['filters_json'], JSON_UNESCAPED_UNICODE) }}</td>
|
|
<td class="px-2 py-1">{{ $row['request_text'] }}</td>
|
|
<td class="px-2 py-1">{{ $row['response_text'] }}</td>
|
|
<td class="px-2 py-1">{{ $row['created_at'] }}</td>
|
|
</tr>
|
|
@empty
|
|
<tr class="border-t"><td class="px-2 py-2 text-center text-gray-500" colspan="7">Nessun record.</td></tr>
|
|
@endforelse
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="bg-white border rounded-md p-4 space-y-3">
|
|
<div class="text-sm font-semibold text-gray-800">Incassi</div>
|
|
<div class="text-xs text-gray-500">Elenco con azioni per dettaglio nominativo e feedback AI.</div>
|
|
{{ $this->table }}
|
|
</div>
|
|
@endif
|
|
</div>
|
|
</x-filament-panels::page> |