Files
mercadodevida/work/artifacts/F-080/implementer.md
2026-08-20 05:59:47 +02:00

1.9 KiB

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.