'date', 'due_date' => 'date', 'paid_at' => 'datetime', 'auto_renew' => 'boolean', ]; protected static function booted(): void { static::creating(function (Invoice $invoice) { $invoice->date ??= now()->toDateString(); }); } public function customer() { return $this->belongsTo(Customer::class); } /** The order that originated this invoice. */ public function clientPath(): string { return '/hoa-don/' . ($this->order?->order_num ?? $this->invoice_number); } /** @param iterable $services */ public function scopeOfServices(Builder $query, iterable $services): Builder { $services = collect($services); $orderIds = $services->map(fn (Service $service) => $service->orderItem?->order_id)->filter()->unique()->values(); return $query->where(fn (Builder $q) => $q ->whereIn('service_id', $services->pluck('id')) ->orWhere(fn (Builder $q) => $q->whereNull('service_id')->whereIn('order_id', $orderIds))); } public function belongsToService(Service $service): bool { if ($this->service_id !== null) { return (int) $this->service_id === (int) $service->id; } return $this->order_id !== null && (int) $this->order_id === (int) $service->orderItem?->order_id; } public function order() { return $this->belongsTo(Order::class, 'order_id'); } /** Line items on this invoice. */ public function invoiceItems() { return $this->hasMany(InvoiceItem::class, 'invoice_id'); } /** Uploaded payment-proof or supporting documents. */ public function attachments() { return $this->hasMany(InvoiceAttachment::class); } /** Services whose active invoice is this one (updated on each renewal). */ public function services() { return $this->hasMany(Service::class, 'invoice_id'); } /** The service this invoice upgrades, for invoice_type = 3 (upgrade). */ public function service() { return $this->belongsTo(Service::class, 'service_id'); } public function payment() { return $this->belongsTo(Payment::class, 'payment_method', 'id'); } public function getStatusLabelAttribute(): string { return InvoiceStatus::from($this->status)->label(); } }