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

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,32 @@
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
+ }
1614
1640
  }
1615
1641
  ]
1616
1642
  }
@@ -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.54+21f315a0",
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) || "";
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.54",
4
4
  "type": "module",
5
5
  "description": "Recalculate, read and write DIYA-GL books from the command line",
6
6
  "license": "Apache-2.0",