Round reimbursement totals to cents#259
Conversation
Code Review by Qodo
1. Item parsing mismatch
|
Review Summary by QodoImplement precise BigInt arithmetic for monetary calculations with cent rounding
WalkthroughsDescription• Implement precise decimal arithmetic using BigInt for accurate financial calculations • Round monetary totals to cents (2 decimals) while maintaining 8-decimal precision for item costs • Add money field formatting on blur and before form submission • Update HTML input step attributes from 0.00000001 to 0.01 for user-friendly input Diagramflowchart LR
A["User Input<br/>Money Fields"] -->|blur event| B["formatMoneyInput<br/>Parse & Format"]
B -->|normalize to cents| C["Money Field<br/>2 decimals"]
D["Item Calculations<br/>8 decimals"] -->|parseScaledAmount| E["BigInt<br/>Arithmetic"]
E -->|roundScaledAmount| F["Round to<br/>Cents"]
F -->|formatMoneyCents| G["Display<br/>2 decimals"]
H["Form Submit"] -->|formatMoneyFields| I["Normalize All<br/>Money Fields"]
I -->|validateSubmission| J["Check Total<br/>≥ $100 CAD"]
File Changes1. src/templates/dashboard.html
|
| const quantity = parseQuantity(quantityInput.value); | ||
| const price = parseScaledAmount(priceInput.value, preciseDecimalPlaces); | ||
| const total = quantity * price; | ||
|
|
||
| totalInput.value = total.toFixed(8); | ||
| totalInput.value = formatPreciseAmount(total); | ||
| calculateSubtotal(formNumber); | ||
| } |
There was a problem hiding this comment.
1. Item parsing mismatch 🐞 Bug ≡ Correctness
calculateItemTotal() now uses parseQuantity()/parseScaledAmount(), but validateSubmission() still uses parseFloat() to decide whether an item row is complete. This can mark rows like quantity="1.0" or price="1e-3" as complete even though the UI calculates totals as 0 and the backend will skip invalid items (or the whole form if no valid items remain).
Agent Prompt
### Issue description
`validateSubmission()` still uses `parseFloat()` for item completeness checks, while item total/subtotal calculations were changed to strict BigInt parsers (`parseQuantity()` / `parseScaledAmount()`). This mismatch allows inputs that the validator considers “complete” (e.g. `1.0`, `1e-3`) to produce zero totals in the UI and/or be rejected/skipped by server-side Pydantic validation.
### Issue Context
- Client calculations:
- `parseQuantity()` only accepts `^\d+$`.
- `parseScaledAmount()` only accepts plain decimal strings (no scientific notation).
- Client validation:
- `validateSubmission()` uses `parseFloat()` and `> 0` checks for quantity/price.
- Server validation:
- `SubmissionLineItem.quantity` is an `int` with `gt=0`; invalid quantities raise `ValidationError` and are skipped.
### Fix Focus Areas
- src/static/js/dashboard.js[402-424]
- src/static/js/dashboard.js[40-44]
- src/static/js/dashboard.js[202-214]
- src/templates/dashboard.html[175-184]
### Suggested fix
1. Update `validateSubmission()` to use the same parsing rules as calculations:
- `const itemQuantity = parseQuantity(quantityInput?.value);`
- `const itemPrice = parseScaledAmount(priceInput?.value, preciseDecimalPlaces);`
- Treat the row as complete only when `itemQuantity > 0n && itemPrice > 0n`.
2. Prevent or normalize problematic number formats at the input level:
- Set `step="1"` on quantity inputs (and consider `inputmode="numeric"`).
- Optionally add a blur formatter for item price/quantity similar to `formatMoneyInput()` (e.g., rewrite `1e-3` into a plain decimal string at the desired precision) so users can’t submit values the calculator treats as 0.
3. If you choose to keep rejecting scientific notation, ensure validation explicitly fails those rows with a clear alert instead of silently treating them as zero.
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
Summary
Verification