645 lines
25 KiB
PHP
Executable File
645 lines
25 KiB
PHP
Executable File
<?php
|
|
namespace App\Console\Commands;
|
|
|
|
use App\Models\Fornitore;
|
|
use App\Models\GestioneContabile;
|
|
use App\Models\Stabile;
|
|
use App\Models\User;
|
|
use App\Models\VoceSpesa;
|
|
use App\Modules\Contabilita\Models\Movimento;
|
|
use App\Modules\Contabilita\Models\Registrazione;
|
|
use Illuminate\Console\Command;
|
|
use Illuminate\Database\Eloquent\Builder;
|
|
use Illuminate\Support\Facades\DB;
|
|
use Illuminate\Support\Facades\Schema;
|
|
|
|
class GesconSyncOperazioniPrimaNota extends Command
|
|
{
|
|
private array $legacyAnnualMetaCache = [];
|
|
|
|
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);
|
|
$stabile = Stabile::query()->find($stabileId);
|
|
$amministratoreId = (int) ($stabile?->amministratore_id ?? 0);
|
|
$legacyStableCodes = array_values(array_unique(array_filter(array_map(
|
|
static fn($value): string => trim((string) $value),
|
|
[$stabile?->codice_stabile ?? null, $stabile?->cod_stabile ?? null]
|
|
))));
|
|
|
|
$query = DB::connection('gescon_import')->table('operazioni');
|
|
|
|
if (Schema::connection('gescon_import')->hasColumn('operazioni', 'cod_stabile') && $legacyStableCodes !== []) {
|
|
$scopedExists = DB::connection('gescon_import')
|
|
->table('operazioni')
|
|
->whereIn('cod_stabile', $legacyStableCodes)
|
|
->exists();
|
|
|
|
if ($scopedExists) {
|
|
$query->whereIn('cod_stabile', $legacyStableCodes);
|
|
} else {
|
|
$this->warn('Nessuna operazione legacy con cod_stabile in [' . implode(', ', $legacyStableCodes) . ']. Non importo righe non scoperte per evitare contaminazioni tra stabili.');
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
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',
|
|
'note',
|
|
'natura',
|
|
'gestione',
|
|
'n_stra',
|
|
'cod_spe',
|
|
'tabella',
|
|
'cod_for',
|
|
'importo',
|
|
'importo_euro',
|
|
'importo_spese',
|
|
'importo_entrate',
|
|
'compet',
|
|
'cod_stabile',
|
|
'legacy_year',
|
|
]);
|
|
|
|
$created = 0;
|
|
$updated = 0;
|
|
$unchanged = 0;
|
|
$movimentiSynced = 0;
|
|
$fornitoriLinked = 0;
|
|
$vociLinked = 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();
|
|
|
|
$tipoGestione = match (strtoupper((string) ($row->gestione ?? 'O'))) {
|
|
'S' => 'straordinaria',
|
|
'R' => 'riscaldamento',
|
|
default => 'ordinaria',
|
|
};
|
|
|
|
$legacyMeta = $this->resolveLegacyAnnualMeta(
|
|
(string) ($row->cod_stabile ?? ($legacyStableCodes[0] ?? '')),
|
|
trim((string) ($row->legacy_year ?? '')),
|
|
$tipoGestione
|
|
);
|
|
|
|
$anno = $legacyMeta['anno_gestione'] ?? (int) substr($dataReg, 0, 4);
|
|
$legacyArchiveCode = $legacyMeta['codice_archivio_legacy'] ?? null;
|
|
$periodStart = $legacyMeta['data_inizio'] ?? null;
|
|
$periodEnd = $legacyMeta['data_fine'] ?? null;
|
|
$legacyLabel = $legacyMeta['label'] ?? null;
|
|
|
|
$gestioneQuery = GestioneContabile::query()
|
|
->where('stabile_id', $stabileId)
|
|
->where('anno_gestione', $anno)
|
|
->where('tipo_gestione', $tipoGestione);
|
|
|
|
if ($legacyArchiveCode && Schema::hasColumn('gestioni_contabili', 'codice_archivio_legacy')) {
|
|
$gestioneQuery->where(function (Builder $q) use ($legacyArchiveCode): void {
|
|
$q->where('codice_archivio_legacy', $legacyArchiveCode)
|
|
->orWhereNull('codice_archivio_legacy');
|
|
});
|
|
}
|
|
|
|
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
|
|
->orderByRaw("CASE WHEN codice_archivio_legacy = ? THEN 0 WHEN codice_archivio_legacy IS NULL THEN 1 ELSE 2 END", [$legacyArchiveCode])
|
|
->orderByDesc('id')
|
|
->first();
|
|
|
|
if (! $gestione instanceof GestioneContabile) {
|
|
$gestione = $this->ensureLegacyGestione(
|
|
$stabileId,
|
|
$anno,
|
|
$tipoGestione,
|
|
$dataReg,
|
|
is_numeric($row->n_stra ?? null) ? (int) $row->n_stra : null,
|
|
$legacyArchiveCode,
|
|
$periodStart,
|
|
$periodEnd,
|
|
$legacyLabel
|
|
);
|
|
} elseif ($legacyArchiveCode && Schema::hasColumn('gestioni_contabili', 'codice_archivio_legacy')) {
|
|
$updates = [];
|
|
if (blank($gestione->codice_archivio_legacy) || str_starts_with((string) $gestione->codice_archivio_legacy, 'operazioni:')) {
|
|
$updates['codice_archivio_legacy'] = $legacyArchiveCode;
|
|
}
|
|
if ($periodStart && empty($gestione->data_inizio)) {
|
|
$updates['data_inizio'] = $periodStart;
|
|
}
|
|
if ($periodEnd && empty($gestione->data_fine)) {
|
|
$updates['data_fine'] = $periodEnd;
|
|
}
|
|
if ($legacyLabel && empty($gestione->denominazione)) {
|
|
$updates['denominazione'] = $legacyLabel;
|
|
}
|
|
if ($updates !== []) {
|
|
$gestione->fill($updates);
|
|
if (! $dry) {
|
|
$gestione->save();
|
|
}
|
|
}
|
|
}
|
|
|
|
$resolvedGestioneId = $gestione
|
|
? Registrazione::resolveGestioneIdOrDefault((int) $gestione->id, $stabileId, $dataReg)
|
|
: Registrazione::resolveGestioneIdOrDefault(0, $stabileId, $dataReg);
|
|
|
|
if (! $resolvedGestioneId) {
|
|
$this->warn('Gestione non risolta per operazione legacy #' . $legacyId . ' anno ' . $anno . ' tipo ' . $tipoGestione . ': riga saltata.');
|
|
continue;
|
|
}
|
|
|
|
$legacyClassification = $this->classifyLegacyOperation($row);
|
|
$voceSpesaId = $this->resolveVoceSpesaId($stabileId, $resolvedGestioneId, (string) ($row->cod_spe ?? ''));
|
|
$fornitoreId = $this->resolveFornitoreId($amministratoreId, $row->cod_for ?? null);
|
|
if ($voceSpesaId > 0) {
|
|
$vociLinked++;
|
|
}
|
|
if ($fornitoreId > 0) {
|
|
$fornitoriLinked++;
|
|
}
|
|
|
|
$payload = [
|
|
'stabile_id' => $stabileId,
|
|
'gestione_id' => $resolvedGestioneId,
|
|
'data_registrazione' => $dataReg,
|
|
'entry_date' => $dataReg,
|
|
'description' => trim((string) ($row->benef ?: $row->note ?: $row->natura ?: '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,
|
|
'protocol' => 'LG' . $anno . '-' . str_pad((string) $legacyId, 6, '0', STR_PAD_LEFT),
|
|
'protocollo_prefix' => 'LG' . $anno,
|
|
'protocollo_numero' => $legacyId,
|
|
'protocollo_completo' => 'LG' . $anno . '-' . $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) {
|
|
$existing = Registrazione::query()->create($payload);
|
|
$this->syncMovimentiLegacy($existing, $row, $voceSpesaId, $fornitoreId, $legacyClassification);
|
|
$movimentiSynced++;
|
|
}
|
|
$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 (! $dry) {
|
|
$this->syncMovimentiLegacy($existing, $row, $voceSpesaId, $fornitoreId, $legacyClassification);
|
|
$movimentiSynced++;
|
|
}
|
|
|
|
if ($dirty) {
|
|
$updated++;
|
|
} else {
|
|
$unchanged++;
|
|
}
|
|
}
|
|
|
|
$this->info('Sync completato: creati=' . $created . ' aggiornati=' . $updated . ' invariati=' . $unchanged . ' movimenti=' . $movimentiSynced . ' voci_link=' . $vociLinked . ' fornitori_link=' . $fornitoriLinked . ($dry ? ' (DRY-RUN)' : ''));
|
|
|
|
return 0;
|
|
}
|
|
|
|
private function resolveVoceSpesaId(int $stabileId, ?int $gestioneId, string $codSpe): int
|
|
{
|
|
$codSpe = trim($codSpe);
|
|
if ($codSpe === '' || ! Schema::hasTable('voci_spesa')) {
|
|
return 0;
|
|
}
|
|
|
|
$query = VoceSpesa::query()
|
|
->where('stabile_id', $stabileId)
|
|
->where(function (Builder $q) use ($codSpe): void {
|
|
$q->where('legacy_codice', $codSpe)
|
|
->orWhere('codice', $codSpe);
|
|
});
|
|
|
|
if ($gestioneId && Schema::hasColumn('voci_spesa', 'gestione_contabile_id')) {
|
|
$clone = (clone $query)->where('gestione_contabile_id', $gestioneId)->orderBy('id')->first();
|
|
if ($clone instanceof VoceSpesa) {
|
|
return (int) $clone->id;
|
|
}
|
|
}
|
|
|
|
$voce = $query->orderByDesc('attiva')->orderBy('id')->first();
|
|
|
|
return $voce instanceof VoceSpesa ? (int) $voce->id : 0;
|
|
}
|
|
|
|
private function ensureLegacyGestione(
|
|
int $stabileId,
|
|
int $anno,
|
|
string $tipoGestione,
|
|
string $dataReg,
|
|
?int $numeroStraordinaria = null,
|
|
?string $legacyArchiveCode = null,
|
|
?string $periodStart = null,
|
|
?string $periodEnd = null,
|
|
?string $legacyLabel = null
|
|
): ?GestioneContabile {
|
|
if ($stabileId <= 0 || $anno <= 0) {
|
|
return null;
|
|
}
|
|
|
|
$query = GestioneContabile::query()
|
|
->where('stabile_id', $stabileId)
|
|
->where('anno_gestione', $anno)
|
|
->where('tipo_gestione', $tipoGestione);
|
|
|
|
if ($tipoGestione === 'straordinaria' && $numeroStraordinaria && $numeroStraordinaria > 0) {
|
|
$query->where('numero_straordinaria', $numeroStraordinaria);
|
|
}
|
|
|
|
$existing = $query->orderByDesc('id')->first();
|
|
if ($existing instanceof GestioneContabile) {
|
|
return $existing;
|
|
}
|
|
|
|
$start = $periodStart ?: sprintf('%04d-01-01', $anno);
|
|
$end = $periodEnd ?: sprintf('%04d-12-31', $anno);
|
|
if ($tipoGestione === 'riscaldamento') {
|
|
$start = $periodStart ?: sprintf('%04d-01-01', $anno);
|
|
$end = $periodEnd ?: sprintf('%04d-12-31', $anno);
|
|
}
|
|
|
|
$denominazione = $legacyLabel ?: ('Legacy GESCON ' . $anno . ' - ' . ucfirst($tipoGestione));
|
|
|
|
return GestioneContabile::query()->create([
|
|
'tenant_id' => $this->resolveTenantIdForStabile($stabileId),
|
|
'stabile_id' => $stabileId,
|
|
'anno_gestione' => $anno,
|
|
'tipo_gestione' => $tipoGestione,
|
|
'numero_straordinaria' => $tipoGestione === 'straordinaria' && $numeroStraordinaria && $numeroStraordinaria > 0 ? $numeroStraordinaria : null,
|
|
'denominazione' => $denominazione,
|
|
'data_inizio' => $start,
|
|
'data_fine' => $end,
|
|
'stato' => 'chiusa',
|
|
'protocollo_prefix' => 'LEG' . $anno,
|
|
'ultimo_protocollo' => 0,
|
|
'gestione_attiva' => false,
|
|
'codice_archivio_legacy' => $legacyArchiveCode ?: ('operazioni:' . $anno),
|
|
'note_gestione' => 'Creata automaticamente per import operazioni legacy GESCON da Prima Nota. Data riferimento: ' . $dataReg,
|
|
]);
|
|
}
|
|
|
|
private function resolveLegacyAnnualMeta(string $codStabile, string $legacyYear, string $tipoGestione): array
|
|
{
|
|
$codStabile = trim($codStabile);
|
|
$legacyYear = trim($legacyYear);
|
|
$cacheKey = implode('|', [$codStabile, $legacyYear, $tipoGestione]);
|
|
|
|
if (array_key_exists($cacheKey, $this->legacyAnnualMetaCache)) {
|
|
return $this->legacyAnnualMetaCache[$cacheKey];
|
|
}
|
|
|
|
if ($codStabile === '' || $legacyYear === '' || ! Schema::connection('gescon_import')->hasTable('gestioni_annuali')) {
|
|
return $this->legacyAnnualMetaCache[$cacheKey] = [];
|
|
}
|
|
|
|
$row = DB::connection('gescon_import')
|
|
->table('gestioni_annuali')
|
|
->where('cod_stabile', $codStabile)
|
|
->where('cartella', $legacyYear)
|
|
->first([
|
|
'cartella',
|
|
'anno_ordinario',
|
|
'anno_riscaldamento',
|
|
'descrizione',
|
|
'ordinaria_dal',
|
|
'ordinaria_al',
|
|
'riscaldamento_dal',
|
|
'riscaldamento_al',
|
|
]);
|
|
|
|
if (! $row) {
|
|
return $this->legacyAnnualMetaCache[$cacheKey] = [];
|
|
}
|
|
|
|
$isRiscaldamento = $tipoGestione === 'riscaldamento';
|
|
$annoLabel = trim((string) ($isRiscaldamento ? ($row->anno_riscaldamento ?? '') : ($row->anno_ordinario ?? '')));
|
|
$anno = $this->extractLegacyYearInt($annoLabel)
|
|
?: $this->extractLegacyYearInt((string) ($row->descrizione ?? ''))
|
|
?: $this->extractLegacyYearInt($legacyYear);
|
|
|
|
$start = $isRiscaldamento
|
|
? ($row->riscaldamento_dal ?: $row->ordinaria_dal)
|
|
: $row->ordinaria_dal;
|
|
$end = $isRiscaldamento
|
|
? ($row->riscaldamento_al ?: $row->ordinaria_al)
|
|
: $row->ordinaria_al;
|
|
|
|
$label = trim((string) ($row->descrizione ?? ''));
|
|
if ($label === '') {
|
|
$label = ucfirst($tipoGestione) . ' ' . ($annoLabel !== '' ? $annoLabel : $legacyYear);
|
|
}
|
|
|
|
return $this->legacyAnnualMetaCache[$cacheKey] = [
|
|
'cartella' => $legacyYear,
|
|
'anno_gestione' => $anno,
|
|
'anno_label' => $annoLabel !== '' ? $annoLabel : null,
|
|
'data_inizio' => $start ? (string) $start : null,
|
|
'data_fine' => $end ? (string) $end : null,
|
|
'label' => $label,
|
|
'codice_archivio_legacy' => 'legacy:gestioni_annuali:' . $legacyYear,
|
|
];
|
|
}
|
|
|
|
private function extractLegacyYearInt(?string $value): ?int
|
|
{
|
|
$value = trim((string) ($value ?? ''));
|
|
if ($value === '') {
|
|
return null;
|
|
}
|
|
|
|
if (preg_match('/(19|20)\d{2}/', $value, $match) === 1) {
|
|
return (int) $match[0];
|
|
}
|
|
|
|
return is_numeric($value) && strlen($value) === 4 ? (int) $value : null;
|
|
}
|
|
|
|
private function resolveTenantIdForStabile(int $stabileId): string
|
|
{
|
|
$tenant = GestioneContabile::query()
|
|
->where('stabile_id', $stabileId)
|
|
->whereNotNull('tenant_id')
|
|
->orderByDesc('id')
|
|
->value('tenant_id');
|
|
|
|
$tenant = trim((string) ($tenant ?? ''));
|
|
|
|
return $tenant !== '' ? $tenant : 'T1';
|
|
}
|
|
|
|
private function resolveFornitoreId(int $amministratoreId, mixed $codFor): int
|
|
{
|
|
$codFor = trim((string) ($codFor ?? ''));
|
|
if ($amministratoreId <= 0 || $codFor === '' || ! Schema::hasTable('fornitori')) {
|
|
return 0;
|
|
}
|
|
|
|
$query = Fornitore::query()->where('amministratore_id', $amministratoreId);
|
|
|
|
if (is_numeric($codFor)) {
|
|
$fornitore = (clone $query)->where('cod_forn', (int) $codFor)->first();
|
|
if ($fornitore instanceof Fornitore) {
|
|
return (int) $fornitore->id;
|
|
}
|
|
|
|
$fornitore = (clone $query)->where('old_id', (int) $codFor)->first();
|
|
if ($fornitore instanceof Fornitore) {
|
|
return (int) $fornitore->id;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
private function syncMovimentiLegacy(Registrazione $registrazione, object $row, int $voceSpesaId, int $fornitoreId, array $legacyClassification): void
|
|
{
|
|
if (! Schema::hasTable('contabilita_movimenti')) {
|
|
return;
|
|
}
|
|
|
|
Movimento::query()->where('registrazione_id', (int) $registrazione->id)->delete();
|
|
|
|
$amount = $this->resolveOperationAmount($row);
|
|
if (abs($amount) < 0.005) {
|
|
return;
|
|
}
|
|
|
|
$metadata = [
|
|
'source' => 'gescon_operazioni',
|
|
'legacy_id_operaz' => (int) ($row->id_operaz ?? 0),
|
|
'legacy_gestione' => trim((string) ($row->gestione ?? '')),
|
|
'legacy_compet' => $legacyClassification['compet'],
|
|
'legacy_natura2' => $legacyClassification['natura2'],
|
|
'legacy_posting_mode' => $legacyClassification['posting_mode'],
|
|
'legacy_cod_spe' => trim((string) ($row->cod_spe ?? '')),
|
|
'legacy_cod_for' => trim((string) ($row->cod_for ?? '')),
|
|
'legacy_tabella' => trim((string) ($row->tabella ?? '')),
|
|
'legacy_year' => trim((string) ($row->legacy_year ?? '')),
|
|
'fornitore_id' => $fornitoreId > 0 ? $fornitoreId : null,
|
|
];
|
|
|
|
$contoId = $this->resolveLegacyContoId((int) $registrazione->stabile_id, $legacyClassification);
|
|
|
|
$payload = [
|
|
'registrazione_id' => (int) $registrazione->id,
|
|
'conto_id' => $contoId,
|
|
'voce_spesa_id' => ($legacyClassification['allow_cost_voice'] ?? true) && $voceSpesaId > 0 ? $voceSpesaId : null,
|
|
'tipo' => $amount >= 0 ? 'dare' : 'avere',
|
|
'importo' => abs($amount),
|
|
'movement_description' => trim((string) ($row->benef ?: $row->note ?: $row->natura ?: 'Operazione legacy')),
|
|
'sequence' => 1,
|
|
];
|
|
|
|
if (Schema::hasColumn('contabilita_movimenti', 'metadata')) {
|
|
$payload['metadata'] = json_encode($metadata, JSON_UNESCAPED_SLASHES);
|
|
}
|
|
if (Schema::hasColumn('contabilita_movimenti', 'entry_id')) {
|
|
$payload['entry_id'] = (int) $registrazione->id;
|
|
}
|
|
if (Schema::hasColumn('contabilita_movimenti', 'debit_amount')) {
|
|
$payload['debit_amount'] = $amount >= 0 ? abs($amount) : 0;
|
|
}
|
|
if (Schema::hasColumn('contabilita_movimenti', 'credit_amount')) {
|
|
$payload['credit_amount'] = $amount < 0 ? abs($amount) : 0;
|
|
}
|
|
|
|
Movimento::query()->create($payload);
|
|
}
|
|
|
|
private function classifyLegacyOperation(object $row): array
|
|
{
|
|
$compet = strtoupper(trim((string) ($row->compet ?? 'C')));
|
|
if (! in_array($compet, ['C', 'P'], true)) {
|
|
$compet = 'C';
|
|
}
|
|
|
|
$natura2 = trim((string) ($row->natura2 ?? ''));
|
|
$naturaNorm = strtoupper($natura2);
|
|
|
|
$postingMode = 'cost';
|
|
$allowCostVoice = true;
|
|
|
|
if ($compet === 'P') {
|
|
$postingMode = 'supplier_debt_payment';
|
|
$allowCostVoice = false;
|
|
} elseif (in_array($naturaNorm, ['DEBITO', 'D'], true)) {
|
|
$postingMode = 'supplier_debt_open';
|
|
} elseif (in_array($naturaNorm, ['CREDITO', 'C'], true)) {
|
|
$postingMode = 'credit';
|
|
$allowCostVoice = false;
|
|
} elseif (in_array($naturaNorm, ['ENTRATA', 'ENTRATE', 'E'], true)) {
|
|
$postingMode = 'income';
|
|
$allowCostVoice = false;
|
|
}
|
|
|
|
return [
|
|
'compet' => $compet,
|
|
'natura2' => $natura2,
|
|
'posting_mode' => $postingMode,
|
|
'allow_cost_voice' => $allowCostVoice,
|
|
];
|
|
}
|
|
|
|
private function resolveLegacyContoId(int $stabileId, array $legacyClassification): int
|
|
{
|
|
$codice = match ($legacyClassification['posting_mode'] ?? 'cost') {
|
|
'supplier_debt_payment', 'supplier_debt_open' => (string) config('contabilita.conti_speciali.debiti_fornitori_codice', '2000'),
|
|
'credit', 'income' => (string) config('contabilita.conti_speciali.crediti_condomini_codice', '1100'),
|
|
default => '5100',
|
|
};
|
|
|
|
return $this->resolveOrCreateSpecialPianoConto($codice);
|
|
}
|
|
|
|
private function resolveOrCreateSpecialPianoConto(string $codice): int
|
|
{
|
|
if (! Schema::hasTable('contabilita_piano_conti')) {
|
|
return 0;
|
|
}
|
|
|
|
$existing = DB::table('contabilita_piano_conti')
|
|
->where('codice', $codice)
|
|
->value('id');
|
|
|
|
if (is_numeric($existing) && (int) $existing > 0) {
|
|
return (int) $existing;
|
|
}
|
|
|
|
$tipoConto = match (substr($codice, 0, 1)) {
|
|
'1' => 'ATTIVO',
|
|
'2' => 'PASSIVO',
|
|
'3' => 'PATRIMONIO',
|
|
'4' => 'RICAVO',
|
|
default => 'COSTO',
|
|
};
|
|
|
|
$descrizione = match ($codice) {
|
|
'2000' => (string) config('contabilita.conti_speciali.debiti_fornitori_descrizione', 'Debiti verso fornitori'),
|
|
'1100' => (string) config('contabilita.conti_speciali.crediti_condomini_descrizione', 'Crediti verso condomini'),
|
|
default => 'Servizi condominiali',
|
|
};
|
|
|
|
return (int) DB::table('contabilita_piano_conti')->insertGetId([
|
|
'codice' => $codice,
|
|
'denominazione' => $descrizione,
|
|
'tipo_conto' => $tipoConto,
|
|
'attivo' => 1,
|
|
'created_at' => now(),
|
|
'updated_at' => now(),
|
|
]);
|
|
}
|
|
|
|
private function resolveOperationAmount(object $row): float
|
|
{
|
|
foreach (['importo_euro', 'importo', 'importo_spese', 'importo_entrate'] as $field) {
|
|
if (isset($row->{$field}) && is_numeric($row->{$field}) && (float) $row->{$field} != 0.0) {
|
|
$value = (float) $row->{$field};
|
|
if ($field === 'importo_entrate') {
|
|
return -abs($value);
|
|
}
|
|
|
|
return $value;
|
|
}
|
|
}
|
|
|
|
return 0.0;
|
|
}
|
|
}
|