<?php
namespace App\Modules\Promotions\Models;
use App\Modules\Core\Models\BaseModel;
use Database\Factories\GiftCardFactory;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Support\Str;
class GiftCard extends BaseModel
{
use HasFactory;
protected static function newFactory(): GiftCardFactory
{
return GiftCardFactory::new();
}
protected $fillable = [
'code', 'amount', 'balance', 'currency',
'purchased_by_user_id', 'redeemed_by_user_id',
'recipient_email', 'recipient_name', 'personal_message',
'order_id', 'status', 'expires_at',
];
protected $hidden = ['code']; // never expose in API lists
protected $casts = [
'amount' => 'float',
'balance' => 'float',
'expires_at' => 'datetime',
];
// ── Boot ───────────────────────────────────────────────────────
protected static function booted(): void
{
static::creating(function (GiftCard $card) {
if (empty($card->code)) {
$card->code = self::generateUniqueCode();
}
});
}
public static function generateUniqueCode(): string
{
do {
// Format: STPGC-XXXX-XXXX-XXXX (16 chars + dashes)
$code = 'STPGC-'
. strtoupper(Str::random(4)) . '-'
. strtoupper(Str::random(4)) . '-'
. strtoupper(Str::random(4));
} while (self::where('code', $code)->exists());
return $code;
}
// ── Relationships ──────────────────────────────────────────────
public function purchasedBy(): BelongsTo
{
return $this->belongsTo(\App\Modules\User\Models\User::class, 'purchased_by_user_id');
}
public function redeemedBy(): BelongsTo
{
return $this->belongsTo(\App\Modules\User\Models\User::class, 'redeemed_by_user_id');
}
public function order(): BelongsTo
{
return $this->belongsTo(\App\Modules\Order\Models\Order::class);
}
// ── Helpers ────────────────────────────────────────────────────
public function getIsValidAttribute(): bool
{
return $this->status === 'active'
&& $this->balance > 0
&& (!$this->expires_at || $this->expires_at->isFuture());
}
public function deduct(float $amount): void
{
$this->decrement('balance', $amount);
$this->update([
'status' => $this->balance <= 0 ? 'fully_used' : 'partially_used',
]);
}
}