'decimal:4', 'importo_pagato_euro' => 'decimal:4', 'scostamento_importo' => 'decimal:4', 'confidenza_match' => 'decimal:2', 'dt_empag' => 'datetime', 'data_pagamento' => 'date', 'data_competenza' => 'date', 'rate_associate' => 'array', 'metadati_gescon' => 'array', 'log_riconciliazione' => 'array', ]; /** * Condominio di appartenenza */ public function condominio(): BelongsTo { return $this->belongsTo(Condominio::class); } /** * Conto bancario utilizzato */ public function contoBancario(): BelongsTo { return $this->belongsTo(ContoBancario::class, 'conto_bancario_id'); } /** * Condomino che ha effettuato il pagamento */ public function condomino(): BelongsTo { return $this->belongsTo(Condomino::class); } /** * Movimento bancario associato */ public function movimentoBancario(): BelongsTo { return $this->belongsTo(MovimentoBancario::class, 'movimento_bancario_id'); } /** * Scope per tenant */ public function scopeForTenant($query, string $tenantId) { return $query->where('tenant_id', $tenantId); } /** * Scope per anno */ public function scopeAnno($query, int $anno) { return $query->where('anno_rif', $anno); } /** * Scope per tipo spesa */ public function scopeTipoSpesa($query, string $ors) { return $query->where('o_r_s', $ors); } /** * Scope per stato riconciliazione */ public function scopeStatoRiconciliazione($query, string $stato) { return $query->where('stato_riconciliazione', $stato); } /** * Scope per condominio */ public function scopeCondominio($query, int $condominioId) { return $query->where('condominio_id', $condominioId); } /** * Scope riconciliati */ public function scopeRiconciliati($query) { return $query->whereIn('stato_riconciliazione', ['automatica', 'manuale']); } /** * Scope sospesi */ public function scopeSospesi($query) { return $query->where('stato_riconciliazione', 'sospesa'); } /** * Scope per periodo */ public function scopePeriodo($query, Carbon $dataInizio, Carbon $dataFine) { return $query->whereBetween('data_pagamento', [$dataInizio, $dataFine]); } /** * Verifica se è riconciliato */ public function isRiconciliato(): bool { return in_array($this->stato_riconciliazione, ['automatica', 'manuale']); } /** * Verifica se è anomalo */ public function isAnomalo(): bool { return $this->stato_riconciliazione === 'anomala' || $this->scostamento_importo > 10 || $this->giorni_scostamento > 30; } /** * Descrizione tipo spesa */ public function getDescrizioneTipoSpesa(): string { return match ($this->o_r_s) { 'O' => 'Ordinarie', 'R' => 'Riscaldamento', 'S' => 'Straordinarie', default => 'Altro' }; } /** * Colore stato riconciliazione */ public function getColoreStatoRiconciliazione(): string { return match ($this->stato_riconciliazione) { 'automatica' => 'success', 'manuale' => 'info', 'sospesa' => 'warning', 'anomala' => 'danger', default => 'secondary' }; } /** * Descrizione stato riconciliazione */ public function getDescrizioneStatoRiconciliazione(): string { return match ($this->stato_riconciliazione) { 'automatica' => 'Riconciliata automaticamente', 'manuale' => 'Riconciliata manualmente', 'sospesa' => 'In attesa di riconciliazione', 'anomala' => 'Anomalia da verificare', default => 'Stato sconosciuto' }; } /** * Formatta importo */ public function getImportoFormattato(): string { return '€ ' . number_format($this->importo_pagato_euro, 2, ',', '.'); } /** * Info per riconciliazione */ public function getInfoRiconciliazione(): array { return [ 'stato' => $this->stato_riconciliazione, 'descrizione_stato' => $this->getDescrizioneStatoRiconciliazione(), 'colore_stato' => $this->getColoreStatoRiconciliazione(), 'confidenza_match' => $this->confidenza_match, 'scostamento_importo' => $this->scostamento_importo, 'giorni_scostamento' => $this->giorni_scostamento, 'movimento_associato' => $this->movimento_bancario_id ? true : false, 'anomalo' => $this->isAnomalo(), ]; } /** * Associa movimento bancario */ public function associaMovimentoBancario(MovimentoBancario $movimento, string $tipoRiconciliazione = 'manuale'): void { $this->update([ 'movimento_bancario_id' => $movimento->id, 'stato_riconciliazione' => $tipoRiconciliazione, 'scostamento_importo' => abs($this->importo_pagato_euro - $movimento->importo), 'giorni_scostamento' => $this->data_pagamento ? abs($this->data_pagamento->diffInDays($movimento->data_operazione)) : 0, 'log_riconciliazione' => array_merge($this->log_riconciliazione ?? [], [[ 'data' => now(), 'tipo' => $tipoRiconciliazione, 'movimento_id' => $movimento->id, 'user_id' => auth()->id(), ]]) ]); $movimento->update([ 'incasso_id' => $this->id, 'stato_riconciliazione' => $tipoRiconciliazione, ]); } /** * Rimuovi associazione movimento */ public function rimuoviAssociazioneMovimento(): void { if ($this->movimento_bancario_id) { $movimento = $this->movimentoBancario; $this->update([ 'movimento_bancario_id' => null, 'stato_riconciliazione' => 'sospesa', 'scostamento_importo' => 0, 'giorni_scostamento' => 0, 'confidenza_match' => 0, 'log_riconciliazione' => array_merge($this->log_riconciliazione ?? [], [[ 'data' => now(), 'tipo' => 'disassociazione', 'movimento_id' => $movimento->id, 'user_id' => auth()->id(), ]]) ]); $movimento->update([ 'incasso_id' => null, 'stato_riconciliazione' => 'sospesa', ]); } } /** * Rate potenzialmente associate */ public function getRatePotenziali(): array { // Logic per trovare rate che potrebbero essere associate a questo incasso // Basato su condominio, anno, mese, tipo spesa, importo return []; } /** * Genera riferimento univoco */ public function getRiferimentoUnico(): string { return sprintf( '%s-%04d-%02d-%s-%d', $this->cod_cond_gescon, $this->anno_rif, (int) $this->n_mese, $this->o_r_s, $this->n_ricevuta ); } /** * Info completa per dashboard */ public function getInfoCompleta(): array { return [ 'id' => $this->id, 'riferimento' => $this->getRiferimentoUnico(), 'condominio' => $this->condominio?->nome_condominio, 'condomino' => $this->condomino?->nome_completo, 'importo' => $this->importo_pagato_euro, 'importo_formattato' => $this->getImportoFormattato(), 'data_pagamento' => $this->data_pagamento?->format('d/m/Y'), 'tipo_spesa' => $this->getDescrizioneTipoSpesa(), 'anno_competenza' => $this->anno_rif, 'mese_competenza' => $this->n_mese, 'conto_bancario' => $this->contoBancario?->descrizione, 'riconciliazione' => $this->getInfoRiconciliazione(), 'note' => $this->note, 'descrizione' => $this->descrizione, ]; } }