@diy-accounting-uk/diya-gl 1.2.39 → 1.2.41

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.
@@ -149,6 +149,7 @@ export function buildFileReportDocument(book, lines, packageName, productMod) {
149
149
  results,
150
150
  productMod,
151
151
  scenario: mergedScenario,
152
+ taxData,
152
153
  checks,
153
154
  scenarioName: book.documentInfo?.entriesComment,
154
155
  yearEnd,
@@ -146,7 +146,7 @@ async function main() {
146
146
  const resolvedOutputDir = resolve(outputDir);
147
147
  mkdirSync(resolvedOutputDir, { recursive: true });
148
148
 
149
- const sectionReports = generateSectionReports(results, productMod, mergedScenario, checks);
149
+ const sectionReports = generateSectionReports(results, productMod, mergedScenario, checks, taxData);
150
150
  for (const [filename, content] of Object.entries(sectionReports)) {
151
151
  writeFileSync(resolve(resolvedOutputDir, filename), content);
152
152
  console.log(` Written: ${filename}`);
@@ -158,6 +158,7 @@ async function main() {
158
158
  results,
159
159
  productMod,
160
160
  scenario: mergedScenario,
161
+ taxData,
161
162
  checks,
162
163
  scenarioName: book.documentInfo?.entriesComment,
163
164
  yearEnd,
@@ -245,6 +246,7 @@ async function main() {
245
246
  // publishes the same compliance verdicts the JS run does, against the
246
247
  // sheet's own figures. Without it the report is the values alone.
247
248
  let excelScenario;
249
+ let excelTaxData;
248
250
  let excelChecks = [];
249
251
  if (dataDir) {
250
252
  const { book, lines } = loadDiyaGlData(resolve(dataDir), offset);
@@ -261,12 +263,13 @@ async function main() {
261
263
  } else {
262
264
  taxData = extractTaxDataFromBook(book, packageName);
263
265
  }
266
+ excelTaxData = taxData;
264
267
  if (typeof productMod.checkCompliance === "function") {
265
268
  excelChecks = productMod.checkCompliance({ ...results }, excelScenario, taxData, calculateExpectedTax, yearEnd);
266
269
  }
267
270
  }
268
271
 
269
- const sectionReports = generateSectionReports(results, productMod, excelScenario, excelChecks);
272
+ const sectionReports = generateSectionReports(results, productMod, excelScenario, excelChecks, excelTaxData);
270
273
  for (const [filename, content] of Object.entries(sectionReports)) {
271
274
  writeFileSync(resolve(resolvedOutputDir, filename), content);
272
275
  console.log(` Written: ${filename}`);
@@ -278,6 +281,7 @@ async function main() {
278
281
  results,
279
282
  productMod,
280
283
  scenario: excelScenario,
284
+ taxData: excelTaxData,
281
285
  checks: excelChecks,
282
286
  yearEnd,
283
287
  });
@@ -44,9 +44,10 @@ fixtures_and_fittings = 0.20
44
44
  computer_equipment = 0.33
45
45
  motor_vehicles = 0.25
46
46
 
47
+ # Approved mileage rates: gov.uk "Travel - mileage and fuel rates and allowances", cars and vans, tax year 2026 to 2027: 55p first 10,000 miles, 25p after.
47
48
  [mileage]
48
49
  higher_rate_limit = 10000
49
- higher_rate_pence = 0.45
50
+ higher_rate_pence = 0.55
50
51
  lower_rate_start = 10001
51
52
  lower_rate_pence = 0.25
52
53
 
@@ -42,9 +42,10 @@ fixtures_and_fittings = 0.20
42
42
  computer_equipment = 0.33
43
43
  motor_vehicles = 0.25
44
44
 
45
+ # Approved mileage rates: gov.uk "Travel - mileage and fuel rates and allowances", cars and vans, tax year 2026 to 2027: 55p first 10,000 miles, 25p after.
45
46
  [mileage]
46
47
  higher_rate_limit = 10000
47
- higher_rate_pence = 0.45
48
+ higher_rate_pence = 0.55
48
49
  lower_rate_start = 10001
49
50
  lower_rate_pence = 0.25
50
51
 
@@ -1247,6 +1247,58 @@
1247
1247
  "scorecard": "101605 passed, 0 warnings, 0 failed"
1248
1248
  }
1249
1249
  }
1250
+ },
1251
+ {
1252
+ "tag": "diya-gl-v1.2.39",
1253
+ "date": "2026-09-30",
1254
+ "formatVersion": "diya-gl/1",
1255
+ "engineVersion": "1.2.37+907683df0",
1256
+ "taxDataHash": "3221a7c2f39c",
1257
+ "reconciledCommit": "54e8731a91279975e61b1a232fbb67fda89515f0",
1258
+ "templates": {
1259
+ "bst": {
1260
+ "hash": "0d003e10e00c",
1261
+ "scorecard": "812 passed, 0 warnings, 0 failed"
1262
+ },
1263
+ "taxi": {
1264
+ "hash": "1ff69654d64d",
1265
+ "scorecard": "686 passed, 0 warnings, 0 failed"
1266
+ },
1267
+ "se": {
1268
+ "hash": "064605ae76ed",
1269
+ "scorecard": "7982 passed, 0 warnings, 0 failed"
1270
+ },
1271
+ "ltd": {
1272
+ "hash": "5bb7be9b6d97",
1273
+ "scorecard": "101605 passed, 0 warnings, 0 failed"
1274
+ }
1275
+ }
1276
+ },
1277
+ {
1278
+ "tag": "diya-gl-v1.2.40",
1279
+ "date": "2026-09-30",
1280
+ "formatVersion": "diya-gl/1",
1281
+ "engineVersion": "1.2.40+57de8f55b",
1282
+ "taxDataHash": "89424bd36c0d",
1283
+ "reconciledCommit": "54e8731a91279975e61b1a232fbb67fda89515f0",
1284
+ "templates": {
1285
+ "bst": {
1286
+ "hash": "0d003e10e00c",
1287
+ "scorecard": "812 passed, 0 warnings, 0 failed"
1288
+ },
1289
+ "taxi": {
1290
+ "hash": "1ff69654d64d",
1291
+ "scorecard": "700 passed, 0 warnings, 0 failed"
1292
+ },
1293
+ "se": {
1294
+ "hash": "064605ae76ed",
1295
+ "scorecard": "8014 passed, 0 warnings, 0 failed"
1296
+ },
1297
+ "ltd": {
1298
+ "hash": "5bb7be9b6d97",
1299
+ "scorecard": "101605 passed, 0 warnings, 0 failed"
1300
+ }
1301
+ }
1250
1302
  }
1251
1303
  ]
1252
1304
  }
