"use client"; import { formatCurrency } from "@/lib/utils"; import { amountToPercent, percentToAmount } from "@/lib/po-money"; /** * PO-level TCS and Discount charges, shown below GST (issue #133). * * Each charge is entered as an absolute rupee amount **or** as a percentage of the * GST-inclusive line-items total (`base`) — the two are bidirectionally linked. * Only the absolute amount is stored (the parent persists `tcs` / `discount`); the * percentage is a convenience. Discount is applied post-GST. */ interface Props { base: number; // GST-inclusive line-items total — the % base currency: string; tcs: number; discount: number; onTcsChange: (amount: number) => void; onDiscountChange: (amount: number) => void; disabled?: boolean; } const INPUT = "w-full rounded-lg border border-neutral-300 px-3 py-2 text-sm focus:border-primary-500 focus:outline-none focus:ring-2 focus:ring-primary-500/20"; function round2(n: number): number { return Math.round((n + Number.EPSILON) * 100) / 100; } function ChargeRow({ label, hint, base, value, onChange, disabled, }: { label: string; hint: string; base: number; value: number; onChange: (amount: number) => void; disabled?: boolean; }) { const percent = round2(amountToPercent(value, base)); return (

{hint}

onChange(Math.max(0, Number(e.target.value) || 0))} className={INPUT} />
onChange(round2(percentToAmount(Number(e.target.value) || 0, base)))} className={INPUT} />
); } export function TcsDiscountFields({ base, currency, tcs, discount, onTcsChange, onDiscountChange, disabled, }: Props) { const netPayable = base + (tcs || 0) - (discount || 0); return (

Optional charges applied after GST. Enter a rupee amount or a percentage of the GST-inclusive total — they stay in sync. Stored as an absolute amount.

Net payable {formatCurrency(netPayable, currency)}
); }