243 lines
9.6 KiB
PHP
243 lines
9.6 KiB
PHP
<?php
|
|
|
|
namespace App\Modules\Contabilita\Services;
|
|
|
|
use App\Models\ContoBancario;
|
|
use App\Models\Condomino;
|
|
use App\Models\Incasso;
|
|
use App\Models\MovimentoBancario;
|
|
use App\Models\User;
|
|
use App\Modules\Contabilita\Models\Movimento;
|
|
use App\Modules\Contabilita\Models\PianoConti;
|
|
use App\Modules\Contabilita\Models\RegolaPrimaNota;
|
|
use App\Modules\Contabilita\Models\Registrazione;
|
|
use Illuminate\Support\Facades\DB;
|
|
use Illuminate\Support\Facades\Schema;
|
|
use RuntimeException;
|
|
|
|
class IncassoPrimaNotaService
|
|
{
|
|
/**
|
|
* @param array{gestione_id?:int, modalita_incasso?:string, condomino_id?:int, conto_dare_id?:int, descrizione?:string, data_registrazione?:string} $override
|
|
*/
|
|
public function generaRegistrazioneDaIncasso(User $user, Incasso $incasso, array $override = []): Registrazione
|
|
{
|
|
if (! Schema::hasTable('contabilita_registrazioni') || ! Schema::hasTable('contabilita_movimenti')) {
|
|
throw new RuntimeException('Tabelle prima nota mancanti.');
|
|
}
|
|
|
|
if (Schema::hasColumn('incassi', 'registrazione_id') && ! empty($incasso->registrazione_id)) {
|
|
$existing = Registrazione::query()->find((int) $incasso->registrazione_id);
|
|
if ($existing) {
|
|
return $existing;
|
|
}
|
|
}
|
|
|
|
$stabileId = (int) ($incasso->condominio_id ?? 0);
|
|
if ($stabileId <= 0) {
|
|
throw new RuntimeException('Incasso senza condominio/stabile.');
|
|
}
|
|
|
|
$gestioneId = (int) (($override['gestione_id'] ?? null) ?: ($incasso->gestione_id ?? 0));
|
|
if ($gestioneId <= 0) {
|
|
throw new RuntimeException('Seleziona una gestione per questo incasso.');
|
|
}
|
|
|
|
if (Schema::hasTable('contabilita_chiusure_gestione')) {
|
|
$chiusa = app(ChiusuraGestioneService::class)->isGestioneChiusa($gestioneId);
|
|
if ($chiusa) {
|
|
throw new RuntimeException('Gestione chiusa: non è possibile generare nuove registrazioni.');
|
|
}
|
|
}
|
|
|
|
$importo = (float) ($incasso->importo_pagato_euro ?? $incasso->importo_pagato ?? 0);
|
|
if (abs($importo) < 0.005) {
|
|
throw new RuntimeException('Importo incasso non valido.');
|
|
}
|
|
$amount = round(abs($importo), 2);
|
|
|
|
$data = isset($override['data_registrazione']) && is_string($override['data_registrazione'])
|
|
? trim((string) $override['data_registrazione'])
|
|
: null;
|
|
|
|
if ($data === '') {
|
|
$data = null;
|
|
}
|
|
|
|
if (! empty($incasso->dt_empag)) {
|
|
try {
|
|
$data = $data ?: $incasso->dt_empag->toDateString();
|
|
} catch (\Throwable) {
|
|
$data = null;
|
|
}
|
|
}
|
|
if (! $data && ! empty($incasso->data_pagamento)) {
|
|
try {
|
|
$data = $incasso->data_pagamento->toDateString();
|
|
} catch (\Throwable) {
|
|
$data = null;
|
|
}
|
|
}
|
|
$data = $data ?: now()->toDateString();
|
|
|
|
$descr = isset($override['descrizione']) && is_string($override['descrizione']) ? trim((string) $override['descrizione']) : '';
|
|
|
|
if ($descr === '' && ! empty($incasso->movimento_bancario_id)) {
|
|
$mb = MovimentoBancario::query()->find((int) $incasso->movimento_bancario_id);
|
|
if ($mb) {
|
|
$parts = [];
|
|
$c = is_string($mb->causale) ? trim((string) $mb->causale) : '';
|
|
if ($c !== '') {
|
|
$parts[] = $c;
|
|
}
|
|
$b = is_string($mb->beneficiario) ? trim((string) $mb->beneficiario) : '';
|
|
if ($b !== '') {
|
|
$parts[] = $b;
|
|
}
|
|
$n = is_string($mb->note) ? trim((string) $mb->note) : '';
|
|
if ($n !== '') {
|
|
$parts[] = $n;
|
|
}
|
|
|
|
$descr = trim(implode(' - ', $parts));
|
|
}
|
|
}
|
|
|
|
if ($descr === '') {
|
|
$descr = is_string($incasso->descrizione) ? trim((string) $incasso->descrizione) : '';
|
|
}
|
|
if ($descr === '') {
|
|
$nr = is_numeric($incasso->n_ricevuta ?? null) ? (' #'.(int) $incasso->n_ricevuta) : '';
|
|
$descr = 'Incasso rata' . $nr;
|
|
}
|
|
|
|
$contoBancarioId = (int) ($incasso->conto_bancario_id ?? 0);
|
|
if ($contoBancarioId <= 0) {
|
|
throw new RuntimeException('Incasso senza conto bancario/cassa.');
|
|
}
|
|
|
|
$contoBancario = ContoBancario::query()->find($contoBancarioId);
|
|
|
|
$modalita = isset($override['modalita_incasso']) && is_string($override['modalita_incasso'])
|
|
? trim((string) $override['modalita_incasso'])
|
|
: (is_string($incasso->modalita_incasso ?? null) ? trim((string) $incasso->modalita_incasso) : '');
|
|
|
|
$chiave = $modalita !== ''
|
|
? $modalita
|
|
: (
|
|
$contoBancario && is_string($contoBancario->codice) && trim($contoBancario->codice) !== ''
|
|
? trim($contoBancario->codice)
|
|
: 'default'
|
|
);
|
|
|
|
$regola = RegolaPrimaNota::query()
|
|
->where('stabile_id', $stabileId)
|
|
->where('origine', 'incasso')
|
|
->where('chiave', $chiave)
|
|
->where('attiva', true)
|
|
->first();
|
|
|
|
if (! $regola) {
|
|
$regola = RegolaPrimaNota::query()
|
|
->where('stabile_id', $stabileId)
|
|
->where('origine', 'incasso')
|
|
->where('chiave', 'default')
|
|
->where('attiva', true)
|
|
->first();
|
|
}
|
|
|
|
$contoDareId = isset($override['conto_dare_id']) && (int) $override['conto_dare_id'] > 0
|
|
? (int) $override['conto_dare_id']
|
|
: ($regola?->conto_dare_id ? (int) $regola->conto_dare_id : null);
|
|
|
|
$contoAvereId = $regola?->conto_avere_id ? (int) $regola->conto_avere_id : null;
|
|
|
|
// Fallback minimo: prova a risolvere conti per codice (banca/cassa = codice conto bancario; crediti condomini = config)
|
|
if (! $contoDareId) {
|
|
if ($contoBancario && is_string($contoBancario->codice)) {
|
|
$byCode = PianoConti::query()->where('codice', trim((string) $contoBancario->codice))->first();
|
|
if ($byCode) {
|
|
$contoDareId = (int) $byCode->id;
|
|
}
|
|
}
|
|
}
|
|
|
|
$condominoId = (int) (($override['condomino_id'] ?? null) ?: ($incasso->condomino_id ?? 0));
|
|
|
|
if (! $contoAvereId && $condominoId > 0) {
|
|
$condomino = Condomino::query()->find($condominoId);
|
|
$conto = app(ContiSoggettiService::class)->resolveContoCreditoCondomino(
|
|
$stabileId,
|
|
$condominoId,
|
|
$condomino?->display_name,
|
|
is_string($condomino?->codice_univoco ?? null) ? trim((string) $condomino->codice_univoco) : null
|
|
);
|
|
$contoAvereId = (int) $conto->id;
|
|
}
|
|
|
|
if (! $contoAvereId) {
|
|
$cod = (string) config('contabilita.conti_speciali.crediti_condomini_codice', '1100');
|
|
$desc = (string) config('contabilita.conti_speciali.crediti_condomini_descrizione', 'Crediti verso condomini');
|
|
$tipo = (string) config('contabilita.conti_speciali.crediti_condomini_tipo', 'Attività');
|
|
$conto = app(ChiusuraGestioneService::class)->resolveOrCreateConto($cod, $desc, $tipo);
|
|
$contoAvereId = (int) $conto->id;
|
|
}
|
|
|
|
if (! $contoDareId || ! $contoAvereId) {
|
|
throw new RuntimeException('Regola prima nota incassi non configurata (origine=incasso, chiave=' . $chiave . ' o default).');
|
|
}
|
|
|
|
return DB::transaction(function () use ($user, $incasso, $stabileId, $gestioneId, $data, $descr, $amount, $contoDareId, $contoAvereId, $modalita, $condominoId) {
|
|
$regPayload = [
|
|
'stabile_id' => $stabileId,
|
|
'gestione_id' => (Schema::hasColumn('contabilita_registrazioni', 'gestione_id')
|
|
? Registrazione::resolveGestioneIdOrDefault($gestioneId, $stabileId, $data)
|
|
: null),
|
|
'data_registrazione' => $data,
|
|
'descrizione' => $descr,
|
|
'created_by' => (int) $user->id,
|
|
'updated_by' => (int) $user->id,
|
|
];
|
|
|
|
if (Schema::hasColumn('contabilita_registrazioni', 'user_id')) {
|
|
$regPayload['user_id'] = (int) $user->id;
|
|
}
|
|
|
|
/** @var Registrazione $reg */
|
|
$reg = Registrazione::query()->create($regPayload);
|
|
|
|
Movimento::query()->create([
|
|
'registrazione_id' => (int) $reg->id,
|
|
'conto_id' => (int) $contoDareId,
|
|
'tipo' => 'dare',
|
|
'importo' => $amount,
|
|
]);
|
|
|
|
Movimento::query()->create([
|
|
'registrazione_id' => (int) $reg->id,
|
|
'conto_id' => (int) $contoAvereId,
|
|
'tipo' => 'avere',
|
|
'importo' => $amount,
|
|
]);
|
|
|
|
$reg->assertBilanciata();
|
|
|
|
if (Schema::hasColumn('incassi', 'registrazione_id')) {
|
|
$incasso->registrazione_id = (int) $reg->id;
|
|
if (Schema::hasColumn('incassi', 'gestione_id') && empty($incasso->gestione_id)) {
|
|
$incasso->gestione_id = $gestioneId;
|
|
}
|
|
if (Schema::hasColumn('incassi', 'modalita_incasso') && $modalita !== '') {
|
|
$incasso->modalita_incasso = $modalita;
|
|
}
|
|
if (Schema::hasColumn('incassi', 'condomino_id') && $condominoId > 0) {
|
|
$incasso->condomino_id = $condominoId;
|
|
}
|
|
$incasso->save();
|
|
}
|
|
|
|
return $reg;
|
|
});
|
|
}
|
|
}
|