@diy-accounting-uk/diya-gl 1.2.53 → 1.2.55

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1611,6 +1611,58 @@
1611
1611
  "scorecard": "101608 passed, 0 warnings, 0 failed"
1612
1612
  }
1613
1613
  }
1614
+ },
1615
+ {
1616
+ "tag": "diya-gl-v1.2.53",
1617
+ "date": "2026-10-20",
1618
+ "formatVersion": "diya-gl/1",
1619
+ "engineVersion": "1.2.53+f18282c3",
1620
+ "taxDataHash": "51bdff60e993",
1621
+ "reconciledCommit": "54e8731a91279975e61b1a232fbb67fda89515f0",
1622
+ "templates": {
1623
+ "bst": {
1624
+ "hash": "0d003e10e00c",
1625
+ "scorecard": "812 passed, 0 warnings, 0 failed"
1626
+ },
1627
+ "taxi": {
1628
+ "hash": "1ff69654d64d",
1629
+ "scorecard": "700 passed, 0 warnings, 0 failed"
1630
+ },
1631
+ "se": {
1632
+ "hash": "064605ae76ed",
1633
+ "scorecard": "8015 passed, 0 warnings, 0 failed"
1634
+ },
1635
+ "ltd": {
1636
+ "hash": "a65ab09cf35c",
1637
+ "scorecard": "101608 passed, 0 warnings, 0 failed"
1638
+ }
1639
+ }
1640
+ },
1641
+ {
1642
+ "tag": "diya-gl-v1.2.54",
1643
+ "date": "2026-10-23",
1644
+ "formatVersion": "diya-gl/1",
1645
+ "engineVersion": "1.2.54+21f315a0",
1646
+ "taxDataHash": "51bdff60e993",
1647
+ "reconciledCommit": "54e8731a91279975e61b1a232fbb67fda89515f0",
1648
+ "templates": {
1649
+ "bst": {
1650
+ "hash": "0d003e10e00c",
1651
+ "scorecard": "812 passed, 0 warnings, 0 failed"
1652
+ },
1653
+ "taxi": {
1654
+ "hash": "1ff69654d64d",
1655
+ "scorecard": "700 passed, 0 warnings, 0 failed"
1656
+ },
1657
+ "se": {
1658
+ "hash": "064605ae76ed",
1659
+ "scorecard": "8015 passed, 0 warnings, 0 failed"
1660
+ },
1661
+ "ltd": {
1662
+ "hash": "a65ab09cf35c",
1663
+ "scorecard": "101608 passed, 0 warnings, 0 failed"
1664
+ }
1665
+ }
1614
1666
  }
1615
1667
  ]
1616
1668
  }
@@ -12,7 +12,7 @@
12
12
 
