netgescon-day0/app/Console/Commands/GesconSyncOperazioniPrimaNota.php

176 lines
6.1 KiB
PHP

<?php
namespace App\Console\Commands;
use App\Models\GestioneContabile;
use App\Models\User;
use App\Modules\Contabilita\Models\Registrazione;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
class GesconSyncOperazioniPrimaNota extends Command
{
protected $signature = 'gescon:sync-operazioni-prima-nota
{--stabile-id= : ID stabile NetGescon}
{--year= : Anno (YYYY)}
{--tipo=all : all|ordinaria|straordinaria|riscaldamento}
{--dry : Simula senza scrivere}';
protected $description = 'Sincronizza operazioni legacy in contabilita_registrazioni (Prima Nota), con upsert idempotente per external_reference.';
public function handle(): int
{
$stabileId = (int) ($this->option('stabile-id') ?? 0);
if ($stabileId <= 0) {
$this->error('Serve --stabile-id valido.');
return 1;
}
$yearOpt = $this->option('year');
$year = is_numeric($yearOpt) ? (int) $yearOpt : null;
$tipo = strtolower((string) ($this->option('tipo') ?? 'all'));
if (! in_array($tipo, ['all', 'ordinaria', 'straordinaria', 'riscaldamento'], true)) {
$this->error('Valore --tipo non valido. Usa all|ordinaria|straordinaria|riscaldamento');
return 1;
}
$dry = (bool) $this->option('dry');
$systemUserId = (int) (User::query()->orderBy('id')->value('id') ?? 0);
$query = DB::connection('gescon_import')->table('operazioni');
if ($year) {
$query->whereYear('dt_spe', $year);
}
if ($tipo !== 'all') {
$gestioneCode = match ($tipo) {
'ordinaria' => 'O',
'straordinaria' => 'S',
'riscaldamento' => 'R',
default => null,
};
if ($gestioneCode) {
$query->where('gestione', $gestioneCode);
}
}
$rows = $query
->orderBy('dt_spe')
->orderBy('id_operaz')
->get([
'id_operaz',
'dt_spe',
'benef',
'num_fat',
'gestione',
'n_stra',
]);
$created = 0;
$updated = 0;
$unchanged = 0;
foreach ($rows as $row) {
$legacyId = (int) ($row->id_operaz ?? 0);
if ($legacyId <= 0) {
continue;
}
$dataReg = ! empty($row->dt_spe) ? (string) $row->dt_spe : now()->toDateString();
$anno = (int) substr($dataReg, 0, 4);
$tipoGestione = match (strtoupper((string) ($row->gestione ?? 'O'))) {
'S' => 'straordinaria',
'R' => 'riscaldamento',
default => 'ordinaria',
};
$gestioneQuery = GestioneContabile::query()
->where('stabile_id', $stabileId)
->where('anno_gestione', $anno)
->where('tipo_gestione', $tipoGestione);
if ($tipoGestione === 'straordinaria') {
$nStra = is_numeric($row->n_stra ?? null) ? (int) $row->n_stra : null;
if ($nStra && $nStra > 0) {
$gestioneQuery->where('numero_straordinaria', $nStra);
}
}
$gestione = $gestioneQuery
->orderByDesc('id')
->first();
$resolvedGestioneId = $gestione
? Registrazione::resolveGestioneIdOrDefault((int) $gestione->id, $stabileId, $dataReg)
: Registrazione::resolveGestioneIdOrDefault(0, $stabileId, $dataReg);
$payload = [
'stabile_id' => $stabileId,
'gestione_id' => $resolvedGestioneId,
'data_registrazione' => $dataReg,
'entry_date' => $dataReg,
'description' => trim((string) ($row->benef ?? 'Operazione legacy #' . $legacyId)),
'document_type' => 'LEGACY_GESCON',
'document_number' => trim((string) ($row->num_fat ?? '')) !== ''
? trim((string) $row->num_fat)
: ('LEG-' . $legacyId),
'external_reference' => 'OPERAZIONE_LEGACY:' . $legacyId,
'status' => 'confirmed',
];
if (Schema::hasColumn('contabilita_registrazioni', 'user_id')) {
$payload['user_id'] = $systemUserId > 0 ? $systemUserId : null;
}
if (Schema::hasColumn('contabilita_registrazioni', 'created_by')) {
$payload['created_by'] = $systemUserId > 0 ? $systemUserId : null;
}
if (Schema::hasColumn('contabilita_registrazioni', 'updated_by')) {
$payload['updated_by'] = $systemUserId > 0 ? $systemUserId : null;
}
$existing = Registrazione::query()
->where('stabile_id', $stabileId)
->where('external_reference', $payload['external_reference'])
->first();
if (! $existing) {
if (! $dry) {
Registrazione::query()->create($payload);
}
$created++;
continue;
}
$dirty = false;
foreach ($payload as $field => $value) {
if ((string) ($existing->{$field} ?? '') !== (string) ($value ?? '')) {
$existing->{$field} = $value;
$dirty = true;
}
}
if (! $dry && $dirty) {
if (empty($existing->protocol) || empty($existing->protocollo_completo)) {
$existing->applyAutoProtocols();
}
$existing->save();
}
if ($dirty) {
$updated++;
} else {
$unchanged++;
}
}
$this->info('Sync completato: creati=' . $created . ' aggiornati=' . $updated . ' invariati=' . $unchanged . ($dry ? ' (DRY-RUN)' : ''));
return 0;
}
}