feat(billing): renewals, coupons, VAT numbering, billing cycles and invoice payment tracking

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
baodev0
2026-10-19 16:37:56 +07:00
co-authored by Claude Sonnet 5.5
parent ea9a53f742
commit 25f23d541e
134 changed files with 4926 additions and 185 deletions
+21 -1
View File
@@ -4,11 +4,13 @@ namespace App\Models;
use App\Enums\Invoice\InvoiceStatus;
use App\Models\Concerns\Markable;
use App\Support\VatNumbering;
use App\Traits\LogsActivity;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Support\Str;
class Invoice extends Model
{
@@ -23,12 +25,26 @@ class Invoice extends Model
'due_date' => 'date',
'paid_at' => 'datetime',
'auto_renew' => 'boolean',
'vat_issued_at' => 'date',
'buyer_snapshot' => 'array',
];
public static function newLookupCode(): string
{
return Str::upper(Str::random(10));
}
protected static function booted(): void
{
static::creating(function (Invoice $invoice) {
$invoice->date ??= now()->toDateString();
$invoice->lookup_code ??= static::newLookupCode();
});
static::updated(function (Invoice $invoice) {
if ($invoice->wasChanged('status')) {
VatNumbering::issueIfAuto($invoice);
}
});
}
@@ -40,7 +56,11 @@ class Invoice extends Model
/** The order that originated this invoice. */
public function clientPath(): string
{
return '/hoa-don/' . ($this->order?->order_num ?? $this->invoice_number);
$path = '/hoa-don/' . ($this->order?->order_num ?? $this->invoice_number);
return $this->order && (int) $this->invoice_type !== 1
? $path . '?invoice=' . $this->invoice_number
: $path;
}
/** @param iterable<Service> $services */