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
+55
View File
@@ -0,0 +1,55 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasMany;
class Coupon extends Model
{
public const TYPE_PERCENT = 'percent';
public const TYPE_FIXED = 'fixed';
public const TYPES = [self::TYPE_PERCENT, self::TYPE_FIXED];
public const APPLIES_NEW = 'new';
public const APPLIES_RENEWAL = 'renewal';
public const APPLIES_ALL = 'all';
public const APPLIES_TO = [self::APPLIES_NEW, self::APPLIES_RENEWAL, self::APPLIES_ALL];
protected $guarded = [];
protected $casts = [
'value' => 'integer',
'max_discount' => 'integer',
'min_order' => 'integer',
'usage_limit' => 'integer',
'per_customer_limit' => 'integer',
'product_types' => 'array',
'product_ids' => 'array',
'billing_cycles' => 'array',
'starts_at' => 'datetime',
'ends_at' => 'datetime',
'is_active' => 'boolean',
];
public static function normalizeCode(string $code): string
{
return strtoupper(trim($code));
}
protected function code(): Attribute
{
return Attribute::set(fn (string $value) => self::normalizeCode($value));
}
public function redemptions(): HasMany
{
return $this->hasMany(CouponRedemption::class);
}
public function activeRedemptions(): HasMany
{
return $this->redemptions()->whereNull('released_at');
}
}