Initial commit
This commit is contained in:
166
app/Models/MembershipPayment.php
Normal file
166
app/Models/MembershipPayment.php
Normal file
@@ -0,0 +1,166 @@
|
||||
<?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);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user