'array', 'total_value' => 'decimal:2', 'paid_amount' => 'decimal:2', 'remaining_amount' => 'decimal:2', 'excess_amount' => 'decimal:2', 'signing_date' => 'date', ]; public function product() { return $this->belongsTo(Product::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); } /** * Lấy trực tiếp các đợt thanh toán của hợp đồng này */ public function scheduleItems(): HasManyThrough { return $this->hasManyThrough( PaymentScheduleItem::class, PaymentSchedule::class, 'contract_id', // Khóa ngoại trên bảng PaymentSchedule 'schedule_id', // Khóa ngoại trên bảng PaymentScheduleItem 'id', // Khóa chính trên bảng Contract 'id' // Khóa chính trên bảng PaymentSchedule ); } public function payments() { return $this->hasMany(Payment::class); } public function paymentFines() { return $this->hasMany(PaymentFine::class); } protected static function booted() { static::creating(function ($contract) { // Tự động lấy giá trị từ sản phẩm nếu chưa có if (empty($contract->total_value) && !empty($contract->product_id)) { $product = Product::find($contract->product_id); if ($product) { $contract->total_value = $product->total_price; } } // Tính toán số tiền còn lại $contract->remaining_amount = ($contract->total_value ?? 0) - ($contract->paid_amount ?? 0); }); } }