'array', // اقلام به‌صورت JSON 'subtotal' => 'decimal:2', 'discount_amount' => 'decimal:2', 'total_amount' => 'decimal:2', 'due_date' => 'date', 'paid_at' => 'datetime', ]; // ─── Relationships ─────────────────────────────── public function user(): BelongsTo { return $this->belongsTo(User::class, 'user_id'); } public function issuedBy(): BelongsTo { return $this->belongsTo(User::class, 'issued_by'); } public function cancelledBy(): BelongsTo { return $this->belongsTo(User::class, 'cancelled_by'); } public function walletTransaction(): BelongsTo { return $this->belongsTo(WalletTransaction::class); } public function payment(): BelongsTo { return $this->belongsTo(Payment::class); } // ─── Helpers ───────────────────────────────────── public function isPending(): bool { return $this->status === 'pending_payment'; } public function isPaid(): bool { return $this->status === 'paid'; } public function isCancelled(): bool { return $this->status === 'cancelled'; } public function isExpired(): bool { return $this->status === 'expired'; } /** * آیا فاکتور منقضی شده است؟ (بررسی بر اساس due_date) */ public function checkExpired(): bool { if ($this->status !== 'pending_payment') { return false; } if (! $this->due_date) { return false; } return $this->due_date->isPast(); } /** * تولید شماره فاکتور بعدی. * فرمت: INV-2026-000001 */ public static function generateInvoiceNumber(): string { $year = now()->year; $prefix = "INV-{$year}-"; $last = self::where('invoice_number', 'like', "{$prefix}%") ->orderByDesc('id') ->first(); $next = 1; if ($last) { $parts = explode('-', $last->invoice_number); $next = (int) end($parts) + 1; } return $prefix . str_pad($next, 6, '0', STR_PAD_LEFT); } /** * محاسبه مبلغ نهایی بر اساس اقلام و تخفیف. */ public static function calculateTotal(array $items, float $discount = 0): array { $subtotal = 0; foreach ($items as $item) { $qty = (float) ($item['quantity'] ?? 1); $unit = (float) ($item['unit_price'] ?? 0); $subtotal += $qty * $unit; } $discount = max(0, $discount); $total = max(0, $subtotal - $discount); return [ 'subtotal' => round($subtotal, 2), 'discount_amount' => round($discount, 2), 'total_amount' => round($total, 2), ]; } }