fix(billing): reject non-positive payment amounts with a 422 #269

Merged
vas2000-work merged 1 commit from fix/PMS-373-reject-non-positive-payment-amount into main 2026-06-16 23:49:32 +02:00
Owner

POST /api/v1/payments accepted amount <= 0 and persisted it (e.g. -50.00), corrupting invoice balances and revenue reporting. The amount field used validate_money_amount, which intentionally bounded only the magnitude and left the sign unconstrained.

Add validate_payment_amount: a payment amount must be strictly positive, at most 2 decimal places, and within the DECIMAL(12, 2) column magnitude. CreatePaymentRequest::amount now uses it, so request.validate()? rejects amount <= 0 (and over-precise / oversized values) with a field-level 422 before any row is created.

Add migration 051: a payments_amount_positive CHECK (amount > 0) backstop, added NOT VALID so the migration does not fail on pre-existing dirty rows while still enforcing the rule on every new write. Any existing amount <= 0 rows are surfaced via a RAISE WARNING (not silently mutated) for deliberate finance cleanup.

Update the billing model tests to assert non-positive and over-precise amounts are rejected (replacing the old test that asserted negative amounts were allowed), and add validation unit tests.

#PMS-373

POST /api/v1/payments accepted amount <= 0 and persisted it (e.g. -50.00), corrupting invoice balances and revenue reporting. The amount field used validate_money_amount, which intentionally bounded only the magnitude and left the sign unconstrained. Add validate_payment_amount: a payment amount must be strictly positive, at most 2 decimal places, and within the DECIMAL(12, 2) column magnitude. CreatePaymentRequest::amount now uses it, so request.validate()? rejects amount <= 0 (and over-precise / oversized values) with a field-level 422 before any row is created. Add migration 051: a payments_amount_positive CHECK (amount > 0) backstop, added NOT VALID so the migration does not fail on pre-existing dirty rows while still enforcing the rule on every new write. Any existing amount <= 0 rows are surfaced via a RAISE WARNING (not silently mutated) for deliberate finance cleanup. Update the billing model tests to assert non-positive and over-precise amounts are rejected (replacing the old test that asserted negative amounts were allowed), and add validation unit tests. #PMS-373
fix(billing): reject non-positive payment amounts with a 422
All checks were successful
Check / fmt + clippy + compile + unit/doc tests (pull_request) Successful in 57s
E2E / Playwright against staging (pull_request) Successful in 1m0s
Integration / integration tests (pull_request) Successful in 5m35s
Create release / Create release from merged PR (pull_request) Has been skipped
ca16ea9475
POST /api/v1/payments accepted amount <= 0 and persisted it (e.g. -50.00), corrupting invoice balances and revenue reporting. The amount field used validate_money_amount, which intentionally bounded only the magnitude and left the sign unconstrained.

Add validate_payment_amount: a payment amount must be strictly positive, at most 2 decimal places, and within the DECIMAL(12, 2) column magnitude. CreatePaymentRequest::amount now uses it, so request.validate()? rejects amount <= 0 (and over-precise / oversized values) with a field-level 422 before any row is created.

Add migration 051: a payments_amount_positive CHECK (amount > 0) backstop, added NOT VALID so the migration does not fail on pre-existing dirty rows while still enforcing the rule on every new write. Any existing amount <= 0 rows are surfaced via a RAISE WARNING (not silently mutated) for deliberate finance cleanup.

Update the billing model tests to assert non-positive and over-precise amounts are rejected (replacing the old test that asserted negative amounts were allowed), and add validation unit tests.

#PMS-373
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
psa-systems/mokosh-server!269
No description provided.