@diy-accounting-uk/diya-gl 1.2.14 → 1.2.15

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.
@@ -597,6 +597,32 @@
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
+ }
600
626
  }
601
627
  ]
602
628
  }
@@ -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 = ["E", "F", "G", "I", "J", "K", "O", "Q", "R", "S", "V", "W", "X", "Y", "Z", "AC", "AE", "AF", "AG"];
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 = {};
@@ -1057,16 +1083,20 @@ export function calculateSeCells(book, lines, taxData, scenario = {}) {
1057
1083
  const scheduleQ = schedule.totals.Q;
1058
1084
  const scheduleR = schedule.totals.R;
1059
1085
  const scheduleAC = schedule.totals.AC;
1060
- const scheduleS = schedule.totals.S;
1061
- // The small pools write-off runs over the pooled balance alone: the
1062
- // single asset pool rows (AE, AF, AG) come out of both the £1,000 test
1063
- // and the figure written off. The sheet reads
1064
- // IF((R1+S1-AE1-AF1-AG1)<1000,S1-AG1,0) on SE Full!O144 and SE Short!D85.
1086
+ // The small pools write-off runs per rate pool over the pooled balance
1087
+ // before this year's allowance, the single asset pool rows (AE, AF) left
1088
+ // out: the main pool's is R1-AE1+AH1 and the special rate pool's
1089
+ // AC1-AF1+AI1, and each pool under £1,000 writes off its own written-down
1090
+ // value. The sheet reads
1091
+ // IF((R1-AE1+AH1)<1000,AH1,0)+IF((AC1-AF1+AI1)<1000,AI1,0) on
1092
+ // SE Full!O144 and SE Short!D85.
1065
1093
  const scheduleAE = schedule.totals.AE;
1066
1094
  const scheduleAF = schedule.totals.AF;
1067
- const scheduleAG = schedule.totals.AG;
1068
- const smallPoolsWriteOff = carry([scheduleR, scheduleS, scheduleAE, scheduleAF, scheduleAG], () =>
1069
- scheduleR + scheduleS - scheduleAE - scheduleAF - scheduleAG < 1000 ? scheduleS - scheduleAG : 0,
1095
+ const scheduleAH = schedule.totals.AH;
1096
+ const scheduleAI = schedule.totals.AI;
1097
+ const smallPoolsWriteOff = carry(
1098
+ [scheduleR, scheduleAC, scheduleAE, scheduleAF, scheduleAH, scheduleAI],
1099
+ () => (scheduleR - scheduleAE + scheduleAH < 1000 ? scheduleAH : 0) + (scheduleAC - scheduleAF + scheduleAI < 1000 ? scheduleAI : 0),
1070
1100
  );
1071
1101
  const scheduleY = schedule.totals.Y;
1072
1102
  const scheduleZ = schedule.totals.Z;
@@ -12,9 +12,9 @@
12
12
 
13
13
  export const PROVENANCE_DATA = {
14
14
  formatVersion: "diya-gl/1",
15
- engineVersion: "1.2.14+959e4a1d",
15
+ engineVersion: "1.2.15+27b706de",
16
16
  taxDataHash: "4ecdbe985d22",
17
- reconciledCommit: "c910fdeefbe4f2f71ae9ec5f5d4a713783a1c0c7",
17
+ reconciledCommit: "54e8731a91279975e61b1a232fbb67fda89515f0",
18
18
  templates: {
19
19
  bst: {
20
20
  hash: "0d003e10e00c",
@@ -25,8 +25,8 @@ export const PROVENANCE_DATA = {
25
25
  scorecard: "686 passed, 0 warnings, 0 failed",
26
26
  },
27
27
  se: {
28
- hash: "94754ec2c44b",
29
- scorecard: "7962 passed, 0 warnings, 0 failed",
28
+ hash: "3c88a8ba129b",
29
+ scorecard: "7966 passed, 0 warnings, 0 failed",
30
30
  },
31
31
  ltd: {
32
32
  hash: "caa14632083b",
@@ -1277,10 +1277,11 @@ export function multiFileOptions() {
1277
1277
  // E57 and E110 are the schedule's own existing-asset and new-asset
1278
1278
  // cost subtotals; row 1 adds the two. Reading both lets the report
1279
1279
  // state the year's asset movement rather than one closing total.
1280
- // AE1, AF1 and AG1 are the single asset pool totals; M40, AD40, AE40
1281
- // and AG40 are the fixture's marked car row (van 38, estate car 39,
1282
- // hatchback 40), read so its marker and private use share are proved
1283
- // on the row itself.
1280
+ // AE1, AF1 and AG1 are the single asset pool totals; AH1 and AI1 the
1281
+ // pooled written-down value by rate pool, which the small pools test
1282
+ // now runs over per pool; M40, AD40, AE40 and AG40 are the fixture's
1283
+ // marked car row (van 38, estate car 39, hatchback 40), read so its
1284
+ // marker and private use share are proved on the row itself.
1284
1285
  Schedule: [
1285
1286
  "E1",
1286
1287
  "F1",
@@ -1301,6 +1302,8 @@ export function multiFileOptions() {
1301
1302
  "AE1",
1302
1303
  "AF1",
1303
1304
  "AG1",
1305
+ "AH1",
1306
+ "AI1",
1304
1307
  "E57",
1305
1308
  "E110",
1306
1309
  "M40",
@@ -1703,6 +1706,8 @@ const FIXED_ASSET_CELL_LABELS = {
1703
1706
  AE1: "Single asset pool writing down allowance at the main rate (the rows marked P in column AD)",
1704
1707
  AF1: "Single asset pool writing down allowance at the special rate (the rows marked P and S)",
1705
1708
  AG1: "Single asset pool tax written down value carried forward",
1709
+ AH1: "Main pool tax written down value carried forward, single asset pool rows left out",
1710
+ AI1: "Special rate pool tax written down value carried forward (the rows marked S), single asset pool rows left out",
1706
1711
  M40: "Private use share of the third motor vehicle brought forward",
1707
1712
  AD40: "Single asset pool marker on the third motor vehicle brought forward (P)",
1708
1713
  AE40: "Single asset pool main rate allowance on the third motor vehicle brought forward",
@@ -1927,42 +1932,47 @@ function openingPoolAllowance(expected, pool) {
1927
1932
  }
1928
1933
 
1929
1934
  // The small pools write-off the way SE Full!O144 and SE Short!D85 state it:
1930
- // IF((R1+S1-AE1-AF1-AG1)<1000,S1-AG1,0). The single asset pool rows leave
1931
- // both the £1,000 test and the figure written off.
1935
+ // IF((R1-AE1+AH1)<1000,AH1,0)+IF((AC1-AF1+AI1)<1000,AI1,0). Each rate pool
1936
+ // takes the £1,000 test on its own balance before this year's allowance, the
1937
+ // single asset pool rows left out, and writes off its own written-down value
1938
+ // when it passes.
1932
1939
  function smallPoolsWriteOff(schedule) {
1933
1940
  const num = (v) => (typeof v === "number" ? v : 0);
1934
- const pooledBalance = num(schedule.R1) + num(schedule.S1) - num(schedule.AE1) - num(schedule.AF1) - num(schedule.AG1);
1935
- return pooledBalance < 1000 ? num(schedule.S1) - num(schedule.AG1) : 0;
1941
+ const mainBalance = num(schedule.R1) - num(schedule.AE1) + num(schedule.AH1);
1942
+ const specialBalance = num(schedule.AC1) - num(schedule.AF1) + num(schedule.AI1);
1943
+ return (mainBalance < 1000 ? num(schedule.AH1) : 0) + (specialBalance < 1000 ? num(schedule.AI1) : 0);
1936
1944
  }
1937
1945
 
1938
- // The same two figures from the fixture's own assets. A pooled opening asset
1939
- // puts its whole tax written-down value into the test (R + S = O on a main
1940
- // rate row, O less the special rate allowance on a special rate row) and its
1946
+ // The same figures from the fixture's own assets, pool by pool. A pooled
1947
+ // opening asset puts its whole tax written-down value into its pool's test
1948
+ // (allowance plus written-down value is the value brought forward) and its
1941
1949
  // written-down balance after this year's allowance into the write-off; a
1942
- // single asset pool row puts nothing into either; an asset bought in the year
1943
- // puts its cost less the annual investment allowance into both.
1950
+ // single asset pool row puts nothing into either; an asset bought in the
1951
+ // year puts its cost less the annual investment allowance into the main
1952
+ // pool's both.
1944
1953
  function fixtureSmallPools(expected, taxData, rate) {
1945
1954
  const wda = taxData.capital_allowances.writing_down_allowance;
1946
1955
  const specialWda = taxData.capital_allowances.writing_down_allowance_special || 0;
1947
1956
  const aia = taxData.capital_allowances.annual_investment_allowance ?? 0;
1948
- let pooledBalance = 0;
1949
- let pooledWrittenDown = 0;
1957
+ const pools = { main: { balance: 0, writtenDown: 0 }, special: { balance: 0, writtenDown: 0 } };
1950
1958
  for (const asset of expected.opening_fixed_assets || []) {
1951
1959
  if (asset.single_asset_pool || !(asset.tax_wdv > 0)) continue;
1960
+ const pool = asset.pool === "special" ? pools.special : pools.main;
1952
1961
  const share = 1 - (asset.private_use || 0);
1953
1962
  const allowance = asset.tax_wdv * (asset.pool === "special" ? specialWda : wda) * share;
1954
- pooledBalance += asset.pool === "special" ? asset.tax_wdv - allowance : asset.tax_wdv;
1955
- pooledWrittenDown += asset.tax_wdv - allowance;
1963
+ pool.balance += asset.tax_wdv;
1964
+ pool.writtenDown += asset.tax_wdv - allowance;
1956
1965
  }
1957
1966
  for (const transactions of Object.values(expected.purchases || {})) {
1958
1967
  for (const tx of transactions) {
1959
1968
  if (tx.code !== "fa") continue;
1960
1969
  const cost = netOfVat(tx.amount, rate);
1961
- pooledBalance += cost - cost * aia;
1962
- pooledWrittenDown += cost - cost * aia;
1970
+ pools.main.balance += cost - cost * aia;
1971
+ pools.main.writtenDown += cost - cost * aia;
1963
1972
  }
1964
1973
  }
1965
- return { pooledBalance, pooledWrittenDown };
1974
+ const writeOff = (pool) => (pool.balance < 1000 ? pool.writtenDown : 0);
1975
+ return { ...pools, writeOff: writeOff(pools.main) + writeOff(pools.special) };
1966
1976
  }
1967
1977
 
1968
1978
  // ── Journal category VAT netting ───────────────────────────────────────────
@@ -2647,11 +2657,11 @@ export function checkCompliance(results, expected, taxData, calculateExpectedTax
2647
2657
  check("SA103F box 49 annual investment allowance (D139) = Schedule Q1", num(seFull.D139), Math.max(0, num(returnSchedule.Q1)));
2648
2658
  check("SA103F box 50 capital allowances at 18% (D144) = Schedule R1", num(seFull.D144), num(returnSchedule.R1));
2649
2659
  check("SA103F box 51 capital allowances at 6% (D147) = Schedule AC1", num(seFull.D147), num(returnSchedule.AC1));
2650
- // The small pools write-off runs over the pooled balance alone: the
2651
- // single asset pool rows (AE1, AF1, AG1) leave both the £1,000 test
2652
- // and the figure written off (O144 = IF((R1+S1-AE1-AF1-AG1)<1000,S1-AG1,0)).
2660
+ // The small pools write-off runs per rate pool over the pooled balance
2661
+ // alone, the single asset pool rows (AE1, AF1) left out:
2662
+ // O144 = IF((R1-AE1+AH1)<1000,AH1,0)+IF((AC1-AF1+AI1)<1000,AI1,0).
2653
2663
  check(
2654
- "SA103F box 55 100% and other enhanced capital allowances (O144) = Schedule S1 less the single asset pools while the pooled balance is under £1,000",
2664
+ "SA103F box 55 100% and other enhanced capital allowances (O144) = each pool's Schedule written-down value (AH1, AI1) while that pool's balance is under £1,000",
2655
2665
  num(seFull.O144),
2656
2666
  smallPoolsWriteOff(returnSchedule),
2657
2667
  );
@@ -2683,13 +2693,12 @@ export function checkCompliance(results, expected, taxData, calculateExpectedTax
2683
2693
  openingPoolAllowance(expected, "special") * (taxData.capital_allowances.writing_down_allowance_special || 0),
2684
2694
  );
2685
2695
  // The same rule the sheet applies, run over the fixture's own pools:
2686
- // a sheet whose R1, S1 and AE1 to AG1 agree with each other but not
2687
- // with the assets fails here.
2688
- const pools = fixtureSmallPools(expected, taxData, rate);
2696
+ // a sheet whose R1, AC1, AE1, AF1, AH1 and AI1 agree with each other
2697
+ // but not with the assets fails here.
2689
2698
  check(
2690
- "SA103F box 55 100% and other enhanced capital allowances (O144) = the small pools write-off computed from the scenario's own pooled assets",
2699
+ "SA103F box 55 100% and other enhanced capital allowances (O144) = the small pools write-off computed per pool from the scenario's own pooled assets",
2691
2700
  num(seFull.O144),
2692
- pools.pooledBalance < 1000 ? pools.pooledWrittenDown : 0,
2701
+ fixtureSmallPools(expected, taxData, rate).writeOff,
2693
2702
  );
2694
2703
  }
2695
2704
 
@@ -2964,6 +2973,34 @@ export function checkCompliance(results, expected, taxData, calculateExpectedTax
2964
2973
  openingPoolAllowance(expected, "special") * (taxData.capital_allowances.writing_down_allowance_special || 0),
2965
2974
  );
2966
2975
 
2976
+ // The pooled written-down values by rate pool (AH, AI), and each
2977
+ // pool's balance before this year's allowance, which is what the small
2978
+ // pools test runs over: the main pool's from the van and the year's
2979
+ // additions, the special rate pool's from the estate car's 9,000
2980
+ // alone, so a pool that counted the other's balance, or a single asset
2981
+ // pool's, moves here.
2982
+ const pools = fixtureSmallPools(expected, taxData, rate);
2983
+ check(
2984
+ "Fixed assets: Schedule main pool written down value (AH1) = the scenario's pooled main rate assets' tax written-down values less this year's allowance, plus additions less their annual investment allowance",
2985
+ sched.AH1 || 0,
2986
+ pools.main.writtenDown,
2987
+ );
2988
+ check(
2989
+ "Fixed assets: Schedule special rate pool written down value (AI1) = the scenario's pooled special rate assets' tax written-down values less this year's allowance",
2990
+ sched.AI1 || 0,
2991
+ pools.special.writtenDown,
2992
+ );
2993
+ check(
2994
+ "Fixed assets: main pool balance before this year's allowance (R1 - AE1 + AH1) = the scenario's pooled main rate assets' tax written-down values plus additions less their annual investment allowance",
2995
+ num(sched.R1) - num(sched.AE1) + num(sched.AH1),
2996
+ pools.main.balance,
2997
+ );
2998
+ check(
2999
+ "Fixed assets: special rate pool balance before this year's allowance (AC1 - AF1 + AI1) = the scenario's pooled special rate assets' tax written-down values",
3000
+ num(sched.AC1) - num(sched.AF1) + num(sched.AI1),
3001
+ pools.special.balance,
3002
+ );
3003
+
2967
3004
  // The single asset pools (column AD marked P): each marked asset's
2968
3005
  // allowance at its own rate on its business share, and its written-down
2969
3006
  // value less that allowance, anchored on the fixture's assets.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@diy-accounting-uk/diya-gl",
3
- "version": "1.2.14",
3
+ "version": "1.2.15",
4
4
  "type": "module",
5
5
  "description": "Recalculate, read and write DIYA-GL books from the command line",
6
6
  "license": "Apache-2.0",