Skip to content

tally: support both Tally ageing methods (bill date and due date), and state which is in use #114

Description

@lamemustafa

Tally offers two ageing methods and lets the user pick. Bridge silently implements one of them and never says which. This proposes supporting both, and records the live measurements showing it is far cheaper than it looks.

This is an enhancement, not a bug. Bridge is not computing anything wrongly — it implements one of two legitimate methods.

What Tally does

F6: Ageing Method offers Ageing by Bill Date and Ageing by Due Date, and the choice changes the buckets. Measured in Bridge Ageing Lab (synthetic, port 9000, Education) on a bill built for the purpose — CREDIT-30, dated 1-May-26 with a 30-day credit period, due 31-May-26:

as-of method days bucket
2-Jul-26 Ageing by Due Date 32 30 to 60
2-Jul-26 Ageing by Bill Date 62 60 to 90

Same bill, same date, different bucket. Both are correct; they answer different questions.

What Bridge does

Ages every bill from BILLDATE, unconditionally. It does not read BILLCREDITPERIOD, and the screen does not state which basis produced the buckets.

On the reference corpus this is invisible, because every bill there has an empty credit period — so bill date equals due date and the two methods coincide. That is why the reconciliation matches Tally exactly, and it is the seventh occasion on which this corpus has been unable to distinguish two candidate behaviours.

Why this is cheap

The data is already in the sealed response. From a VoucherOutstandingsV1 capture of the reference corpus:

BILLCREDITPERIOD occurrences in one partition capture: 19

<BILLDATE TYPE="Date">20240401</BILLDATE> <BILLCREATIONDATE TYPE="Date">20240401</BILLCREATIONDATE>
<NAME>INV-0001</NAME> <BILLCREDITPERIOD/> <BILLTYPE>New Ref</BILLTYPE> <BILLID TYPE="Number">1</BILLID>

The ALLLEDGERENTRIES.* wildcard already returns it on every scan. The parser discards it.

So this needs no request-shape change, no template-hash repin, and no sealed-boundary review. It is a parse-and-compute change plus UI — a different cost class from anything currently in flight.

BILLCREATIONDATE and BILLID are also returned and also unread; worth deciding deliberately whether they matter rather than continuing to drop them by default.

Proposed shape

  • A two-state control directly above the ageing buckets, not in a settings page. Use Tally's own vocabulary: Ageing by Bill Date / Ageing by Due Date.
  • Default to bill date, so present behaviour is unchanged for everyone.
  • Print the basis in the freshness line, so an exported or screenshotted figure is self-describing. A bucket that does not carry its own basis is exactly what made this confusing to diagnose.

Switching costs no Tally traffic. Bridge holds the allocations locally, so it is a client-side recompute — instant, no refetch, no request budget. Tally itself has to re-render the report; Bridge would not.

There is a real analytical benefit beyond parity: showing the difference is informative. A bill 62 days old by date but 32 by terms is precisely the distinction a CA wants visible, and today Bridge picks one silently.

Note for the oracle work (#111)

The native Bills Receivable export returns BILLDATE, BILLDUE and BILLOVERDUE. Measured: BILLOVERDUE is always computed from BILLDUE and does not follow the UI ageing-method setting — verified by toggling the UI to Ageing by Bill Date and re-running the export, which still reported 61 rather than 91 for CREDIT-30.

That makes the export deterministic and safe as an oracle. But the comparison should still be built on amounts and dates, recomputing buckets for whichever method Bridge is presenting, rather than comparing against BILLOVERDUE directly.

Acceptance

  1. Both methods selectable, defaulting to bill date.
  2. The active basis is visible wherever buckets are shown.
  3. A regression with a credit-period bill proving the two methods produce different buckets — the reference corpus cannot test this, so it needs a fixture that carries a non-empty BILLCREDITPERIOD.
  4. Documented in TALLY_PROTOCOL_REFERENCE.md with these measurements.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions