Kimi chinh sua
This commit is contained in:
120
app/Observers/PaymentObserver.php
Normal file
120
app/Observers/PaymentObserver.php
Normal file
@@ -0,0 +1,120 @@
|
||||
<?php
|
||||
|
||||
namespace App\Observers;
|
||||
|
||||
use App\Models\Payment;
|
||||
use App\Models\Contract;
|
||||
use App\Models\PaymentScheduleItem;
|
||||
|
||||
class PaymentObserver
|
||||
{
|
||||
private static bool $handlingSurplus = false;
|
||||
|
||||
/**
|
||||
* Tính toán lại tài chính hợp đồng sau mỗi thay đổi payment.
|
||||
*/
|
||||
private function recalculateContract(Contract $contract): void
|
||||
{
|
||||
$totalPaid = (float) $contract->payments()->sum('amount');
|
||||
$contractValue = (float) $contract->total_value;
|
||||
|
||||
$contract->paid_amount = $totalPaid;
|
||||
|
||||
if ($totalPaid > $contractValue) {
|
||||
$contract->remaining_amount = 0;
|
||||
$contract->excess_amount = $totalPaid - $contractValue;
|
||||
} else {
|
||||
$contract->remaining_amount = $contractValue - $totalPaid;
|
||||
$contract->excess_amount = 0;
|
||||
}
|
||||
|
||||
$contract->saveQuietly();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tự động khấu trừ tiền dư vào đợt thanh toán tiếp theo.
|
||||
*/
|
||||
private function applySurplusToNextInstallment(Contract $contract): void
|
||||
{
|
||||
if (self::$handlingSurplus) {
|
||||
return;
|
||||
}
|
||||
|
||||
$excess = (float) $contract->excess_amount;
|
||||
if ($excess <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Tìm đợt tiếp theo chưa thanh toán đủ (hoặc chưa có payment nào)
|
||||
$nextItem = PaymentScheduleItem::query()
|
||||
->whereHas('schedule', fn ($q) => $q->where('contract_id', $contract->id))
|
||||
->whereNotNull('amount')
|
||||
->orderBy('installment_no')
|
||||
->get()
|
||||
->first(function ($item) use ($contract) {
|
||||
$paidForItem = (float) $contract->payments()
|
||||
->where('schedule_item_id', $item->id)
|
||||
->sum('amount');
|
||||
return $paidForItem < (float) $item->amount;
|
||||
});
|
||||
|
||||
if (! $nextItem) {
|
||||
return;
|
||||
}
|
||||
|
||||
$paidForItem = (float) $contract->payments()
|
||||
->where('schedule_item_id', $nextItem->id)
|
||||
->sum('amount');
|
||||
$remainingForItem = (float) $nextItem->amount - $paidForItem;
|
||||
|
||||
if ($remainingForItem <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
$applyAmount = min($excess, $remainingForItem);
|
||||
|
||||
self::$handlingSurplus = true;
|
||||
|
||||
Payment::create([
|
||||
'contract_id' => $contract->id,
|
||||
'schedule_item_id' => $nextItem->id,
|
||||
'amount' => $applyAmount,
|
||||
'paid_date' => now(),
|
||||
'method' => 'Tự động khấu trừ',
|
||||
'receipt_number' => 'AUTO-SURPLUS-' . now()->format('YmdHis'),
|
||||
'metadata' => ['auto_surplus' => true, 'source' => 'excess_amount'],
|
||||
]);
|
||||
|
||||
self::$handlingSurplus = false;
|
||||
}
|
||||
|
||||
public function created(Payment $payment): void
|
||||
{
|
||||
if ($payment->contract) {
|
||||
$this->recalculateContract($payment->contract);
|
||||
$this->applySurplusToNextInstallment($payment->contract);
|
||||
}
|
||||
}
|
||||
|
||||
public function updated(Payment $payment): void
|
||||
{
|
||||
if ($payment->contract) {
|
||||
$this->recalculateContract($payment->contract);
|
||||
$this->applySurplusToNextInstallment($payment->contract);
|
||||
}
|
||||
|
||||
if ($payment->wasChanged('contract_id') && $payment->getOriginal('contract_id')) {
|
||||
$oldContract = Contract::find($payment->getOriginal('contract_id'));
|
||||
if ($oldContract) {
|
||||
$this->recalculateContract($oldContract);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function deleted(Payment $payment): void
|
||||
{
|
||||
if ($payment->contract) {
|
||||
$this->recalculateContract($payment->contract);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user