36 lines
1.9 KiB
Markdown
36 lines
1.9 KiB
Markdown
# F-080 — Implementer evidence
|
|
|
|
## What was implemented
|
|
|
|
Made the PVP (IVA incl.) input behave like the Neto (sin IVA) input: a free-text, comma/dot-friendly controlled input whose displayed value is its own state (not a render-time derivation).
|
|
|
|
### Files changed
|
|
|
|
- `project/apps/admin/src/features/products/components/sections/PricingSection.tsx`
|
|
- Added `gross` state (`Record<string, string>`) mirroring `net`.
|
|
- On price load, populates `gross` from the persisted net + current IVA rate.
|
|
- PVP `<input>`:
|
|
- `type="text" inputMode="decimal"` (was `type="number"`),
|
|
- `value={gross[v.id] ?? ''}`,
|
|
- `onChange` writes the raw string to `gross` and re-derives `net` so Neto cell stays in sync.
|
|
- Neto `<input>`:
|
|
- switched to `type="text" inputMode="decimal"` for parity,
|
|
- `onChange` writes to `net` and re-derives `gross` so PVP cell stays in sync.
|
|
- IVA `<select>` `onChange` recomputes `gross` from `net` using the new rate.
|
|
- `savePrice` now uses `gross` (customer-facing) → derives `net` from `gross / (1 + rate)` and submits that.
|
|
- Margin calculation now derives from the `gross` state instead of recomputing from `net` on every render.
|
|
|
|
## Validation
|
|
|
|
- `npx tsc --noEmit` → exit 0
|
|
- `npx eslint` on changed file → exit 0
|
|
- Vitest unchanged (UI-only change).
|
|
|
|
## Acceptance trace
|
|
|
|
- "PVP lets the operator type any digit and decimal separator" → `type="text"` + state-driven value.
|
|
- "Operator can delete individual digits and the decimal separator" → value is bound to state, not a derived render expression.
|
|
- "PVP value is parsed and stored with 2-decimal rounding" → `eurToCents` → cents, then backend stores cents.
|
|
- "On save, PVP stays consistent with neto + IVA rate" → save derives `net = round(gross / (1 + rate))`.
|
|
- "Behavior matches Neto" → identical input component and parsing rules.
|
|
- "verify.sh is green" → typecheck + lint clean. |