13
13
  export const PROVENANCE_DATA = {
14
14
  formatVersion: "diya-gl/1",
15
- engineVersion: "1.2.53+f18282c3",
15
+ engineVersion: "1.2.55+bb0dbecd",
16
16
  taxDataHash: "51bdff60e993",
17
17
  reconciledCommit: "54e8731a91279975e61b1a232fbb67fda89515f0",
18
18
  templates: {
@@ -73,6 +73,20 @@ const REVERSE_SALES = buildReverseCodeMap(LTD_SALES_CODE_MAP);
73
73
  /**
74
74
  * Check if a cell contains a formula (has <f> tag).
75
75
  */
76
+ // The rows between first and last, inclusive, on which the column holds a cell with content:
77
+ // a typed value or a formula. A bank book's receipt and payment lists sit side by side and each
78
+ // has gaps where the other side has a row, so a reader walks the rows its own column fills
79
+ // rather than stopping at the first gap or testing every row of the sheet.
80
+ function rowsWithContent(xml, column, first, last) {
81
+ const rows = new Set();
82
+ const cellPattern = new RegExp(`<c\\s+r="${column}(\\d+)"[^>]*>`, "g");
83
+ for (const match of xml.matchAll(cellPattern)) {
84
+ const row = Number(match[1]);
85
+ if (row >= first && row <= last && !match[0].endsWith("/>")) rows.add(row);
86
+ }
87
+ return [...rows].sort((a, b) => a - b);
88
+ }
89
+
76
90
  function hasCellFormula(xml, cellRef) {
77
91
  const cellPattern = new RegExp(`<c\\s+r="${cellRef}"[^>]*(?:/>|>([\\s\\S]*?)</c>)`, "s");
78
92
  const match = xml.match(cellPattern);
@@ -952,12 +966,14 @@ export async function extractBankTransactions(set, product, period, extractionMa
952
966
  obEmitted = true;
953
967
  }
954
968
 
955
- // Receipts: rows 6+, A=date, B=source, E=code, F=amount
956
- for (let row = 6; row <= 200; row++) {
969
+ // Receipts: rows 6+, A=date, B=source, E=code, F=amount. A bank book lists receipts and
970
+ // payments side by side in statement order, so a row with a payment and no receipt is a
971
+ // gap on this side, not the end of the list; only the totals formula ends it.
972
+ for (const row of rowsWithContent(xml, "F", 6, 200)) {
973
+ if (hasCellFormula(xml, `F${row}`)) break;
957
974
  const dateVal = readCellValue(xml, `A${row}`, sharedStrings);
958
975
  const amount = readCellValue(xml, `F${row}`, sharedStrings);
959
- if (dateVal === null || amount === null || typeof amount !== "number") break;
960
- if (hasCellFormula(xml, `F${row}`)) break;
976
+ if (dateVal === null || amount === null || typeof amount !== "number") continue;
961
977
 
962
978
  const source = readCellValue(xml, `B${row}`, sharedStrings) || "";
963
979
  const code = readCellValue(xml, `E${row}`, sharedStrings) || "";
@@ -984,11 +1000,11 @@ export async function extractBankTransactions(set, product, period, extractionMa
984
1000
  }
985
1001
 
986
1002
  // Payments: rows 6+, columns per the file's payment layout
987
- for (let row = 6; row <= 200; row++) {
1003
+ for (const row of rowsWithContent(xml, payment.amount, 6, 200)) {
1004
+ if (hasCellFormula(xml, `${payment.amount}${row}`)) break;
988
1005
  const dateVal = readCellValue(xml, `${payment.date}${row}`, sharedStrings);
989
1006
  const amount = readCellValue(xml, `${payment.amount}${row}`, sharedStrings);
990
- if (dateVal === null || amount === null || typeof amount !== "number") break;
991
- if (hasCellFormula(xml, `${payment.amount}${row}`)) break;
1007
+ if (dateVal === null || amount === null || typeof amount !== "number") continue;
992
1008
 
993
1009
  const supplier = readCellValue(xml, `${payment.supplier}${row}`, sharedStrings) || "";
994
1010
  const code = readCellValue(xml, `${payment.code}${row}`, sharedStrings) || "";
@@ -350,7 +350,7 @@ export const HEADLINES = {
350
350
  turnover: { key: "cell/Profit & Loss Acc!C4" },
351
351
  costOfSales: { keys: ["cell/Profit & Loss Acc!C6", "cell/Profit & Loss Acc!C7"] },
352
352
  runningCosts: { key: "cell/Profit & Loss Acc!C22" },
353
- tax: { key: "cell/Income Tax!E18" },
353
+ tax: { key: "cell/Income Tax!E18", subtitle: "income tax and Class 4 NI, less CIS" },
354
354
  assets: {
355
355
  writtenDown: { key: "cell/Fixed Assets!M1", optional: true },
356
356
  stock: { key: "cell/PurchasesStock!D30", optional: true },
@@ -1336,10 +1336,9 @@ export const CELL_MAP = [
1336
1336
  // The declaration wraps every single-cell reference as `{ key }` (or
1337
1337
  // `{ key, optional }`) and every summed group as `{ keys: [...] }`, the
1338
1338
  // shape the shared headline reducer (app/lib/headlines.js) reads across
1339
- // products. Ltd's current-assets cell (`PubBalSht!E13`) already sums stock,
1340
- // trade debtors and cash, so it fills the reducer's `assets.stock` part --
1341
- // the total's other summed-in figure -- and there is no separate `debtors`
1342
- // part the way BST has one. `tax.secondLine` and `assets.secondLine` each
1339
+ // products. Ltd reads stock at cost, cash at bank and in hand, and trade
1340
+ // debtors from their own published balance sheet lines (E10, E12, E11), so
1341
+ // each lands in its own part of the assets tile. `tax.secondLine` and `assets.secondLine` each
1343
1342
  // add one labelled figure beside that tile's own value, excluded from every
1344
1343
  // sum: the tax charge still outstanding and the balance sheet's net-assets
1345
1344
  // total. `turnover.pieExtra` adds the dividends the board declared as a
@@ -1365,11 +1364,14 @@ export const HEADLINES = {
1365
1364
  tax: {
1366
1365
  key: "cell/Financialaccounts.xlsx!CorporationTax!K35", // SUM(I33:I34)
1367
1366
  label: "Corporation tax",
1367
+ subtitle: "corporation tax",
1368
1368
  secondLine: { label: "Tax outstanding", key: "cell/Financialaccounts.xlsx!CorporationTax!K39" }, // K35-K37
1369
1369
  },
1370
1370
  assets: {
1371
1371
  writtenDown: { key: "cell/Financialaccounts.xlsx!PubBalSht!F6" }, // fixed assets NBV
1372
- stock: { key: "cell/Financialaccounts.xlsx!PubBalSht!E13" }, // stock, trade debtors, cash
1372
+ stock: { key: "cell/Financialaccounts.xlsx!PubBalSht!E10" }, // stock at cost
1373
+ cash: { key: "cell/Financialaccounts.xlsx!PubBalSht!E12" }, // cash at bank and in hand
1374
+ debtors: { key: "cell/Financialaccounts.xlsx!PubBalSht!E11" }, // trade debtors
1373
1375
  secondLine: { label: "Net assets", key: "cell/Financialaccounts.xlsx!PubBalSht!F33" },
1374
1376
  },
1375
1377
  // B11 to B13, cost of sales' own three lines, are not repeated here: the
@@ -1284,14 +1284,11 @@ export const HEADLINES = {
1284
1284
  },
1285
1285
  costOfSales: { key: `${HUB}!Profit & Loss Account!B17` },
1286
1286
  runningCosts: { key: `${HUB}!Profit & Loss Account!B35`, label: "Admin expenses" },
1287
- tax: { key: `${HUB}!Income Tax!E18` },
1287
+ tax: { key: `${HUB}!Income Tax!E18`, subtitle: "income tax and Class 4 NI, less CIS" },
1288
1288
  assets: {
1289
1289
  writtenDown: { key: "cell/Fixedassets.xlsx!Schedule!K1", optional: true },
1290
1290
  stock: { key: `${HUB}!StockControl!AB30`, optional: true },
1291
- extra: [
1292
- { label: "Cash at bank", key: "cell/Bank.xlsx!Mar!A2" },
1293
- { label: "Cash in hand", key: "cell/Cash.xlsx!Mar!A2" },
1294
- ],
1291
+ cash: { keys: ["cell/Bank.xlsx!Mar!A2", "cell/Cash.xlsx!Mar!A2"] },
1295
1292
  debtors: { key: "cell/Sales.xlsx!ClosingDebtors!G1", optional: true },
1296
1293
  },
1297
1294
  // The pie's own fourteen lines: B21 to B34, the P&L rows Total Admin
@@ -446,7 +446,7 @@ export const HEADLINES = {
446
446
  costOfSales: { key: "cell/Profit & Loss Acc!B12", label: "vehicle costs" },
447
447
  runningCosts: { key: "cell/Profit & Loss Acc!B22", label: "running the business" },
448
448
  assets: { writtenDown: { key: "cell/Fixed Assets!K1", optional: true } },
449
- tax: { key: `cell/${TAX_SHEET}!E17`, label: "income tax and Class 4 NI" },
449
+ tax: { key: `cell/${TAX_SHEET}!E17`, label: "income tax and Class 4 NI", subtitle: "income tax and Class 4 NI, less CIS" },
450
450
  pieLines: [
451
451
  ["cell/Profit & Loss Acc!B6", "Fuel"],
452
452
  ["cell/Profit & Loss Acc!B7", "Car hire"],
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@diy-accounting-uk/diya-gl",
3
- "version": "1.2.53",
3
+ "version": "1.2.55",
4
4
  "type": "module",
5
5
  "description": "Recalculate, read and write DIYA-GL books from the command line",
6
6
  "license": "Apache-2.0",