167 lines
4.3 KiB
PHP
167 lines
4.3 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::exists($payment->receipt_path)) {
|
|
Storage::delete($payment->receipt_path);
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|