'Activo', self::STATUS_SOLD => 'Vendido', self::STATUS_DEPRECIATED => 'Depreciado', self::STATUS_WRITTEN_OFF => 'Dado de baja', ]; /** * Tipos de ativo */ public const ASSET_TYPE_REAL_ESTATE = 'real_estate'; public const ASSET_TYPE_VEHICLE = 'vehicle'; public const ASSET_TYPE_INVESTMENT = 'investment'; public const ASSET_TYPE_EQUIPMENT = 'equipment'; public const ASSET_TYPE_INVENTORY = 'inventory'; public const ASSET_TYPE_RECEIVABLE = 'receivable'; public const ASSET_TYPE_CASH = 'cash'; public const ASSET_TYPE_OTHER = 'other'; public const ASSET_TYPES = [ self::ASSET_TYPE_REAL_ESTATE => [ 'name' => 'Inmueble', 'description' => 'Casa, apartamento, terreno, local comercial', 'icon' => 'home', 'is_depreciable' => true, 'fields' => ['property_type', 'address', 'property_area_m2', 'registry_number'], ], self::ASSET_TYPE_VEHICLE => [ 'name' => 'Vehículo', 'description' => 'Coche, moto, camión, maquinaria móvil', 'icon' => 'truck', 'is_depreciable' => true, 'fields' => ['vehicle_brand', 'vehicle_model', 'vehicle_year', 'vehicle_plate', 'vehicle_mileage'], ], self::ASSET_TYPE_INVESTMENT => [ 'name' => 'Inversión', 'description' => 'Acciones, fondos, bonos, criptomonedas', 'icon' => 'chart-bar', 'is_depreciable' => false, 'fields' => ['investment_type', 'institution', 'ticker', 'quantity', 'unit_price'], ], self::ASSET_TYPE_EQUIPMENT => [ 'name' => 'Equipamiento', 'description' => 'Maquinaria, herramientas, ordenadores', 'icon' => 'cog', 'is_depreciable' => true, 'fields' => ['equipment_brand', 'equipment_model', 'serial_number', 'warranty_expiry'], ], self::ASSET_TYPE_INVENTORY => [ 'name' => 'Inventario', 'description' => 'Stock, mercancías, materias primas', 'icon' => 'archive-box', 'is_depreciable' => false, 'fields' => ['quantity'], ], self::ASSET_TYPE_RECEIVABLE => [ 'name' => 'Cuenta por Cobrar', 'description' => 'Créditos, préstamos otorgados', 'icon' => 'banknotes', 'is_depreciable' => false, 'fields' => ['debtor_name', 'receivable_due_date', 'receivable_amount'], ], self::ASSET_TYPE_CASH => [ 'name' => 'Efectivo/Caja', 'description' => 'Dinero en efectivo, caja chica', 'icon' => 'currency-euro', 'is_depreciable' => false, 'fields' => [], ], self::ASSET_TYPE_OTHER => [ 'name' => 'Otro', 'description' => 'Otros tipos de activos', 'icon' => 'document-text', 'is_depreciable' => false, 'fields' => [], ], ]; /** * Tipos de imóvel */ public const PROPERTY_TYPES = [ 'house' => 'Casa', 'apartment' => 'Apartamento/Piso', 'land' => 'Terreno', 'commercial' => 'Local Comercial', 'industrial' => 'Nave Industrial', 'office' => 'Oficina', 'parking' => 'Plaza de Garaje', 'warehouse' => 'Almacén', 'rural' => 'Finca Rústica', ]; /** * Tipos de investimento */ public const INVESTMENT_TYPES = [ 'stocks' => ['name' => 'Acciones', 'description' => 'Participaciones en empresas cotizadas'], 'bonds' => ['name' => 'Bonos', 'description' => 'Títulos de deuda pública o privada'], 'funds' => ['name' => 'Fondos de Inversión', 'description' => 'Fondos mutuos, ETFs'], 'fixed_income' => ['name' => 'Renta Fija', 'description' => 'Depósitos, letras del tesoro'], 'crypto' => ['name' => 'Criptomonedas', 'description' => 'Bitcoin, Ethereum, etc.'], 'real_estate_fund' => ['name' => 'Fondo Inmobiliario', 'description' => 'REITs, SOCIMIs'], 'pension' => ['name' => 'Plan de Pensiones', 'description' => 'Ahorro para jubilación'], 'savings' => ['name' => 'Cuenta de Ahorro', 'description' => 'Cuentas remuneradas'], ]; /** * Métodos de depreciação */ public const DEPRECIATION_METHODS = [ 'linear' => ['name' => 'Lineal', 'description' => 'Depreciación constante cada año'], 'declining_balance' => ['name' => 'Saldo Decreciente', 'description' => 'Mayor depreciación al inicio'], 'units_production' => ['name' => 'Unidades Producidas', 'description' => 'Según uso/producción'], 'sum_years' => ['name' => 'Suma de Años', 'description' => 'Depreciación acelerada'], ]; /** * Tipos de indexadores (para investimentos) */ public const INDEX_TYPES = [ 'fixed' => ['name' => 'Tasa Fija', 'description' => 'Rentabilidad fija'], 'cdi' => ['name' => 'CDI', 'description' => '% del CDI (Brasil)'], 'selic' => ['name' => 'SELIC', 'description' => 'Tasa SELIC (Brasil)'], 'ipca' => ['name' => 'IPCA+', 'description' => 'Inflación + spread (Brasil)'], 'euribor' => ['name' => 'Euribor+', 'description' => 'Euribor + spread (UE)'], 'ibex' => ['name' => 'IBEX 35', 'description' => 'Índice bursátil español'], 'sp500' => ['name' => 'S&P 500', 'description' => 'Índice bursátil americano'], ]; protected $fillable = [ 'user_id', 'business_id', 'asset_type', 'name', 'description', 'currency', 'color', // Valores 'acquisition_value', 'current_value', 'acquisition_date', // Depreciação 'is_depreciable', 'depreciation_method', 'useful_life_years', 'residual_value', 'accumulated_depreciation', // Imóveis 'property_type', 'address', 'city', 'state', 'postal_code', 'country', 'property_area_m2', 'registry_number', // Veículos 'vehicle_brand', 'vehicle_model', 'vehicle_year', 'vehicle_plate', 'vehicle_vin', 'vehicle_mileage', // Investimentos 'investment_type', 'institution', 'account_number', 'quantity', 'unit_price', 'ticker', 'maturity_date', 'interest_rate', 'index_type', // Equipamentos 'equipment_brand', 'equipment_model', 'serial_number', 'warranty_expiry', // Recebíveis 'debtor_name', 'debtor_document', 'receivable_due_date', 'receivable_amount', // Garantias 'is_collateral', 'collateral_for', 'linked_liability_id', // Seguros 'has_insurance', 'insurance_company', 'insurance_policy', 'insurance_value', 'insurance_expiry', // Gestão 'alert_days_before', 'internal_responsible', 'internal_notes', 'document_number', // Status 'status', 'disposal_date', 'disposal_value', 'disposal_reason', ]; protected $casts = [ 'acquisition_value' => 'decimal:2', 'current_value' => 'decimal:2', 'residual_value' => 'decimal:2', 'accumulated_depreciation' => 'decimal:2', 'property_area_m2' => 'decimal:2', 'useful_life_years' => 'decimal:2', 'unit_price' => 'decimal:6', 'insurance_value' => 'decimal:2', 'receivable_amount' => 'decimal:2', 'disposal_value' => 'decimal:2', 'interest_rate' => 'decimal:4', 'is_depreciable' => 'boolean', 'is_collateral' => 'boolean', 'has_insurance' => 'boolean', 'acquisition_date' => 'date', 'maturity_date' => 'date', 'warranty_expiry' => 'date', 'receivable_due_date' => 'date', 'insurance_expiry' => 'date', 'disposal_date' => 'date', ]; /** * Relações */ public function user(): BelongsTo { return $this->belongsTo(User::class); } public function business(): BelongsTo { return $this->belongsTo(Business::class); } public function linkedLiability(): BelongsTo { return $this->belongsTo(LiabilityAccount::class, 'linked_liability_id'); } /** * Scopes */ public function scopeActive($query) { return $query->where('status', self::STATUS_ACTIVE); } public function scopeOfType($query, string $type) { return $query->where('asset_type', $type); } public function scopeDepreciable($query) { return $query->where('is_depreciable', true); } /** * Accessors */ public function getAssetTypeNameAttribute(): string { return self::ASSET_TYPES[$this->asset_type]['name'] ?? $this->asset_type; } public function getStatusNameAttribute(): string { return self::STATUSES[$this->status] ?? $this->status; } public function getNetValueAttribute(): float { return $this->current_value - $this->accumulated_depreciation; } public function getGainLossAttribute(): float { return $this->current_value - $this->acquisition_value; } public function getGainLossPercentAttribute(): float { if ($this->acquisition_value == 0) return 0; return (($this->current_value - $this->acquisition_value) / $this->acquisition_value) * 100; } /** * Calcular depreciação anual (método linear) */ public function calculateAnnualDepreciation(): float { if (!$this->is_depreciable || !$this->useful_life_years || $this->useful_life_years == 0) { return 0; } $depreciableValue = $this->acquisition_value - ($this->residual_value ?? 0); return $depreciableValue / $this->useful_life_years; } /** * Verificar se seguro está próximo do vencimento */ public function isInsuranceExpiringSoon(int $days = 30): bool { if (!$this->has_insurance || !$this->insurance_expiry) { return false; } return $this->insurance_expiry->diffInDays(now()) <= $days; } }