'array', 'discount_details' => 'array', 'total_value' => 'decimal:2', 'land_value' => 'decimal:2', 'foundation_value' => 'decimal:2', 'total_value_with_foundation' => 'decimal:2', 'paid_amount' => 'decimal:2', 'remaining_amount' => 'decimal:2', 'excess_amount' => 'decimal:2', 'signing_date' => 'date', 'sale_date' => 'date', 'hql_confirmation_date' => 'date', ]; public function product() { return $this->belongsTo(Product::class); } public function paymentTemplate() { return $this->belongsTo(PaymentTemplate::class); } public function customers() { return $this->belongsToMany(Customer::class, 'contract_customers') ->using(ContractCustomer::class) ->withPivot('id', 'role', 'transfer_order') ->withTimestamps(); } public function appendices() { return $this->hasMany(Appendix::class); } public function paymentSchedule() { return $this->hasOne(PaymentSchedule::class); } public function scheduleItems(): HasManyThrough { return $this->hasManyThrough( PaymentScheduleItem::class, PaymentSchedule::class, 'contract_id', 'schedule_id', 'id', 'id' ); } public function payments() { return $this->hasMany(Payment::class); } public function paymentFines() { return $this->hasMany(PaymentFine::class); } /** * Giá trị sau chiết khấu. */ public function getFinalValueAttribute(): float { $result = \App\Services\DiscountEngine::calculate( (float) $this->total_value, $this->discount_details ); return $result['final_value']; } protected static function booted() { static::saving(function ($contract) { // Bảo vệ tính toán tài chính: total_value luôn bằng land_value + foundation_value $landValue = (float) ($contract->land_value ?? 0); $foundationValue = (float) ($contract->foundation_value ?? 0); if ($landValue > 0 || $foundationValue > 0) { $contract->total_value = $landValue + $foundationValue; } elseif ($contract->exists === false && empty($contract->total_value) && !empty($contract->product_id)) { // Fallback khi tạo mới và chưa có giá trị tài chính chi tiết $product = Product::find($contract->product_id); if ($product) { $contract->total_value = $product->total_price; } } $contract->remaining_amount = (float) ($contract->total_value ?? 0) - (float) ($contract->paid_amount ?? 0); }); } }