@diy-accounting-uk/diya-gl 1.2.14 → 1.2.16
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/hmrc/form-layouts/se.json +8 -4
- package/dist/app/data/hmrc/sa103-mtd-mapping.json +4 -4
- package/dist/app/data/releases.json +52 -0
- package/dist/app/data/render-unrepresentable/se.json +17 -1
- package/dist/app/data/se-2020-2021.toml +2 -0
- package/dist/app/data/se-2021-2022.toml +2 -0
- package/dist/app/data/se-2022-2023.toml +2 -0
- package/dist/app/data/se-2023-2024.toml +2 -0
- package/dist/app/data/se-2024-2025.toml +2 -0
- package/dist/app/data/se-2025-2026.toml +2 -0
- package/dist/app/data/se-2026-2027.toml +2 -0
- package/dist/app/lib/anchors/se.js +9 -1
- package/dist/app/lib/calculators/se-derivations.js +44 -6
- package/dist/app/lib/calculators/se.js +125 -15
- package/dist/app/lib/diya-gl-canonical.js +28 -6
- package/dist/app/lib/diya-gl-loader.js +17 -2
- package/dist/app/lib/generator.js +5 -1
- package/dist/app/lib/provenance-data.js +5 -5
- package/dist/app/lib/scenario-extractor.js +20 -0
- package/dist/app/lib/xlsx-exporter.js +35 -3
- package/dist/app/products/se.js +285 -60
- package/dist/web/spreadsheets.diyaccounting.co.uk/public/schema/diya-gl-book-v2.schema.json +55 -3
- package/package.json +1 -1
|
@@ -251,10 +251,14 @@
|
|
|
251
251
|
"label": "Capital allowances at 6% on equipment, including cars with higher CO2 emissions",
|
|
252
252
|
"cell": "Financialaccounts.xlsx!SE Full!D147"
|
|
253
253
|
},
|
|
254
|
-
{ "box": "52", "label": "Zero-emission goods vehicle allowance", "cell": "Financialaccounts.xlsx!SE Full!
|
|
255
|
-
{ "box": "52.1", "label": "Zero-emission car allowance", "cell": "Financialaccounts.xlsx!SE Full!
|
|
256
|
-
{ "box": "53", "label": "The Structures and Buildings Allowance", "cell": "Financialaccounts.xlsx!SE Full!
|
|
257
|
-
{
|
|
254
|
+
{ "box": "52", "label": "Zero-emission goods vehicle allowance", "cell": "Financialaccounts.xlsx!SE Full!D150" },
|
|
255
|
+
{ "box": "52.1", "label": "Zero-emission car allowance", "cell": "Financialaccounts.xlsx!SE Full!D152" },
|
|
256
|
+
{ "box": "53", "label": "The Structures and Buildings Allowance", "cell": "Financialaccounts.xlsx!SE Full!D156" },
|
|
257
|
+
{
|
|
258
|
+
"box": "53.1",
|
|
259
|
+
"label": "Freeport and Investment Zones Structures and Buildings Allowance",
|
|
260
|
+
"cell": "Financialaccounts.xlsx!SE Full!D160"
|
|
261
|
+
},
|
|
258
262
|
{ "box": "54", "label": "Electric charge-point allowance", "cell": "Financialaccounts.xlsx!SE Full!O139" },
|
|
259
263
|
{ "box": "55", "label": "100% and other enhanced capital allowances", "cell": "Financialaccounts.xlsx!SE Full!O144" },
|
|
260
264
|
{ "box": "56", "label": "Allowances on sale or cessation of business use", "cell": "Financialaccounts.xlsx!SE Full!O149" },
|
|
@@ -452,7 +452,7 @@
|
|
|
452
452
|
"form": "SA103F",
|
|
453
453
|
"box": "52",
|
|
454
454
|
"label": "Zero-emission goods vehicle allowance",
|
|
455
|
-
"cell": "SE Full!
|
|
455
|
+
"cell": "SE Full!D150",
|
|
456
456
|
"field": "allowances.zeroEmissionsGoodsVehicleAllowance",
|
|
457
457
|
"route": "annual"
|
|
458
458
|
},
|
|
@@ -460,7 +460,7 @@
|
|
|
460
460
|
"form": "SA103F",
|
|
461
461
|
"box": "52.1",
|
|
462
462
|
"label": "Zero-emission car allowance",
|
|
463
|
-
"cell": "SE Full!
|
|
463
|
+
"cell": "SE Full!D152",
|
|
464
464
|
"field": "allowances.zeroEmissionsCarAllowance",
|
|
465
465
|
"route": "annual"
|
|
466
466
|
},
|
|
@@ -468,7 +468,7 @@
|
|
|
468
468
|
"form": "SA103F",
|
|
469
469
|
"box": "53",
|
|
470
470
|
"label": "The Structures and Buildings Allowance",
|
|
471
|
-
"cell": "SE Full!
|
|
471
|
+
"cell": "SE Full!D156",
|
|
472
472
|
"field": "allowances.structuredBuildingAllowance",
|
|
473
473
|
"route": "annual"
|
|
474
474
|
},
|
|
@@ -476,7 +476,7 @@
|
|
|
476
476
|
"form": "SA103F",
|
|
477
477
|
"box": "53.1",
|
|
478
478
|
"label": "Freeport Structures and Buildings Allowance",
|
|
479
|
-
"cell":
|
|
479
|
+
"cell": "SE Full!D160",
|
|
480
480
|
"field": "allowances.enhancedStructuredBuildingAllowance",
|
|
481
481
|
"route": "annual"
|
|
482
482
|
},
|
|
@@ -597,6 +597,58 @@
|
|
|
597
597
|
"scorecard": "101605 passed, 0 warnings, 0 failed"
|
|
598
598
|
}
|
|
599
599
|
}
|
|
600
|
+
},
|
|
601
|
+
{
|
|
602
|
+
"tag": "diya-gl-v1.2.14",
|
|
603
|
+
"date": "2026-09-14",
|
|
604
|
+
"formatVersion": "diya-gl/1",
|
|
605
|
+
"engineVersion": "1.2.14+959e4a1d",
|
|
606
|
+
"taxDataHash": "4ecdbe985d22",
|
|
607
|
+
"reconciledCommit": "c910fdeefbe4f2f71ae9ec5f5d4a713783a1c0c7",
|
|
608
|
+
"templates": {
|
|
609
|
+
"bst": {
|
|
610
|
+
"hash": "0d003e10e00c",
|
|
611
|
+
"scorecard": "812 passed, 0 warnings, 0 failed"
|
|
612
|
+
},
|
|
613
|
+
"taxi": {
|
|
614
|
+
"hash": "1ff69654d64d",
|
|
615
|
+
"scorecard": "686 passed, 0 warnings, 0 failed"
|
|
616
|
+
},
|
|
617
|
+
"se": {
|
|
618
|
+
"hash": "94754ec2c44b",
|
|
619
|
+
"scorecard": "7962 passed, 0 warnings, 0 failed"
|
|
620
|
+
},
|
|
621
|
+
"ltd": {
|
|
622
|
+
"hash": "caa14632083b",
|
|
623
|
+
"scorecard": "101605 passed, 0 warnings, 0 failed"
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
},
|
|
627
|
+
{
|
|
628
|
+
"tag": "diya-gl-v1.2.15",
|
|
629
|
+
"date": "2026-09-15",
|
|
630
|
+
"formatVersion": "diya-gl/1",
|
|
631
|
+
"engineVersion": "1.2.15+27b706de",
|
|
632
|
+
"taxDataHash": "4ecdbe985d22",
|
|
633
|
+
"reconciledCommit": "54e8731a91279975e61b1a232fbb67fda89515f0",
|
|
634
|
+
"templates": {
|
|
635
|
+
"bst": {
|
|
636
|
+
"hash": "0d003e10e00c",
|
|
637
|
+
"scorecard": "812 passed, 0 warnings, 0 failed"
|
|
638
|
+
},
|
|
639
|
+
"taxi": {
|
|
640
|
+
"hash": "1ff69654d64d",
|
|
641
|
+
"scorecard": "686 passed, 0 warnings, 0 failed"
|
|
642
|
+
},
|
|
643
|
+
"se": {
|
|
644
|
+
"hash": "3c88a8ba129b",
|
|
645
|
+
"scorecard": "7966 passed, 0 warnings, 0 failed"
|
|
646
|
+
},
|
|
647
|
+
"ltd": {
|
|
648
|
+
"hash": "caa14632083b",
|
|
649
|
+
"scorecard": "101605 passed, 0 warnings, 0 failed"
|
|
650
|
+
}
|
|
651
|
+
}
|
|
600
652
|
}
|
|
601
653
|
]
|
|
602
654
|
}
|
|
@@ -339,6 +339,7 @@
|
|
|
339
339
|
"section/accounting-profit-to-tax-profit-bridge/less-small-balance-allowance-box-24": "The page has no profit-bridge view; the bridge from accounting profit to tax profit is not printed anywhere on the books page.",
|
|
340
340
|
"section/accounting-profit-to-tax-profit-bridge/less-the-full-return-s-own-box-62-adjustment": "The page has no profit-bridge view; the bridge from accounting profit to tax profit is not printed anywhere on the books page.",
|
|
341
341
|
"section/accounting-profit-to-tax-profit-bridge/less-the-full-return-s-own-electric-charge-point-allowance-box-54": "The page has no profit-bridge view; the bridge from accounting profit to tax profit is not printed anywhere on the books page.",
|
|
342
|
+
"section/accounting-profit-to-tax-profit-bridge/less-the-full-return-s-own-freeport-and-investment-zone-structures-and-buildings-allowance-box-53-1": "The page has no profit-bridge view; the bridge from accounting profit to tax profit is not printed anywhere on the books page.",
|
|
342
343
|
"section/accounting-profit-to-tax-profit-bridge/less-the-full-return-s-own-structures-and-buildings-allowance-box-53": "The page has no profit-bridge view; the bridge from accounting profit to tax profit is not printed anywhere on the books page.",
|
|
343
344
|
"section/accounting-profit-to-tax-profit-bridge/less-the-full-return-s-own-zero-emission-car-allowance-box-52-1": "The page has no profit-bridge view; the bridge from accounting profit to tax profit is not printed anywhere on the books page.",
|
|
344
345
|
"section/accounting-profit-to-tax-profit-bridge/less-the-full-return-s-own-zero-emission-goods-vehicle-allowance-box-52": "The page has no profit-bridge view; the bridge from accounting profit to tax profit is not printed anywhere on the books page.",
|
|
@@ -466,5 +467,20 @@
|
|
|
466
467
|
"cell/Fixedassets.xlsx!Schedule!AD40": "The single asset pool car's own Schedule row (the third motor asset brought forward): its private use share, its P marker, its allowance and its written-down value. The Fixed assets view lists the brought-forward register by asset, without a cell key a row, and the AE1, AF1 and AG1 totals those rows sum into are on the same view under their own cell keys.",
|
|
467
468
|
"cell/Fixedassets.xlsx!Schedule!AE40": "The single asset pool car's own Schedule row (the third motor asset brought forward): its private use share, its P marker, its allowance and its written-down value. The Fixed assets view lists the brought-forward register by asset, without a cell key a row, and the AE1, AF1 and AG1 totals those rows sum into are on the same view under their own cell keys.",
|
|
468
469
|
"cell/Fixedassets.xlsx!Schedule!AG40": "The single asset pool car's own Schedule row (the third motor asset brought forward): its private use share, its P marker, its allowance and its written-down value. The Fixed assets view lists the brought-forward register by asset, without a cell key a row, and the AE1, AF1 and AG1 totals those rows sum into are on the same view under their own cell keys.",
|
|
469
|
-
"section/accounting-profit-to-tax-profit-bridge/add-the-full-return-s-own-box-71-adjustment-for-change-of-accounting-practice": "The page has no profit-bridge view; the bridge from accounting profit to tax profit is not printed anywhere on the books page."
|
|
470
|
+
"section/accounting-profit-to-tax-profit-bridge/add-the-full-return-s-own-box-71-adjustment-for-change-of-accounting-practice": "The page has no profit-bridge view; the bridge from accounting profit to tax profit is not printed anywhere on the books page.",
|
|
471
|
+
"cell/Fixedassets.xlsx!Schedule!B115": "The fixture's own Structures and Buildings Allowance claim row (standard rate): its date, building, expenditure and postcode. The Fixed assets view has no per-claim table, and the K120 total those rows sum into is on the same view under its own cell key.",
|
|
472
|
+
"cell/Fixedassets.xlsx!Schedule!C115": "The fixture's own Structures and Buildings Allowance claim row (standard rate): its date, building, expenditure and postcode. The Fixed assets view has no per-claim table, and the K120 total those rows sum into is on the same view under its own cell key.",
|
|
473
|
+
"cell/Fixedassets.xlsx!Schedule!E115": "The fixture's own Structures and Buildings Allowance claim row (standard rate): its date, building, expenditure and postcode. The Fixed assets view has no per-claim table, and the K120 total those rows sum into is on the same view under its own cell key.",
|
|
474
|
+
"cell/Fixedassets.xlsx!Schedule!F115": "The fixture's own Structures and Buildings Allowance claim row (standard rate): its date, building, expenditure and postcode. The Fixed assets view has no per-claim table, and the K120 total those rows sum into is on the same view under its own cell key.",
|
|
475
|
+
"cell/Fixedassets.xlsx!Schedule!H115": "The fixture's own Structures and Buildings Allowance claim row (standard rate): its rate, its days claimed and its allowance. The Fixed assets view has no per-claim table, and the K120 total those rows sum into is on the same view under its own cell key.",
|
|
476
|
+
"cell/Fixedassets.xlsx!Schedule!J115": "The fixture's own Structures and Buildings Allowance claim row (standard rate): its rate, its days claimed and its allowance. The Fixed assets view has no per-claim table, and the K120 total those rows sum into is on the same view under its own cell key.",
|
|
477
|
+
"cell/Fixedassets.xlsx!Schedule!K115": "The fixture's own Structures and Buildings Allowance claim row (standard rate): its rate, its days claimed and its allowance. The Fixed assets view has no per-claim table, and the K120 total those rows sum into is on the same view under its own cell key.",
|
|
478
|
+
"cell/Fixedassets.xlsx!Schedule!B116": "The fixture's own Structures and Buildings Allowance claim row (the Freeport claim): its date, building, expenditure, postcode and tax site marker. The Fixed assets view has no per-claim table, and the K121 total those rows sum into is on the same view under its own cell key.",
|
|
479
|
+
"cell/Fixedassets.xlsx!Schedule!D116": "The fixture's own Structures and Buildings Allowance claim row (the Freeport claim): its date, building, expenditure, postcode and tax site marker. The Fixed assets view has no per-claim table, and the K121 total those rows sum into is on the same view under its own cell key.",
|
|
480
|
+
"cell/Fixedassets.xlsx!Schedule!E116": "The fixture's own Structures and Buildings Allowance claim row (the Freeport claim): its date, building, expenditure, postcode and tax site marker. The Fixed assets view has no per-claim table, and the K121 total those rows sum into is on the same view under its own cell key.",
|
|
481
|
+
"cell/Fixedassets.xlsx!Schedule!F116": "The fixture's own Structures and Buildings Allowance claim row (the Freeport claim): its date, building, expenditure, postcode and tax site marker. The Fixed assets view has no per-claim table, and the K121 total those rows sum into is on the same view under its own cell key.",
|
|
482
|
+
"cell/Fixedassets.xlsx!Schedule!G116": "The fixture's own Structures and Buildings Allowance claim row (the Freeport claim): its date, building, expenditure, postcode and tax site marker. The Fixed assets view has no per-claim table, and the K121 total those rows sum into is on the same view under its own cell key.",
|
|
483
|
+
"cell/Fixedassets.xlsx!Schedule!H116": "The fixture's own Structures and Buildings Allowance claim row (the Freeport claim): its rate, its days claimed and its allowance. The Fixed assets view has no per-claim table, and the K121 total those rows sum into is on the same view under its own cell key.",
|
|
484
|
+
"cell/Fixedassets.xlsx!Schedule!J116": "The fixture's own Structures and Buildings Allowance claim row (the Freeport claim): its rate, its days claimed and its allowance. The Fixed assets view has no per-claim table, and the K121 total those rows sum into is on the same view under its own cell key.",
|
|
485
|
+
"cell/Fixedassets.xlsx!Schedule!K116": "The fixture's own Structures and Buildings Allowance claim row (the Freeport claim): its rate, its days claimed and its allowance. The Fixed assets view has no per-claim table, and the K121 total those rows sum into is on the same view under its own cell key."
|
|
470
486
|
}
|
|
@@ -36,6 +36,8 @@ class2_small_profits_threshold = 6475
|
|
|
36
36
|
annual_investment_allowance = 1.00
|
|
37
37
|
writing_down_allowance = 0.18
|
|
38
38
|
writing_down_allowance_special = 0.06
|
|
39
|
+
structures_and_buildings_allowance = 0.03
|
|
40
|
+
structures_and_buildings_allowance_enhanced = 0.10
|
|
39
41
|
|
|
40
42
|
[depreciation]
|
|
41
43
|
land_and_property = 0.00
|
|
@@ -36,6 +36,8 @@ class2_small_profits_threshold = 6515
|
|
|
36
36
|
annual_investment_allowance = 1.00
|
|
37
37
|
writing_down_allowance = 0.18
|
|
38
38
|
writing_down_allowance_special = 0.06
|
|
39
|
+
structures_and_buildings_allowance = 0.03
|
|
40
|
+
structures_and_buildings_allowance_enhanced = 0.10
|
|
39
41
|
|
|
40
42
|
[depreciation]
|
|
41
43
|
land_and_property = 0.00
|
|
@@ -39,6 +39,8 @@ class2_small_profits_threshold = 6725
|
|
|
39
39
|
annual_investment_allowance = 1.00
|
|
40
40
|
writing_down_allowance = 0.18
|
|
41
41
|
writing_down_allowance_special = 0.06
|
|
42
|
+
structures_and_buildings_allowance = 0.03
|
|
43
|
+
structures_and_buildings_allowance_enhanced = 0.10
|
|
42
44
|
|
|
43
45
|
[depreciation]
|
|
44
46
|
land_and_property = 0.00
|
|
@@ -38,6 +38,8 @@ class2_small_profits_threshold = 6725
|
|
|
38
38
|
annual_investment_allowance = 1.00
|
|
39
39
|
writing_down_allowance = 0.18
|
|
40
40
|
writing_down_allowance_special = 0.06
|
|
41
|
+
structures_and_buildings_allowance = 0.03
|
|
42
|
+
structures_and_buildings_allowance_enhanced = 0.10
|
|
41
43
|
|
|
42
44
|
[depreciation]
|
|
43
45
|
land_and_property = 0.00
|
|
@@ -35,6 +35,8 @@ class2_small_profits_threshold = 6725
|
|
|
35
35
|
annual_investment_allowance = 1.00
|
|
36
36
|
writing_down_allowance = 0.18
|
|
37
37
|
writing_down_allowance_special = 0.06
|
|
38
|
+
structures_and_buildings_allowance = 0.03
|
|
39
|
+
structures_and_buildings_allowance_enhanced = 0.10
|
|
38
40
|
|
|
39
41
|
[depreciation]
|
|
40
42
|
land_and_property = 0.00
|
|
@@ -35,6 +35,8 @@ class2_small_profits_threshold = 6845
|
|
|
35
35
|
annual_investment_allowance = 1.00
|
|
36
36
|
writing_down_allowance = 0.18
|
|
37
37
|
writing_down_allowance_special = 0.06
|
|
38
|
+
structures_and_buildings_allowance = 0.03
|
|
39
|
+
structures_and_buildings_allowance_enhanced = 0.10
|
|
38
40
|
|
|
39
41
|
[depreciation]
|
|
40
42
|
land_and_property = 0.00
|
|
@@ -35,6 +35,8 @@ class2_small_profits_threshold = 7105
|
|
|
35
35
|
annual_investment_allowance = 1.00
|
|
36
36
|
writing_down_allowance = 0.14
|
|
37
37
|
writing_down_allowance_special = 0.06
|
|
38
|
+
structures_and_buildings_allowance = 0.03
|
|
39
|
+
structures_and_buildings_allowance_enhanced = 0.10
|
|
38
40
|
|
|
39
41
|
[depreciation]
|
|
40
42
|
land_and_property = 0.00
|
|
@@ -41,6 +41,8 @@ import {
|
|
|
41
41
|
EXISTING_ASSET_ROWS,
|
|
42
42
|
NEW_PLANT_ROWS,
|
|
43
43
|
HP_AGREEMENT_ROWS,
|
|
44
|
+
SBA_CLAIM_ROWS,
|
|
45
|
+
SBA_CLAIM_COLUMNS,
|
|
44
46
|
} from "../../products/se.js";
|
|
45
47
|
import { SALES_ANALYSIS_COLUMNS, PURCHASES_ANALYSIS_COLUMNS } from "../calculators/se.js";
|
|
46
48
|
import {
|
|
@@ -230,6 +232,7 @@ export const SE_ANCHORS = {
|
|
|
230
232
|
{ sheet: "Schedule", cell: "C1", label: "FIXED ASSETS" },
|
|
231
233
|
{ sheet: "Schedule", cell: "B59", label: "NEW FIXED ASSETS Bought AFTER" }, // template carries a trailing space; textAt() trims it
|
|
232
234
|
{ sheet: "Schedule", cell: "B64", label: "New Land & Property" },
|
|
235
|
+
{ sheet: "Schedule", cell: "B113", label: "STRUCTURES AND BUILDINGS ALLOWANCE (SA103F boxes 53 and 53.1)" },
|
|
233
236
|
{ sheet: "HPfinance", cell: "B5", label: "Agreement Date" },
|
|
234
237
|
{ sheet: "HPfinance", cell: "C5", label: "Finance Company" },
|
|
235
238
|
{ sheet: "HPfinance", cell: "E5", label: "Total Amount Financed excluding Admin & Interest" },
|
|
@@ -361,7 +364,9 @@ function isPayslipsInputCell(sheet, cellRef) {
|
|
|
361
364
|
// its private use share (M), its special rate pool marker (AB) and its single
|
|
362
365
|
// asset pool marker (AD) on its existing-asset row, or an
|
|
363
366
|
// in-year disposal's date/proceeds (U, V) on that same row; a new purchase's
|
|
364
|
-
// date/supplier/cost (B, C, E) on a New Plant & Machinery row
|
|
367
|
+
// date/supplier/cost (B, C, E) on a New Plant & Machinery row; a Structures
|
|
368
|
+
// and Buildings Allowance claim's date/building/expenditure/postcode/tax
|
|
369
|
+
// site/ceased date (B, C, D, E, F, G, I) on an SBA claim row. See
|
|
365
370
|
// app/products/se.js's cellWrites() Schedule writer.
|
|
366
371
|
const EXISTING_SCHEDULE_ROWS = new Set([...EXISTING_ASSET_ROWS.motor, ...EXISTING_ASSET_ROWS.computer]);
|
|
367
372
|
const NEW_SCHEDULE_ROWS = new Set(NEW_PLANT_ROWS);
|
|
@@ -377,6 +382,8 @@ const EXISTING_SCHEDULE_COLUMNS = [
|
|
|
377
382
|
SINGLE_ASSET_POOL_MARKER_COLUMN,
|
|
378
383
|
];
|
|
379
384
|
const NEW_SCHEDULE_COLUMNS = ["B", "C", "E"];
|
|
385
|
+
const SBA_SCHEDULE_ROWS = new Set(SBA_CLAIM_ROWS);
|
|
386
|
+
const SBA_SCHEDULE_COLUMNS = Object.values(SBA_CLAIM_COLUMNS);
|
|
380
387
|
const HP_ROWS = new Set(HP_AGREEMENT_ROWS);
|
|
381
388
|
const HP_COLUMNS = ["B", "C", "D", "E", "F", "G", "H", "L"];
|
|
382
389
|
|
|
@@ -386,6 +393,7 @@ function isFixedAssetsInputCell(sheet, cellRef) {
|
|
|
386
393
|
if (sheet === "Schedule") {
|
|
387
394
|
if (EXISTING_SCHEDULE_ROWS.has(ref.row)) return EXISTING_SCHEDULE_COLUMNS.includes(ref.col);
|
|
388
395
|
if (NEW_SCHEDULE_ROWS.has(ref.row)) return NEW_SCHEDULE_COLUMNS.includes(ref.col);
|
|
396
|
+
if (SBA_SCHEDULE_ROWS.has(ref.row)) return SBA_SCHEDULE_COLUMNS.includes(ref.col);
|
|
389
397
|
return false;
|
|
390
398
|
}
|
|
391
399
|
if (sheet === "HPfinance") return HP_ROWS.has(ref.row) && HP_COLUMNS.includes(ref.col);
|
|
@@ -17,7 +17,7 @@ import { resolve, dirname } from "path";
|
|
|
17
17
|
import { fileURLToPath } from "url";
|
|
18
18
|
import { diyaGlToScenario } from "../diya-gl-loader.js";
|
|
19
19
|
import { calculateSeCells } from "./se.js";
|
|
20
|
-
import { SE_YEAR_END_MONTH } from "../../products/se.js";
|
|
20
|
+
import { SE_YEAR_END_MONTH, SBA_CLAIM_ROWS } from "../../products/se.js";
|
|
21
21
|
import { extractTaxYearStart, parseDate } from "../scenario-loader.js";
|
|
22
22
|
import { shiftMonths, periodShiftMonths } from "../period-shift.js";
|
|
23
23
|
import { splitVat } from "../tax/vat.js";
|
|
@@ -465,9 +465,8 @@ export function buildSelfEmploymentQuarterlyUpdates(book, lines, taxData, option
|
|
|
465
465
|
// reads it back from there, so the payload carries what the return prints.
|
|
466
466
|
// A box the book does not state stays blank and warns.
|
|
467
467
|
const BOOK_STATED_ANNUAL_BOXES = [
|
|
468
|
-
{ box: "52", cell: "
|
|
469
|
-
{ box: "52.1", cell: "
|
|
470
|
-
{ box: "53", cell: "D160", table: "allowances" }, // structuredBuildingAllowance
|
|
468
|
+
{ box: "52", cell: "D150", table: "allowances" }, // zeroEmissionsGoodsVehicleAllowance -- gone from 2025-26
|
|
469
|
+
{ box: "52.1", cell: "D152", table: "allowances" }, // zeroEmissionsCarAllowance
|
|
471
470
|
{ box: "62", cell: "D179", table: "adjustments" }, // includedNonTaxableProfits
|
|
472
471
|
{ box: "71", cell: "D210", table: "adjustments" }, // accountingAdjustment
|
|
473
472
|
];
|
|
@@ -477,9 +476,10 @@ const BOOK_STATED_ANNUAL_BOXES = [
|
|
|
477
476
|
// out of reach today: no cell in the template, or a figure the book has no
|
|
478
477
|
// record for. Box 69's field also moves out of HMRC's own schema by tax
|
|
479
478
|
// year -- annualFieldsUnavailableForYear() below is what keeps a year that
|
|
480
|
-
// no longer accepts a field from warning about it as if it still did.
|
|
479
|
+
// no longer accepts a field from warning about it as if it still did. Boxes
|
|
480
|
+
// 53 and 53.1 are not here: the Schedule's SBA block computes them, and
|
|
481
|
+
// they are filed as arrays below, one item per claim.
|
|
481
482
|
const NO_SOURCE_ANNUAL_BOXES = [
|
|
482
|
-
{ box: "53.1", pick: 0 }, // allowances.enhancedStructuredBuildingAllowance
|
|
483
483
|
{ box: "55", pick: 1 }, // allowances.businessPremisesRenovationAllowance (shared with enhancedCapitalAllowance)
|
|
484
484
|
{ box: "59", pick: 1 }, // adjustments.balancingChargeBpra (shared with balancingChargeOther)
|
|
485
485
|
{ box: "68", pick: 0 }, // adjustments.basisAdjustment
|
|
@@ -624,6 +624,44 @@ export function buildSelfEmploymentAnnualSubmission(book, lines, taxData, option
|
|
|
624
624
|
});
|
|
625
625
|
}
|
|
626
626
|
|
|
627
|
+
// Structures and Buildings Allowance (boxes 53 and 53.1): the Schedule's
|
|
628
|
+
// SBA block computes each claim's year allowance from the book's own
|
|
629
|
+
// inputs, so the claim files as one item per row, not a stated scalar. A
|
|
630
|
+
// claim whose allowance is nil this year (ceased before the period, or
|
|
631
|
+
// past the 33 1/3 year limit) carries nothing to file. firstYear is the
|
|
632
|
+
// API's first-year details, filed once, on the claim's own qualifying
|
|
633
|
+
// date -- a claim already running before this package's period does not
|
|
634
|
+
// repeat them.
|
|
635
|
+
const admin = rawResults["Admin"] || {};
|
|
636
|
+
const structuredBuildingAllowance = [];
|
|
637
|
+
const enhancedStructuredBuildingAllowance = [];
|
|
638
|
+
SBA_CLAIM_ROWS.forEach((row, index) => {
|
|
639
|
+
const claim = (scenario.sba_claims || [])[index];
|
|
640
|
+
if (!claim) return;
|
|
641
|
+
const amount = schedule?.[`K${row}`];
|
|
642
|
+
if (typeof amount !== "number" || amount === 0) return;
|
|
643
|
+
const item = { amount: round2(amount), building: { ...claim.building } };
|
|
644
|
+
const qualifyingSerial = schedule[`B${row}`];
|
|
645
|
+
if (typeof qualifyingSerial === "number" && typeof admin.B4 === "number" && qualifyingSerial >= admin.B4) {
|
|
646
|
+
// A book's own TOML date parses as a Date instance; the API payload
|
|
647
|
+
// states a date the same way every time, regardless of how the
|
|
648
|
+
// caller's scenario happened to carry it.
|
|
649
|
+
item.firstYear = {
|
|
650
|
+
qualifyingDate: parseDate(claim.qualifyingDate).toISOString().slice(0, 10),
|
|
651
|
+
qualifyingAmountExpenditure: claim.qualifyingAmountExpenditure,
|
|
652
|
+
};
|
|
653
|
+
}
|
|
654
|
+
(claim.enhanced ? enhancedStructuredBuildingAllowance : structuredBuildingAllowance).push(item);
|
|
655
|
+
});
|
|
656
|
+
const structuredBuildingField = primaryField(boxes, "53");
|
|
657
|
+
const enhancedStructuredBuildingField = primaryField(boxes, "53.1");
|
|
658
|
+
if (structuredBuildingAllowance.length > 0 && !unavailableFields.has(structuredBuildingField)) {
|
|
659
|
+
setPath(root, structuredBuildingField, structuredBuildingAllowance);
|
|
660
|
+
}
|
|
661
|
+
if (enhancedStructuredBuildingAllowance.length > 0 && !unavailableFields.has(enhancedStructuredBuildingField)) {
|
|
662
|
+
setPath(root, enhancedStructuredBuildingField, enhancedStructuredBuildingAllowance);
|
|
663
|
+
}
|
|
664
|
+
|
|
627
665
|
const allowances = root.allowances || {};
|
|
628
666
|
const adjustments = root.adjustments || {};
|
|
629
667
|
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
|
|
17
17
|
import { MONTH_SHEETS, extractTaxYearStart } from "../scenario-loader.js";
|
|
18
18
|
import { shiftMonths, periodShiftMonths } from "../period-shift.js";
|
|
19
|
-
import { standardReads, multiFileOptions, SE_YEAR_END_MONTH } from "../../products/se.js";
|
|
19
|
+
import { standardReads, multiFileOptions, SE_YEAR_END_MONTH, SBA_CLAIM_ROWS } from "../../products/se.js";
|
|
20
20
|
import { generateAdminDates, seVatPaymentDueDate, generatePayslipsCalendar } from "../generator.js";
|
|
21
21
|
import { calculateIncomeTax } from "../tax/income-tax.js";
|
|
22
22
|
import { calculateMileageAllowance } from "../tax/mileage.js";
|
|
@@ -491,6 +491,10 @@ function scheduleRow({
|
|
|
491
491
|
row.AE = singleAssetPool && !specialPool ? sheetNumber(row.R) : SHEET_BLANK;
|
|
492
492
|
row.AF = singleAssetPool && specialPool ? sheetNumber(row.AC) : SHEET_BLANK;
|
|
493
493
|
row.AG = singleAssetPool ? sheetNumber(row.S) : SHEET_BLANK;
|
|
494
|
+
// AH and AI split the pooled written-down value by rate pool, single asset
|
|
495
|
+
// pool rows left out, so the small pools test can run on each pool alone.
|
|
496
|
+
row.AH = !singleAssetPool && !specialPool ? sheetNumber(row.S) : SHEET_BLANK;
|
|
497
|
+
row.AI = !singleAssetPool && specialPool ? sheetNumber(row.S) : SHEET_BLANK;
|
|
494
498
|
|
|
495
499
|
row.V = disposal ? disposal.proceeds : SHEET_BLANK;
|
|
496
500
|
row.W = disposal ? cost : SHEET_BLANK;
|
|
@@ -521,7 +525,29 @@ function carry(inputs, compute) {
|
|
|
521
525
|
return inputs.some((value) => value === SHEET_ERROR) ? SHEET_ERROR : compute();
|
|
522
526
|
}
|
|
523
527
|
|
|
524
|
-
const SCHEDULE_TOTAL_COLUMNS = [
|
|
528
|
+
const SCHEDULE_TOTAL_COLUMNS = [
|
|
529
|
+
"E",
|
|
530
|
+
"F",
|
|
531
|
+
"G",
|
|
532
|
+
"I",
|
|
533
|
+
"J",
|
|
534
|
+
"K",
|
|
535
|
+
"O",
|
|
536
|
+
"Q",
|
|
537
|
+
"R",
|
|
538
|
+
"S",
|
|
539
|
+
"V",
|
|
540
|
+
"W",
|
|
541
|
+
"X",
|
|
542
|
+
"Y",
|
|
543
|
+
"Z",
|
|
544
|
+
"AC",
|
|
545
|
+
"AE",
|
|
546
|
+
"AF",
|
|
547
|
+
"AG",
|
|
548
|
+
"AH",
|
|
549
|
+
"AI",
|
|
550
|
+
];
|
|
525
551
|
|
|
526
552
|
function scheduleTotals(rows) {
|
|
527
553
|
const totals = {};
|
|
@@ -606,6 +632,62 @@ function buildSchedule(scenario, taxData, rate) {
|
|
|
606
632
|
return { existing, additions, totals: addScheduleTotals(existing, additions), motorRowCells };
|
|
607
633
|
}
|
|
608
634
|
|
|
635
|
+
// ── Structures and Buildings Allowance (SA103F boxes 53 and 53.1) ──────────
|
|
636
|
+
//
|
|
637
|
+
// Fixedassets.xlsx!Schedule rows 115 to 119, below the fixed asset register.
|
|
638
|
+
// The book states each claim's inputs; the sheet computes the year's
|
|
639
|
+
// allowance from the year file's rate over the days of the chargeable
|
|
640
|
+
// period the claim covers. Verified against the template:
|
|
641
|
+
// H115 = IF(E115>0,IF(G115="F",[1]Admin!$G$10,[1]Admin!$G$9)," ")
|
|
642
|
+
// J115 = IF(E115>0,MAX(0,MIN($S$4,IF(N(I115)>0,I115,$S$4),
|
|
643
|
+
// EDATE(B115,IF(G115="F",120,400))-1)-MAX($D$6,B115)+1)," ")
|
|
644
|
+
// K115 = IF(E115>0,E115*H115*J115/($S$4-$D$6+1)," ")
|
|
645
|
+
// $D$6 = [1]Admin!$B$4 (period start) and $S$4 = [1]Admin!$B$17 (period
|
|
646
|
+
// end); 400 and 120 months are the 33 1/3 and 10 year limits. K120 =
|
|
647
|
+
// SUMIF(G115:G119,"<>F",K115:K119) (box 53), K121 the same with "F"
|
|
648
|
+
// (box 53.1). A claim's dates shift by the same whole-year offset as every
|
|
649
|
+
// other scenario date, so every package year sees the same day counts.
|
|
650
|
+
function buildStructuresAndBuildings(scenario, admin, monthOffset) {
|
|
651
|
+
const periodStart = admin.B4;
|
|
652
|
+
const periodEnd = admin.B17;
|
|
653
|
+
const claims = scenario.sba_claims || [];
|
|
654
|
+
const cells = {};
|
|
655
|
+
let standardTotal = 0;
|
|
656
|
+
let enhancedTotal = 0;
|
|
657
|
+
|
|
658
|
+
SBA_CLAIM_ROWS.forEach((row, index) => {
|
|
659
|
+
const claim = claims[index];
|
|
660
|
+
if (!claim) return;
|
|
661
|
+
const enhanced = claim.enhanced === true;
|
|
662
|
+
const qualifyingDate = excelSerial(shiftMonths(new Date(claim.qualifyingDate), monthOffset));
|
|
663
|
+
cells[`B${row}`] = qualifyingDate;
|
|
664
|
+
if (claim.building?.name) cells[`C${row}`] = claim.building.name;
|
|
665
|
+
if (claim.building?.number) cells[`D${row}`] = claim.building.number;
|
|
666
|
+
cells[`E${row}`] = claim.qualifyingAmountExpenditure;
|
|
667
|
+
cells[`F${row}`] = claim.building.postcode;
|
|
668
|
+
if (enhanced) cells[`G${row}`] = "F";
|
|
669
|
+
let ceasedDate;
|
|
670
|
+
if (claim.ceasedDate) {
|
|
671
|
+
ceasedDate = excelSerial(shiftMonths(new Date(claim.ceasedDate), monthOffset));
|
|
672
|
+
cells[`I${row}`] = ceasedDate;
|
|
673
|
+
}
|
|
674
|
+
const rate = enhanced ? admin.G10 : admin.G9;
|
|
675
|
+
cells[`H${row}`] = rate;
|
|
676
|
+
const limitMonths = enhanced ? 120 : 400;
|
|
677
|
+
const limitEndSerial = excelSerial(shiftMonths(dateFromExcelSerial(qualifyingDate), limitMonths)) - 1;
|
|
678
|
+
const upperBound = Math.min(periodEnd, ceasedDate !== undefined ? ceasedDate : periodEnd, limitEndSerial);
|
|
679
|
+
const lowerBound = Math.max(periodStart, qualifyingDate);
|
|
680
|
+
const days = Math.max(0, upperBound - lowerBound + 1);
|
|
681
|
+
cells[`J${row}`] = days;
|
|
682
|
+
const allowance = (claim.qualifyingAmountExpenditure * rate * days) / (periodEnd - periodStart + 1);
|
|
683
|
+
cells[`K${row}`] = allowance;
|
|
684
|
+
if (enhanced) enhancedTotal += allowance;
|
|
685
|
+
else standardTotal += allowance;
|
|
686
|
+
});
|
|
687
|
+
|
|
688
|
+
return { cells, K120: standardTotal, K121: enhancedTotal };
|
|
689
|
+
}
|
|
690
|
+
|
|
609
691
|
// ── Hire purchase ──────────────────────────────────────────────────────────
|
|
610
692
|
|
|
611
693
|
function buildHpFinance(scenario) {
|
|
@@ -724,6 +806,8 @@ function buildAdmin(taxData, dateSerials) {
|
|
|
724
806
|
cells.G4 = ca.annual_investment_allowance;
|
|
725
807
|
cells.G5 = ca.writing_down_allowance;
|
|
726
808
|
cells.G6 = ca.writing_down_allowance_special;
|
|
809
|
+
cells.G9 = ca.structures_and_buildings_allowance;
|
|
810
|
+
cells.G10 = ca.structures_and_buildings_allowance_enhanced;
|
|
727
811
|
cells.G13 = dep.land_and_property;
|
|
728
812
|
cells.G14 = dep.plant_and_machinery;
|
|
729
813
|
cells.G15 = dep.fixtures_and_fittings;
|
|
@@ -798,6 +882,7 @@ export function calculateSeCells(book, lines, taxData, scenario = {}) {
|
|
|
798
882
|
const payroll = payrollMonths(scenario.payroll);
|
|
799
883
|
const schedule = buildSchedule(scenario, taxData, rate);
|
|
800
884
|
const scheduleNumber = (column) => sheetNumber(schedule.totals[column]);
|
|
885
|
+
const sba = buildStructuresAndBuildings(scenario, admin, monthOffset);
|
|
801
886
|
|
|
802
887
|
// The twelve monthly stock cells telescope, so whatever is counted between
|
|
803
888
|
// them the year's movement is the difference between its two ends. A count at
|
|
@@ -994,7 +1079,15 @@ export function calculateSeCells(book, lines, taxData, scenario = {}) {
|
|
|
994
1079
|
const boxes32to45Total = sheetSum(Object.values(seFullDisallowable)) + pl.B34;
|
|
995
1080
|
|
|
996
1081
|
// ── The fixed asset workbook ──
|
|
997
|
-
const scheduleCells = {
|
|
1082
|
+
const scheduleCells = {
|
|
1083
|
+
E57: schedule.existing.E,
|
|
1084
|
+
E110: schedule.additions.E,
|
|
1085
|
+
AC4: admin.G6,
|
|
1086
|
+
...schedule.motorRowCells,
|
|
1087
|
+
...sba.cells,
|
|
1088
|
+
K120: sba.K120,
|
|
1089
|
+
K121: sba.K121,
|
|
1090
|
+
};
|
|
998
1091
|
for (const column of SCHEDULE_TOTAL_COLUMNS) scheduleCells[`${column}1`] = schedule.totals[column];
|
|
999
1092
|
const faReconciliation = {
|
|
1000
1093
|
E11: schedule.additions.E,
|
|
@@ -1057,16 +1150,20 @@ export function calculateSeCells(book, lines, taxData, scenario = {}) {
|
|
|
1057
1150
|
const scheduleQ = schedule.totals.Q;
|
|
1058
1151
|
const scheduleR = schedule.totals.R;
|
|
1059
1152
|
const scheduleAC = schedule.totals.AC;
|
|
1060
|
-
|
|
1061
|
-
//
|
|
1062
|
-
//
|
|
1063
|
-
// and
|
|
1064
|
-
//
|
|
1153
|
+
// The small pools write-off runs per rate pool over the pooled balance
|
|
1154
|
+
// before this year's allowance, the single asset pool rows (AE, AF) left
|
|
1155
|
+
// out: the main pool's is R1-AE1+AH1 and the special rate pool's
|
|
1156
|
+
// AC1-AF1+AI1, and each pool under £1,000 writes off its own written-down
|
|
1157
|
+
// value. The sheet reads
|
|
1158
|
+
// IF((R1-AE1+AH1)<1000,AH1,0)+IF((AC1-AF1+AI1)<1000,AI1,0) on
|
|
1159
|
+
// SE Full!O144 and SE Short!D85.
|
|
1065
1160
|
const scheduleAE = schedule.totals.AE;
|
|
1066
1161
|
const scheduleAF = schedule.totals.AF;
|
|
1067
|
-
const
|
|
1068
|
-
const
|
|
1069
|
-
|
|
1162
|
+
const scheduleAH = schedule.totals.AH;
|
|
1163
|
+
const scheduleAI = schedule.totals.AI;
|
|
1164
|
+
const smallPoolsWriteOff = carry(
|
|
1165
|
+
[scheduleR, scheduleAC, scheduleAE, scheduleAF, scheduleAH, scheduleAI],
|
|
1166
|
+
() => (scheduleR - scheduleAE + scheduleAH < 1000 ? scheduleAH : 0) + (scheduleAC - scheduleAF + scheduleAI < 1000 ? scheduleAI : 0),
|
|
1070
1167
|
);
|
|
1071
1168
|
const scheduleY = schedule.totals.Y;
|
|
1072
1169
|
const scheduleZ = schedule.totals.Z;
|
|
@@ -1191,18 +1288,31 @@ export function calculateSeCells(book, lines, taxData, scenario = {}) {
|
|
|
1191
1288
|
seFull.D147 = carry([scheduleAC], () => scheduleAC);
|
|
1192
1289
|
// Boxes with no formula behind them, carrying whatever figure the book
|
|
1193
1290
|
// states and blank otherwise.
|
|
1194
|
-
seFull.
|
|
1195
|
-
seFull.
|
|
1196
|
-
seFull.D160 = stated(annualAllowances.structuredBuildingAllowance);
|
|
1291
|
+
seFull.D150 = stated(annualAllowances.zeroEmissionsGoodsVehicleAllowance);
|
|
1292
|
+
seFull.D152 = stated(annualAllowances.zeroEmissionsCarAllowance);
|
|
1197
1293
|
seFull.O139 = stated(annualAllowances.electricChargePointAllowance);
|
|
1198
1294
|
seFull.D179 = stated(annualAdjustments.includedNonTaxableProfits);
|
|
1199
1295
|
seFull.D210 = stated(annualAdjustments.accountingAdjustment);
|
|
1296
|
+
// Boxes 53 and 53.1: the Schedule's SBA block computes them, not the book.
|
|
1297
|
+
seFull.D156 = sba.K120;
|
|
1298
|
+
seFull.D160 = sba.K121;
|
|
1200
1299
|
// Box 50 carries the whole writing down allowance the schedule claims.
|
|
1201
1300
|
seFull.D144 = carry([scheduleR], () => scheduleR);
|
|
1202
1301
|
seFull.O144 = smallPoolsWriteOff;
|
|
1203
1302
|
seFull.O149 = scheduleY;
|
|
1204
1303
|
seFull.O154 = carry([seFull.D139, seFull.D144, seFull.O144, seFull.O149], () =>
|
|
1205
|
-
sheetSum([
|
|
1304
|
+
sheetSum([
|
|
1305
|
+
seFull.D139,
|
|
1306
|
+
seFull.D144,
|
|
1307
|
+
seFull.D147,
|
|
1308
|
+
seFull.D150,
|
|
1309
|
+
seFull.D152,
|
|
1310
|
+
seFull.D156,
|
|
1311
|
+
seFull.D160,
|
|
1312
|
+
seFull.O139,
|
|
1313
|
+
seFull.O144,
|
|
1314
|
+
seFull.O149,
|
|
1315
|
+
]),
|
|
1206
1316
|
);
|
|
1207
1317
|
seFull.O160 = scheduleZ;
|
|
1208
1318
|
seFull.D169 = goodsForOwnUse;
|
|
@@ -265,16 +265,20 @@ function renderAccounts(bookSchema, accounts, lines) {
|
|
|
265
265
|
// A plain object table (documentInfo, entityInformation, stock, tax's own
|
|
266
266
|
// sub-sections, openingBalances' assetClassAmounts): every property in
|
|
267
267
|
// schema order, scalars as `key = value`, a nested object recursed as
|
|
268
|
-
// `[header.key]`,
|
|
269
|
-
//
|
|
268
|
+
// `[header.key]`, an array as `[[header.key]]` blocks (structuresBuildings
|
|
269
|
+
// AllowanceClaim, tax.selfEmployment.allowances' own claim arrays), and a
|
|
270
|
+
// patternProperties dict (only openingBalances.bankAccounts is one) as a
|
|
271
|
+
// table of bare account-code keys.
|
|
270
272
|
function renderObjectTable(bookSchema, header, value, objectSchema, lines) {
|
|
271
273
|
const props = objectSchema?.properties || {};
|
|
272
274
|
const scalarKeys = [];
|
|
273
275
|
const nestedKeys = [];
|
|
276
|
+
const arrayKeys = [];
|
|
274
277
|
for (const key of Object.keys(props)) {
|
|
275
278
|
if (value[key] === undefined) continue;
|
|
276
279
|
const propSchema = resolveRef(bookSchema, props[key]);
|
|
277
|
-
if (propSchema.type === "
|
|
280
|
+
if (propSchema.type === "array") arrayKeys.push(key);
|
|
281
|
+
else if (propSchema.type === "object") nestedKeys.push(key);
|
|
278
282
|
else scalarKeys.push(key);
|
|
279
283
|
}
|
|
280
284
|
if (scalarKeys.length > 0) {
|
|
@@ -292,16 +296,34 @@ function renderObjectTable(bookSchema, header, value, objectSchema, lines) {
|
|
|
292
296
|
renderObjectTable(bookSchema, `${header}.${key}`, value[key], propSchema, lines);
|
|
293
297
|
}
|
|
294
298
|
}
|
|
299
|
+
for (const key of arrayKeys) {
|
|
300
|
+
const propSchema = resolveRef(bookSchema, props[key]);
|
|
301
|
+
renderArrayOfTables(bookSchema, `${header}.${key}`, value[key], resolveRef(bookSchema, propSchema.items), lines);
|
|
302
|
+
}
|
|
295
303
|
}
|
|
296
304
|
|
|
297
|
-
|
|
305
|
+
// items is an array-of-tables ([[key]] blocks); an item field whose own
|
|
306
|
+
// schema is an object (structuresBuildingsAllowanceClaim's building) prints
|
|
307
|
+
// as a [key.field] table straight after that item's own [[key]] block,
|
|
308
|
+
// rather than as a scalar -- the one shape "[[key]]" plus a following
|
|
309
|
+
// object header can express without a nesting level of its own.
|
|
310
|
+
function renderArrayOfTables(bookSchema, key, items, itemSchema, lines) {
|
|
298
311
|
for (const item of sortById(items, itemSchema)) {
|
|
299
312
|
lines.push(`[[${key}]]`);
|
|
313
|
+
const nestedFields = [];
|
|
300
314
|
for (const field of Object.keys(itemSchema.properties)) {
|
|
301
315
|
if (item[field] === undefined) continue;
|
|
302
|
-
|
|
316
|
+
const fieldSchema = resolveRef(bookSchema, itemSchema.properties[field]);
|
|
317
|
+
if (fieldSchema.type === "object") {
|
|
318
|
+
nestedFields.push(field);
|
|
319
|
+
continue;
|
|
320
|
+
}
|
|
321
|
+
lines.push(`${tomlKey(field)} = ${tomlScalar(item[field], fieldSchema)}`);
|
|
303
322
|
}
|
|
304
323
|
lines.push("");
|
|
324
|
+
for (const field of nestedFields) {
|
|
325
|
+
renderObjectTable(bookSchema, `${key}.${field}`, item[field], resolveRef(bookSchema, itemSchema.properties[field]), lines);
|
|
326
|
+
}
|
|
305
327
|
}
|
|
306
328
|
}
|
|
307
329
|
|
|
@@ -326,7 +348,7 @@ export function canonicalBookToml(book) {
|
|
|
326
348
|
}
|
|
327
349
|
const propSchema = resolveRef(bookSchema, bookSchema.properties[key]);
|
|
328
350
|
if (propSchema.type === "array") {
|
|
329
|
-
renderArrayOfTables(key, book[key], resolveRef(bookSchema, propSchema.items), lines);
|
|
351
|
+
renderArrayOfTables(bookSchema, key, book[key], resolveRef(bookSchema, propSchema.items), lines);
|
|
330
352
|
} else {
|
|
331
353
|
renderObjectTable(bookSchema, key, book[key], propSchema, lines);
|
|
332
354
|
}
|