fix(display): uniform currency, billing-cycle label, resolved audit-log diff #229

Merged
nrupard merged 1 commit from fix/PMS-365-display-formatting-sweep into main 2026-06-16 18:34:34 +02:00
Owner

What

PMS-365 display-correctness sweep (external review #2, findings #8 + #9). Three areas: uniform currency, enum labels, and resolved audit-log diff.

Root cause for all three: shared helpers already exist (utils/money.rs from MAPPS-197; many humanize_* enum helpers), but a handful of ad-hoc render sites bypassed them, and the audit-log diff dumped raw JSON. This routes every flagged site through a helper.

1. Currency (AC #1) - 9 sites routed to the shared formatter

File:line Was Now
projects.rs (Total Budget stat) format!("${total_value:.0}") -> $25000 format_money_f64 -> $25,000.00
projects.rs (Budget panel Remaining) "${remaining:.0}" -> $25000 format_money_f64
reports.rs Invoiced / Paid / Outstanding format!("${}", ...) format_money_str
reports.rs A/R aging total format!("${}", a.total) format_money_str
reports.rs Budget / Actual format!("${:.0}", pf(...)) format_money_str
settings.rs work-type rate format!("${rate}") format_money_str

Fixes the reviewer's same-flow mismatch (Total Budget stat / Remaining showed $25000 next to a correctly formatted $25,000.00 card).

2. Enum label (AC #2) - 1 gap

Added humanize_billing_cycle (mirrors humanize_contract_type / humanize_contract_status) and applied it on the contract detail panel: monthly -> Monthly. Every other user-facing enum already passes through a humanize_* helper (tickets, contract type/status, invoice status, payment method, tenant status, plan, provider, KB visibility).

3. Audit-log diff (AC #3) - FK resolution + humanized labels

Replaced the two raw old_values / new_values JSON blobs with a field-by-field "Changes" view:

  • Field keys humanized: project_manager_id -> "Project manager" (trailing _id dropped, sentence-cased).
  • User-FK ids resolve to names via the same /auth/users list the project pickers use; unresolved ids fall back to a short UUID prefix; null/empty render as (empty). So Project manager id: (empty) -> (reference) now reads Project manager: (empty) -> Jane Doe.
  • Canonical audit JSON is unchanged server-side; only the render resolves (per the issue).
  • Non-object payloads fall back to the previous raw-JSON view.

Seven unit tests cover the pure helpers (key humanization, FK resolve, unknown-FK fallback, null/empty, non-user-FK passthrough, key union order, non-object fallback).

Scope notes (AC #4 audit)

  • Other FK ids (companies, contacts) stay raw in the diff: the audit page does not cache those lists. User FKs were the reviewer's example and the cheap, correct win.
  • portal.rs keeps its own portal_money on the separate client-portal surface; folding it into the shared helper is left out of this sweep.
  • Field-value enums inside the diff (e.g. a status: in_progress change) render literally; per-field enum humanization in the generic diff is out of scope (no per-field enum map).

Verification

  • cargo fmt --all --check
  • cargo clippy --target wasm32-unknown-unknown -- -D warnings clean
  • cargo test --lib audit -> 7 passed
  • Compiles to wasm32-unknown-unknown

🤖 Generated with Claude Code

## What PMS-365 display-correctness sweep (external review #2, findings #8 + #9). Three areas: uniform currency, enum labels, and resolved audit-log diff. Root cause for all three: shared helpers already exist (`utils/money.rs` from MAPPS-197; many `humanize_*` enum helpers), but a handful of ad-hoc render sites bypassed them, and the audit-log diff dumped raw JSON. This routes every flagged site through a helper. ## 1. Currency (AC #1) - 9 sites routed to the shared formatter | File:line | Was | Now | |---|---|---| | projects.rs (Total Budget stat) | `format!("${total_value:.0}")` -> `$25000` | `format_money_f64` -> `$25,000.00` | | projects.rs (Budget panel Remaining) | `"${remaining:.0}"` -> `$25000` | `format_money_f64` | | reports.rs Invoiced / Paid / Outstanding | `format!("${}", ...)` | `format_money_str` | | reports.rs A/R aging total | `format!("${}", a.total)` | `format_money_str` | | reports.rs Budget $ / Actual $ | `format!("${:.0}", pf(...))` | `format_money_str` | | settings.rs work-type rate | `format!("${rate}")` | `format_money_str` | Fixes the reviewer's same-flow mismatch (Total Budget stat / Remaining showed `$25000` next to a correctly formatted `$25,000.00` card). ## 2. Enum label (AC #2) - 1 gap Added `humanize_billing_cycle` (mirrors `humanize_contract_type` / `humanize_contract_status`) and applied it on the contract detail panel: `monthly` -> `Monthly`. Every other user-facing enum already passes through a `humanize_*` helper (tickets, contract type/status, invoice status, payment method, tenant status, plan, provider, KB visibility). ## 3. Audit-log diff (AC #3) - FK resolution + humanized labels Replaced the two raw `old_values` / `new_values` JSON blobs with a field-by-field "Changes" view: - Field keys humanized: `project_manager_id` -> "Project manager" (trailing `_id` dropped, sentence-cased). - User-FK ids resolve to names via the same `/auth/users` list the project pickers use; unresolved ids fall back to a short UUID prefix; null/empty render as `(empty)`. So `Project manager id: (empty) -> (reference)` now reads `Project manager: (empty) -> Jane Doe`. - Canonical audit JSON is unchanged server-side; only the render resolves (per the issue). - Non-object payloads fall back to the previous raw-JSON view. Seven unit tests cover the pure helpers (key humanization, FK resolve, unknown-FK fallback, null/empty, non-user-FK passthrough, key union order, non-object fallback). ## Scope notes (AC #4 audit) - Other FK ids (companies, contacts) stay raw in the diff: the audit page does not cache those lists. User FKs were the reviewer's example and the cheap, correct win. - `portal.rs` keeps its own `portal_money` on the separate client-portal surface; folding it into the shared helper is left out of this sweep. - Field-value enums inside the diff (e.g. a `status: in_progress` change) render literally; per-field enum humanization in the generic diff is out of scope (no per-field enum map). ## Verification - `cargo fmt --all --check` - `cargo clippy --target wasm32-unknown-unknown -- -D warnings` clean - `cargo test --lib audit` -> 7 passed - Compiles to wasm32-unknown-unknown 🤖 Generated with [Claude Code](https://claude.com/claude-code)
fix(display): uniform currency formatting, billing-cycle label, resolved audit-log diff
All checks were successful
Check / clippy + fmt + tests (pull_request) Successful in 2m51s
Create release / Create release from merged PR (pull_request) Has been skipped
1cbc34de03
PMS-365 display-correctness sweep across three areas.

Currency: route the remaining ad-hoc money renders through the shared `crate::utils::money` formatter (MAPPS-197) so every figure reads `$1,234.00`. Fixes the reviewer's same-flow mismatch where the Projects "Total Budget" stat and the project Budget panel "Remaining" showed a bare `$25000` next to a correctly formatted card. Sites: projects.rs (Total Budget stat, Budget panel Remaining), reports.rs (Invoiced/Paid/Outstanding/A-R-aging/Budget $/Actual $), settings.rs (work-type rate).

Enum label: add `humanize_billing_cycle` (matching the sibling `humanize_contract_type`/`humanize_contract_status`) and apply it on the contract detail panel so the Billing Cycle reads `Monthly` instead of the raw lowercase `monthly`. The other user-facing enums already pass through `humanize_*` helpers.

Audit-log diff: replace the two raw `old_values` / `new_values` JSON blobs with a field-by-field "Changes" view. Field keys are humanized (`project_manager_id` -> "Project manager", trailing `_id` dropped, sentence-cased); user-FK ids (`project_manager_id`, `assigned_to_id`, ...) resolve to names via the same `/auth/users` list the project pickers use, falling back to a short UUID prefix when a user is not cached; null/empty render as `(empty)`. The canonical audit JSON is unchanged server-side; only the render resolves. Non-object payloads fall back to the previous raw-JSON view. Pure helpers covered by unit tests (7).

Scope notes:

- Other FK ids (companies, contacts) stay raw in the diff because the audit page does not cache those lists; user FKs were the reviewer's example and the cheap win.
- `portal.rs` keeps its own `portal_money` on the separate client-portal surface; folding it into the shared helper is left out of this sweep.

#PMS-365

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
nrupard deleted branch fix/PMS-365-display-formatting-sweep 2026-06-16 18:34:34 +02:00
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-apps!229
No description provided.