fix(billing): bound approved/paid amounts on claim transition (M1)

approve/pay accepted any approved_rials/paid_rials with no bounds, so the
claiming tenant could write arbitrary figures into the insurer-debt ledger
(negative, or far above the claimed total). Validate: approved ∈ [0, claimed],
paid ∈ [0, approved] → 422 otherwise. (The "force arbitrary status" half of the
finding was already prevented by Claim::canTransitionTo.)

Regression: tests/Billing/ClaimAmountBoundsTest.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
hamed
2026-06-28 20:07:19 +03:30
co-authored by Claude Opus 4.8
parent 131a78343b
commit 23ca56b293
4 changed files with 84 additions and 4 deletions
@@ -224,6 +224,22 @@ class BillingController extends BaseController
return $this->error(ErrorCodes::ERR_VALIDATION_001, 'دلیل رد الزامی است', 422);
}
// Bound the financial figures: approved/paid cannot be negative, approved
// cannot exceed the claimed total, and paid cannot exceed approved.
if ($action === 'approve' && isset($data['approved_rials'])) {
$approved = (int) $data['approved_rials'];
if ($approved < 0 || $approved > $claim->getTotalClaimedRials()) {
return $this->error(ErrorCodes::ERR_VALIDATION_001, 'مبلغ تأییدشده باید بین ۰ و مبلغ مطالبه‌شده باشد', 422, 'approved_rials');
}
}
if ($action === 'pay' && isset($data['paid_rials'])) {
$paid = (int) $data['paid_rials'];
$ceiling = $claim->getTotalApprovedRials() ?? $claim->getTotalClaimedRials();
if ($paid < 0 || $paid > $ceiling) {
return $this->error(ErrorCodes::ERR_VALIDATION_001, 'مبلغ پرداختی باید بین ۰ و مبلغ تأییدشده باشد', 422, 'paid_rials');
}
}
$this->claimService->transition($claim, $target, [
'approved_rials' => isset($data['approved_rials']) ? (int) $data['approved_rials'] : null,
'paid_rials' => isset($data['paid_rials']) ? (int) $data['paid_rials'] : null,