*/ use HasFactory, LogsActivity; /** * Audit trail on status transitions only (domain.md §6; T6.2). */ public function getActivitylogOptions(): LogOptions { return LogOptions::defaults() ->logOnly(['status']) ->logOnlyDirty() ->dontLogEmptyChanges() ->useLogName('payment'); } /** * @var list */ protected $fillable = [ 'booking_id', 'gateway', 'status', 'amount', 'currency', 'gateway_transaction_id', 'gateway_payload', 'initiated_at', 'completed_at', ]; /** * @return array */ protected function casts(): array { return [ 'gateway' => PaymentMethod::class, 'status' => PaymentStatus::class, 'amount' => 'decimal:2', 'gateway_payload' => 'array', 'initiated_at' => 'datetime', 'completed_at' => 'datetime', ]; } public function booking(): BelongsTo { return $this->belongsTo(Booking::class); } public function refunds(): HasMany { return $this->hasMany(Refund::class); } /** * What's left to refund on this Payment — its total minus whatever has * already been completed-refunded (partial refunds supported, domain.md * §6). Shared by RefundBookingAction's own guard and the Filament refund * forms, which surface it to staff before they submit. */ public function refundableBalance(): string { $alreadyRefunded = (string) $this->refunds()->where('status', RefundStatus::Completed->value)->sum('amount'); return bcsub((string) $this->amount, $alreadyRefunded, 2); } }