Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/tally/compatibility/compatibility-matrix.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"schema_version": 1,
"bridge_commit_sha": "be1c20cc3fd66fa1ece196505c69f26e555e4b8e",
"compatibility_surface_sha256": "731155b112eacc5e8374d12a92cf0494c63a5a3de9879e6bea62950698f8c192",
"compatibility_surface_sha256": "54d5e83c80569da050230117deff05fb9fa6dcd0c33ed0c6cc50fbbb5e1c1e09",
"claims": [
{
"claim_id": "erp9-6-6-3-windows-education-xml-one-company",
Expand Down
16 changes: 10 additions & 6 deletions docs/tally/compatibility/compatibility-surface.json
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@
},
{
"path": "scripts/outstandings-copy.test.mjs",
"sha256": "77a8d992e00e02a1da22d19d6701a567e89e87124265c8e2b2b6394f93d5fe8b"
"sha256": "8c9adb100a45704ca8ba72203a397defca3e8b01a297e96043c543cc052b980a"
},
{
"path": "scripts/tally-company-selection.test.mjs",
Expand Down Expand Up @@ -359,23 +359,27 @@
},
{
"path": "src/OutstandingsScreen.tsx",
"sha256": "d51921b342436ef431b0e771702b1331ec16d1b346693f9adc1f5918995e5426"
"sha256": "be442a765fbf8f3440abb6c4673e5baefec8f628743c314693f9d5ebed276dab"
},
{
"path": "src/TallyReadinessFlow.tsx",
"sha256": "939d0c29743ce3df09df0c6b1cc97c177e99f4a7b8a3c6c1310aadb6e34b0705"
},
{
"path": "src/main.tsx",
"sha256": "ead26567bb7f256bd7f92f9988d4a655884801246f6f38f4979125f0e2069bbc"
"sha256": "afdcba045263ee790264c171bb9a3e5286f565b6c6aa27036a33c7f4c1382ba1"
},
{
"path": "src/outstandings-copy.ts",
"sha256": "948a310fa1d3c94d1fc46a940be11cb6ab27bb5d166e7ed966291ddb3d4d3f65"
"sha256": "a2bcf820f694443ac122e91aa98fb354b6e2d5c6be3e1e9503b368a3a0a4f696"
},
{
"path": "src/outstandings-csv.ts",
"sha256": "3c836edf03c6d71e26e726e4b31f2c4ae9c98acb703629b2e24b578b33145796"
},
{
"path": "src/styles.css",
"sha256": "0dd2517e24e126118cee071058946ab0301055ebdbd7985641448523ee468504"
"sha256": "33bd1f956b6b1ece2924fa8741fec9cb46a4b3b912c421b435b587c2e6293d6d"
},
{
"path": "src/tally-company-selection.ts",
Expand Down Expand Up @@ -430,5 +434,5 @@
"sha256": "a27f294ee15e407b69fdfc73609e8708ac0509b6e6a8872daef5451fde61a8db"
}
],
"manifest_sha256": "731155b112eacc5e8374d12a92cf0494c63a5a3de9879e6bea62950698f8c192"
"manifest_sha256": "54d5e83c80569da050230117deff05fb9fa6dcd0c33ed0c6cc50fbbb5e1c1e09"
}
31 changes: 30 additions & 1 deletion scripts/outstandings-copy.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,19 @@ import assert from "node:assert/strict";
import { readFile } from "node:fs/promises";
import test from "node:test";

import { isNonRetryableOutstandingsBoundary, outstandingsAgeingDisclosure, outstandingsPartialReason, outstandingsPartialState } from "../src/outstandings-copy.ts";
import { isNonRetryableOutstandingsBoundary, outstandingsAgeingAnchorLabel, outstandingsAgeingDisclosure, outstandingsPartialReason, outstandingsPartialState } from "../src/outstandings-copy.ts";

test("the backend ageing anchor is disclosed in the bucket label", () => {
assert.equal(outstandingsAgeingAnchorLabel("due_date"), "aged from due date");
assert.equal(outstandingsAgeingAnchorLabel("bill_date"), "aged from bill date");
});

test("new native and sweep boundaries have operator-readable reasons", () => {
assert.match(outstandingsPartialReason("native_overdue_crosscheck_mismatch"), /overdue-day cross-check/i);
assert.match(outstandingsPartialReason("company_currency_probe_failed"), /base currency/i);
assert.match(outstandingsPartialReason("company_base_currency_not_inr"), /not INR/i);
assert.match(outstandingsPartialReason("company_outstandings_read_failed"), /company read failed/i);
});

test("uncalibrated sizing says the voucher read was not sent", () => {
const message = outstandingsPartialReason("outstandings_segment_sizing_uncalibrated");
Expand Down Expand Up @@ -92,3 +104,20 @@ test("unaged receivables disclose the ageing scope without inventing an On Accou
assert.match(disclosure, /cannot prove the full unallocated balance/i);
assert.equal(outstandingsAgeingDisclosure(false), null);
});

test("a path that can prove the unallocated balance says so instead of disclaiming it", () => {
// The voucher scan derives bills from vouchers and genuinely cannot
// establish the unallocated remainder, so its disclaimer is honest. The
// native bills path recovers that figure exactly from the party ledgers, so
// repeating "Bridge does not show an On Account amount" there would be false
// while a screen right above it displays exactly that amount.
const known = outstandingsAgeingDisclosure(true, true);
assert.match(known, /shown as Unallocated above/i);
assert.doesNotMatch(known, /cannot prove/i);
assert.doesNotMatch(known, /does not show/i);

// Absent knowledge must keep the original disclaimer, never silently claim a
// figure it does not have.
assert.match(outstandingsAgeingDisclosure(true, false), /cannot prove the full unallocated balance/i);
assert.equal(outstandingsAgeingDisclosure(false, true), null);
});
28 changes: 28 additions & 0 deletions scripts/outstandings-csv.test.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import assert from "node:assert/strict";
import test from "node:test";

import { csvNumericCell, csvRow, csvTextCell } from "../src/outstandings-csv.ts";

test("neutralizes every active spreadsheet prefix in text cells", () => {
for (const [value, expected] of [
["=BVL Zeta Formula", "'=BVL Zeta Formula"],
["+SUM(A1:A2)", "'+SUM(A1:A2)"],
["-1+2", "'-1+2"],
["@SUM(A1:A2)", "'@SUM(A1:A2)"],
["\t=SUM(A1:A2)", "'\t=SUM(A1:A2)"],
["\r=SUM(A1:A2)", "\"'\r=SUM(A1:A2)\""],
]) {
assert.equal(csvRow(csvTextCell(value)), expected);
}
});

test("preserves numeric amount and count cells", () => {
assert.equal(
csvRow(csvNumericCell("-11111.00"), csvNumericCell(5)),
"-11111.00,5",
);
});

test("quotes neutralized text with CSV syntax after prefixing", () => {
assert.equal(csvRow(csvTextCell('=HYPERLINK("https://example.invalid","x")')), '"\'=HYPERLINK(""https://example.invalid"",""x"")"');
});
Loading
Loading