Document the sale-date contract, and rate the packaged goods

parsePosSaleDate needed no change — RFC3339Nano already accepts the offset the
terminal now sends, and Format("2006-01-02") on a zoned time still yields the
till's own trading day rather than UTC's. But the ordering of those layouts is
load-bearing and nothing said so, and the two bare layouts are a legacy that
should be recognisable as one: they exist for terminals built before the offset,
whose bills record an instant wrong by the offset with nothing in the payload to
recover it from. Two tests pin both halves, including the case that motivated
this — 00:30 IST, where UTC has not yet rolled into the same day.

The GST script writes only the four packaged lines at 1185, which sat at 0 and
were being billed with no tax at all.

It deliberately does not touch the produce at 1135. That was written believing
every rate was 0 — read from a field name that does not exist in the response,
so the check silently returned nothing. The rows in fact hold 8, 12 and 18, and
under Indian GST fresh unbranded fruit and chilled fish are nil-rated, so
several look like overcharging. Every correction there is a reduction of a live
rate, which belongs to whoever signs the returns rather than to a script. They
are reported as REVIEW and left as found.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Suriya
2026-08-05 20:18:17 +05:30
parent 11595ad415
commit d0c3cb751e
3 changed files with 240 additions and 0 deletions

View File

@@ -197,3 +197,57 @@ func TestABillTakesItsTerminalFromTheBatchWhenItNamesNone(t *testing.T) {
})
}
}
// billedat and businessdate are derived from the same parsed value and pull in
// opposite directions, so they are tested together.
//
// Live bill INV-2608-T5EDD-00116 carried billedat 2026-08-05T12:49:28Z beside
// receivedat 2026-08-05T07:19:28Z — the sale appearing to happen five and a
// half hours after it was received. The till was sending a naive local
// timestamp and time.Parse fills that silence with UTC, so a Coimbatore wall
// clock was recorded as though read in London.
//
// The daily figures survived it by luck: businessdate comes off the wall clock
// either way, and the wall clock was always the till's own. Anything comparing
// billedat against real time did not.
func TestASaleDateKeepsBothTheInstantAndTheTradingDay(t *testing.T) {
// Coimbatore, late enough that UTC has not yet rolled into the same day.
const ist = "2026-08-05T00:30:00+05:30"
at, err := parsePosSaleDate(ist)
if err != nil {
t.Fatalf("parsePosSaleDate(%q) errored: %v", ist, err)
}
// The instant. 00:30 IST is 19:00 UTC the previous evening.
wantInstant := time.Date(2026, 8, 4, 19, 0, 0, 0, time.UTC)
if !at.UTC().Equal(wantInstant) {
t.Errorf("instant = %v, want %v", at.UTC(), wantInstant)
}
// The trading day. This is the one that must NOT follow UTC — the shop rang
// this sale on the 5th and its takings belong to the 5th. Deriving the
// business date from UTC would file it under the 4th and leave two days
// wrong: one short, one over.
if got := at.Format("2006-01-02"); got != "2026-08-05" {
t.Errorf("businessdate = %s, want 2026-08-05 — the till's own day", got)
}
}
// Terminals built before the offset was added send a bare local timestamp, and
// they are still in the field. Parsing must not start refusing them.
//
// The instant such a bill records is wrong by the offset and cannot be
// recovered — there is nothing in the payload that says which zone it was read
// in. Its business date is still right, which is why the daily figures held up,
// and why this stays a tolerated legacy rather than a rejection.
func TestANaiveSaleDateIsStillAccepted(t *testing.T) {
at, err := parsePosSaleDate("2026-08-05T12:49:28.245")
if err != nil {
t.Fatalf("a pre-offset terminal must not be refused: %v", err)
}
if got := at.Format("2006-01-02"); got != "2026-08-05" {
t.Errorf("businessdate = %s, want 2026-08-05", got)
}
}