Initial commit

This commit is contained in:
2025-11-20 23:21:05 +08:00
commit 13bc6db529
378 changed files with 54527 additions and 0 deletions

View File

@@ -0,0 +1,213 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
class BankReconciliation extends Model
{
use HasFactory;
protected $fillable = [
'reconciliation_month',
'bank_statement_balance',
'bank_statement_date',
'bank_statement_file_path',
'system_book_balance',
'outstanding_checks',
'deposits_in_transit',
'bank_charges',
'adjusted_balance',
'discrepancy_amount',
'reconciliation_status',
'prepared_by_cashier_id',
'reviewed_by_accountant_id',
'approved_by_manager_id',
'prepared_at',
'reviewed_at',
'approved_at',
'notes',
];
protected $casts = [
'reconciliation_month' => 'date',
'bank_statement_balance' => 'decimal:2',
'bank_statement_date' => 'date',
'system_book_balance' => 'decimal:2',
'outstanding_checks' => 'array',
'deposits_in_transit' => 'array',
'bank_charges' => 'array',
'adjusted_balance' => 'decimal:2',
'discrepancy_amount' => 'decimal:2',
'prepared_at' => 'datetime',
'reviewed_at' => 'datetime',
'approved_at' => 'datetime',
];
/**
* 狀態常數
*/
const STATUS_PENDING = 'pending';
const STATUS_COMPLETED = 'completed';
const STATUS_DISCREPANCY = 'discrepancy';
/**
* 製作調節表的出納人員
*/
public function preparedByCashier(): BelongsTo
{
return $this->belongsTo(User::class, 'prepared_by_cashier_id');
}
/**
* 覆核的會計人員
*/
public function reviewedByAccountant(): BelongsTo
{
return $this->belongsTo(User::class, 'reviewed_by_accountant_id');
}
/**
* 核准的主管
*/
public function approvedByManager(): BelongsTo
{
return $this->belongsTo(User::class, 'approved_by_manager_id');
}
/**
* 計算調整後餘額
*/
public function calculateAdjustedBalance(): float
{
$adjusted = $this->system_book_balance;
// 加上在途存款
if ($this->deposits_in_transit) {
foreach ($this->deposits_in_transit as $deposit) {
$adjusted += floatval($deposit['amount'] ?? 0);
}
}
// 減去未兌現支票
if ($this->outstanding_checks) {
foreach ($this->outstanding_checks as $check) {
$adjusted -= floatval($check['amount'] ?? 0);
}
}
// 減去銀行手續費
if ($this->bank_charges) {
foreach ($this->bank_charges as $charge) {
$adjusted -= floatval($charge['amount'] ?? 0);
}
}
return $adjusted;
}
/**
* 計算差異金額
*/
public function calculateDiscrepancy(): float
{
return abs($this->adjusted_balance - $this->bank_statement_balance);
}
/**
* 檢查是否有差異
*/
public function hasDiscrepancy(float $tolerance = 0.01): bool
{
return $this->calculateDiscrepancy() > $tolerance;
}
/**
* 是否待覆核
*/
public function isPending(): bool
{
return $this->reconciliation_status === self::STATUS_PENDING;
}
/**
* 是否已完成
*/
public function isCompleted(): bool
{
return $this->reconciliation_status === self::STATUS_COMPLETED;
}
/**
* 是否有差異待處理
*/
public function hasUnresolvedDiscrepancy(): bool
{
return $this->reconciliation_status === self::STATUS_DISCREPANCY;
}
/**
* 是否可以被會計覆核
*/
public function canBeReviewed(): bool
{
return $this->isPending() && $this->prepared_at !== null;
}
/**
* 是否可以被主管核准
*/
public function canBeApproved(): bool
{
return $this->reviewed_at !== null && $this->approved_at === null;
}
/**
* 取得狀態文字
*/
public function getStatusText(): string
{
return match ($this->reconciliation_status) {
self::STATUS_PENDING => '待覆核',
self::STATUS_COMPLETED => '已完成',
self::STATUS_DISCREPANCY => '有差異',
default => '未知',
};
}
/**
* 取得未達帳項總計
*/
public function getOutstandingItemsSummary(): array
{
$checksTotal = 0;
if ($this->outstanding_checks) {
foreach ($this->outstanding_checks as $check) {
$checksTotal += floatval($check['amount'] ?? 0);
}
}
$depositsTotal = 0;
if ($this->deposits_in_transit) {
foreach ($this->deposits_in_transit as $deposit) {
$depositsTotal += floatval($deposit['amount'] ?? 0);
}
}
$chargesTotal = 0;
if ($this->bank_charges) {
foreach ($this->bank_charges as $charge) {
$chargesTotal += floatval($charge['amount'] ?? 0);
}
}
return [
'outstanding_checks_total' => $checksTotal,
'deposits_in_transit_total' => $depositsTotal,
'bank_charges_total' => $chargesTotal,
'net_adjustment' => $depositsTotal - $checksTotal - $chargesTotal,
];
}
}