fix: enforce cash balance validation, add due date constraint, and improve error message feedback in finance modules

This commit is contained in:
Yoga Pangestu 2026-06-14 13:36:25 +07:00
parent 1ff1e73cd7
commit c40e9e5e87
6 changed files with 34 additions and 12 deletions

View File

@ -44,7 +44,7 @@ public function rules(): array
return [
'amount' => ['required', 'integer', 'min:1'],
'description' => ['required', 'string', 'max:100'],
'due_date' => ['required', 'date'],
'due_date' => ['required', 'date','after_or_equal:today'],
...$this->photoRules(),
];
}

View File

@ -181,6 +181,14 @@ public function updateDeposit(CashTransaction $transaction, array $validated): v
$this->syncPhotos($transaction, $validated);
$this->recalculateBalances($transaction->cashAccount);
$account = $transaction->cashAccount->fresh();
if ($account->balance < 0) {
throw ValidationException::withMessages([
'amount' => 'Saldo kas tidak mencukupi.',
]);
}
});
$this->pushNotificationService->sendToRoles(
@ -198,10 +206,18 @@ public function deleteTransaction(CashTransaction $transaction): void
DB::transaction(function () use ($transaction): void {
CashAccount::query()->lockForUpdate()->findOrFail($transaction->cash_account_id);
$account = $transaction->cashAccount;
$transaction->clearMediaCollection('photos');
$transaction->delete();
$this->recalculateBalances($transaction->cashAccount);
$this->recalculateBalances($account);
if ($account->fresh()->balance < 0) {
throw ValidationException::withMessages([
'transaction' => 'Saldo kas tidak mencukupi jika transaksi ini dihapus.',
]);
}
});
$this->pushNotificationService->sendToRoles(
@ -245,6 +261,12 @@ public function deleteReferencedTransaction(CashTransaction $transaction): void
$transaction->delete();
$this->recalculateBalances($account);
if ($account->fresh()->balance < 0) {
throw ValidationException::withMessages([
'transaction' => 'Saldo kas tidak mencukupi jika transaksi ini dihapus.',
]);
}
});
}

View File

@ -32,8 +32,8 @@ function destroyTransaction() {
onSuccess: () => {
deleteConfirmOpen.value = false;
},
onError: () => {
toast.error('Gagal menghapus setor kas.');
onError: (errors) => {
toast.error(errors.amount || errors.transaction || 'Gagal menghapus setor kas.');
},
onFinish: () => {
deleteProcessing.value = false;

View File

@ -72,8 +72,8 @@ function approveEmployeeAdvance() {
onSuccess: () => {
approveConfirmOpen.value = false;
},
onError: () => {
toast.error('Gagal menyetujui kasbon.');
onError: (errors) => {
toast.error(errors.amount || errors.employee_advance || 'Gagal menyetujui kasbon.');
},
onFinish: () => {
approveProcessing.value = false;
@ -89,8 +89,8 @@ function payEmployeeAdvance() {
onSuccess: () => {
payConfirmOpen.value = false;
},
onError: () => {
toast.error('Gagal melunasi kasbon.');
onError: (errors) => {
toast.error(errors.amount || errors.employee_advance || 'Gagal melunasi kasbon.');
},
onFinish: () => {
payProcessing.value = false;

View File

@ -30,8 +30,8 @@ function destroyExpense() {
onSuccess: () => {
deleteConfirmOpen.value = false;
},
onError: () => {
toast.error('Gagal menghapus pengeluaran.');
onError: (errors) => {
toast.error(errors.amount || errors.transaction || 'Gagal menghapus pengeluaran.');
},
onFinish: () => {
deleteProcessing.value = false;

View File

@ -30,8 +30,8 @@ function payPayroll() {
onSuccess: () => {
payConfirmOpen.value = false;
},
onError: () => {
toast.error('Gagal membayar gaji.');
onError: (errors) => {
toast.error(errors.amount || errors.payroll || 'Gagal membayar gaji.');
},
onFinish: () => {
payProcessing.value = false;