@diy-accounting-uk/diya-gl 1.2.55 → 1.2.56
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.
- package/dist/app/data/releases.json +26 -0
- package/dist/app/lib/calculators/ltd.js +2 -1
- package/dist/app/lib/diya-gl-interchange.js +39 -12
- package/dist/app/lib/diya-gl-loader.js +1 -0
- package/dist/app/lib/ixbrl-accounts.js +748 -0
- package/dist/app/lib/ixbrl-reader.js +583 -0
- package/dist/app/lib/ixbrl-summary-book.js +576 -0
- package/dist/app/lib/provenance-data.js +1 -1
- package/package.json +2 -1
|
@@ -1663,6 +1663,32 @@
|
|
|
1663
1663
|
"scorecard": "101608 passed, 0 warnings, 0 failed"
|
|
1664
1664
|
}
|
|
1665
1665
|
}
|
|
1666
|
+
},
|
|
1667
|
+
{
|
|
1668
|
+
"tag": "diya-gl-v1.2.55",
|
|
1669
|
+
"date": "2026-10-24",
|
|
1670
|
+
"formatVersion": "diya-gl/1",
|
|
1671
|
+
"engineVersion": "1.2.55+bb0dbecd",
|
|
1672
|
+
"taxDataHash": "51bdff60e993",
|
|
1673
|
+
"reconciledCommit": "54e8731a91279975e61b1a232fbb67fda89515f0",
|
|
1674
|
+
"templates": {
|
|
1675
|
+
"bst": {
|
|
1676
|
+
"hash": "0d003e10e00c",
|
|
1677
|
+
"scorecard": "812 passed, 0 warnings, 0 failed"
|
|
1678
|
+
},
|
|
1679
|
+
"taxi": {
|
|
1680
|
+
"hash": "1ff69654d64d",
|
|
1681
|
+
"scorecard": "700 passed, 0 warnings, 0 failed"
|
|
1682
|
+
},
|
|
1683
|
+
"se": {
|
|
1684
|
+
"hash": "064605ae76ed",
|
|
1685
|
+
"scorecard": "8015 passed, 0 warnings, 0 failed"
|
|
1686
|
+
},
|
|
1687
|
+
"ltd": {
|
|
1688
|
+
"hash": "a65ab09cf35c",
|
|
1689
|
+
"scorecard": "101608 passed, 0 warnings, 0 failed"
|
|
1690
|
+
}
|
|
1691
|
+
}
|
|
1666
1692
|
}
|
|
1667
1693
|
]
|
|
1668
1694
|
}
|
|
@@ -554,7 +554,8 @@ function buildSchedule(scenario, rate, depreciationRates, investmentAllowancePer
|
|
|
554
554
|
}
|
|
555
555
|
|
|
556
556
|
for (const row of rows) {
|
|
557
|
-
|
|
557
|
+
// An asset that states its own rate depreciates at it; any other takes its class's rate.
|
|
558
|
+
const ratePercent = row.openingAsset?.depreciation_rate ?? depreciationRates[row.assetClass];
|
|
558
559
|
const netBookValue = row.cost - row.depreciationBroughtForward;
|
|
559
560
|
row.depreciationCharge = row.cost > 0 ? Math.min(row.cost * ratePercent, netBookValue) : 0;
|
|
560
561
|
row.depreciationCarriedForward = row.cost > 0 ? row.depreciationBroughtForward + row.depreciationCharge : 0;
|
|
@@ -9,13 +9,14 @@
|
|
|
9
9
|
// writeDiyaGlZip/writeBookJson, so a download from one matches an export
|
|
10
10
|
// from another byte-for-byte.
|
|
11
11
|
//
|
|
12
|
-
//
|
|
12
|
+
// Nine byte kinds, told apart by content, never by file extension: a
|
|
13
13
|
// workbook, the zip a single-workbook package ships as, the zip a
|
|
14
14
|
// multi-file package ships as, this module's own zip (book.toml +
|
|
15
|
-
// lines.jsonl), that pair as one JSON file, the same JSON zipped,
|
|
16
|
-
//
|
|
17
|
-
//
|
|
18
|
-
//
|
|
15
|
+
// lines.jsonl), that pair as one JSON file, the same JSON zipped, an Inline
|
|
16
|
+
// XBRL accounts document, a plain XBRL instance, and the legacy .xls this
|
|
17
|
+
// pipeline cannot read directly. A customer's upload can be any of the first
|
|
18
|
+
// six under any name at all -- a renamed .xlsx is still a workbook -- so the
|
|
19
|
+
// kind is decided by what the bytes actually contain.
|
|
19
20
|
//
|
|
20
21
|
// Reading a workbook or its package zip runs the pipeline export.js has
|
|
21
22
|
// always run: the anchor guard, then the extractors and book builder
|
|
@@ -45,6 +46,9 @@ import { canonicalBookToml, canonicalLinesJsonl, compareLines, orderedBookTopLev
|
|
|
45
46
|
import { serializeReportDocument } from "./report-serializer.js";
|
|
46
47
|
import { parseDiyaGlData } from "./diya-gl-loader.js";
|
|
47
48
|
import { stampBook } from "./provenance.js";
|
|
49
|
+
import { sniffIxbrl } from "./ixbrl-reader.js";
|
|
50
|
+
import { mapIxbrlAccounts } from "./ixbrl-accounts.js";
|
|
51
|
+
import { buildIxbrlSummaryBooks } from "./ixbrl-summary-book.js";
|
|
48
52
|
import * as bst from "../products/bst.js";
|
|
49
53
|
|
|
50
54
|
export { AnchorError };
|
|
@@ -70,7 +74,7 @@ export class UnknownBookSourceError extends Error {
|
|
|
70
74
|
constructor(name) {
|
|
71
75
|
super(
|
|
72
76
|
`${name ? `"${name}"` : "This file"} is not one of the kinds diya-gl reads: a Basic Sole Trader workbook (.xlsx), ` +
|
|
73
|
-
`its package zip, a diya-gl zip, a diya-gl JSON file,
|
|
77
|
+
`its package zip, a diya-gl zip, a diya-gl JSON file, that JSON zipped, or an iXBRL accounts file.`,
|
|
74
78
|
);
|
|
75
79
|
this.name = "UnknownBookSourceError";
|
|
76
80
|
}
|
|
@@ -196,14 +200,14 @@ async function zipKind(bytes) {
|
|
|
196
200
|
* error messages only.
|
|
197
201
|
* @param {Uint8Array} bytes
|
|
198
202
|
* @param {string} [name] - a hint for messages, not for detection
|
|
199
|
-
* @returns {Promise<"workbook"|"package-zip"|"package-set"|"diya-gl-zip"|"json-zip"|"json"|"xls"|"unknown">}
|
|
203
|
+
* @returns {Promise<"workbook"|"package-zip"|"package-set"|"diya-gl-zip"|"json-zip"|"json"|"ixbrl"|"xbrl"|"xls"|"unknown">}
|
|
200
204
|
*/
|
|
201
205
|
export async function detectBookSource(bytes, name) {
|
|
202
206
|
void name; // content decides the kind; the name is a hint for a caller's own error messages, never for detection
|
|
203
207
|
if (isZipContainer(bytes)) return zipKind(bytes);
|
|
204
208
|
if (startsWithBytes(bytes, OLE_MAGIC)) return "xls";
|
|
205
209
|
if (looksLikeJsonObject(bytes)) return "json";
|
|
206
|
-
return "unknown";
|
|
210
|
+
return sniffIxbrl(bytes) ?? "unknown";
|
|
207
211
|
}
|
|
208
212
|
|
|
209
213
|
// ============================================================================
|
|
@@ -456,17 +460,37 @@ async function readJsonZipSource(bytes) {
|
|
|
456
460
|
return { ...validated("json-zip", document.book, document.lines), product: document.product };
|
|
457
461
|
}
|
|
458
462
|
|
|
463
|
+
// An accounts file stands for two Company books, the file's own year and the
|
|
464
|
+
// year before, each a summary with one line per tagged line. The comparative
|
|
465
|
+
// pair, the accounts figures and the facts no figure uses ride beside them.
|
|
466
|
+
async function readIxbrlSource(kind, bytes, deps) {
|
|
467
|
+
const accounts = mapIxbrlAccounts(bytes, deps.expect);
|
|
468
|
+
const summary = await buildIxbrlSummaryBooks(accounts, { resources: deps.resources });
|
|
469
|
+
const current = validated(kind, summary.book, summary.lines);
|
|
470
|
+
const prior = validated(kind, summary.comparative.book, summary.comparative.lines);
|
|
471
|
+
return {
|
|
472
|
+
...current,
|
|
473
|
+
product: "ltd",
|
|
474
|
+
comparative: { book: prior.book, lines: prior.lines },
|
|
475
|
+
accounts,
|
|
476
|
+
unmapped: accounts.unmapped,
|
|
477
|
+
differences: summary.differences,
|
|
478
|
+
};
|
|
479
|
+
}
|
|
480
|
+
|
|
459
481
|
/**
|
|
460
|
-
* Turn a byte array into D: the book and its lines, whichever of the
|
|
461
|
-
*
|
|
482
|
+
* Turn a byte array into D: the book and its lines, whichever of the kinds
|
|
483
|
+
* it sniffs as. The CLI's --file mode, the MCP server's extract_book
|
|
462
484
|
* tool and the books page all call this, so a file that loads in one loads
|
|
463
485
|
* in all.
|
|
464
486
|
* @param {Uint8Array} bytes
|
|
465
487
|
* @param {string} [name] - a hint for error messages
|
|
466
488
|
* @param {Object} [deps] - {products}: product id to product module
|
|
467
489
|
* (CELL_MAP, cellLabels()) for the products this caller can read;
|
|
468
|
-
* defaults to app/products/bst.js alone
|
|
469
|
-
*
|
|
490
|
+
* defaults to app/products/bst.js alone. {expect, resources} serve an
|
|
491
|
+
* iXBRL accounts file: what the page expects of the file (company number,
|
|
492
|
+
* period, regime), and the loader of the tax year's data.
|
|
493
|
+
* @returns {Promise<{kind: string, product?: string, book: Object, lines: Array, overtyped?: Object, workbookSet?: Object, comparative?: {book: Object, lines: Array}, accounts?: Object, unmapped?: Array, differences?: string[]}>}
|
|
470
494
|
*/
|
|
471
495
|
export async function readBookSource(bytes, name, deps = {}) {
|
|
472
496
|
const kind = await detectBookSource(bytes, name);
|
|
@@ -481,6 +505,9 @@ export async function readBookSource(bytes, name, deps = {}) {
|
|
|
481
505
|
return readJsonSource(bytes);
|
|
482
506
|
case "json-zip":
|
|
483
507
|
return readJsonZipSource(bytes);
|
|
508
|
+
case "ixbrl":
|
|
509
|
+
case "xbrl":
|
|
510
|
+
return readIxbrlSource(kind, bytes, deps);
|
|
484
511
|
case "xls":
|
|
485
512
|
throw new XlsBookSourceError(name);
|
|
486
513
|
default:
|
|
@@ -607,6 +607,7 @@ export function diyaGlToScenario(book, lines, product) {
|
|
|
607
607
|
}
|
|
608
608
|
const opening = { category, description: asset.description, cost: asset.cost, acc_dep: asset.accumulatedDepreciation };
|
|
609
609
|
if (asset.taxWrittenDownValue !== undefined) opening.tax_wdv = asset.taxWrittenDownValue;
|
|
610
|
+
if (asset.depreciationRate !== undefined) opening.depreciation_rate = asset.depreciationRate;
|
|
610
611
|
if (asset.capitalAllowancePool === "special") opening.pool = "special";
|
|
611
612
|
// A single asset pool is a fact the book states, never one the loader
|
|
612
613
|
// infers: private use puts an asset in its own pool (CAA 2001 s.206),
|