Files
usher-manage-stack/app/Models/MembershipPayment.php

166 lines
4.4 KiB
PHP

<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\Storage;
class MembershipPayment extends Model
{
use HasFactory;
// Status constants
const STATUS_PENDING = 'pending';
const STATUS_APPROVED_CASHIER = 'approved_cashier';
const STATUS_APPROVED_ACCOUNTANT = 'approved_accountant';
const STATUS_APPROVED_CHAIR = 'approved_chair';
const STATUS_REJECTED = 'rejected';
// Payment method constants
const METHOD_BANK_TRANSFER = 'bank_transfer';
const METHOD_CONVENIENCE_STORE = 'convenience_store';
const METHOD_CASH = 'cash';
const METHOD_CREDIT_CARD = 'credit_card';
protected $fillable = [
'member_id',
'paid_at',
'amount',
'method',
'reference',
'status',
'payment_method',
'receipt_path',
'submitted_by_user_id',
'verified_by_cashier_id',
'cashier_verified_at',
'verified_by_accountant_id',
'accountant_verified_at',
'verified_by_chair_id',
'chair_verified_at',
'rejected_by_user_id',
'rejected_at',
'rejection_reason',
'notes',
];
protected $casts = [
'paid_at' => 'date',
'cashier_verified_at' => 'datetime',
'accountant_verified_at' => 'datetime',
'chair_verified_at' => 'datetime',
'rejected_at' => 'datetime',
];
// Relationships
public function member()
{
return $this->belongsTo(Member::class);
}
public function submittedBy()
{
return $this->belongsTo(User::class, 'submitted_by_user_id');
}
public function verifiedByCashier()
{
return $this->belongsTo(User::class, 'verified_by_cashier_id');
}
public function verifiedByAccountant()
{
return $this->belongsTo(User::class, 'verified_by_accountant_id');
}
public function verifiedByChair()
{
return $this->belongsTo(User::class, 'verified_by_chair_id');
}
public function rejectedBy()
{
return $this->belongsTo(User::class, 'rejected_by_user_id');
}
// Status check methods
public function isPending(): bool
{
return $this->status === self::STATUS_PENDING;
}
public function isApprovedByCashier(): bool
{
return $this->status === self::STATUS_APPROVED_CASHIER;
}
public function isApprovedByAccountant(): bool
{
return $this->status === self::STATUS_APPROVED_ACCOUNTANT;
}
public function isFullyApproved(): bool
{
return $this->status === self::STATUS_APPROVED_CHAIR;
}
public function isRejected(): bool
{
return $this->status === self::STATUS_REJECTED;
}
// Workflow validation methods
public function canBeApprovedByCashier(): bool
{
return $this->isPending();
}
public function canBeApprovedByAccountant(): bool
{
return $this->isApprovedByCashier();
}
public function canBeApprovedByChair(): bool
{
return $this->isApprovedByAccountant();
}
// Accessor for status label
public function getStatusLabelAttribute(): string
{
return match($this->status) {
self::STATUS_PENDING => '待審核',
self::STATUS_APPROVED_CASHIER => '出納已審',
self::STATUS_APPROVED_ACCOUNTANT => '會計已審',
self::STATUS_APPROVED_CHAIR => '主席已審',
self::STATUS_REJECTED => '已拒絕',
default => $this->status,
};
}
// Accessor for payment method label
public function getPaymentMethodLabelAttribute(): string
{
return match($this->payment_method) {
self::METHOD_BANK_TRANSFER => '銀行轉帳',
self::METHOD_CONVENIENCE_STORE => '超商繳費',
self::METHOD_CASH => '現金',
self::METHOD_CREDIT_CARD => '信用卡',
default => $this->payment_method ?? '未指定',
};
}
// Clean up receipt file when payment is deleted
protected static function boot()
{
parent::boot();
static::deleting(function ($payment) {
if ($payment->receipt_path && Storage::disk('private')->exists($payment->receipt_path)) {
Storage::disk('private')->delete($payment->receipt_path);
}
});
}
}