'Activo', self::STATUS_PAID_OFF => 'Liquidado', self::STATUS_DEFAULTED => 'En mora', self::STATUS_RENEGOTIATED => 'Renegociado', ]; /** * Tipos de contrato */ public const CONTRACT_TYPE_PERSONAL_LOAN = 'personal_loan'; public const CONTRACT_TYPE_VEHICLE = 'vehicle_financing'; public const CONTRACT_TYPE_MORTGAGE = 'mortgage'; public const CONTRACT_TYPE_CREDIT_CARD = 'credit_card'; public const CONTRACT_TYPE_CONSORTIUM = 'consortium'; public const CONTRACT_TYPE_LEASING = 'leasing'; public const CONTRACT_TYPE_OVERDRAFT = 'overdraft'; public const CONTRACT_TYPE_PAYROLL_LOAN = 'payroll_loan'; public const CONTRACT_TYPE_OTHER = 'other'; public const CONTRACT_TYPES = [ self::CONTRACT_TYPE_PERSONAL_LOAN => [ 'name' => 'Préstamo Personal', 'description' => 'Préstamo con cuotas fijas (Sistema PRICE)', 'icon' => 'banknotes', 'default_amortization' => 'price', 'fields' => ['principal_amount', 'annual_interest_rate', 'total_installments', 'start_date', 'first_due_date'], ], self::CONTRACT_TYPE_VEHICLE => [ 'name' => 'Financiación de Vehículo', 'description' => 'Crédito para compra de coche o moto', 'icon' => 'truck', 'default_amortization' => 'price', 'fields' => ['principal_amount', 'annual_interest_rate', 'total_installments', 'start_date', 'first_due_date', 'asset_value'], ], self::CONTRACT_TYPE_MORTGAGE => [ 'name' => 'Hipoteca / Financiación Inmobiliaria', 'description' => 'Crédito para compra de inmueble', 'icon' => 'home', 'default_amortization' => 'sac', 'fields' => ['principal_amount', 'annual_interest_rate', 'total_installments', 'start_date', 'first_due_date', 'asset_value', 'insurance_amount'], ], self::CONTRACT_TYPE_CREDIT_CARD => [ 'name' => 'Tarjeta de Crédito', 'description' => 'Financiación de compras a plazos', 'icon' => 'credit-card', 'default_amortization' => 'price', 'fields' => ['principal_amount', 'annual_interest_rate', 'total_installments', 'first_due_date'], ], self::CONTRACT_TYPE_CONSORTIUM => [ 'name' => 'Consorcio', 'description' => 'Grupo de compras con cuotas variables', 'icon' => 'users', 'default_amortization' => 'consortium', 'fields' => ['principal_amount', 'total_installments', 'admin_fee_percent', 'start_date', 'first_due_date'], ], self::CONTRACT_TYPE_LEASING => [ 'name' => 'Leasing', 'description' => 'Arrendamiento con opción de compra', 'icon' => 'key', 'default_amortization' => 'price', 'fields' => ['principal_amount', 'annual_interest_rate', 'total_installments', 'start_date', 'first_due_date', 'residual_value'], ], self::CONTRACT_TYPE_OVERDRAFT => [ 'name' => 'Descubierto / Cheque Especial', 'description' => 'Línea de crédito rotativa', 'icon' => 'arrow-trending-down', 'default_amortization' => 'american', 'fields' => ['principal_amount', 'monthly_interest_rate'], ], self::CONTRACT_TYPE_PAYROLL_LOAN => [ 'name' => 'Préstamo con Nómina', 'description' => 'Crédito con descuento en nómina', 'icon' => 'briefcase', 'default_amortization' => 'price', 'fields' => ['principal_amount', 'annual_interest_rate', 'total_installments', 'start_date', 'first_due_date'], ], self::CONTRACT_TYPE_OTHER => [ 'name' => 'Otro', 'description' => 'Otro tipo de pasivo', 'icon' => 'document-text', 'default_amortization' => 'price', 'fields' => ['principal_amount', 'total_installments', 'first_due_date'], ], ]; /** * Sistemas de amortização */ public const AMORTIZATION_PRICE = 'price'; public const AMORTIZATION_SAC = 'sac'; public const AMORTIZATION_AMERICAN = 'american'; public const AMORTIZATION_CONSORTIUM = 'consortium'; public const AMORTIZATION_SYSTEMS = [ self::AMORTIZATION_PRICE => [ 'name' => 'PRICE (Cuota Fija)', 'description' => 'Cuotas iguales. Intereses decrecientes, amortización creciente.', ], self::AMORTIZATION_SAC => [ 'name' => 'SAC (Amortización Constante)', 'description' => 'Amortización fija. Cuotas e intereses decrecientes.', ], self::AMORTIZATION_AMERICAN => [ 'name' => 'Americano', 'description' => 'Solo intereses durante el plazo, principal al final.', ], self::AMORTIZATION_CONSORTIUM => [ 'name' => 'Consorcio', 'description' => 'Cuotas variables según el grupo.', ], ]; /** * Tipos de indexadores */ public const INDEX_TYPES = [ 'fixed' => ['name' => 'Tasa Fija', 'description' => 'Sin indexación'], 'cdi' => ['name' => 'CDI', 'description' => 'Certificado de Depósito Interbancario (Brasil)'], 'selic' => ['name' => 'SELIC', 'description' => 'Tasa básica de interés (Brasil)'], 'ipca' => ['name' => 'IPCA', 'description' => 'Índice de precios al consumidor (Brasil)'], 'igpm' => ['name' => 'IGP-M', 'description' => 'Índice general de precios (Brasil)'], 'tr' => ['name' => 'TR', 'description' => 'Tasa referencial (Brasil)'], 'euribor' => ['name' => 'Euribor', 'description' => 'Euro Interbank Offered Rate (UE)'], 'libor' => ['name' => 'LIBOR', 'description' => 'London Interbank Offered Rate'], 'sofr' => ['name' => 'SOFR', 'description' => 'Secured Overnight Financing Rate (EUA)'], 'prime' => ['name' => 'Prime Rate', 'description' => 'Tasa preferencial (EUA)'], 'ipc' => ['name' => 'IPC', 'description' => 'Índice de precios al consumidor (España)'], 'other' => ['name' => 'Otro', 'description' => 'Otro indexador'], ]; /** * Tipos de garantia */ public const GUARANTEE_TYPES = [ 'none' => ['name' => 'Sin garantía', 'description' => 'Préstamo sin garantía'], 'fiduciary_alienation' => ['name' => 'Alienación Fiduciaria', 'description' => 'El bien queda en garantía hasta el pago total'], 'mortgage' => ['name' => 'Hipoteca', 'description' => 'Garantía sobre inmueble'], 'pledge' => ['name' => 'Prenda', 'description' => 'Garantía sobre bien mueble'], 'guarantor' => ['name' => 'Fiador/Avalista', 'description' => 'Persona que garantiza la deuda'], 'payroll' => ['name' => 'Descuento en Nómina', 'description' => 'Descuento directo del salario'], 'investment' => ['name' => 'Inversión', 'description' => 'Garantía con inversiones/aplicaciones'], 'letter_of_credit' => ['name' => 'Carta de Crédito', 'description' => 'Garantía bancaria'], 'surety_bond' => ['name' => 'Seguro Fianza', 'description' => 'Seguro que garantiza la obligación'], 'other' => ['name' => 'Otra', 'description' => 'Otro tipo de garantía'], ]; protected $fillable = [ 'user_id', 'account_id', 'name', 'contract_type', 'amortization_system', 'contract_number', 'creditor', 'description', 'principal_amount', 'total_interest', 'total_fees', 'total_contract_value', 'total_paid', 'total_pending', 'principal_paid', 'interest_paid', 'fees_paid', 'monthly_interest_rate', 'annual_interest_rate', 'total_interest_rate', 'total_installments', 'paid_installments', 'pending_installments', 'start_date', 'end_date', 'first_due_date', 'has_grace_period', 'grace_period_months', 'currency', 'color', 'icon', 'status', 'is_active', // Campos avançados - Indexadores 'index_type', 'index_spread', 'total_effective_cost', // Campos avançados - Garantias 'guarantee_type', 'guarantee_value', 'guarantee_description', 'guarantor_name', // Campos avançados - Penalidades 'late_fee_percent', 'daily_penalty_percent', 'grace_days_for_penalty', // Campos avançados - Específicos por tipo 'asset_value', 'asset_description', 'residual_value', 'admin_fee_percent', 'reserve_fund_percent', // Campos avançados - Covenants e gestão 'covenants', 'alert_days_before', 'internal_responsible', 'internal_notes', 'document_number', 'registry_office', ]; protected $casts = [ 'principal_amount' => 'decimal:2', 'total_interest' => 'decimal:2', 'total_fees' => 'decimal:2', 'total_contract_value' => 'decimal:2', 'total_paid' => 'decimal:2', 'total_pending' => 'decimal:2', 'principal_paid' => 'decimal:2', 'interest_paid' => 'decimal:2', 'fees_paid' => 'decimal:2', 'monthly_interest_rate' => 'decimal:4', 'annual_interest_rate' => 'decimal:4', 'total_interest_rate' => 'decimal:4', 'start_date' => 'date', 'end_date' => 'date', 'first_due_date' => 'date', 'is_active' => 'boolean', 'has_grace_period' => 'boolean', 'grace_period_months' => 'integer', // Campos avançados 'index_spread' => 'decimal:4', 'total_effective_cost' => 'decimal:4', 'guarantee_value' => 'decimal:2', 'late_fee_percent' => 'decimal:2', 'daily_penalty_percent' => 'decimal:4', 'grace_days_for_penalty' => 'integer', 'asset_value' => 'decimal:2', 'residual_value' => 'decimal:2', 'admin_fee_percent' => 'decimal:2', 'reserve_fund_percent' => 'decimal:2', 'covenants' => 'array', 'alert_days_before' => 'integer', ]; protected $appends = ['progress_percentage', 'remaining_balance']; /** * Relação com o usuário */ public function user(): BelongsTo { return $this->belongsTo(User::class); } /** * Relação com a conta geral (opcional) */ public function account(): BelongsTo { return $this->belongsTo(Account::class); } /** * Parcelas do contrato */ public function installments(): HasMany { return $this->hasMany(LiabilityInstallment::class)->orderBy('installment_number'); } /** * Parcelas pagas */ public function paidInstallments(): HasMany { return $this->hasMany(LiabilityInstallment::class)->where('status', 'paid'); } /** * Parcelas pendentes */ public function pendingInstallments(): HasMany { return $this->hasMany(LiabilityInstallment::class)->where('status', 'pending'); } /** * Próxima parcela a vencer */ public function nextInstallment() { return $this->installments() ->where('status', 'pending') ->orderBy('due_date') ->first(); } /** * Percentual de progresso (quanto já foi pago do principal) */ public function getProgressPercentageAttribute(): float { if ($this->principal_amount <= 0) { return 0; } return round(($this->principal_paid / $this->principal_amount) * 100, 2); } /** * Saldo restante do principal */ public function getRemainingBalanceAttribute(): float { return $this->principal_amount - $this->principal_paid; } /** * Recalcular totais baseado nas parcelas */ public function recalculateTotals(): void { $installments = $this->installments()->get(); $this->total_installments = $installments->count(); $this->paid_installments = $installments->where('status', 'paid')->count(); $this->pending_installments = $installments->where('status', 'pending')->count(); // Totais do contrato $this->total_interest = $installments->sum('interest_amount'); $this->total_fees = $installments->sum('fee_amount'); $this->principal_amount = $installments->sum('principal_amount'); $this->total_contract_value = $installments->sum('installment_amount'); // Valores pagos $paidInstallments = $installments->where('status', 'paid'); $this->total_paid = $paidInstallments->sum('installment_amount'); $this->principal_paid = $paidInstallments->sum('principal_amount'); $this->interest_paid = $paidInstallments->sum('interest_amount'); $this->fees_paid = $paidInstallments->sum('fee_amount'); // Valores pendentes $pendingInstallments = $installments->where('status', 'pending'); $this->total_pending = $pendingInstallments->sum('installment_amount'); // Calcular taxas de juros $this->calculateInterestRates(); // Datas $firstInstallment = $installments->sortBy('due_date')->first(); $lastInstallment = $installments->sortBy('due_date')->last(); if ($firstInstallment) { $this->first_due_date = $firstInstallment->due_date; $this->start_date = $firstInstallment->due_date; } if ($lastInstallment) { $this->end_date = $lastInstallment->due_date; } // Atualizar status if ($this->pending_installments === 0 && $this->paid_installments > 0) { $this->status = self::STATUS_PAID_OFF; } $this->save(); } /** * Calcular taxas de juros baseado nos dados */ protected function calculateInterestRates(): void { if ($this->principal_amount <= 0) { return; } // Taxa total do contrato $this->total_interest_rate = round(($this->total_interest / $this->principal_amount) * 100, 4); // Taxa mensal média if ($this->total_installments > 0) { $this->monthly_interest_rate = round($this->total_interest_rate / $this->total_installments, 4); $this->annual_interest_rate = round($this->monthly_interest_rate * 12, 4); } } /** * Scope para contas ativas */ public function scopeActive($query) { return $query->where('is_active', true); } /** * Scope para um status específico */ public function scopeOfStatus($query, string $status) { return $query->where('status', $status); } }