@@ -45,9 +45,10 @@ fixtures_and_fittings = 0.20
45
45
  computer_equipment = 0.33
46
46
  motor_vehicles = 0.25
47
47
 
48
+ # Approved mileage rates: gov.uk "Travel - mileage and fuel rates and allowances", cars and vans, tax year 2026 to 2027: 55p first 10,000 miles, 25p after.
48
49
  [mileage]
49
50
  higher_rate_limit = 10000
50
- higher_rate_pence = 0.45
51
+ higher_rate_pence = 0.55
51
52
  lower_rate_start = 10001
52
53
  lower_rate_pence = 0.25
53
54
 
@@ -33,7 +33,7 @@ import {
33
33
  deriveStraddlingEntries,
34
34
  signedAmount,
35
35
  } from "./scenario-extractor.js";
36
- import { totalBusinessMiles, calculateMileageAllowance, HMRC_CAR_MILEAGE_RATES } from "./tax/mileage.js";
36
+ import { totalBusinessMiles, calculateMileageAllowance, FIXTURE_CAR_MILEAGE_RATES } from "./tax/mileage.js";
37
37
  import { compareLines } from "./diya-gl-canonical.js";
38
38
 
39
39
  // The Taxi Driver masters keep their own chart of accounts (fuel at 5100,
@@ -385,7 +385,7 @@ export function diyaGlToScenario(book, lines, product) {
385
385
  const code = purchaseCodeMap[l.accountMainID];
386
386
  if (code) bstByCode[code] = (bstByCode[code] || 0) + signedAmount(l);
387
387
  });
388
- if (businessMiles) bstByCode.m = (bstByCode.m || 0) + calculateMileageAllowance(businessMiles, HMRC_CAR_MILEAGE_RATES);
388
+ if (businessMiles) bstByCode.m = (bstByCode.m || 0) + calculateMileageAllowance(businessMiles, FIXTURE_CAR_MILEAGE_RATES);
389
389
 
