feat(payments): outstanding panel + settled-to-document column

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
main
Thomas Joise 2 days ago
parent f1a7eac9dd
commit 78ed947422

@ -422,12 +422,35 @@ export function ClientDetail() {
<StatCard label="Advance on account" value={formatINR(ledger.data.advancePaise)} hint="unallocated payments" /> <StatCard label="Advance on account" value={formatINR(ledger.data.advancePaise)} hint="unallocated payments" />
</Stats> </Stats>
)} )}
{ledger.data !== undefined && ledger.data.outstanding.length > 0 && (
<div className="wf-card">
<h3 style={{ display: 'flex', alignItems: 'center', gap: 8, margin: '0 0 10px' }}>
Outstanding
<Badge tone="warn">{inr(ledger.data.outstanding.reduce((s, o) => s + o.outstandingPaise, 0))} due</Badge>
</h3>
<div className="cdr-out">
<div className="oh"><span style={{ fontWeight: 700, fontSize: 13 }}>Open documents</span>
<span style={{ color: 'var(--text-dim)', fontSize: 12 }}> oldest settles first</span></div>
{ledger.data.outstanding.map((o) => (
<div key={o.docId} className="orow" onClick={() => nav(`/documents/${o.docId}`)} style={{ cursor: 'pointer' }}>
<span className="mono" style={{ minWidth: 78 }}>{o.docNo ?? 'draft'}</span>
<span className="doc-pill">{DOC_TYPE_LABEL[o.docType as keyof typeof DOC_TYPE_LABEL] ?? o.docType}</span>
<span style={{ color: 'var(--text-dim)' }}>{o.label}</span>
<span className="due">{inr(o.outstandingPaise)}</span>
</div>
))}
<div className="ofoot"><span style={{ color: 'var(--text-dim)', fontSize: 12 }}>Advance on account</span>
<span className="mono" style={{ marginLeft: 'auto', fontWeight: 600 }}>{formatINR(ledger.data.advancePaise)}</span></div>
</div>
</div>
)}
<PaymentForm clientId={id} onDone={() => { ledger.reload(); cms.reload(); amc.reload() }} /> <PaymentForm clientId={id} onDone={() => { ledger.reload(); cms.reload(); amc.reload() }} />
{ledger.data !== undefined && ledger.data.payments.length > 0 && ( {ledger.data !== undefined && ledger.data.payments.length > 0 && (
<DataTable <DataTable
columns={[ columns={[
{ key: 'on', label: 'Received' }, { key: 'mode', label: 'Mode' }, { key: 'on', label: 'Received' }, { key: 'mode', label: 'Mode' },
{ key: 'ref', label: 'Reference', mono: true }, { key: 'ref', label: 'Reference', mono: true },
{ key: 'settled', label: 'Settled' },
{ key: 'amount', label: 'Amount', numeric: true }, { key: 'amount', label: 'Amount', numeric: true },
{ key: 'tds', label: 'TDS', numeric: true }, { key: 'tds', label: 'TDS', numeric: true },
]} ]}
@ -435,6 +458,9 @@ export function ClientDetail() {
.sort((a, b) => (a.receivedOn === b.receivedOn ? (a.id < b.id ? 1 : -1) : b.receivedOn.localeCompare(a.receivedOn))) .sort((a, b) => (a.receivedOn === b.receivedOn ? (a.id < b.id ? 1 : -1) : b.receivedOn.localeCompare(a.receivedOn)))
.map((p) => ({ .map((p) => ({
on: p.receivedOn, mode: p.mode, ref: p.reference !== '' ? p.reference : '—', on: p.receivedOn, mode: p.mode, ref: p.reference !== '' ? p.reference : '—',
settled: p.allocations.length === 0
? <span style={{ color: 'var(--text-dim)' }}>advance</span>
: <span style={{ color: 'var(--text-dim)', fontSize: 12 }}> {p.allocations.map((a) => a.docNo).join(', ')}</span>,
amount: inr(p.amountPaise), tds: p.tdsPaise > 0 ? inr(p.tdsPaise) : '—', amount: inr(p.amountPaise), tds: p.tdsPaise > 0 ? inr(p.tdsPaise) : '—',
}))} }))}
/> />

Loading…
Cancel
Save