Files
usher-manage-stack/app/Models/PaymentOrder.php
Gbanyan 642b879dd4 Add membership fee system with disability discount and fix document permissions
Features:
- Implement two fee types: entrance fee and annual fee (both NT$1,000)
- Add 50% discount for disability certificate holders
- Add disability certificate upload in member profile
- Integrate disability verification into cashier approval workflow
- Add membership fee settings in system admin

Document permissions:
- Fix hard-coded role logic in Document model
- Use permission-based authorization instead of role checks

Additional features:
- Add announcements, general ledger, and trial balance modules
- Add income management and accounting entries
- Add comprehensive test suite with factories
- Update UI translations to Traditional Chinese

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-01 09:56:01 +08:00

175 lines
4.6 KiB
PHP

<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
class PaymentOrder extends Model
{
use HasFactory;
protected $attributes = [
'status' => self::STATUS_DRAFT,
'verification_status' => self::VERIFICATION_PENDING,
'execution_status' => self::EXECUTION_PENDING,
];
protected $fillable = [
'finance_document_id',
'payee_name',
'payee_bank_code',
'payee_account_number',
'payee_bank_name',
'payment_amount',
'payment_method',
'created_by_accountant_id',
'payment_order_number',
'notes',
'verified_by_cashier_id',
'verified_at',
'verification_status',
'verification_notes',
'executed_by_cashier_id',
'executed_at',
'execution_status',
'transaction_reference',
'payment_receipt_path',
'status',
];
protected $casts = [
'payment_amount' => 'decimal:2',
'verified_at' => 'datetime',
'executed_at' => 'datetime',
];
/**
* 狀態常數
*/
const STATUS_DRAFT = 'draft';
const STATUS_PENDING_VERIFICATION = 'pending_verification';
const STATUS_VERIFIED = 'verified';
const STATUS_EXECUTED = 'executed';
const STATUS_CANCELLED = 'cancelled';
const VERIFICATION_PENDING = 'pending';
const VERIFICATION_APPROVED = 'approved';
const VERIFICATION_REJECTED = 'rejected';
const EXECUTION_PENDING = 'pending';
const EXECUTION_COMPLETED = 'completed';
const EXECUTION_FAILED = 'failed';
const PAYMENT_METHOD_BANK_TRANSFER = 'bank_transfer';
const PAYMENT_METHOD_CHECK = 'check';
const PAYMENT_METHOD_CASH = 'cash';
/**
* 關聯到報銷申請單
*/
public function financeDocument(): BelongsTo
{
return $this->belongsTo(FinanceDocument::class);
}
/**
* 會計製單人
*/
public function createdByAccountant(): BelongsTo
{
return $this->belongsTo(User::class, 'created_by_accountant_id');
}
/**
* 出納覆核人
*/
public function verifiedByCashier(): BelongsTo
{
return $this->belongsTo(User::class, 'verified_by_cashier_id');
}
/**
* 出納執行人
*/
public function executedByCashier(): BelongsTo
{
return $this->belongsTo(User::class, 'executed_by_cashier_id');
}
/**
* 產生付款單號
*/
public static function generatePaymentOrderNumber(): string
{
$date = now()->format('Ymd');
$latest = self::where('payment_order_number', 'like', "PO-{$date}%")->latest('id')->first();
if ($latest) {
$lastNumber = (int) substr($latest->payment_order_number, -4);
$newNumber = $lastNumber + 1;
} else {
$newNumber = 1;
}
return sprintf('PO-%s%04d', $date, $newNumber);
}
/**
* 檢查是否可以被出納覆核
*/
public function canBeVerifiedByCashier(): bool
{
return $this->status === self::STATUS_PENDING_VERIFICATION &&
$this->verification_status === self::VERIFICATION_PENDING;
}
/**
* 檢查是否可以執行付款
*/
public function canBeExecuted(): bool
{
return $this->status === self::STATUS_VERIFIED &&
$this->verification_status === self::VERIFICATION_APPROVED &&
$this->execution_status === self::EXECUTION_PENDING;
}
/**
* 是否已執行
*/
public function isExecuted(): bool
{
return $this->status === self::STATUS_EXECUTED &&
$this->execution_status === self::EXECUTION_COMPLETED;
}
/**
* 取得付款方式文字
*/
public function getPaymentMethodText(): string
{
return match ($this->payment_method) {
self::PAYMENT_METHOD_BANK_TRANSFER => '銀行轉帳',
self::PAYMENT_METHOD_CHECK => '支票',
self::PAYMENT_METHOD_CASH => '現金',
default => '未知',
};
}
/**
* 取得狀態文字
*/
public function getStatusText(): string
{
return match ($this->status) {
self::STATUS_DRAFT => '草稿',
self::STATUS_PENDING_VERIFICATION => '待出納覆核',
self::STATUS_VERIFIED => '已覆核',
self::STATUS_EXECUTED => '已執行付款',
self::STATUS_CANCELLED => '已取消',
default => '未知',
};
}
}