InvoiceStatus::class, 'amount' => 'decimal:2', 'invoice_date' => 'date', 'due_date' => 'date', 'paid_at' => 'datetime', ]; } public function contractor(): BelongsTo { return $this->belongsTo(Contractor::class); } public function project(): BelongsTo { return $this->belongsTo(Project::class); } public function payments(): HasMany { return $this->hasMany(ContractorPayment::class); } public function transitionTo(InvoiceStatus $newStatus): void { $allowed = $this->status->allowedTransitions(); if (!in_array($newStatus, $allowed)) { throw new \InvalidArgumentException( "Cannot transition invoice from {$this->status->label()} to {$newStatus->label()}" ); } $updates = ['status' => $newStatus]; if ($newStatus === InvoiceStatus::Paid) { $updates['paid_at'] = now(); } $this->update($updates); } public function getTotalPaidAttribute(): float { return (float) $this->payments()->sum('amount'); } }