390
390
  const stockPurchases = bstByCode.s || 0;
391
391
  const openingStock = book.stock?.openingValue ?? 0;
@@ -417,7 +417,7 @@ export function diyaGlToScenario(book, lines, product) {
417
417
  .filter((l) => !(product === "se" && l.measurableUnitOfMeasure === "miles" && typeof l.measurableQuantity === "number"))
418
418
  .filter((l) => purchaseCodeMap[l.accountMainID] === "v")
419
419
  .reduce((sum, l) => sum + signedAmount(l), 0);
420
- const mileageClaim = product === "se" ? calculateMileageAllowance(businessMiles, HMRC_CAR_MILEAGE_RATES) : 0;
420
+ const mileageClaim = product === "se" ? calculateMileageAllowance(businessMiles, FIXTURE_CAR_MILEAGE_RATES) : 0;
421
421
  expected.total_motor_net = Math.round(cashMotor / vatDivisor + mileageClaim);
422
422
  expected.total_legal_net = Math.round((byCode.l || 0) / vatDivisor);
423
423
  if (product === "ltd") {
@@ -12,8 +12,8 @@
12
12
 
13
13
  export const PROVENANCE_DATA = {
14
14
  formatVersion: "diya-gl/1",
15
- engineVersion: "1.2.37+907683df0",
16
- taxDataHash: "3221a7c2f39c",
15
+ engineVersion: "1.2.40+57de8f55b",
16
+ taxDataHash: "89424bd36c0d",
17
17
  reconciledCommit: "54e8731a91279975e61b1a232fbb67fda89515f0",
18
18
  templates: {
19
19
  bst: {
@@ -22,11 +22,11 @@ export const PROVENANCE_DATA = {
22
22
  },
23
23
  taxi: {
24
24
  hash: "1ff69654d64d",
25
- scorecard: "686 passed, 0 warnings, 0 failed",
25
+ scorecard: "700 passed, 0 warnings, 0 failed",
26
26
  },
27
27
  se: {
28
28
  hash: "064605ae76ed",
29
- scorecard: "7982 passed, 0 warnings, 0 failed",
29
+ scorecard: "8014 passed, 0 warnings, 0 failed",
30
30
  },
31
31
  ltd: {
32
32
  hash: "5bb7be9b6d97",
@@ -219,7 +219,7 @@ export function complianceChecksLines(checks) {
219
219
  return lines;
220
220
  }
221
221
 
222
- export function generateReport(packageName, scenarioName, results, checks, productMod, scenario) {
222
+ export function generateReport(packageName, scenarioName, results, checks, productMod, scenario, taxData) {
223
223
  const hasFail = checks.some((c) => !c.pass && c.severity !== "warning");
224
224
  const hasWarning = checks.some((c) => !c.pass && c.severity === "warning");
225
225
  const status = hasFail ? "ANOMALYDETECTED" : hasWarning ? "RECONCILES (with warnings)" : "RECONCILES";
@@ -242,7 +242,7 @@ export function generateReport(packageName, scenarioName, results, checks, produ
242
242
  // Then the netting, which explains the other difference the checks only
243
243
  // prove correct: a journal figure and the statement figure it becomes.
244
244
  if (typeof productMod.categoryNetting === "function") {
245
- lines.push(...categoryNettingLines(productMod.categoryNetting(results, scenario)));
245
+ lines.push(...categoryNettingLines(productMod.categoryNetting(results, scenario, taxData)));
246
246
  }
247
247
 
248
248
  // Formatted accounting statements (if product module provides them)
@@ -299,7 +299,7 @@ export function generateReport(packageName, scenarioName, results, checks, produ
299
299
  * Generate individual report files, one per reportSections() section.
300
300
  * Returns { "filename.md": content } map.
301
301
  */
302
- export function generateSectionReports(results, productMod, scenario, checks) {
302
+ export function generateSectionReports(results, productMod, scenario, checks, taxData) {
303
303
  const reports = {};
304
304
 
305
305
  if (typeof productMod.reportSections !== "function") return reports;
@@ -341,7 +341,7 @@ export function generateSectionReports(results, productMod, scenario, checks) {
341
341
  }
342
342
 
343
343
  if (typeof productMod.categoryNetting === "function") {
344
- const nettingLines = categoryNettingLines(productMod.categoryNetting(results, scenario));
344
+ const nettingLines = categoryNettingLines(productMod.categoryNetting(results, scenario, taxData));
345
345
  if (nettingLines.length > 0) {
346
346
  reports["journal-category-vat-netting.md"] = [`# ${CATEGORY_NETTING_TITLE}`, ...nettingLines.slice(2), ""].join("\n");
347
347
  }
@@ -323,12 +323,13 @@ function checkEntries(checks) {
323
323
  * @param {Object} options.results - the cell read map, sheet -> cell -> value
324
324
  * @param {Object} options.productMod - the product module (app/products/<name>.js)
325
325
  * @param {Object} [options.scenario] - the merged scenario, where the run has one
326
+ * @param {Object} [options.taxData] - the tax year's data, where the run has it
326
327
  * @param {Array} [options.checks] - checkCompliance() output, where the run has one
327
328
  * @param {string} [options.scenarioName]
328
329
  * @param {string} [options.yearEnd] - YYYY-MM-DD
329
330
  * @returns {Object} the R document, entries sorted by key
330
331
  */
331
- export function buildReportDocument({ packageName, engine, results, productMod, scenario, checks, scenarioName, yearEnd }) {
332
+ export function buildReportDocument({ packageName, engine, results, productMod, scenario, taxData, checks, scenarioName, yearEnd }) {
332
333
  const multiFile = Boolean(productMod.MULTI_FILE);
333
334
  const labels = typeof productMod.cellLabels === "function" ? productMod.cellLabels() : {};
334
335
  const cellEntries = collectCellEntries(results, multiFile);
@@ -349,7 +350,7 @@ export function buildReportDocument({ packageName, engine, results, productMod,
349
350
  values.push(...bridgeEntries(productMod.profitBridge(results), multiFile));
350
351
  }
351
352
  if (typeof productMod.categoryNetting === "function") {
352
- values.push(...nettingEntries(productMod.categoryNetting(results, scenario), multiFile));
353
+ values.push(...nettingEntries(productMod.categoryNetting(results, scenario, taxData), multiFile));
353
354
  }
354
355
  values.push(...checkEntries(checks));
355
356
 
@@ -4,7 +4,7 @@
4
4
  // scenario-extractor.js — Pure functions for extracting test scenario data
5
5
  // from Precision Code Ltd master data.
6
6
 
7
- import { totalBusinessMiles, calculateMileageAllowance, HMRC_CAR_MILEAGE_RATES } from "./tax/mileage.js";
7
+ import { totalBusinessMiles, calculateMileageAllowance, FIXTURE_CAR_MILEAGE_RATES } from "./tax/mileage.js";
8
8
  import { generateTaxYearWeeks, groupWeeksIntoMonths } from "./generator.js";
9
9
 
10
10
  // ============================================================================
@@ -948,7 +948,7 @@ export function bstExpectedFigures(lines, stock, purchaseCodeMap = BST_PURCHASE_
948
948
  const byCode = totalsByCode(cashPurchaseLines, purchaseCodeMap);
949
949
  const businessMiles = totalBusinessMiles(purchaseLines);
950
950
  if (businessMiles) {
951
- byCode.m = Math.round(((byCode.m || 0) + calculateMileageAllowance(businessMiles, HMRC_CAR_MILEAGE_RATES)) * 100) / 100;
951
+ byCode.m = Math.round(((byCode.m || 0) + calculateMileageAllowance(businessMiles, FIXTURE_CAR_MILEAGE_RATES)) * 100) / 100;
952
952
  }
953
953
 
954
954
  const stockAdjustment = stock ? stock.openingValue - stock.closingValue : 0;
@@ -4,13 +4,27 @@
4
4
  // mileage.js — the HMRC approved mileage allowance, shared by the Basic
5
5
  // Sole Trader and Taxi Driver engines.
6
6
 
7
- // HMRC's approved mileage rate for a car: 45p to the first 10,000 business
8
- // miles in the tax year, 25p beyond. It has held since 2011/12 and matches
9
- // every tax year this app's own data files carry (app/data/*.toml). A figure
10
- // worked out from it ahead of any one tax year's data -- an expected value at
11
- // fixture-extraction time, say -- does not go stale the way a rate that does
12
- // change year to year would.
13
- export const HMRC_CAR_MILEAGE_RATES = { higher_rate_limit: 10000, higher_rate_pence: 0.45, lower_rate_pence: 0.25 };
7
+ // HMRC's approved mileage rate for a car in tax year 2025-26 and every year
8
+ // back to 2011-12: 45p to the first 10,000 business miles, 25p beyond. The
9
+ // committed scenario fixtures and example books are dated in 2025-26, so their
10
+ // expected motoring figures are worked out at these rates. Tax year 2026-27
11
+ // pays 55p (app/data/se-2026-2027.toml), so a check against a package built
12
+ // for another year restates the fixture's claim at that year's rates.
13
+ export const FIXTURE_CAR_MILEAGE_RATES = { higher_rate_limit: 10000, higher_rate_pence: 0.45, lower_rate_pence: 0.25 };
14
+
15
+ /**
16
+ * How much more the mileage claim is at a tax year's rates than at the
17
+ * fixture's. A fixture figure that has the claim in it moves by this amount
18
+ * when the package under test was built for another year: added for a cost,
19
+ * taken off for a profit.
20
+ *
21
+ * @param {number} totalMiles - the business miles the fixture's claim was worked out from
22
+ * @param {Object} yearRates - the package's tax year [mileage] table
23
+ * @returns {number} the year's claim less the fixture's
24
+ */
25
+ export function mileageClaimChangeFromFixture(totalMiles, yearRates) {
26
+ return calculateMileageAllowance(totalMiles, yearRates) - calculateMileageAllowance(totalMiles, FIXTURE_CAR_MILEAGE_RATES);
27
+ }
14
28
 
15
29
  /**
16
30
  * The allowance a year's business miles claim: the first band of miles at
@@ -11,7 +11,7 @@ import { parseDate, MONTH_SHEETS, fixedAssetAdditions } from "../lib/scenario-lo
11
11
  import { shiftMonths, periodShiftMonths } from "../lib/period-shift.js";
12
12
  import { MONTH_ORDER } from "../lib/scenario-extractor.js";
13
13
  import { buildProfitBridge, PROFIT_BRIDGE_CHECK } from "../lib/report-generator.js";
14
- import { calculateMileageAllowance } from "../lib/tax/mileage.js";
14
+ import { calculateMileageAllowance, mileageClaimChangeFromFixture } from "../lib/tax/mileage.js";
15
15
  import { canonicalForUnit } from "../lib/canonical-report-value.js";
16
16
 
17
17
  export const PRODUCT = {
@@ -450,7 +450,10 @@ export function checkCompliance(results, expected, taxData, calculateExpectedTax
450
450
  const pl = results["Profit & Loss Acc"];
451
451
  if (expected.total_sales !== undefined) check("Total Sales", pl.C4, expected.total_sales);
452
452
  if (expected.gross_profit !== undefined) check("Gross Profit", pl.C9, expected.gross_profit);
453
- if (expected.net_profit !== undefined) check("Net Profit", pl.C24, expected.net_profit);
453
+ if (expected.net_profit !== undefined) {
454
+ const mileageChange = taxData && expected.total_mileage ? mileageClaimChangeFromFixture(expected.total_mileage, taxData.mileage) : 0;
455
+ check("Net Profit", pl.C24, expected.net_profit - mileageChange);
456
+ }
454
457
  if (expected.total_premises !== undefined) check("Premises Costs", pl.C12, expected.total_premises);
455
458
  if (expected.total_gen_admin !== undefined) check("Gen Admin", pl.C14, expected.total_gen_admin);
456
459
  if (expected.total_legal !== undefined) check("Legal & Professional", pl.C18, expected.total_legal);
@@ -39,7 +39,7 @@ import {
39
39
  vatCycleRows,
40
40
  vatReturnCoverage,
41
41
  } from "../lib/report-generator.js";
42
- import { calculateMileageAllowance, HMRC_CAR_MILEAGE_RATES } from "../lib/tax/mileage.js";
42
+ import { calculateMileageAllowance, mileageClaimChangeFromFixture, FIXTURE_CAR_MILEAGE_RATES } from "../lib/tax/mileage.js";
43
43
  import { checkForecastTaxAndNi } from "../lib/tax/income-tax.js";
44
44
  import { canonicalForUnit } from "../lib/canonical-report-value.js";
45
45
 
@@ -2259,7 +2259,7 @@ function mileageClaimsByMonth(scenario, mileageRates) {
2259
2259
 
2260
2260
  // One row per journal category that crosses into another statement, so the
2261
2261
  // gross-to-net step is stated where it happens rather than only in total.
2262
- export function categoryNetting(results, scenario) {
2262
+ export function categoryNetting(results, scenario, taxData) {
2263
2263
  // With no journal there is nothing to net: every row would compare a nil
2264
2264
  // against whatever the sheet holds and read as a category that lost its
2265
2265
  // whole value on the way.
@@ -2277,7 +2277,7 @@ export function categoryNetting(results, scenario) {
2277
2277
  // Motor Expenses because there was no VAT on it to strip.
2278
2278
  const businessMiles = journalMiles(scenario.sales) + journalMiles(scenario.purchases);
2279
2279
  if (businessMiles) {
2280
- const claim = calculateMileageAllowance(businessMiles, HMRC_CAR_MILEAGE_RATES);
2280
+ const claim = calculateMileageAllowance(businessMiles, taxData?.mileage || FIXTURE_CAR_MILEAGE_RATES);
2281
2281
  purchases.gross.v = (purchases.gross.v || 0) + claim;
2282
2282
  purchases.net.v = (purchases.net.v || 0) + claim;
2283
2283
  }
@@ -2387,10 +2387,9 @@ export function checkCompliance(results, expected, taxData, calculateExpectedTax
2387
2387
  const blank = (v) => String(v ?? "").trim();
2388
2388
 
2389
2389
  // The approved rates the generator injected into the Admin sheet, which is
2390
- // what the Purchases sheets band their running mileage total by. The rates
2391
- // have held since 2011/12, so a book checked without a tax year's data
2392
- // still has them.
2393
- const mileageRates = taxData?.mileage || HMRC_CAR_MILEAGE_RATES;
2390
+ // what the Purchases sheets band their running mileage total by. A book
2391
+ // checked without a tax year's data is priced at the fixture year's rates.
2392
+ const mileageRates = taxData?.mileage || FIXTURE_CAR_MILEAGE_RATES;
2394
2393
  const monthlyMileageClaims = mileageClaimsByMonth(expected, mileageRates);
2395
2394
 
2396
2395
  // The rate cell itself, month by month on both journals. A non-registered
@@ -2452,7 +2451,14 @@ export function checkCompliance(results, expected, taxData, calculateExpectedTax
2452
2451
  }
2453
2452
 
2454
2453
  // Expense line totals (6f)
2455
- if (expected.total_motor_net) check("Motor Expenses", pl.B25 || 0, expected.total_motor_net);
2454
+ if (expected.total_motor_net) {
2455
+ const fixtureMotorNet = expected.total_motor_net;
2456
+ check(
2457
+ "Motor Expenses",
2458
+ pl.B25 || 0,
2459
+ fixtureMotorNet + (expected.total_mileage ? mileageClaimChangeFromFixture(expected.total_mileage, mileageRates) : 0),
2460
+ );
2461
+ }
2456
2462
  if (expected.total_legal_net) check("Legal & Professional", pl.B28 || 0, expected.total_legal_net);
2457
2463
 
2458
2464
  // The mileage route. A mileage-log entry buys nothing: it states the miles
@@ -4264,7 +4270,7 @@ export function checkCompliance(results, expected, taxData, calculateExpectedTax
4264
4270
  // monthly ties above prove each month landed in the right column; these
4265
4271
  // prove the year's gross figure reaches the statement with the VAT taken
4266
4272
  // off and nothing else lost on the way.
4267
- const netting = categoryNetting(results, expected);
4273
+ const netting = categoryNetting(results, expected, taxData);
4268
4274
  for (const row of netting?.rows || []) check(categoryNettingCheckName(row), row.residue, 0, 0.01);
4269
4275
 
4270
4276
  // ── The customer-facing invoice against the tax year's own VAT rate ──────
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@diy-accounting-uk/diya-gl",
3
- "version": "1.2.39",
3
+ "version": "1.2.41",
4
4
  "type": "module",
5
5
  "description": "Recalculate, read and write DIYA-GL books from the command line",
6
6
  "license": "Apache-2.0",