384 lines
12 KiB
PHP
Executable File
384 lines
12 KiB
PHP
Executable File
<?php
|
|
|
|
namespace App\Modules\Contabilita\Models;
|
|
|
|
use App\Models\DatiBancari;
|
|
use App\Models\Fornitore;
|
|
use App\Models\GestioneContabile;
|
|
use App\Models\RubricaUniversale;
|
|
use App\Models\Stabile;
|
|
use Illuminate\Database\Eloquent\Model;
|
|
|
|
class MovimentoBanca extends Model
|
|
{
|
|
protected static ?array $cleaningConfigCache = null;
|
|
protected $table = 'contabilita_movimenti_banca';
|
|
|
|
protected $fillable = [
|
|
'stabile_id',
|
|
'conto_id',
|
|
'gestione_id',
|
|
'iban',
|
|
'data',
|
|
'valuta',
|
|
'descrizione',
|
|
'descrizione_estesa',
|
|
'importo',
|
|
'causale',
|
|
'tipo_operazione',
|
|
'mittente',
|
|
'beneficiario',
|
|
'rif_documento',
|
|
'rif_disposizione',
|
|
'codice_cbill',
|
|
'codice_sdd',
|
|
'cod_abi',
|
|
'cod_cab',
|
|
'banca_nome',
|
|
'categoria_banca',
|
|
'unita_immobiliare_id',
|
|
'incasso_id',
|
|
'operazione_contabile_id',
|
|
'stato_riconciliazione',
|
|
'source_file',
|
|
'raw_line',
|
|
'row_hash',
|
|
'da_confermare',
|
|
'match_data',
|
|
'rubrica_mittente_id',
|
|
'rubrica_beneficiario_id',
|
|
'fornitore_id',
|
|
'registrazione_id',
|
|
];
|
|
|
|
protected $casts = [
|
|
'data' => 'date',
|
|
'valuta' => 'date',
|
|
'importo' => 'decimal:2',
|
|
'da_confermare' => 'boolean',
|
|
'match_data' => 'array',
|
|
];
|
|
|
|
public function getMittenteAttribute(): ?string
|
|
{
|
|
if ($this->rubricaMittente) {
|
|
return (string) ($this->rubricaMittente->ragione_sociale ?: trim(($this->rubricaMittente->cognome ?? '') . ' ' . ($this->rubricaMittente->nome ?? '')));
|
|
}
|
|
|
|
$val = $this->attributes['mittente'] ?? null;
|
|
if (! empty($val)) {
|
|
return (string) $val;
|
|
}
|
|
|
|
if (is_array($this->match_data) && ! empty($this->match_data['mittente'])) {
|
|
return (string) $this->match_data['mittente'];
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
public function getBeneficiarioAttribute(): ?string
|
|
{
|
|
if ($this->fornitore) {
|
|
return (string) $this->fornitore->ragione_sociale;
|
|
}
|
|
|
|
if ($this->rubricaBeneficiario) {
|
|
return (string) ($this->rubricaBeneficiario->ragione_sociale ?: trim(($this->rubricaBeneficiario->cognome ?? '') . ' ' . ($this->rubricaBeneficiario->nome ?? '')));
|
|
}
|
|
|
|
$val = $this->attributes['beneficiario'] ?? null;
|
|
if (! empty($val)) {
|
|
return (string) $val;
|
|
}
|
|
|
|
if (is_array($this->match_data) && ! empty($this->match_data['beneficiario'])) {
|
|
return (string) $this->match_data['beneficiario'];
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
public function getTipoOperazioneAttribute(): ?string
|
|
{
|
|
$val = $this->attributes['tipo_operazione'] ?? null;
|
|
if (! empty($val)) {
|
|
return (string) $val;
|
|
}
|
|
|
|
if (is_array($this->match_data) && ! empty($this->match_data['tipo'])) {
|
|
return (string) $this->match_data['tipo'];
|
|
}
|
|
|
|
return $this->causale;
|
|
}
|
|
|
|
public function getRifDocumentoAttribute(): ?string
|
|
{
|
|
$val = $this->attributes['rif_documento'] ?? null;
|
|
if (! empty($val)) {
|
|
return (string) $val;
|
|
}
|
|
|
|
if (is_array($this->match_data)) {
|
|
if (! empty($this->match_data['rif_fattura'])) {
|
|
$doc = (string) $this->match_data['rif_fattura'];
|
|
if (! empty($this->match_data['data_fattura'])) {
|
|
$doc .= ' del ' . $this->match_data['data_fattura'];
|
|
}
|
|
return $doc;
|
|
}
|
|
if (! empty($this->match_data['riferimento'])) {
|
|
return (string) $this->match_data['riferimento'];
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
public function getDescrizioneEstesaPulitaAttribute(): ?string
|
|
{
|
|
$raw = $this->descrizione_estesa ?? $this->descrizione;
|
|
if (! is_string($raw)) {
|
|
return null;
|
|
}
|
|
|
|
$text = trim($raw);
|
|
if ($text === '') {
|
|
return null;
|
|
}
|
|
|
|
if (is_array($this->match_data ?? null) && ! empty($this->match_data['descrizione_base'])) {
|
|
$base = trim((string) $this->match_data['descrizione_base']);
|
|
if ($base !== '') {
|
|
$text = $base . ' ' . $text;
|
|
}
|
|
}
|
|
|
|
$text = $this->applyCleaningRules($text);
|
|
$text = preg_replace('/\s{2,}/', ' ', $text) ?? $text;
|
|
$text = trim($text, " \t\n\r\0\x0B|-");
|
|
|
|
return $text !== '' ? $text : null;
|
|
}
|
|
|
|
public function getDettaglioEstrattoAttribute(): array
|
|
{
|
|
$rawText = $this->descrizione_estesa ?? $this->descrizione ?? '';
|
|
$text = trim($rawText);
|
|
|
|
$commissioni = '';
|
|
$pos = -1;
|
|
foreach (['COMM', 'SPESE', 'TRN', 'COMMISSIONI', 'COMMISSIONE'] as $key) {
|
|
$p = stripos($text, $key);
|
|
if ($p !== false && ($pos === -1 || $p < $pos)) {
|
|
$pos = $p;
|
|
}
|
|
}
|
|
if ($pos !== -1) {
|
|
$commissioni = trim(substr($text, $pos));
|
|
$text = trim(substr($text, 0, $pos));
|
|
}
|
|
|
|
$bankPrefixes = [
|
|
'BONIFICO A VOSTRO FAVORE BONIFICO SEPA DA',
|
|
'BONIFICO A VOSTRO FAVORE BONIFICO SEPA',
|
|
'BONIFICO SEPA A VOSTRO FAVORE DA',
|
|
'BONIFICO SEPA A VOSTRO FAVORE',
|
|
'BONIFICO A VOSTRO FAVORE DA',
|
|
'BONIFICO A VOSTRO FAVORE',
|
|
'BONIFICO SEPA DA',
|
|
'BONIFICO SEPA',
|
|
'BONIFICO DA',
|
|
'BONIFICO ESEGUITO DA',
|
|
'ADDEBITO CORRISPETTIVI',
|
|
'GIROCONTO DA',
|
|
'GIROCONTO',
|
|
'DISPOSIZIONE DI PAGAMENTO DA',
|
|
'DISPOSIZIONE DI PAGAMENTO',
|
|
'PAGAMENTO CBILL',
|
|
'PAGAMENTO PAGOPA',
|
|
'VERSAMENTO DI CASSA',
|
|
'VERSAMENTO DA',
|
|
'VERSAMENTO',
|
|
'PRELEVAMENTO DA',
|
|
'PRELEVAMENTO',
|
|
'PAGAMENTO CON CARTA',
|
|
'PAGAMENTO POS',
|
|
'ADDEBITO DISPOSIZIONE SEPA',
|
|
'ADDEBITO SEPA',
|
|
];
|
|
|
|
$messaggioBanca = '';
|
|
$messaggioCliente = $text;
|
|
|
|
foreach ($bankPrefixes as $prefix) {
|
|
if (stripos($text, $prefix) === 0) {
|
|
$messaggioBanca = $prefix;
|
|
$messaggioCliente = trim(substr($text, strlen($prefix)));
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (empty($messaggioBanca)) {
|
|
if (is_array($this->match_data) && !empty($this->match_data['tipo'])) {
|
|
$messaggioBanca = ucwords(str_replace('_', ' ', (string) $this->match_data['tipo']));
|
|
} elseif (!empty($this->causale)) {
|
|
$messaggioBanca = $this->causale;
|
|
}
|
|
}
|
|
|
|
if (is_array($this->match_data) && !empty($this->match_data['dettaglio'])) {
|
|
$messaggioCliente = (string) $this->match_data['dettaglio'];
|
|
}
|
|
|
|
$cbillCode = null;
|
|
if (is_array($this->match_data) && !empty($this->match_data['codice_cbill'])) {
|
|
$cbillCode = (string) $this->match_data['codice_cbill'];
|
|
} elseif (preg_match('/(?:CBILL|PAGOPA|IUV|AVVISO|CODICE\s*AVVISO)\s*:?\s*(\d{10,20})/i', $rawText, $cbillMatches)) {
|
|
$cbillCode = $cbillMatches[1];
|
|
}
|
|
|
|
$sddCode = null;
|
|
if (is_array($this->match_data) && !empty($this->match_data['codice_sdd'])) {
|
|
$sddCode = (string) $this->match_data['codice_sdd'];
|
|
}
|
|
|
|
$abi = null;
|
|
if (is_array($this->match_data) && !empty($this->match_data['cod_abi'])) {
|
|
$abi = (string) $this->match_data['cod_abi'];
|
|
} elseif (!empty($this->raw_line)) {
|
|
$parts = explode(';', $this->raw_line);
|
|
if (count($parts) >= 2) {
|
|
$last = trim(end($parts));
|
|
if (preg_match('/^[a-zA-Z0-9]{3,5}$/', $last)) {
|
|
$abi = $last;
|
|
}
|
|
}
|
|
}
|
|
|
|
$bancaNome = is_array($this->match_data) && !empty($this->match_data['banca_nome'])
|
|
? (string) $this->match_data['banca_nome']
|
|
: null;
|
|
|
|
return [
|
|
'abi' => $abi,
|
|
'banca_nome' => $bancaNome,
|
|
'messaggio_banca' => $messaggioBanca ?: '—',
|
|
'messaggio_cliente' => $messaggioCliente ?: '—',
|
|
'commissioni_spese' => $commissioni ?: '—',
|
|
'cbill_code' => $cbillCode,
|
|
'sdd_code' => $sddCode,
|
|
'mittente' => $this->mittente,
|
|
'beneficiario' => $this->beneficiario,
|
|
'rif_documento' => $this->rif_documento,
|
|
];
|
|
}
|
|
|
|
protected function applyCleaningRules(string $text): string
|
|
{
|
|
$patterns = [];
|
|
$config = self::loadCleaningConfig();
|
|
if (isset($config['base']['remove_patterns']) && is_array($config['base']['remove_patterns'])) {
|
|
$patterns = array_merge($patterns, $config['base']['remove_patterns']);
|
|
}
|
|
|
|
$codice = $this->resolveCodiceBreve();
|
|
if ($codice && isset($config['codici'][$codice]['remove_patterns']) && is_array($config['codici'][$codice]['remove_patterns'])) {
|
|
$patterns = array_merge($patterns, $config['codici'][$codice]['remove_patterns']);
|
|
}
|
|
|
|
foreach ($patterns as $pattern) {
|
|
if (! is_string($pattern) || $pattern === '') {
|
|
continue;
|
|
}
|
|
$text = preg_replace('/' . $pattern . '/i', '', $text) ?? $text;
|
|
}
|
|
|
|
return $text;
|
|
}
|
|
|
|
protected function resolveCodiceBreve(): ?string
|
|
{
|
|
$raw = strtoupper((string) ($this->descrizione ?? ''));
|
|
if (str_contains($raw, 'ACCREDITO_BEU_CON_CONTABILE')) {
|
|
return 'ACCBEUCONCON';
|
|
}
|
|
if (str_contains($raw, 'COMBONMYB')) {
|
|
return 'COMBONMYB';
|
|
}
|
|
return null;
|
|
}
|
|
|
|
protected static function loadCleaningConfig(): array
|
|
{
|
|
if (self::$cleaningConfigCache !== null) {
|
|
return self::$cleaningConfigCache;
|
|
}
|
|
|
|
$path = base_path('resources/bank-cleaning.json');
|
|
if (! is_file($path)) {
|
|
return self::$cleaningConfigCache = [];
|
|
}
|
|
|
|
$json = file_get_contents($path);
|
|
$data = is_string($json) ? json_decode($json, true) : null;
|
|
if (! is_array($data)) {
|
|
return self::$cleaningConfigCache = [];
|
|
}
|
|
|
|
return self::$cleaningConfigCache = $data;
|
|
}
|
|
|
|
public function registrazione()
|
|
{
|
|
return $this->belongsTo(Registrazione::class, 'registrazione_id');
|
|
}
|
|
|
|
public function conto()
|
|
{
|
|
return $this->belongsTo(DatiBancari::class, 'conto_id');
|
|
}
|
|
|
|
public function gestioneContabile()
|
|
{
|
|
return $this->belongsTo(GestioneContabile::class, 'gestione_id');
|
|
}
|
|
|
|
public function fornitore()
|
|
{
|
|
return $this->belongsTo(Fornitore::class, 'fornitore_id');
|
|
}
|
|
|
|
public function rubricaMittente()
|
|
{
|
|
return $this->belongsTo(RubricaUniversale::class, 'rubrica_mittente_id');
|
|
}
|
|
|
|
public function rubricaBeneficiario()
|
|
{
|
|
return $this->belongsTo(RubricaUniversale::class, 'rubrica_beneficiario_id');
|
|
}
|
|
|
|
public function stabile()
|
|
{
|
|
return $this->belongsTo(Stabile::class, 'stabile_id');
|
|
}
|
|
|
|
public function unitaImmobiliare()
|
|
{
|
|
return $this->belongsTo(\App\Models\UnitaImmobiliare::class, 'unita_immobiliare_id');
|
|
}
|
|
|
|
public function incasso()
|
|
{
|
|
return $this->belongsTo(\App\Models\Incasso::class, 'incasso_id');
|
|
}
|
|
|
|
public function operazioneContabile()
|
|
{
|
|
return $this->belongsTo(\App\Models\OperazioneContabile::class, 'operazione_contabile_id');
|
|
}
|
|
}
|
|
|