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

235 lines
6.3 KiB
PHP

<?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 static function booted()
{
static::creating(function (BankReconciliation $model) {
$model->adjusted_balance = $model->adjusted_balance ?? (float) $model->calculateAdjustedBalance();
$model->discrepancy_amount = $model->discrepancy_amount ?? (float) $model->calculateDiscrepancy();
$model->reconciliation_status = $model->reconciliation_status ?? self::STATUS_PENDING;
});
}
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
{
$adjusted = $this->adjusted_balance ?? $this->calculateAdjustedBalance();
return abs($adjusted - floatval($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
|| $this->discrepancy_amount > 0.01;
}
/**
* 是否可以被會計覆核
*/
public function canBeReviewed(): bool
{
return $this->isPending() && $this->reviewed_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;
$checksCount = 0;
if ($this->outstanding_checks) {
foreach ($this->outstanding_checks as $check) {
$checksTotal += floatval($check['amount'] ?? 0);
$checksCount++;
}
}
$depositsTotal = 0;
$depositsCount = 0;
if ($this->deposits_in_transit) {
foreach ($this->deposits_in_transit as $deposit) {
$depositsTotal += floatval($deposit['amount'] ?? 0);
$depositsCount++;
}
}
$chargesTotal = 0;
$chargesCount = 0;
if ($this->bank_charges) {
foreach ($this->bank_charges as $charge) {
$chargesTotal += floatval($charge['amount'] ?? 0);
$chargesCount++;
}
}
return [
'total_outstanding_checks' => $checksTotal,
'outstanding_checks_count' => $checksCount,
'total_deposits_in_transit' => $depositsTotal,
'deposits_in_transit_count' => $depositsCount,
'total_bank_charges' => $chargesTotal,
'bank_charges_count' => $chargesCount,
'net_adjustment' => $depositsTotal - $checksTotal - $chargesTotal,
];
}
}