@classytic/ca-tax 0.0.15 → 0.0.17
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/CHANGELOG.md +227 -0
- package/dist/forms/index.d.mts +2 -2
- package/dist/forms/index.mjs +2 -2
- package/dist/forms.mjs +1642 -199
- package/dist/index.d.mts +27 -1
- package/dist/index.mjs +3 -3
- package/dist/index3.d.mts +1269 -277
- package/dist/index4.d.mts +3 -3
- package/dist/t2/index.d.mts +3 -3
- package/dist/t2/index.mjs +3 -3
- package/dist/t2.mjs +1388 -574
- package/package.json +3 -3
package/dist/t2.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Mt as AT1_SCHEDULE_21_POOLS, ot as SCHEDULE_1_LINE_BY_NUMBER } from "./forms.mjs";
|
|
2
2
|
//#region src/t2/rates/rate-book.ts
|
|
3
3
|
/**
|
|
4
4
|
* Resolve the table in effect for `taxYear` — the entry with the greatest
|
|
@@ -242,11 +242,6 @@ function computeAlbertaTax(input, rates = AB_TAX_2024) {
|
|
|
242
242
|
//#endregion
|
|
243
243
|
//#region src/t2/at1/filing/at1-schedule-line-items.ts
|
|
244
244
|
/**
|
|
245
|
-
* Schedules the engine computes but cannot yet file, because their line numbers
|
|
246
|
-
* have not been transcribed from the specification. Named so the difference
|
|
247
|
-
* between "no data" and "not implemented" is visible rather than silent.
|
|
248
|
-
*/
|
|
249
|
-
/**
|
|
250
245
|
* Schedules this module can put into a filing payload. Exported so callers and
|
|
251
246
|
* tests share one source of truth — a hard-coded copy in a test drifts the moment
|
|
252
247
|
* a builder is added, and then quietly stops guarding anything.
|
|
@@ -697,6 +692,7 @@ function schedule12Values(input) {
|
|
|
697
692
|
alwaysPair("072", "073", d?.limitedPartnership);
|
|
698
693
|
alwaysPair("056", "057", input.donations?.charitable);
|
|
699
694
|
alwaysPair("058", "059", input.donations?.gifts);
|
|
695
|
+
alwaysPair("130", "131", input.restrictedInterestAndFinancing);
|
|
700
696
|
put("054", input.albertaNetIncomeForTax);
|
|
701
697
|
return {
|
|
702
698
|
scheduleId: "012",
|
|
@@ -724,7 +720,7 @@ const POOL_FIELD_TO_RESULT_KEY = {
|
|
|
724
720
|
carryBack: "carriedBack",
|
|
725
721
|
closing: "closingBalance"
|
|
726
722
|
};
|
|
727
|
-
function schedule21Values(input) {
|
|
723
|
+
function schedule21Values$1(input) {
|
|
728
724
|
const values = [];
|
|
729
725
|
const put = (fieldId, value) => values.push({
|
|
730
726
|
lineItemId: at1LineItemId("021", fieldId),
|
|
@@ -827,7 +823,7 @@ function schedule21Values(input) {
|
|
|
827
823
|
values
|
|
828
824
|
};
|
|
829
825
|
}
|
|
830
|
-
function schedule1Values(input) {
|
|
826
|
+
function schedule1Values$1(input) {
|
|
831
827
|
const values = [];
|
|
832
828
|
const put = (fieldId, value, occurrence = 1) => values.push({
|
|
833
829
|
lineItemId: at1LineItemId("001", fieldId, occurrence),
|
|
@@ -853,7 +849,7 @@ function schedule1Values(input) {
|
|
|
853
849
|
values
|
|
854
850
|
};
|
|
855
851
|
}
|
|
856
|
-
function schedule2Values(input) {
|
|
852
|
+
function schedule2Values$1(input) {
|
|
857
853
|
const values = [];
|
|
858
854
|
const put = (fieldId, value) => {
|
|
859
855
|
if (value === void 0) return;
|
|
@@ -1060,16 +1056,16 @@ function schedule16Values(result) {
|
|
|
1060
1056
|
}
|
|
1061
1057
|
//#endregion
|
|
1062
1058
|
//#region src/t2/at1/schedules/at4970-ieg-projects.ts
|
|
1063
|
-
const nn$
|
|
1059
|
+
const nn$36 = (v) => Math.max(0, Math.round(v ?? 0));
|
|
1064
1060
|
function computeAt4970(input) {
|
|
1065
1061
|
const projects = input.projects.map((p) => ({
|
|
1066
1062
|
title: p.title,
|
|
1067
1063
|
...p.projectCode !== void 0 ? { projectCode: p.projectCode } : {},
|
|
1068
|
-
albertaPortion: nn$
|
|
1069
|
-
otherPortion: nn$
|
|
1070
|
-
salariesAndWages: nn$
|
|
1071
|
-
federalProxyAmount: nn$
|
|
1072
|
-
albertaProxyAmount: nn$
|
|
1064
|
+
albertaPortion: nn$36(p.albertaPortion),
|
|
1065
|
+
otherPortion: nn$36(p.otherPortion),
|
|
1066
|
+
salariesAndWages: nn$36(p.salariesAndWages),
|
|
1067
|
+
federalProxyAmount: nn$36(p.federalProxyAmount),
|
|
1068
|
+
albertaProxyAmount: nn$36(p.albertaProxyAmount)
|
|
1073
1069
|
}));
|
|
1074
1070
|
const totals = {
|
|
1075
1071
|
albertaPortion: projects.reduce((s, p) => s + p.albertaPortion, 0),
|
|
@@ -1080,7 +1076,7 @@ function computeAt4970(input) {
|
|
|
1080
1076
|
};
|
|
1081
1077
|
const jurisdictions = (input.jurisdictions ?? []).map((j) => ({
|
|
1082
1078
|
jurisdiction: j.jurisdiction,
|
|
1083
|
-
amountIncurred: nn$
|
|
1079
|
+
amountIncurred: nn$36(j.amountIncurred)
|
|
1084
1080
|
}));
|
|
1085
1081
|
return {
|
|
1086
1082
|
projects,
|
|
@@ -1196,15 +1192,15 @@ function computeAllocationFactor(input) {
|
|
|
1196
1192
|
*
|
|
1197
1193
|
* Whole dollars, pure.
|
|
1198
1194
|
*/
|
|
1199
|
-
const nn$
|
|
1195
|
+
const nn$35 = (v) => Math.max(0, Math.round(v ?? 0));
|
|
1200
1196
|
const raw = (v) => Math.round(v ?? 0);
|
|
1201
1197
|
function computeItc(input, roomCap, issues) {
|
|
1202
|
-
const certificatesIssued = nn$
|
|
1203
|
-
const carryforwardFromPriorYear = nn$
|
|
1204
|
-
const expired = nn$
|
|
1198
|
+
const certificatesIssued = nn$35(input.certificatesIssued);
|
|
1199
|
+
const carryforwardFromPriorYear = nn$35(input.carryforwardFromPriorYear);
|
|
1200
|
+
const expired = nn$35(input.expired);
|
|
1205
1201
|
const availableBeforeClaim = certificatesIssued + carryforwardFromPriorYear;
|
|
1206
1202
|
const cap = Math.min(availableBeforeClaim, roomCap);
|
|
1207
|
-
const wanted = input.amountApplied != null ? nn$
|
|
1203
|
+
const wanted = input.amountApplied != null ? nn$35(input.amountApplied) : cap;
|
|
1208
1204
|
const amountApplied = Math.max(0, Math.min(wanted, cap));
|
|
1209
1205
|
const carryforwardToNextYear = availableBeforeClaim - amountApplied - expired;
|
|
1210
1206
|
if (carryforwardToNextYear < 0) issues.push(`Alberta Schedule 3 (ITC): expired (${expired}) plus the amount applied (${amountApplied}) exceed the available pool (${availableBeforeClaim}) by ${-carryforwardToNextYear}. Check the 100/102/104/106 inputs.`);
|
|
@@ -1218,17 +1214,17 @@ function computeItc(input, roomCap, issues) {
|
|
|
1218
1214
|
};
|
|
1219
1215
|
}
|
|
1220
1216
|
function computeCitc(input, roomCap, itcApplied, itcCarryforwardRemaining, issues) {
|
|
1221
|
-
const certificatesIssued = nn$
|
|
1222
|
-
const carryforwardFromPriorYear = nn$
|
|
1223
|
-
const expired = nn$
|
|
1217
|
+
const certificatesIssued = nn$35(input.certificatesIssued);
|
|
1218
|
+
const carryforwardFromPriorYear = nn$35(input.carryforwardFromPriorYear);
|
|
1219
|
+
const expired = nn$35(input.expired);
|
|
1224
1220
|
const availableBeforeClaim = certificatesIssued + carryforwardFromPriorYear;
|
|
1225
1221
|
let amountApplied;
|
|
1226
1222
|
if (itcCarryforwardRemaining > 0) {
|
|
1227
1223
|
amountApplied = 0;
|
|
1228
|
-
if (input.amountApplied != null && nn$
|
|
1224
|
+
if (input.amountApplied != null && nn$35(input.amountApplied) > 0) issues.push(`Alberta Schedule 3 (CITC): a claim of ${nn$35(input.amountApplied)} was requested, but the Investor Tax Credit still has an unused carryforward balance (${itcCarryforwardRemaining}) after this year's application, so line 204 must be nil until ITC is fully drawn down.`);
|
|
1229
1225
|
} else {
|
|
1230
1226
|
const cap = Math.min(availableBeforeClaim, Math.max(0, roomCap - itcApplied));
|
|
1231
|
-
const wanted = input.amountApplied != null ? nn$
|
|
1227
|
+
const wanted = input.amountApplied != null ? nn$35(input.amountApplied) : cap;
|
|
1232
1228
|
amountApplied = Math.max(0, Math.min(wanted, cap));
|
|
1233
1229
|
}
|
|
1234
1230
|
const carryforwardToNextYear = availableBeforeClaim - amountApplied - expired;
|
|
@@ -1247,18 +1243,18 @@ function computeApitc(input, roomCap, issues) {
|
|
|
1247
1243
|
const first = input.firstPreceding ?? {};
|
|
1248
1244
|
const second = input.secondPreceding ?? {};
|
|
1249
1245
|
const thirdToTenth = input.thirdToTenthPreceding ?? {};
|
|
1250
|
-
const currentAvailable = nn$
|
|
1251
|
-
const firstAvailable = nn$
|
|
1252
|
-
const secondAvailable = nn$
|
|
1253
|
-
const thirdToTenthAvailable = nn$
|
|
1246
|
+
const currentAvailable = nn$35(current.received);
|
|
1247
|
+
const firstAvailable = nn$35(first.availableAtBeginning);
|
|
1248
|
+
const secondAvailable = nn$35(second.availableAtBeginning);
|
|
1249
|
+
const thirdToTenthAvailable = nn$35(thirdToTenth.availableAtBeginning);
|
|
1254
1250
|
const currentCap = Math.round(currentAvailable * .2);
|
|
1255
1251
|
const firstCap = Math.round(firstAvailable * .3);
|
|
1256
1252
|
const secondCap = Math.round(secondAvailable * .5);
|
|
1257
1253
|
const thirdToTenthCap = thirdToTenthAvailable;
|
|
1258
|
-
const currentAsk = Math.min(current.amountApplied != null ? nn$
|
|
1259
|
-
const firstAsk = Math.min(first.amountApplied != null ? nn$
|
|
1260
|
-
const secondAsk = Math.min(second.amountApplied != null ? nn$
|
|
1261
|
-
const thirdToTenthAsk = Math.min(thirdToTenth.amountApplied != null ? nn$
|
|
1254
|
+
const currentAsk = Math.min(current.amountApplied != null ? nn$35(current.amountApplied) : currentCap, currentCap);
|
|
1255
|
+
const firstAsk = Math.min(first.amountApplied != null ? nn$35(first.amountApplied) : firstCap, firstCap);
|
|
1256
|
+
const secondAsk = Math.min(second.amountApplied != null ? nn$35(second.amountApplied) : secondCap, secondCap);
|
|
1257
|
+
const thirdToTenthAsk = Math.min(thirdToTenth.amountApplied != null ? nn$35(thirdToTenth.amountApplied) : thirdToTenthCap, thirdToTenthCap);
|
|
1262
1258
|
const totalRequested = currentAsk + firstAsk + secondAsk + thirdToTenthAsk;
|
|
1263
1259
|
let room = Math.max(0, roomCap);
|
|
1264
1260
|
const allocate = (ask) => {
|
|
@@ -1274,7 +1270,7 @@ function computeApitc(input, roomCap, issues) {
|
|
|
1274
1270
|
if (totalApplied < totalRequested) issues.push(`Alberta Schedule 3 (APITC): the shared Maximum Allowable Deduction room (${roomCap}) was insufficient to cover ${totalRequested} requested across vintages; ${totalRequested - totalApplied} went unapplied. Allocation prioritized the oldest vintage first (closest to the 10-year expiry) — the spec states only the combined ceiling on 312, not an application order across 304/306/308/310. Supply amountApplied on each vintage directly for exact filing parity.`);
|
|
1275
1271
|
const totalReceived = currentAvailable;
|
|
1276
1272
|
const carryforwardFromPriorYear = firstAvailable + secondAvailable + thirdToTenthAvailable;
|
|
1277
|
-
const expired = nn$
|
|
1273
|
+
const expired = nn$35(input.expiredThisYear);
|
|
1278
1274
|
const availableForCarryforward = totalReceived + carryforwardFromPriorYear - totalApplied - expired;
|
|
1279
1275
|
if (availableForCarryforward < 0) issues.push(`Alberta Schedule 3 (APITC): applied (${totalApplied}) plus expired (${expired}) exceed the available pool (${totalReceived + carryforwardFromPriorYear}) by ${-availableForCarryforward}. Check the 300/302/312/314 inputs.`);
|
|
1280
1276
|
return {
|
|
@@ -1308,11 +1304,11 @@ function computeApitc(input, roomCap, issues) {
|
|
|
1308
1304
|
function computeSchedule3(input) {
|
|
1309
1305
|
const issues = [];
|
|
1310
1306
|
const mad = input.mad ?? {};
|
|
1311
|
-
const line068 = nn$
|
|
1312
|
-
const line070 = nn$
|
|
1313
|
-
const line071 = nn$
|
|
1314
|
-
const line072 = nn$
|
|
1315
|
-
const line074 = nn$
|
|
1307
|
+
const line068 = nn$35(mad.taxPayableBeforeDeduction);
|
|
1308
|
+
const line070 = nn$35(mad.line070);
|
|
1309
|
+
const line071 = nn$35(mad.line071);
|
|
1310
|
+
const line072 = nn$35(mad.line072);
|
|
1311
|
+
const line074 = nn$35(mad.line074);
|
|
1316
1312
|
const room602 = raw(line068) - (line070 + line071 + line072 + line074);
|
|
1317
1313
|
const itcCitcCap = Math.max(0, room602);
|
|
1318
1314
|
const itc = computeItc(input.itc ?? {}, itcCitcCap, issues);
|
|
@@ -1378,26 +1374,26 @@ function schedule3Values(result) {
|
|
|
1378
1374
|
}
|
|
1379
1375
|
//#endregion
|
|
1380
1376
|
//#region src/t2/at1/schedules/schedule4-foreign-investment-tax-credit.ts
|
|
1381
|
-
const nn$
|
|
1377
|
+
const nn$34 = (v) => Math.max(0, v ?? 0);
|
|
1382
1378
|
/** Round to 3 decimal places, half-up — the precision the spec directs for D and G. */
|
|
1383
1379
|
function round3(v) {
|
|
1384
1380
|
return Math.round((v + Number.EPSILON) * 1e3) / 1e3;
|
|
1385
1381
|
}
|
|
1386
1382
|
function computeSchedule4(input) {
|
|
1387
1383
|
const issues = [];
|
|
1388
|
-
const albertaTaxableIncome = nn$
|
|
1389
|
-
const royaltyTaxDeduction = nn$
|
|
1384
|
+
const albertaTaxableIncome = nn$34(input.albertaTaxableIncome);
|
|
1385
|
+
const royaltyTaxDeduction = nn$34(input.royaltyTaxDeduction);
|
|
1390
1386
|
const allocationFactor = input.allocationFactor ?? 0;
|
|
1391
|
-
const basicAlbertaTax = nn$
|
|
1387
|
+
const basicAlbertaTax = nn$34(input.basicAlbertaTax);
|
|
1392
1388
|
const denominator = (albertaTaxableIncome - royaltyTaxDeduction) * allocationFactor;
|
|
1393
1389
|
const countries = input.countries.map((c) => {
|
|
1394
1390
|
if (!c.country) issues.push("Alberta Schedule 4: a country code is required for each occurrence (004002).");
|
|
1395
|
-
const netForeignInvestmentIncome = nn$
|
|
1396
|
-
const fedForeignTaxPaid = nn$
|
|
1397
|
-
const fedIta2012Deduction = nn$
|
|
1391
|
+
const netForeignInvestmentIncome = nn$34(c.netForeignInvestmentIncome);
|
|
1392
|
+
const fedForeignTaxPaid = nn$34(c.fedForeignTaxPaid);
|
|
1393
|
+
const fedIta2012Deduction = nn$34(c.fedIta2012Deduction);
|
|
1398
1394
|
const albertaDeduction = Math.max(c.albertaActa82Deduction ?? fedIta2012Deduction, fedIta2012Deduction);
|
|
1399
1395
|
const taxPaidNetOfDeduction = Math.max(0, fedForeignTaxPaid - albertaDeduction);
|
|
1400
|
-
const federalNonBusinessForeignTaxCredit = nn$
|
|
1396
|
+
const federalNonBusinessForeignTaxCredit = nn$34(c.fedNonBusinessForeignTaxCredit);
|
|
1401
1397
|
let incomeProrationAmount;
|
|
1402
1398
|
if (denominator === 0) {
|
|
1403
1399
|
incomeProrationAmount = 0;
|
|
@@ -1454,7 +1450,7 @@ function schedule4Values(result) {
|
|
|
1454
1450
|
}
|
|
1455
1451
|
//#endregion
|
|
1456
1452
|
//#region src/t2/at1/schedules/schedule5-royalty-tax-deduction.ts
|
|
1457
|
-
const nn$
|
|
1453
|
+
const nn$33 = (v) => Math.max(0, Math.round(v ?? 0));
|
|
1458
1454
|
const num$2 = (v) => Math.round(v ?? 0);
|
|
1459
1455
|
function processSuccessoredPool(entries, label, issues) {
|
|
1460
1456
|
return (entries ?? []).map((e, i) => {
|
|
@@ -1462,9 +1458,9 @@ function processSuccessoredPool(entries, label, issues) {
|
|
|
1462
1458
|
const hasAcquired = e.acquisitionAmount !== void 0;
|
|
1463
1459
|
if (hasBrought && hasAcquired) issues.push(`Alberta Schedule 5: ${label} occurrence ${i + 1} (${e.vendorName}) has both a pool-brought-forward and an acquisition amount; the spec allows only one per occurrence. Using poolBroughtForward and ignoring acquisitionAmount.`);
|
|
1464
1460
|
else if (!hasBrought && !hasAcquired) issues.push(`Alberta Schedule 5: ${label} occurrence ${i + 1} (${e.vendorName}) has neither a pool-brought-forward nor an acquisition amount; treating the pool base as zero.`);
|
|
1465
|
-
const base = nn$
|
|
1461
|
+
const base = nn$33(hasBrought ? e.poolBroughtForward : e.acquisitionAmount);
|
|
1466
1462
|
const baseKind = hasBrought ? "broughtForward" : hasAcquired ? "acquired" : "unspecified";
|
|
1467
|
-
const propertyIncome = nn$
|
|
1463
|
+
const propertyIncome = nn$33(e.propertyIncome);
|
|
1468
1464
|
const claim = Math.min(base, propertyIncome);
|
|
1469
1465
|
return {
|
|
1470
1466
|
vendorName: e.vendorName,
|
|
@@ -1479,11 +1475,11 @@ function processSuccessoredPool(entries, label, issues) {
|
|
|
1479
1475
|
}
|
|
1480
1476
|
function computeAlbertaSchedule5(input) {
|
|
1481
1477
|
const issues = [];
|
|
1482
|
-
const crownCharges = nn$
|
|
1483
|
-
const resourceAllowance = nn$
|
|
1484
|
-
const reimbursements = nn$
|
|
1485
|
-
const predecessorTransfersTotal = (input.predecessorTransfers ?? []).reduce((s, t) => s + nn$
|
|
1486
|
-
const attributedRoyaltyIncomeCarryForwardIn = nn$
|
|
1478
|
+
const crownCharges = nn$33(input.crownChargesNetOfReimbursements);
|
|
1479
|
+
const resourceAllowance = nn$33(input.albertaResourceAllowance ?? input.federalResourceAllowance);
|
|
1480
|
+
const reimbursements = nn$33(input.reimbursementsForCrownCharges);
|
|
1481
|
+
const predecessorTransfersTotal = (input.predecessorTransfers ?? []).reduce((s, t) => s + nn$33(t.amountTransferred), 0);
|
|
1482
|
+
const attributedRoyaltyIncomeCarryForwardIn = nn$33(input.openingUnsuccessoredPoolBalance) + predecessorTransfersTotal;
|
|
1487
1483
|
const unsuccessoredPoolAvailable = crownCharges - resourceAllowance - reimbursements + attributedRoyaltyIncomeCarryForwardIn;
|
|
1488
1484
|
const hasSuccessoredPools = input.hasSuccessoredPools ?? false;
|
|
1489
1485
|
if (!hasSuccessoredPools && ((input.secondSuccessoredPools?.length ?? 0) > 0 || (input.firstSuccessoredPools?.length ?? 0) > 0)) issues.push("Alberta Schedule 5: hasSuccessoredPools (005200) is false, but successored pool occurrences were supplied. Per the spec, 005101-005140 must not exist when 005200 = 2 (No); the supplied occurrences were ignored.");
|
|
@@ -1496,7 +1492,7 @@ function computeAlbertaSchedule5(input) {
|
|
|
1496
1492
|
const crtdMaxClaimable = Math.max(0, Math.min(unsuccessoredPoolAvailable, albertaTaxableIncome - successoredTotal));
|
|
1497
1493
|
const crtdClaim = input.crtdAmountClaimed != null ? Math.max(0, Math.min(Math.round(input.crtdAmountClaimed), crtdMaxClaimable)) : crtdMaxClaimable;
|
|
1498
1494
|
const poolAvailableCarryForward = unsuccessoredPoolAvailable - crtdClaim;
|
|
1499
|
-
const transferredOnDisposal = nn$
|
|
1495
|
+
const transferredOnDisposal = nn$33(input.transferredOnDisposal);
|
|
1500
1496
|
const uncappedTotal = crtdClaim + successoredTotal;
|
|
1501
1497
|
const totalRoyaltyTaxDeduction = Math.max(0, Math.min(uncappedTotal, albertaTaxableIncome));
|
|
1502
1498
|
if (totalRoyaltyTaxDeduction < uncappedTotal && uncappedTotal > albertaTaxableIncome) if (albertaTaxableIncome < 0) issues.push(`Alberta Schedule 5: Alberta taxable income before the deduction (AT1 line 062) is ${albertaTaxableIncome}, which is negative. AT1 line 064 is specified as "005016 + 005140, cannot exceed 000062" with no stated floor; this engine floors the combined deduction at zero rather than reporting a negative Royalty Tax Deduction. The successored-pool claims (005140 = ${successoredTotal}) are computed independently of line 062 and are NOT reduced by this cap — review manually if this scenario occurs.`);
|
|
@@ -1606,7 +1602,7 @@ function schedule5Values(result) {
|
|
|
1606
1602
|
//#endregion
|
|
1607
1603
|
//#region src/t2/at1/schedules/schedule6-royalty-tax-credit.ts
|
|
1608
1604
|
const rd$1 = (v) => Math.round(v ?? 0);
|
|
1609
|
-
const nn$
|
|
1605
|
+
const nn$32 = (v) => Math.max(0, Math.round(v ?? 0));
|
|
1610
1606
|
const round4$1 = (v) => Math.round(v * 1e4) / 1e4;
|
|
1611
1607
|
function computeWeightedAverageRate(quarters, issues) {
|
|
1612
1608
|
if (quarters.length === 0) {
|
|
@@ -1622,11 +1618,11 @@ function computeWeightedAverageRate(quarters, issues) {
|
|
|
1622
1618
|
return round4$1(weighted);
|
|
1623
1619
|
}
|
|
1624
1620
|
function resolveAllocations(allocations, pool, issues) {
|
|
1625
|
-
const totalRequested = allocations.reduce((s, a) => s + nn$
|
|
1621
|
+
const totalRequested = allocations.reduce((s, a) => s + nn$32(a.allocatedAmount), 0);
|
|
1626
1622
|
if (totalRequested > pool) issues.push(`Alberta Schedule 6: the associated group allocated ${totalRequested} of a Crown Royalty Shelter pool of ${pool} (006034 occurrences exceed the $2,000,000 × (006028/365) limit). Allocations were capped in the order given — the group must agree a valid split.`);
|
|
1627
1623
|
let remaining = pool;
|
|
1628
1624
|
return allocations.map((a) => {
|
|
1629
|
-
const requestedAmount = nn$
|
|
1625
|
+
const requestedAmount = nn$32(a.allocatedAmount);
|
|
1630
1626
|
const allocatedAmount = Math.min(requestedAmount, remaining);
|
|
1631
1627
|
remaining -= allocatedAmount;
|
|
1632
1628
|
return {
|
|
@@ -1749,7 +1745,7 @@ function computeAlbertaSchedule6(input) {
|
|
|
1749
1745
|
/** Signed whole-dollar rounding — no floor, several of these lines are marked "+/-". */
|
|
1750
1746
|
const rd = (v) => Math.round(v ?? 0);
|
|
1751
1747
|
/** Non-negative whole-dollar rounding, for the "+"-only lines. */
|
|
1752
|
-
const nn$
|
|
1748
|
+
const nn$31 = (v) => Math.max(0, Math.round(v ?? 0));
|
|
1753
1749
|
const round4 = (v) => Math.round(v * 1e4) / 1e4;
|
|
1754
1750
|
function resolvePartnership(p, index, issues) {
|
|
1755
1751
|
if (!p.name) issues.push(`Alberta Schedule 7: partnership row ${index + 1} has no name (007071 is mandatory for every PITI occurrence).`);
|
|
@@ -1758,9 +1754,9 @@ function resolvePartnership(p, index, issues) {
|
|
|
1758
1754
|
name: p.name,
|
|
1759
1755
|
interestPercent: round4(p.interestPercent),
|
|
1760
1756
|
...p.fiscalPeriodEnd !== void 0 ? { fiscalPeriodEnd: p.fiscalPeriodEnd } : {},
|
|
1761
|
-
shareEligibleForCredit: nn$
|
|
1762
|
-
shareOtherRoyaltiesNotEligible: nn$
|
|
1763
|
-
shareOtherCrownChargesEligibleForDeduction: nn$
|
|
1757
|
+
shareEligibleForCredit: nn$31(p.shareEligibleForCredit),
|
|
1758
|
+
shareOtherRoyaltiesNotEligible: nn$31(p.shareOtherRoyaltiesNotEligible),
|
|
1759
|
+
shareOtherCrownChargesEligibleForDeduction: nn$31(p.shareOtherCrownChargesEligibleForDeduction)
|
|
1764
1760
|
};
|
|
1765
1761
|
}
|
|
1766
1762
|
function resolveAdjustment(a, index, issues) {
|
|
@@ -1769,8 +1765,8 @@ function resolveAdjustment(a, index, issues) {
|
|
|
1769
1765
|
return {
|
|
1770
1766
|
...a.priorProductionPeriodEnd !== void 0 ? { priorProductionPeriodEnd: a.priorProductionPeriodEnd } : {},
|
|
1771
1767
|
...a.sourceOfAdjustment !== void 0 ? { sourceOfAdjustment: a.sourceOfAdjustment } : {},
|
|
1772
|
-
increase: nn$
|
|
1773
|
-
decrease: nn$
|
|
1768
|
+
increase: nn$31(a.increase),
|
|
1769
|
+
decrease: nn$31(a.decrease),
|
|
1774
1770
|
adjustmentNotEligibleForCredit: rd(a.adjustmentNotEligibleForCredit)
|
|
1775
1771
|
};
|
|
1776
1772
|
}
|
|
@@ -1790,7 +1786,7 @@ function schedule7LineItemId(fieldId, occurrence = 1) {
|
|
|
1790
1786
|
* "Schedule 7, line 061" and gives its formula in full, so it is filed here
|
|
1791
1787
|
* under that citation rather than omitted for lack of a home row.
|
|
1792
1788
|
*/
|
|
1793
|
-
function schedule7Values(result) {
|
|
1789
|
+
function schedule7Values$1(result) {
|
|
1794
1790
|
const values = [];
|
|
1795
1791
|
const put = (fieldId, value, occurrence = 1) => values.push({
|
|
1796
1792
|
lineItemId: schedule7LineItemId(fieldId, occurrence),
|
|
@@ -1864,7 +1860,7 @@ function computeAlbertaSchedule7(input) {
|
|
|
1864
1860
|
otherNonDeductibleCrownCharges = 0;
|
|
1865
1861
|
}
|
|
1866
1862
|
const crownLeaseRentalsCapitalized = rd(input.crownLeaseRentalsCapitalized);
|
|
1867
|
-
let otherBalanceSheetDeduction = nn$
|
|
1863
|
+
let otherBalanceSheetDeduction = nn$31(input.otherBalanceSheetDeduction);
|
|
1868
1864
|
if (!input.otherBalanceSheetDeductionName && otherBalanceSheetDeduction !== 0) {
|
|
1869
1865
|
issues.push("Alberta Schedule 7: an amount was given for another balance sheet eligible deduction (007029) but no deduction was named (007027). The spec defaults 007029 to zero when no name is given; the amount was zeroed out.");
|
|
1870
1866
|
otherBalanceSheetDeduction = 0;
|
|
@@ -1905,7 +1901,7 @@ function computeAlbertaSchedule7(input) {
|
|
|
1905
1901
|
}
|
|
1906
1902
|
//#endregion
|
|
1907
1903
|
//#region src/t2/at1/schedules/schedule8-political-contributions.ts
|
|
1908
|
-
const nn$
|
|
1904
|
+
const nn$30 = (v) => Math.max(0, Math.round(v ?? 0));
|
|
1909
1905
|
function yearOf(dateIso) {
|
|
1910
1906
|
if (!dateIso || dateIso.length < 4) return void 0;
|
|
1911
1907
|
const y = Number(dateIso.slice(0, 4));
|
|
@@ -1930,12 +1926,12 @@ function computeSchedule8$1(input) {
|
|
|
1930
1926
|
if (!c.dateOfDonation) issues.push(`Alberta Schedule 8: contribution #${i + 1} (${c.name || "unnamed"}) has no date of donation (008006) — the spec requires one for every receipted contribution.`);
|
|
1931
1927
|
if (!c.receiptNumber) issues.push(`Alberta Schedule 8: contribution #${i + 1} (${c.name || "unnamed"}) has no official receipt number (008004).`);
|
|
1932
1928
|
});
|
|
1933
|
-
const partnershipContributionsTo2003 = nn$
|
|
1934
|
-
const partnershipContributionsFrom2004 = nn$
|
|
1935
|
-
const totalDirect = contributions.reduce((sum, c) => sum + nn$
|
|
1936
|
-
const directTo2003 = contributions.filter((c) => (yearOf(c.dateOfDonation) ?? 0) <= 2003).reduce((sum, c) => sum + nn$
|
|
1937
|
-
const directFrom2004 = contributions.filter((c) => (yearOf(c.dateOfDonation) ?? 9999) >= 2004).reduce((sum, c) => sum + nn$
|
|
1938
|
-
const directIn2004Only = contributions.filter((c) => yearOf(c.dateOfDonation) === 2004).reduce((sum, c) => sum + nn$
|
|
1929
|
+
const partnershipContributionsTo2003 = nn$30(input.partnershipContributionsTo2003);
|
|
1930
|
+
const partnershipContributionsFrom2004 = nn$30(input.partnershipContributionsFrom2004);
|
|
1931
|
+
const totalDirect = contributions.reduce((sum, c) => sum + nn$30(c.amount), 0);
|
|
1932
|
+
const directTo2003 = contributions.filter((c) => (yearOf(c.dateOfDonation) ?? 0) <= 2003).reduce((sum, c) => sum + nn$30(c.amount), 0);
|
|
1933
|
+
const directFrom2004 = contributions.filter((c) => (yearOf(c.dateOfDonation) ?? 9999) >= 2004).reduce((sum, c) => sum + nn$30(c.amount), 0);
|
|
1934
|
+
const directIn2004Only = contributions.filter((c) => yearOf(c.dateOfDonation) === 2004).reduce((sum, c) => sum + nn$30(c.amount), 0);
|
|
1939
1935
|
const hasTo2003 = directTo2003 > 0 || partnershipContributionsTo2003 > 0;
|
|
1940
1936
|
const hasFrom2004 = directFrom2004 > 0 || partnershipContributionsFrom2004 > 0;
|
|
1941
1937
|
if (!hasTo2003 && !hasFrom2004) return {
|
|
@@ -2004,7 +2000,7 @@ function computeSchedule8$1(input) {
|
|
|
2004
2000
|
* Does NOT emit jacket line 000074 (the actual tax credit) — that is a
|
|
2005
2001
|
* jacket line, not a Schedule 8 line. Use `result.credit` for that.
|
|
2006
2002
|
*/
|
|
2007
|
-
function schedule8Values(result) {
|
|
2003
|
+
function schedule8Values$1(result) {
|
|
2008
2004
|
const values = [];
|
|
2009
2005
|
result.contributions.forEach((c, i) => {
|
|
2010
2006
|
const n = i + 1;
|
|
@@ -2032,7 +2028,7 @@ function schedule8Values(result) {
|
|
|
2032
2028
|
}
|
|
2033
2029
|
//#endregion
|
|
2034
2030
|
//#region src/t2/at1/schedules/schedule9-sred-tax-credit.ts
|
|
2035
|
-
const nn$
|
|
2031
|
+
const nn$29 = (v) => Math.max(0, Math.round(v ?? 0));
|
|
2036
2032
|
/** Signed whole-dollar rounding, for fields the spec marks "+/-". */
|
|
2037
2033
|
const signed = (v) => Math.round(v);
|
|
2038
2034
|
/** 009120's flat rate — "lesser of line 009031 and 009108 X 10%". */
|
|
@@ -2051,17 +2047,17 @@ function computeSchedule9MaximumExpenditureLimit(daysInTaxYear = 365) {
|
|
|
2051
2047
|
}
|
|
2052
2048
|
function computeAlbertaSchedule9(input) {
|
|
2053
2049
|
const issues = [];
|
|
2054
|
-
const federalQualifiedExpenditures = nn$
|
|
2055
|
-
const albertaPortionOfExpenditures = nn$
|
|
2056
|
-
const federalProxyAmountInAlbertaPortion = nn$
|
|
2057
|
-
const albertaProxyAmount = nn$
|
|
2058
|
-
const albertaCreditReducingFederalExpense = nn$
|
|
2059
|
-
const priorYearFederalItcReceived = nn$
|
|
2060
|
-
const totalAlbertaExpendituresAllYears = nn$
|
|
2061
|
-
const totalFederalExpendituresAllYears = nn$
|
|
2062
|
-
const albertaPortionOfRepayments = nn$
|
|
2063
|
-
const disposalRecapture = nn$
|
|
2064
|
-
const priorYearFederalItcAdjustment = nn$
|
|
2050
|
+
const federalQualifiedExpenditures = nn$29(input.federalQualifiedExpenditures);
|
|
2051
|
+
const albertaPortionOfExpenditures = nn$29(input.albertaPortionOfExpenditures);
|
|
2052
|
+
const federalProxyAmountInAlbertaPortion = nn$29(input.federalProxyAmountInAlbertaPortion);
|
|
2053
|
+
const albertaProxyAmount = nn$29(input.albertaProxyAmount);
|
|
2054
|
+
const albertaCreditReducingFederalExpense = nn$29(input.albertaCreditReducingFederalExpense);
|
|
2055
|
+
const priorYearFederalItcReceived = nn$29(input.priorYearFederalItcReceived);
|
|
2056
|
+
const totalAlbertaExpendituresAllYears = nn$29(input.totalAlbertaExpendituresAllYears);
|
|
2057
|
+
const totalFederalExpendituresAllYears = nn$29(input.totalFederalExpendituresAllYears);
|
|
2058
|
+
const albertaPortionOfRepayments = nn$29(input.albertaPortionOfRepayments);
|
|
2059
|
+
const disposalRecapture = nn$29(input.disposalRecapture);
|
|
2060
|
+
const priorYearFederalItcAdjustment = nn$29(input.priorYearFederalItcAdjustment);
|
|
2065
2061
|
if (albertaPortionOfExpenditures > federalQualifiedExpenditures) issues.push(`Alberta Schedule 9: the Alberta portion of expenditures (009005 = ${albertaPortionOfExpenditures}) exceeds the federal total (009003 = ${federalQualifiedExpenditures}). 009005 must not exceed 009003.`);
|
|
2066
2062
|
const priorYearItcAlbertaPortion = totalFederalExpendituresAllYears > 0 ? Math.round(priorYearFederalItcReceived * totalAlbertaExpendituresAllYears / totalFederalExpendituresAllYears) : 0;
|
|
2067
2063
|
if (totalFederalExpendituresAllYears === 0 && priorYearFederalItcReceived > 0) issues.push("Alberta Schedule 9: a prior-year federal ITC (009015) was supplied but total federal expenditures for those years (009019) is nil, so no Alberta portion (009023) could be allocated. Supply 009019 if a prior-year ITC allocation is expected.");
|
|
@@ -2075,7 +2071,7 @@ function computeAlbertaSchedule9(input) {
|
|
|
2075
2071
|
if (isAssociated) if (input.allocatedExpenditureLimit === void 0) {
|
|
2076
2072
|
issues.push("Alberta Schedule 9: the corporation is associated (009100 = 1) but no allocated expenditure limit (009102) was supplied. Complete the Allocation of the Maximum Expenditure Limit (page 3) and pass its result as allocatedExpenditureLimit — see allocateSchedule9ExpenditureLimit.");
|
|
2077
2073
|
maximumExpenditureLimit = 0;
|
|
2078
|
-
} else maximumExpenditureLimit = nn$
|
|
2074
|
+
} else maximumExpenditureLimit = nn$29(input.allocatedExpenditureLimit);
|
|
2079
2075
|
else maximumExpenditureLimit = nonAssociatedMaximumExpenditureLimit;
|
|
2080
2076
|
if (input.taxationYearEnd !== void 0 && input.taxationYearEnd > "2019-12-31") issues.push(`Alberta Schedule 9: the taxation year end (${input.taxationYearEnd}) falls after ${ALBERTA_SRED_EXPENDITURE_CUTOFF}. The Alberta SR&ED Tax Credit may not be claimed for expenditures carried out in Alberta after that date — confirm albertaPortionOfExpenditures (009005) excludes any post-cutoff spending.`);
|
|
2081
2077
|
const netCredit = Math.round(Math.min(eligibleExpenditures, maximumExpenditureLimit) * ALBERTA_SRED_TAX_CREDIT_RATE) - disposalRecapture - priorYearFederalItcAdjustment;
|
|
@@ -2114,7 +2110,7 @@ function allocateSchedule9ExpenditureLimit(daysInLongestYear, requested) {
|
|
|
2114
2110
|
const days = Math.max(0, Math.min(daysInLongestYear, 366));
|
|
2115
2111
|
const maximumExpenditureLimit = computeSchedule9MaximumExpenditureLimit(days);
|
|
2116
2112
|
const members = requested.map((m) => {
|
|
2117
|
-
const requestedAmount = nn$
|
|
2113
|
+
const requestedAmount = nn$29(m.allocated);
|
|
2118
2114
|
if (requestedAmount > maximumExpenditureLimit) issues.push(`Alberta Schedule 9: ${m.name} was allocated ${requestedAmount}, exceeding the maximum expenditure limit of ${maximumExpenditureLimit} (009240 cannot exceed $4,000,000 x 009206/365). Capped at ${maximumExpenditureLimit}.`);
|
|
2119
2115
|
return {
|
|
2120
2116
|
name: m.name,
|
|
@@ -2358,7 +2354,7 @@ function schedule9Values(result, group) {
|
|
|
2358
2354
|
*
|
|
2359
2355
|
* Whole dollars, pure functions, no I/O.
|
|
2360
2356
|
*/
|
|
2361
|
-
const nn$
|
|
2357
|
+
const nn$28 = (v) => Math.max(0, v ?? 0);
|
|
2362
2358
|
const num$1 = (v) => v ?? 0;
|
|
2363
2359
|
const round$1 = (v) => Math.round(v);
|
|
2364
2360
|
/** `override ?? federal`, tracking whether an Alberta-specific figure was actually entered. */
|
|
@@ -2862,7 +2858,7 @@ function computeCfreRegular(entries) {
|
|
|
2862
2858
|
const partA = Math.max(CCOGPE_CLAIM_RATE * linear * pool, Math.min(CDE_CLAIM_RATE * linear * pool, foreignResourceIncome, sumForeignResourceIncome));
|
|
2863
2859
|
const remainder = Math.max(0, pool - partA);
|
|
2864
2860
|
if (e.globalForeignResourceLimit === void 0) issues.push(`Schedule 15 CFRE regular, country ${e.federal.countryCode} (015293): the "global foreign resource limit for the year designated for that country" (source lines 15703-15711) was not supplied — this quantity has no source anywhere in this engine, so the B-component of the claim is treated as 0 (conservative — the pool may be under-claimed relative to what the corporation is actually entitled to).`);
|
|
2865
|
-
const partB = Math.min(remainder, nn$
|
|
2861
|
+
const partB = Math.min(remainder, nn$28(e.globalForeignResourceLimit));
|
|
2866
2862
|
claim = claimUpToCap$1(e.claimed, partA + partB, issues, `Schedule 15 CFRE regular, country ${e.federal.countryCode} (015293)`);
|
|
2867
2863
|
}
|
|
2868
2864
|
const closingBalance = pool - claim;
|
|
@@ -3294,15 +3290,15 @@ function schedule15Values(result) {
|
|
|
3294
3290
|
function iegT661SourceLine(taxationYearEnd) {
|
|
3295
3291
|
return taxationYearEnd >= "2024-12-16" ? "557" : "559";
|
|
3296
3292
|
}
|
|
3297
|
-
const nn$
|
|
3293
|
+
const nn$27 = (v) => Math.round(v ?? 0);
|
|
3298
3294
|
/** Line 031 = 005 − 007 + 009 + 011 + 025. Every term but 005 defaults to nil. */
|
|
3299
3295
|
function computeIegEligibleExpenditures(input) {
|
|
3300
|
-
const federalAmount = nn$
|
|
3301
|
-
const albertaPortion = nn$
|
|
3302
|
-
const federalProxyAmount = nn$
|
|
3303
|
-
const albertaProxyAmount = nn$
|
|
3304
|
-
const iegReducingFederalExpenditure = nn$
|
|
3305
|
-
const repaymentOrContractPayment = nn$
|
|
3296
|
+
const federalAmount = nn$27(input.federalAmount);
|
|
3297
|
+
const albertaPortion = nn$27(input.albertaPortion);
|
|
3298
|
+
const federalProxyAmount = nn$27(input.federalProxyAmount);
|
|
3299
|
+
const albertaProxyAmount = nn$27(input.albertaProxyAmount);
|
|
3300
|
+
const iegReducingFederalExpenditure = nn$27(input.iegReducingFederalExpenditure);
|
|
3301
|
+
const repaymentOrContractPayment = nn$27(input.repaymentOrContractPayment);
|
|
3306
3302
|
return {
|
|
3307
3303
|
federalAmount,
|
|
3308
3304
|
albertaPortion,
|
|
@@ -3522,7 +3518,7 @@ function computeIeg(input) {
|
|
|
3522
3518
|
*
|
|
3523
3519
|
* Whole dollars, pure.
|
|
3524
3520
|
*/
|
|
3525
|
-
const nn$
|
|
3521
|
+
const nn$26 = (v) => Math.max(0, Math.round(v ?? 0));
|
|
3526
3522
|
/**
|
|
3527
3523
|
* The group's taxable capital and base level of spending, from every associated
|
|
3528
3524
|
* member's own figures.
|
|
@@ -3533,11 +3529,11 @@ const nn$24 = (v) => Math.max(0, Math.round(v ?? 0));
|
|
|
3533
3529
|
function computeIegGroupFigures(members, priorYears = IEG_2024.PRIOR_YEARS) {
|
|
3534
3530
|
const issues = [];
|
|
3535
3531
|
const detail = members.map((m) => {
|
|
3536
|
-
const priorYearAlbertaExpenditures = (m.priorYearAlbertaExpenditures ?? []).map(nn$
|
|
3532
|
+
const priorYearAlbertaExpenditures = (m.priorYearAlbertaExpenditures ?? []).map(nn$26);
|
|
3537
3533
|
if (priorYearAlbertaExpenditures.length > priorYears) issues.push(`Alberta Schedule 29: ${m.name} supplied ${priorYearAlbertaExpenditures.length} prior-year expenditure figures, but the base level of spending averages the prior ${priorYears} years. Every figure supplied was included, which raises the base — check that only the prior ${priorYears} taxation years were given.`);
|
|
3538
3534
|
return {
|
|
3539
3535
|
name: m.name,
|
|
3540
|
-
taxableCapital: nn$
|
|
3536
|
+
taxableCapital: nn$26(m.taxableCapital),
|
|
3541
3537
|
priorYearAlbertaExpenditures,
|
|
3542
3538
|
priorYearTotal: priorYearAlbertaExpenditures.reduce((a, b) => a + b, 0)
|
|
3543
3539
|
};
|
|
@@ -3564,11 +3560,11 @@ function computeIegGroupFigures(members, priorYears = IEG_2024.PRIOR_YEARS) {
|
|
|
3564
3560
|
function allocateIegExpenditureLimit(groupExpenditureLimit, requested) {
|
|
3565
3561
|
const issues = [];
|
|
3566
3562
|
const limit = Math.max(0, Math.round(groupExpenditureLimit));
|
|
3567
|
-
const totalRequested = requested.reduce((s, a) => s + nn$
|
|
3563
|
+
const totalRequested = requested.reduce((s, a) => s + nn$26(a.allocated), 0);
|
|
3568
3564
|
if (totalRequested > limit) issues.push(`Alberta Schedule 29: the associated group allocated ${totalRequested} of an expenditure limit of ${limit}. The allocation cannot exceed the limit; members were capped in the order given and the group must agree a valid split.`);
|
|
3569
3565
|
let remaining = limit;
|
|
3570
3566
|
const allocations = requested.map((a) => {
|
|
3571
|
-
const allocated = Math.min(nn$
|
|
3567
|
+
const allocated = Math.min(nn$26(a.allocated), remaining);
|
|
3572
3568
|
remaining -= allocated;
|
|
3573
3569
|
return {
|
|
3574
3570
|
name: a.name,
|
|
@@ -3602,10 +3598,10 @@ function allocateIegEvenly(groupExpenditureLimit, names) {
|
|
|
3602
3598
|
})));
|
|
3603
3599
|
}
|
|
3604
3600
|
function computeAgreementMember(m, index, issues) {
|
|
3605
|
-
const allocatedExpenditureLimit = nn$
|
|
3606
|
-
const currentYearExpenditures = nn$
|
|
3607
|
-
const priorYear1 = nn$
|
|
3608
|
-
const priorYear2 = nn$
|
|
3601
|
+
const allocatedExpenditureLimit = nn$26(m.allocatedExpenditureLimit);
|
|
3602
|
+
const currentYearExpenditures = nn$26(m.currentYearExpenditures);
|
|
3603
|
+
const priorYear1 = nn$26(m.priorYear1);
|
|
3604
|
+
const priorYear2 = nn$26(m.priorYear2);
|
|
3609
3605
|
const base = Math.round((priorYear1 + priorYear2) / 2);
|
|
3610
3606
|
const individualMaximumAllowedAmount = currentYearExpenditures - base;
|
|
3611
3607
|
const days = Math.max(0, Math.min(m.daysInTaxYear ?? 365, 366));
|
|
@@ -3624,7 +3620,7 @@ function computeAgreementMember(m, index, issues) {
|
|
|
3624
3620
|
currentYearExpenditures,
|
|
3625
3621
|
priorYear1,
|
|
3626
3622
|
priorYear2,
|
|
3627
|
-
taxableCapitalPriorYear: nn$
|
|
3623
|
+
taxableCapitalPriorYear: nn$26(m.taxableCapitalPriorYear),
|
|
3628
3624
|
hasAlbertaPermanentEstablishment,
|
|
3629
3625
|
individualMaximumAllowedAmount,
|
|
3630
3626
|
allocatedAllowedAmount
|
|
@@ -3752,10 +3748,10 @@ function computeAlbertaReturn(input) {
|
|
|
3752
3748
|
const schedulePayloads = [];
|
|
3753
3749
|
const sched = input.schedules;
|
|
3754
3750
|
if (sched?.smallBusinessDeduction) {
|
|
3755
|
-
schedulePayloads.push(schedule1Values(sched.smallBusinessDeduction));
|
|
3751
|
+
schedulePayloads.push(schedule1Values$1(sched.smallBusinessDeduction));
|
|
3756
3752
|
issues.push(...sched.smallBusinessDeduction.result.issues);
|
|
3757
3753
|
}
|
|
3758
|
-
if (sched?.allocation) schedulePayloads.push(schedule2Values(sched.allocation));
|
|
3754
|
+
if (sched?.allocation) schedulePayloads.push(schedule2Values$1(sched.allocation));
|
|
3759
3755
|
if (sched?.otherDeductionsCredits) {
|
|
3760
3756
|
schedulePayloads.push(schedule3Values(sched.otherDeductionsCredits));
|
|
3761
3757
|
issues.push(...sched.otherDeductionsCredits.issues);
|
|
@@ -3773,11 +3769,11 @@ function computeAlbertaReturn(input) {
|
|
|
3773
3769
|
issues.push(...sched.royaltyTaxCredit.issues);
|
|
3774
3770
|
}
|
|
3775
3771
|
if (sched?.royaltySupplemental) {
|
|
3776
|
-
schedulePayloads.push(schedule7Values(sched.royaltySupplemental));
|
|
3772
|
+
schedulePayloads.push(schedule7Values$1(sched.royaltySupplemental));
|
|
3777
3773
|
issues.push(...sched.royaltySupplemental.issues);
|
|
3778
3774
|
}
|
|
3779
3775
|
if (sched?.politicalContributions) {
|
|
3780
|
-
schedulePayloads.push(schedule8Values(sched.politicalContributions));
|
|
3776
|
+
schedulePayloads.push(schedule8Values$1(sched.politicalContributions));
|
|
3781
3777
|
issues.push(...sched.politicalContributions.issues);
|
|
3782
3778
|
}
|
|
3783
3779
|
if (sched?.sredTaxCredit) {
|
|
@@ -3812,7 +3808,7 @@ function computeAlbertaReturn(input) {
|
|
|
3812
3808
|
issues.push(...sched.donations.gifts?.issues ?? []);
|
|
3813
3809
|
}
|
|
3814
3810
|
if (sched?.losses) {
|
|
3815
|
-
schedulePayloads.push(schedule21Values(sched.losses));
|
|
3811
|
+
schedulePayloads.push(schedule21Values$1(sched.losses));
|
|
3816
3812
|
issues.push(...sched.losses.limitedPartnershipLosses?.issues ?? []);
|
|
3817
3813
|
issues.push(...sched.losses.nonCapitalByYearOfOrigin?.issues ?? []);
|
|
3818
3814
|
issues.push(...sched.losses.otherLossesByYearOfOrigin?.issues ?? []);
|
|
@@ -4648,6 +4644,128 @@ function toRsiHeader(data) {
|
|
|
4648
4644
|
};
|
|
4649
4645
|
}
|
|
4650
4646
|
//#endregion
|
|
4647
|
+
//#region src/t2/at1/filing/at1-transmitter-validation.ts
|
|
4648
|
+
/**
|
|
4649
|
+
* §3.2.1.18 — the characters TRA accepts anywhere on the AT1 RSI.
|
|
4650
|
+
*
|
|
4651
|
+
* Latin letters, digits, space, the listed punctuation, and the accented Latin
|
|
4652
|
+
* set. The accented characters are given in the spec as a literal glyph list
|
|
4653
|
+
* that `pdftotext` cannot round-trip, so they are expressed here as the
|
|
4654
|
+
* Latin-1 supplement range they come from (À-ÿ) rather than transcribed
|
|
4655
|
+
* one by one from mojibake.
|
|
4656
|
+
*/
|
|
4657
|
+
const ALLOWABLE = /^[A-Za-z0-9 \-'/&*#!@+=?$%()_;:",.<>~`^{}[\]|\\À-ÿ]*$/;
|
|
4658
|
+
/** Canadian provinces and territories, per the spec's province table. */
|
|
4659
|
+
const CA_PROVINCES = /* @__PURE__ */ new Set([
|
|
4660
|
+
"AB",
|
|
4661
|
+
"BC",
|
|
4662
|
+
"MB",
|
|
4663
|
+
"NB",
|
|
4664
|
+
"NL",
|
|
4665
|
+
"NS",
|
|
4666
|
+
"NT",
|
|
4667
|
+
"NU",
|
|
4668
|
+
"ON",
|
|
4669
|
+
"PE",
|
|
4670
|
+
"QC",
|
|
4671
|
+
"SK",
|
|
4672
|
+
"YT"
|
|
4673
|
+
]);
|
|
4674
|
+
/** A9A 9A9, with or without the space. */
|
|
4675
|
+
const CA_POSTAL = /^[A-Za-z]\d[A-Za-z][ ]?\d[A-Za-z]\d$/;
|
|
4676
|
+
/** Five digits, or nine as 12345-6789 / 123456789. */
|
|
4677
|
+
const US_ZIP = /^\d{5}(-?\d{4})?$/;
|
|
4678
|
+
/** Deliberately permissive: TRA checks format and length, not deliverability. */
|
|
4679
|
+
const EMAIL = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
4680
|
+
/**
|
|
4681
|
+
* The dev placeholder certification code. Blocked because TRA validates the
|
|
4682
|
+
* SCC against its own registry (20010), so `AB0000` cannot succeed — unlike
|
|
4683
|
+
* the serial number, where the rule is presence only (20013) and `SR_DEV` is
|
|
4684
|
+
* a legitimate, if unlovely, value. Only rules TRA actually applies are
|
|
4685
|
+
* enforced here; being stricter than TRA would refuse returns TRA accepts.
|
|
4686
|
+
*/
|
|
4687
|
+
const PLACEHOLDER_CERT_CODE = "AB0000";
|
|
4688
|
+
function validateAt1Transmitter(info) {
|
|
4689
|
+
const defects = [];
|
|
4690
|
+
const add = (field, traCode, message) => defects.push({
|
|
4691
|
+
field,
|
|
4692
|
+
traCode,
|
|
4693
|
+
message
|
|
4694
|
+
});
|
|
4695
|
+
/** Present, within `max` characters, and drawn from the allowable set. */
|
|
4696
|
+
const text = (value, field, traCode, label, max, required = true) => {
|
|
4697
|
+
const v = (value ?? "").trim();
|
|
4698
|
+
if (v === "") {
|
|
4699
|
+
if (required) add(field, traCode, `${label} must be provided.`);
|
|
4700
|
+
return;
|
|
4701
|
+
}
|
|
4702
|
+
if (v.length > max) add(field, traCode, `${label} must not exceed ${max} characters (is ${v.length}).`);
|
|
4703
|
+
if (!ALLOWABLE.test(v)) add(field, "20145", `${label} contains a character TRA does not accept — see the allowable set in specification §3.2.1.18.`);
|
|
4704
|
+
};
|
|
4705
|
+
if (!info.softwareCertCode?.trim()) add("softwareCertCode", "20010", "The TRA-issued Software Certification Code must be provided.");
|
|
4706
|
+
else if (info.softwareCertCode.trim() === PLACEHOLDER_CERT_CODE) add("softwareCertCode", "20010", `The Software Certification Code is still the development placeholder "${info.softwareCertCode}". Set TRA_SOFTWARE_CERT_CODE to the code TRA issued at certification.`);
|
|
4707
|
+
if (!info.webServiceVersion?.trim()) add("webServiceVersion", "20011", "Web Service Version must be provided.");
|
|
4708
|
+
if (!info.softwareVersion?.trim()) add("softwareVersion", "20012", "Software Version must be provided.");
|
|
4709
|
+
if (!info.serialNumber?.trim()) add("serialNumber", "20013", "Software Serial Number must be provided.");
|
|
4710
|
+
const isThirdParty = info.thirdPartyIndicator === "1";
|
|
4711
|
+
if (info.thirdPartyIndicator !== "1" && info.thirdPartyIndicator !== "2") add("thirdPartyIndicator", "20065", "Third Party Service Provider Indicator must be \"1\" (yes) or \"2\" (no).");
|
|
4712
|
+
text(info.legalName, "legalName", "20070", "Organization Legal Name", 70, isThirdParty);
|
|
4713
|
+
if (isThirdParty && !info.organizationType) add("organizationType", "20080", "Type of Organization must be CORPORATION, PARTNERSHIP or INDIVIDUAL when filing as a third party.");
|
|
4714
|
+
const c = info.contact;
|
|
4715
|
+
text(c?.firstName, "contact.firstName", "20085", "Contact First Name", 35);
|
|
4716
|
+
text(c?.lastName, "contact.lastName", "20090", "Contact Last Name", 35);
|
|
4717
|
+
text(c?.position, "contact.position", "20095", "Position", 40);
|
|
4718
|
+
const phone = (c?.phone ?? "").trim();
|
|
4719
|
+
const phoneDigits = phone.replace(/\D/g, "");
|
|
4720
|
+
if (phone === "") add("contact.phone", "20100", "Phone Number must be provided.");
|
|
4721
|
+
else if (phoneDigits.length < 10 || phoneDigits.length > 15) add("contact.phone", "20100", `Phone Number must be 10 to 15 digits (is ${phoneDigits.length}).`);
|
|
4722
|
+
else if (new Set(phoneDigits).size === 1) add("contact.phone", "20100", `Phone Number "${phone}" is a placeholder, not a number TRA will accept. Set TRANSMITTER_PHONE to the filer's real phone number.`);
|
|
4723
|
+
const email = (c?.email ?? "").trim();
|
|
4724
|
+
if (email === "") add("contact.email", "20110", "Email Address must be provided.");
|
|
4725
|
+
else if (email.length > 50) add("contact.email", "20110", `Email Address must not exceed 50 characters (is ${email.length}).`);
|
|
4726
|
+
else if (!EMAIL.test(email)) add("contact.email", "20110", `Email Address "${email}" is not a valid format.`);
|
|
4727
|
+
const a = info.address;
|
|
4728
|
+
if (isThirdParty && !a) add("address", "20115", "A third-party filer must supply a mailing address.");
|
|
4729
|
+
else if (a) {
|
|
4730
|
+
text(a.street, "address.street", "20115", "Address Line 1", 35);
|
|
4731
|
+
if (a.line2?.trim()) {
|
|
4732
|
+
text(a.line2, "address.line2", "20120", "Address Line 2", 35, false);
|
|
4733
|
+
if (a.line2.trim().toUpperCase() === (a.street ?? "").trim().toUpperCase()) add("address.line2", "20120", "Address Line 2 cannot repeat Address Line 1.");
|
|
4734
|
+
}
|
|
4735
|
+
text(a.city, "address.city", "20125", "City", 35);
|
|
4736
|
+
const country = (a.country ?? "").trim().toUpperCase();
|
|
4737
|
+
const province = (a.province ?? "").trim().toUpperCase();
|
|
4738
|
+
const postal = (a.postalCode ?? "").trim();
|
|
4739
|
+
if (country === "") add("address.country", "20140", "Country must be provided.");
|
|
4740
|
+
else if (!/^[A-Z]{2}$/.test(country)) add("address.country", "20140", `Country must be a two-character code accepted by Canada Post (is "${a.country}").`);
|
|
4741
|
+
if (country === "CA" || country === "US") {
|
|
4742
|
+
if (province === "") add("address.province", "20130", `Province must be provided when the country is ${country}.`);
|
|
4743
|
+
else if (country === "CA" && !CA_PROVINCES.has(province)) add("address.province", "20130", `"${a.province}" is not a Canadian province or territory code.`);
|
|
4744
|
+
else if (country === "US" && !/^[A-Z]{2}$/.test(province)) add("address.province", "20130", `"${a.province}" is not a two-letter US state code.`);
|
|
4745
|
+
if (postal === "") add("address.postalCode", "20135", `Postal Code must be provided when the country is ${country}.`);
|
|
4746
|
+
else if (country === "CA" && !CA_POSTAL.test(postal)) add("address.postalCode", "20135", `Postal Code "${postal}" is not in Canadian A9A 9A9 format.`);
|
|
4747
|
+
else if (country === "US" && !US_ZIP.test(postal)) add("address.postalCode", "20135", `Postal Code "${postal}" is not a 5- or 9-digit US ZIP.`);
|
|
4748
|
+
} else if (country !== "") {
|
|
4749
|
+
if (province !== "") add("address.province", "20130", "Province must be blank when the country is not CA or US.");
|
|
4750
|
+
if (postal !== "") add("address.postalCode", "20135", "Postal Code must be blank when the country is not CA or US.");
|
|
4751
|
+
}
|
|
4752
|
+
}
|
|
4753
|
+
return defects;
|
|
4754
|
+
}
|
|
4755
|
+
var At1TransmitterInvalidError = class extends Error {
|
|
4756
|
+
defects;
|
|
4757
|
+
constructor(defects) {
|
|
4758
|
+
super(`AT1 cannot be transmitted: the filer (transmitter) configuration would be rejected by TRA — ` + defects.map((d) => `${d.field} [TRA ${d.traCode}]: ${d.message}`).join(" ") + " These are deployment settings, not anything on the return.");
|
|
4759
|
+
this.name = "At1TransmitterInvalidError";
|
|
4760
|
+
this.defects = defects;
|
|
4761
|
+
}
|
|
4762
|
+
};
|
|
4763
|
+
/** Throw unless every filer-detail rule TRA applies is satisfied. */
|
|
4764
|
+
function assertAt1TransmitterValid(info) {
|
|
4765
|
+
const defects = validateAt1Transmitter(info);
|
|
4766
|
+
if (defects.length > 0) throw new At1TransmitterInvalidError(defects);
|
|
4767
|
+
}
|
|
4768
|
+
//#endregion
|
|
4651
4769
|
//#region src/t2/schedules/loss-carryback.ts
|
|
4652
4770
|
var LossCarrybackError = class extends Error {
|
|
4653
4771
|
constructor(message) {
|
|
@@ -5675,33 +5793,33 @@ function computeAlbertaSchedule13(input) {
|
|
|
5675
5793
|
}
|
|
5676
5794
|
//#endregion
|
|
5677
5795
|
//#region src/t2/at1/schedules/schedule16-sred.ts
|
|
5678
|
-
const nn$
|
|
5796
|
+
const nn$25 = (v) => Math.max(0, Math.round(v ?? 0));
|
|
5679
5797
|
/**
|
|
5680
5798
|
* Line 016004 for federal T661 versions from 2008 onward: lines 429 + 431 + 432.
|
|
5681
5799
|
* The 2007-and-earlier form used a single line 430, which can be passed to
|
|
5682
5800
|
* `assistance` directly.
|
|
5683
5801
|
*/
|
|
5684
5802
|
function assistanceFrom(line429, line431, line432) {
|
|
5685
|
-
return nn$
|
|
5803
|
+
return nn$25(line429) + nn$25(line431) + nn$25(line432);
|
|
5686
5804
|
}
|
|
5687
5805
|
function computeAlbertaSchedule16(input) {
|
|
5688
5806
|
const issues = [];
|
|
5689
|
-
const currentYearExpenditures = nn$
|
|
5690
|
-
const assistance = nn$
|
|
5691
|
-
const priorYearItcClaimed = nn$
|
|
5692
|
-
const saleOfCapitalAssetsAndOther = nn$
|
|
5693
|
-
const assistanceRepayments = nn$
|
|
5694
|
-
const openingPoolBalance = nn$
|
|
5695
|
-
const poolTransferredIn = nn$
|
|
5696
|
-
const priorYearItcRecaptured = nn$
|
|
5807
|
+
const currentYearExpenditures = nn$25(input.currentYearExpenditures);
|
|
5808
|
+
const assistance = nn$25(input.assistance);
|
|
5809
|
+
const priorYearItcClaimed = nn$25(input.priorYearItcClaimed);
|
|
5810
|
+
const saleOfCapitalAssetsAndOther = nn$25(input.saleOfCapitalAssetsAndOther);
|
|
5811
|
+
const assistanceRepayments = nn$25(input.assistanceRepayments);
|
|
5812
|
+
const openingPoolBalance = nn$25(input.openingPoolBalance);
|
|
5813
|
+
const poolTransferredIn = nn$25(input.poolTransferredIn);
|
|
5814
|
+
const priorYearItcRecaptured = nn$25(input.priorYearItcRecaptured);
|
|
5697
5815
|
const totalDeductions = assistance + priorYearItcClaimed + saleOfCapitalAssetsAndOther;
|
|
5698
5816
|
const totalAdditions = assistanceRepayments + openingPoolBalance + poolTransferredIn + priorYearItcRecaptured;
|
|
5699
5817
|
const subtotal = currentYearExpenditures - totalDeductions + totalAdditions;
|
|
5700
5818
|
const deductionAvailable = Math.max(0, subtotal);
|
|
5701
5819
|
if (subtotal < 0) issues.push(`Alberta Schedule 16: assistance, prior-year credits and asset sales exceed the SR&ED expenditures by ${-subtotal}. No pool deduction is available and the pool carries forward at nil.`);
|
|
5702
5820
|
const amountClaimed = input.amountClaimed != null ? Math.max(0, Math.min(Math.round(input.amountClaimed), deductionAvailable)) : deductionAvailable;
|
|
5703
|
-
const openingDiffers = input.federalOpeningPoolBalance !== void 0 && nn$
|
|
5704
|
-
const claimDiffers = input.federalAmountClaimed !== void 0 && nn$
|
|
5821
|
+
const openingDiffers = input.federalOpeningPoolBalance !== void 0 && nn$25(input.federalOpeningPoolBalance) !== openingPoolBalance;
|
|
5822
|
+
const claimDiffers = input.federalAmountClaimed !== void 0 && nn$25(input.federalAmountClaimed) !== amountClaimed;
|
|
5705
5823
|
const formRequired = openingDiffers || claimDiffers;
|
|
5706
5824
|
const formPermitted = (input.reportsDifferentAlbertaIncome ?? false) || (input.electsDifferentDiscretionaryAmounts ?? false);
|
|
5707
5825
|
if (formRequired && !formPermitted) issues.push("Alberta Schedule 16: the SR&ED opening pool balance or the deduction claimed differs from federal, so the form is required, but neither line 000060 nor 000061 is set to 1. Set line 000061 and file a Schedule 12.");
|
|
@@ -5829,10 +5947,10 @@ const AT1_RESERVE_LINES = Object.freeze({
|
|
|
5829
5947
|
closing: "017077"
|
|
5830
5948
|
}
|
|
5831
5949
|
});
|
|
5832
|
-
const nn$
|
|
5950
|
+
const nn$24 = (v) => Math.max(0, Math.round(v ?? 0));
|
|
5833
5951
|
/** `undefined` falls back to federal; a `0` is a real Alberta override. */
|
|
5834
5952
|
function pick(alberta, federal) {
|
|
5835
|
-
return nn$
|
|
5953
|
+
return nn$24(alberta !== void 0 ? alberta : federal);
|
|
5836
5954
|
}
|
|
5837
5955
|
function computeAlbertaSchedule17(input) {
|
|
5838
5956
|
const issues = [];
|
|
@@ -5935,7 +6053,7 @@ const AT1_DISPOSITION_CATEGORIES = [
|
|
|
5935
6053
|
* Line 018076 then applies the inclusion rate once, to the total.
|
|
5936
6054
|
*/
|
|
5937
6055
|
const SECTION_34_2_GROSS_UP = 2;
|
|
5938
|
-
const nn$
|
|
6056
|
+
const nn$23 = (v) => Math.max(0, v ?? 0);
|
|
5939
6057
|
const num = (v) => v ?? 0;
|
|
5940
6058
|
/** Merge one category: an omitted Alberta field takes federal; a `0` overrides. */
|
|
5941
6059
|
function mergeCategory(federal, alberta) {
|
|
@@ -5946,9 +6064,9 @@ function mergeCategory(federal, alberta) {
|
|
|
5946
6064
|
const o = f.outlays;
|
|
5947
6065
|
return {
|
|
5948
6066
|
totals: {
|
|
5949
|
-
proceeds: nn$
|
|
6067
|
+
proceeds: nn$23(p),
|
|
5950
6068
|
acb: num(c),
|
|
5951
|
-
outlays: nn$
|
|
6069
|
+
outlays: nn$23(o)
|
|
5952
6070
|
},
|
|
5953
6071
|
differs: a.proceeds !== void 0 || a.acb !== void 0
|
|
5954
6072
|
};
|
|
@@ -5970,17 +6088,17 @@ function computeAlbertaSchedule18(input) {
|
|
|
5970
6088
|
const gainOf = (c) => categories.find((x) => x.category === c)?.gain ?? 0;
|
|
5971
6089
|
const personalUseGain = gainOf("personalUse");
|
|
5972
6090
|
const listedPersonalGain = gainOf("listedPersonal");
|
|
5973
|
-
const lppLossesApplied = listedPersonalGain > 0 ? Math.min(nn$
|
|
6091
|
+
const lppLossesApplied = listedPersonalGain > 0 ? Math.min(nn$23(input.unappliedLppLosses), listedPersonalGain) : 0;
|
|
5974
6092
|
const ordinaryGains = gainOf("shares") + gainOf("realEstate") + gainOf("bonds") + gainOf("otherProperties");
|
|
5975
6093
|
const lppComponent = listedPersonalGain >= 0 ? listedPersonalGain - lppLossesApplied : 0;
|
|
5976
|
-
const reserveOpening = nn$
|
|
5977
|
-
const reserveClosing = nn$
|
|
5978
|
-
const netBeforeInclusionRate = ordinaryGains + personalUseGain + lppComponent + nn$
|
|
6094
|
+
const reserveOpening = nn$23(input.albertaReserveOpening ?? input.federalReserveOpening);
|
|
6095
|
+
const reserveClosing = nn$23(input.albertaReserveClosing ?? input.federalReserveClosing);
|
|
6096
|
+
const netBeforeInclusionRate = ordinaryGains + personalUseGain + lppComponent + nn$23(input.capitalGainsDividends) + reserveOpening - reserveClosing - nn$23(input.gainOnDonatedSecurities) - nn$23(input.gainOnDonatedEcologicalLand) + Math.min(nn$23(input.exemptionThreshold), nn$23(input.capitalGainsFromActualProperty)) + 2 * nn$23(input.section342TaxableCapitalGains) - 2 * nn$23(input.section342AllowableCapitalLosses);
|
|
5979
6097
|
const taxableCapitalGain = Math.max(0, Math.round(inclusionRate * netBeforeInclusionRate));
|
|
5980
6098
|
const abil = (input.abilEntries ?? []).map((e) => ({
|
|
5981
6099
|
name: e.name,
|
|
5982
6100
|
kind: e.kind,
|
|
5983
|
-
businessInvestmentLoss: nn$
|
|
6101
|
+
businessInvestmentLoss: nn$23(e.proceeds) - (nn$23(e.acb) + nn$23(e.outlays))
|
|
5984
6102
|
}));
|
|
5985
6103
|
const totalBil = abil.reduce((s, e) => s + Math.min(0, e.businessInvestmentLoss), 0);
|
|
5986
6104
|
const allowableBusinessInvestmentLoss = -Math.round(inclusionRate * -totalBil);
|
|
@@ -6011,7 +6129,7 @@ function computeAlbertaSchedule18(input) {
|
|
|
6011
6129
|
}
|
|
6012
6130
|
//#endregion
|
|
6013
6131
|
//#region src/t2/at1/schedules/schedule20-donations.ts
|
|
6014
|
-
const nn$
|
|
6132
|
+
const nn$22 = (v) => Math.max(0, v ?? 0);
|
|
6015
6133
|
/**
|
|
6016
6134
|
* Alberta figures default to federal, per-field. A `0` entered on the Alberta
|
|
6017
6135
|
* side is a real override and must not be swallowed by the default, so the
|
|
@@ -6036,11 +6154,11 @@ function resolveCarryforward(federal, alberta) {
|
|
|
6036
6154
|
return out;
|
|
6037
6155
|
}
|
|
6038
6156
|
function computeSchedule20(input) {
|
|
6039
|
-
const openingBalance = nn$
|
|
6040
|
-
const expired = nn$
|
|
6041
|
-
const transferredIn = nn$
|
|
6042
|
-
const currentYearGifts = nn$
|
|
6043
|
-
const acquisitionOfControlAdjustment = nn$
|
|
6157
|
+
const openingBalance = nn$22(input.openingBalance);
|
|
6158
|
+
const expired = nn$22(input.expired);
|
|
6159
|
+
const transferredIn = nn$22(input.transferredIn);
|
|
6160
|
+
const currentYearGifts = nn$22(input.currentYearGifts);
|
|
6161
|
+
const acquisitionOfControlAdjustment = nn$22(input.acquisitionOfControlAdjustment);
|
|
6044
6162
|
const availableBeforeClaim = Math.max(0, openingBalance - expired + transferredIn + currentYearGifts - acquisitionOfControlAdjustment);
|
|
6045
6163
|
const issues = [];
|
|
6046
6164
|
let ceiling;
|
|
@@ -6111,12 +6229,12 @@ function computeSchedule20(input) {
|
|
|
6111
6229
|
const AT1_DONATION_INCOME_RATE = .75;
|
|
6112
6230
|
/** Gains and recapture on gifted capital property add back at 25%. */
|
|
6113
6231
|
const AT1_DONATION_GAIN_RATE = .25;
|
|
6114
|
-
const nn$
|
|
6232
|
+
const nn$21 = (v) => Math.max(0, v ?? 0);
|
|
6115
6233
|
function computeDonationMaximum(input) {
|
|
6116
6234
|
const incomeComponent = Math.round(AT1_DONATION_INCOME_RATE * Math.max(0, input.albertaNetIncomeForTax));
|
|
6117
|
-
const lesserOfProceedsAndCost = Math.min(nn$
|
|
6118
|
-
const allowableRecapture = Math.min(nn$
|
|
6119
|
-
const gainsComponent = Math.round(AT1_DONATION_GAIN_RATE * (nn$
|
|
6235
|
+
const lesserOfProceedsAndCost = Math.min(nn$21(input.proceedsNetOfOutlays), nn$21(input.capitalCost));
|
|
6236
|
+
const allowableRecapture = Math.min(nn$21(input.recaptureOnGifts), lesserOfProceedsAndCost);
|
|
6237
|
+
const gainsComponent = Math.round(AT1_DONATION_GAIN_RATE * (nn$21(input.taxableCapitalGainsOnGifts) + nn$21(input.deemedGiftGains) + allowableRecapture));
|
|
6120
6238
|
return {
|
|
6121
6239
|
incomeComponent,
|
|
6122
6240
|
lesserOfProceedsAndCost,
|
|
@@ -6209,6 +6327,37 @@ function computeLossSchedule(input) {
|
|
|
6209
6327
|
};
|
|
6210
6328
|
}
|
|
6211
6329
|
//#endregion
|
|
6330
|
+
//#region src/t2/at1/schedules/schedule21-rife.ts
|
|
6331
|
+
function computeRifeContinuity(input = {}) {
|
|
6332
|
+
const openingBalance = Math.max(0, input.openingBalance ?? 0);
|
|
6333
|
+
const transferredOnWindUp = Math.max(0, input.transferredOnWindUp ?? 0);
|
|
6334
|
+
const acquisitionOfControlAdjustment = Math.max(0, input.acquisitionOfControlAdjustment ?? 0);
|
|
6335
|
+
const currentYearRife = Math.max(0, input.currentYearRife ?? 0);
|
|
6336
|
+
const excessCapacity = Math.max(0, input.excessCapacity ?? 0);
|
|
6337
|
+
const receivedCapacity = Math.max(0, input.receivedCapacity ?? 0);
|
|
6338
|
+
const rifeFromPreviousYears = Math.max(0, openingBalance + transferredOnWindUp - acquisitionOfControlAdjustment);
|
|
6339
|
+
const totalCapacity = excessCapacity + receivedCapacity;
|
|
6340
|
+
const maxDeductible = Math.max(0, Math.min(rifeFromPreviousYears, totalCapacity));
|
|
6341
|
+
const issues = [];
|
|
6342
|
+
const requestedClaim = Math.max(0, input.deductedClaim ?? maxDeductible);
|
|
6343
|
+
if (requestedClaim > maxDeductible) issues.push(`Line 240 (RIFE deducted, ${requestedClaim}) cannot exceed line 350 (${maxDeductible}). Capped at ${maxDeductible}.`);
|
|
6344
|
+
const deducted = Math.min(requestedClaim, maxDeductible);
|
|
6345
|
+
return {
|
|
6346
|
+
openingBalance,
|
|
6347
|
+
transferredOnWindUp,
|
|
6348
|
+
acquisitionOfControlAdjustment,
|
|
6349
|
+
currentYearRife,
|
|
6350
|
+
rifeFromPreviousYears,
|
|
6351
|
+
excessCapacity,
|
|
6352
|
+
receivedCapacity,
|
|
6353
|
+
totalCapacity,
|
|
6354
|
+
maxDeductible,
|
|
6355
|
+
deducted,
|
|
6356
|
+
closingBalance: openingBalance + transferredOnWindUp - acquisitionOfControlAdjustment + currentYearRife - deducted,
|
|
6357
|
+
issues
|
|
6358
|
+
};
|
|
6359
|
+
}
|
|
6360
|
+
//#endregion
|
|
6212
6361
|
//#region src/t2/at1/schedules/schedule21-year-of-origin.ts
|
|
6213
6362
|
function sumRows(rows) {
|
|
6214
6363
|
const sum = (f) => rows.reduce((s, r) => s + f(r), 0);
|
|
@@ -6458,6 +6607,241 @@ const T2_CERTIFICATION_FIXTURES = [
|
|
|
6458
6607
|
}
|
|
6459
6608
|
];
|
|
6460
6609
|
//#endregion
|
|
6610
|
+
//#region src/t2/filing/t2-schedule-line-items.ts
|
|
6611
|
+
/**
|
|
6612
|
+
* Federal T2 — the per-schedule, per-line breakdown of a computed return.
|
|
6613
|
+
*
|
|
6614
|
+
* Alberta has had this since the AT1 filing path was built
|
|
6615
|
+
* (`at1-schedule-line-items.ts`): every schedule's result turned into a flat
|
|
6616
|
+
* list of `{lineItemId, value}` pairs, persisted with the computed return, and
|
|
6617
|
+
* read back by the paper Form Views so a preparer sees the actual figure
|
|
6618
|
+
* against the actual line. Federal had nothing equivalent. Its computed return
|
|
6619
|
+
* carried only summary fields under symbolic names — `netIncomeForTax`,
|
|
6620
|
+
* `ccaClaimed` — which no form can be keyed by, so every federal paper view
|
|
6621
|
+
* rendered "not available" against every computed line of every schedule.
|
|
6622
|
+
*
|
|
6623
|
+
* ── The rule this file follows, and why it is strict ────────────────────────
|
|
6624
|
+
*
|
|
6625
|
+
* A value is emitted ONLY where the line it belongs on is recorded in code:
|
|
6626
|
+
* carried in the data (Schedule 1's own `Schedule1Line.line`), exported as a
|
|
6627
|
+
* named constant (`SCHEDULE_8_CCA_LINE`), or stated in the result type's own
|
|
6628
|
+
* doc comment. Nothing here is a line number typed from memory or inferred from
|
|
6629
|
+
* a caption that looks close.
|
|
6630
|
+
*
|
|
6631
|
+
* The reason is the failure this repository keeps hitting: a figure filed under
|
|
6632
|
+
* the wrong line is not a missing figure, it is a WRONG return, and it looks
|
|
6633
|
+
* completely correct on screen. Schedule 4's jacket references claimed lines 150
|
|
6634
|
+
* and 250 where the form prints 130 and 225; Schedule 33's own result type said
|
|
6635
|
+
* line 690 where the form has 790. Both were plausible, both were wrong, and
|
|
6636
|
+
* neither was caught by a type.
|
|
6637
|
+
*
|
|
6638
|
+
* So a schedule whose result has no recorded line mapping produces NO entry
|
|
6639
|
+
* rather than a guessed one, and the paper view keeps saying "not available"
|
|
6640
|
+
* for it. That is the honest state, and it is visibly incomplete, which is what
|
|
6641
|
+
* makes it safe to extend one verified line at a time.
|
|
6642
|
+
*
|
|
6643
|
+
* ── Identifier shape ────────────────────────────────────────────────────────
|
|
6644
|
+
*
|
|
6645
|
+
* Six characters: the three-digit CRA line, then a three-digit occurrence.
|
|
6646
|
+
* Alberta uses nine (`SSSFFFOOO`) because a TRA line item id names its schedule
|
|
6647
|
+
* too; a federal line number is already unique across the whole return, so the
|
|
6648
|
+
* schedule is carried once on the envelope instead of repeated on every row.
|
|
6649
|
+
* The trailing occurrence exists for the grid forms, where one line number
|
|
6650
|
+
* repeats down a column — Schedule 8 has one row per capital cost allowance
|
|
6651
|
+
* class, all of them line 217.
|
|
6652
|
+
*/
|
|
6653
|
+
/** `LLLOOO` — three-digit CRA line, three-digit occurrence. Occurrence is 1-based. */
|
|
6654
|
+
function t2LineItemId(line, occurrence = 1) {
|
|
6655
|
+
return `${line}${String(occurrence).padStart(3, "0")}`;
|
|
6656
|
+
}
|
|
6657
|
+
/**
|
|
6658
|
+
* Split a federal line item id back into its line and occurrence.
|
|
6659
|
+
*
|
|
6660
|
+
* Returns `undefined` for anything that is not six digits, so a caller handed
|
|
6661
|
+
* an Alberta nine-digit id (or a malformed one) drops it rather than reading
|
|
6662
|
+
* the first three characters as a line number and displaying a figure against
|
|
6663
|
+
* a line it does not belong to.
|
|
6664
|
+
*/
|
|
6665
|
+
function parseT2LineItemId(lineItemId) {
|
|
6666
|
+
if (!/^\d{6}$/.test(lineItemId)) return void 0;
|
|
6667
|
+
return {
|
|
6668
|
+
line: lineItemId.slice(0, 3),
|
|
6669
|
+
occurrence: Number(lineItemId.slice(3, 6))
|
|
6670
|
+
};
|
|
6671
|
+
}
|
|
6672
|
+
/** Drop entries with no value, so an absent figure stays absent rather than becoming 0. */
|
|
6673
|
+
const present = (values) => values.filter((v) => v !== null);
|
|
6674
|
+
/** One value, or `null` when the figure was not computed. */
|
|
6675
|
+
const at = (line, value, occurrence = 1) => value === void 0 ? null : {
|
|
6676
|
+
lineItemId: t2LineItemId(line, occurrence),
|
|
6677
|
+
value
|
|
6678
|
+
};
|
|
6679
|
+
/**
|
|
6680
|
+
* Schedule 1 — the only federal schedule that needs no line table here.
|
|
6681
|
+
*
|
|
6682
|
+
* `Schedule1Line` carries its own `line`, and has since the schedule was built,
|
|
6683
|
+
* precisely because "a reconciling item recorded only as a description with an
|
|
6684
|
+
* amount has nowhere to go on the wire". Reading it back out is the whole job.
|
|
6685
|
+
*
|
|
6686
|
+
* A line may legitimately repeat: the form provides open rows (135, 295, 395,
|
|
6687
|
+
* 495) for items it does not name, and a return can carry several. Those get
|
|
6688
|
+
* successive occurrences rather than being summed, so the paper view can show
|
|
6689
|
+
* each on its own row. A line with no number is skipped — `assertSchedule1Fileable`
|
|
6690
|
+
* is what refuses the return over it, not this.
|
|
6691
|
+
*/
|
|
6692
|
+
function schedule1Values(r) {
|
|
6693
|
+
const values = [];
|
|
6694
|
+
const seen = /* @__PURE__ */ new Map();
|
|
6695
|
+
for (const l of [...r.additions, ...r.deductions]) {
|
|
6696
|
+
if (!l.line) continue;
|
|
6697
|
+
const occurrence = (seen.get(l.line) ?? 0) + 1;
|
|
6698
|
+
seen.set(l.line, occurrence);
|
|
6699
|
+
values.push({
|
|
6700
|
+
lineItemId: t2LineItemId(l.line, occurrence),
|
|
6701
|
+
value: l.amount
|
|
6702
|
+
});
|
|
6703
|
+
}
|
|
6704
|
+
values.push({
|
|
6705
|
+
lineItemId: t2LineItemId("500"),
|
|
6706
|
+
value: r.totalAdditions
|
|
6707
|
+
});
|
|
6708
|
+
values.push({
|
|
6709
|
+
lineItemId: t2LineItemId("510"),
|
|
6710
|
+
value: r.totalDeductions
|
|
6711
|
+
});
|
|
6712
|
+
return {
|
|
6713
|
+
scheduleId: "T2SCH1",
|
|
6714
|
+
values
|
|
6715
|
+
};
|
|
6716
|
+
}
|
|
6717
|
+
/** Schedule 2 — the donation claim. Only line 210 is a named constant. */
|
|
6718
|
+
function schedule2Values(r) {
|
|
6719
|
+
return {
|
|
6720
|
+
scheduleId: "T2SCH2",
|
|
6721
|
+
values: present([at("210", r.donationsClaimed)])
|
|
6722
|
+
};
|
|
6723
|
+
}
|
|
6724
|
+
/**
|
|
6725
|
+
* Schedule 7 — the adjusted aggregate investment income that grinds the
|
|
6726
|
+
* business limit. Line 745 is exported by the form module; the rest of Part 2's
|
|
6727
|
+
* working lines are not recorded anywhere, so they are not emitted.
|
|
6728
|
+
*/
|
|
6729
|
+
function schedule7Values(r) {
|
|
6730
|
+
return {
|
|
6731
|
+
scheduleId: "T2SCH7",
|
|
6732
|
+
values: present([at("745", r.adjustedAggregateInvestmentIncome)])
|
|
6733
|
+
};
|
|
6734
|
+
}
|
|
6735
|
+
/**
|
|
6736
|
+
* Schedule 8 — capital cost allowance, one occurrence per class.
|
|
6737
|
+
*
|
|
6738
|
+
* Only the three lines the form module exports are emitted: recapture (213),
|
|
6739
|
+
* terminal loss (215) and the claim (217). The grid's other twenty columns are
|
|
6740
|
+
* either intermediate arithmetic the form shows without numbering, or columns
|
|
6741
|
+
* whose number this package has not recorded — see `SCHEDULE_8_COLUMNS`.
|
|
6742
|
+
*/
|
|
6743
|
+
function schedule8Values(r) {
|
|
6744
|
+
const values = [];
|
|
6745
|
+
r.classes.forEach((c, i) => {
|
|
6746
|
+
const occurrence = i + 1;
|
|
6747
|
+
values.push(...present([
|
|
6748
|
+
at("213", c.recapture, occurrence),
|
|
6749
|
+
at("215", c.terminalLoss, occurrence),
|
|
6750
|
+
at("217", c.ccaClaimed, occurrence)
|
|
6751
|
+
]));
|
|
6752
|
+
});
|
|
6753
|
+
return {
|
|
6754
|
+
scheduleId: "T2SCH8",
|
|
6755
|
+
values
|
|
6756
|
+
};
|
|
6757
|
+
}
|
|
6758
|
+
/**
|
|
6759
|
+
* Schedule 21 — the two foreign tax credits.
|
|
6760
|
+
*
|
|
6761
|
+
* These land on different jacket lines (632 non-business, 636 business) and the
|
|
6762
|
+
* form module's own doc comment warns that swapping them "is not cosmetic".
|
|
6763
|
+
* Both come from named constants for exactly that reason.
|
|
6764
|
+
*/
|
|
6765
|
+
function schedule21Values(r) {
|
|
6766
|
+
return {
|
|
6767
|
+
scheduleId: "T2SCH21",
|
|
6768
|
+
values: present([at("180", r.nonBusinessFtc), at("280", r.businessFtc)])
|
|
6769
|
+
};
|
|
6770
|
+
}
|
|
6771
|
+
/**
|
|
6772
|
+
* Schedule 33 — taxable capital.
|
|
6773
|
+
*
|
|
6774
|
+
* The four figures whose lines the result type states: capital (190), the
|
|
6775
|
+
* investment allowance (490), taxable capital (500) and taxable capital
|
|
6776
|
+
* employed in Canada (790, from the form module's constant — the result type's
|
|
6777
|
+
* comment used to say 690, which is not a line of this form).
|
|
6778
|
+
*/
|
|
6779
|
+
function schedule33Values(r) {
|
|
6780
|
+
return {
|
|
6781
|
+
scheduleId: "T2SCH33",
|
|
6782
|
+
values: present([
|
|
6783
|
+
at("190", r.capital),
|
|
6784
|
+
at("490", r.investmentAllowance),
|
|
6785
|
+
at("500", r.taxableCapital),
|
|
6786
|
+
at("790", r.taxableCapitalEmployedInCanada)
|
|
6787
|
+
])
|
|
6788
|
+
};
|
|
6789
|
+
}
|
|
6790
|
+
/** Schedule 53 — the closing general rate income pool. */
|
|
6791
|
+
function schedule53Values(r) {
|
|
6792
|
+
return {
|
|
6793
|
+
scheduleId: "T2SCH53",
|
|
6794
|
+
values: present([at("590", r.closingGrip)])
|
|
6795
|
+
};
|
|
6796
|
+
}
|
|
6797
|
+
/**
|
|
6798
|
+
* Schedule 55 — Part III.1 tax.
|
|
6799
|
+
*
|
|
6800
|
+
* The result type states "20% of amount B (s.185.1(1)(a)) — line 190 / line
|
|
6801
|
+
* 290". Two lines for one figure because the form splits by corporation type:
|
|
6802
|
+
* Part 1 (line 190) for CCPCs and deposit insurance corporations, Part 2 (line
|
|
6803
|
+
* 290) for everyone else. Nothing in the result says which part applied, so the
|
|
6804
|
+
* base tax is emitted against BOTH and the paper view shows it under whichever
|
|
6805
|
+
* part the reader is looking at, rather than this file picking one and being
|
|
6806
|
+
* wrong for half of all filers.
|
|
6807
|
+
*/
|
|
6808
|
+
function schedule55Values(r) {
|
|
6809
|
+
return {
|
|
6810
|
+
scheduleId: "T2SCH55",
|
|
6811
|
+
values: present([at("190", r.baseTax), at("290", r.baseTax)])
|
|
6812
|
+
};
|
|
6813
|
+
}
|
|
6814
|
+
/** The jacket — the three headline figures the form module names. */
|
|
6815
|
+
function jacketValues(r) {
|
|
6816
|
+
return {
|
|
6817
|
+
scheduleId: "T2",
|
|
6818
|
+
values: present([
|
|
6819
|
+
at("300", r.netIncomeForTax),
|
|
6820
|
+
at("360", r.taxableIncome),
|
|
6821
|
+
at("770", r.totalFederalTax)
|
|
6822
|
+
])
|
|
6823
|
+
};
|
|
6824
|
+
}
|
|
6825
|
+
/**
|
|
6826
|
+
* Every schedule's filed line items for one computed federal return.
|
|
6827
|
+
*
|
|
6828
|
+
* A schedule that was not computed is ABSENT, not present and empty — the same
|
|
6829
|
+
* rule Alberta's assembler follows. An empty schedule on a return says "this
|
|
6830
|
+
* schedule was completed and everything on it is nil", which is a different
|
|
6831
|
+
* statement from "this schedule does not apply", and only one of them is true.
|
|
6832
|
+
*/
|
|
6833
|
+
function federalSchedulePayloads(r) {
|
|
6834
|
+
const payloads = [jacketValues(r), schedule1Values(r.schedule1)];
|
|
6835
|
+
if (r.donations) payloads.push(schedule2Values(r.donations));
|
|
6836
|
+
if (r.adjustedAggregateInvestmentIncomeSchedule) payloads.push(schedule7Values(r.adjustedAggregateInvestmentIncomeSchedule));
|
|
6837
|
+
if (r.cca) payloads.push(schedule8Values(r.cca));
|
|
6838
|
+
if (r.foreignTaxCredit) payloads.push(schedule21Values(r.foreignTaxCredit));
|
|
6839
|
+
if (r.taxableCapitalSchedule) payloads.push(schedule33Values(r.taxableCapitalSchedule));
|
|
6840
|
+
if (r.grip) payloads.push(schedule53Values(r.grip));
|
|
6841
|
+
if (r.partIII1) payloads.push(schedule55Values(r.partIII1));
|
|
6842
|
+
return payloads.filter((p) => p.values.length > 0);
|
|
6843
|
+
}
|
|
6844
|
+
//#endregion
|
|
6461
6845
|
//#region src/t2/rates/corporate-rates.ts
|
|
6462
6846
|
/**
|
|
6463
6847
|
* Federal corporate-tax rate table — the Part I rate stack, the small-business
|
|
@@ -6560,12 +6944,12 @@ function computeSBD(input, rates = CORP_TAX_2024) {
|
|
|
6560
6944
|
sbdAmount: Math.round(rates.SBD_RATE * sbdIncome)
|
|
6561
6945
|
};
|
|
6562
6946
|
}
|
|
6563
|
-
const nn$
|
|
6947
|
+
const nn$20 = (v) => v ?? 0;
|
|
6564
6948
|
function computeAggregateInvestmentIncome(input) {
|
|
6565
|
-
const amountA = nn$
|
|
6566
|
-
const amountB = Math.max(0, nn$
|
|
6567
|
-
const amountC = nn$
|
|
6568
|
-
const amountD = nn$
|
|
6949
|
+
const amountA = nn$20(input.allowableCapitalLosses) + nn$20(input.netCapitalLossesClaimed);
|
|
6950
|
+
const amountB = Math.max(0, nn$20(input.taxableCapitalGains) - amountA);
|
|
6951
|
+
const amountC = nn$20(input.exemptIncome) + nn$20(input.agriInvestFundReceived) + nn$20(input.taxableDividendsDeductible) + nn$20(input.trustPropertyIncome);
|
|
6952
|
+
const amountD = nn$20(input.incomeFromProperty) - amountC;
|
|
6569
6953
|
const amountE = amountB + amountD;
|
|
6570
6954
|
return {
|
|
6571
6955
|
amountA,
|
|
@@ -6573,20 +6957,20 @@ function computeAggregateInvestmentIncome(input) {
|
|
|
6573
6957
|
amountC,
|
|
6574
6958
|
amountD,
|
|
6575
6959
|
amountE,
|
|
6576
|
-
aggregateInvestmentIncome: Math.max(0, amountE - nn$
|
|
6960
|
+
aggregateInvestmentIncome: Math.max(0, amountE - nn$20(input.lossesFromProperty))
|
|
6577
6961
|
};
|
|
6578
6962
|
}
|
|
6579
6963
|
function computeAdjustedAggregateInvestmentIncome(input) {
|
|
6580
|
-
const amountF = Math.max(0, nn$
|
|
6581
|
-
const amountG = nn$
|
|
6582
|
-
const amountH = nn$
|
|
6964
|
+
const amountF = Math.max(0, nn$20(input.taxableCapitalGains) - nn$20(input.allowableCapitalLosses));
|
|
6965
|
+
const amountG = nn$20(input.exemptIncome) + nn$20(input.agriInvestFundReceived) + nn$20(input.dividendsFromConnectedCorporations) + nn$20(input.trustPropertyIncome);
|
|
6966
|
+
const amountH = nn$20(input.incomeFromProperty) - amountG;
|
|
6583
6967
|
const amountI = amountF + amountH;
|
|
6584
6968
|
return {
|
|
6585
6969
|
amountF,
|
|
6586
6970
|
amountG,
|
|
6587
6971
|
amountH,
|
|
6588
6972
|
amountI,
|
|
6589
|
-
adjustedAggregateInvestmentIncome: Math.max(0, amountI - nn$
|
|
6973
|
+
adjustedAggregateInvestmentIncome: Math.max(0, amountI - nn$20(input.lossesFromProperty) + nn$20(input.subsection91_4Deduction))
|
|
6590
6974
|
};
|
|
6591
6975
|
}
|
|
6592
6976
|
//#endregion
|
|
@@ -6827,6 +7211,165 @@ function isSchedule5Province(code) {
|
|
|
6827
7211
|
return code in PROVINCE_RATES_2024;
|
|
6828
7212
|
}
|
|
6829
7213
|
//#endregion
|
|
7214
|
+
//#region src/t2/schedules/eifel-adjusted-taxable-income.ts
|
|
7215
|
+
/**
|
|
7216
|
+
* ITA subsection 18.2(1) — **adjusted taxable income**, the base the EIFEL
|
|
7217
|
+
* ceiling is computed on.
|
|
7218
|
+
*
|
|
7219
|
+
* `eifel-limitation.ts` took this as a required input because deriving it
|
|
7220
|
+
* partially would produce a plausible figure from an incomplete definition. This
|
|
7221
|
+
* derives it, and is explicit about the components it does and does not cover.
|
|
7222
|
+
*
|
|
7223
|
+
* ── What it is ──────────────────────────────────────────────────────────────
|
|
7224
|
+
*
|
|
7225
|
+
* An EBITDA-like measure, built from taxable income by adding back the things the
|
|
7226
|
+
* regime is measuring against and removing the things that would double-count.
|
|
7227
|
+
*
|
|
7228
|
+
* ATI = A + B − C
|
|
7229
|
+
*
|
|
7230
|
+
* A = D − E the income base
|
|
7231
|
+
* B the ADD-BACKS
|
|
7232
|
+
* C the REDUCTIONS
|
|
7233
|
+
*
|
|
7234
|
+
* **The add-backs include the interest and financing expenses themselves.** That
|
|
7235
|
+
* is the point of the measure and the thing to hold on to: the ceiling is a
|
|
7236
|
+
* percentage of income computed *before* the very expenses being limited, so a
|
|
7237
|
+
* corporation cannot shrink its own ceiling by borrowing more.
|
|
7238
|
+
*
|
|
7239
|
+
* ── A — the income base (D − E) ─────────────────────────────────────────────
|
|
7240
|
+
*
|
|
7241
|
+
* **D** is taxable income for the year, determined **without regard to** s.18.2(2)
|
|
7242
|
+
* itself, paragraphs 12(1)(l.2) and 111(1)(a.1), and clause 95(2)(f.11)(ii)(D) —
|
|
7243
|
+
* a non-resident uses taxable income earned in Canada on the same basis. The
|
|
7244
|
+
* circularity is deliberate: the limitation cannot be an input to its own base.
|
|
7245
|
+
*
|
|
7246
|
+
* **E** subtracts the year's non-capital loss on the same basis, any amount
|
|
7247
|
+
* claimed under paragraph 111(1)(a) that did not actually reduce taxable income,
|
|
7248
|
+
* and a controlled-foreign-affiliate component (`T × U ÷ V`).
|
|
7249
|
+
*
|
|
7250
|
+
* ── B — the add-backs ───────────────────────────────────────────────────────
|
|
7251
|
+
*
|
|
7252
|
+
* (a) interest and financing expenses for the year
|
|
7253
|
+
* (b) capital cost allowance and resource deductions — paragraph 20(1)(a),
|
|
7254
|
+
* 59.1(a) and subsections 66(4), 66.1(2)/(3), 66.2(2), 66.21(4), 66.4(2),
|
|
7255
|
+
* 66.7(1)-(5)
|
|
7256
|
+
* (c) terminal losses — subsection 20(16)
|
|
7257
|
+
* (d) the taxpayer's share of a partnership's 20(1)(a) and 20(16) deductions
|
|
7258
|
+
* (e) the portion of a paragraph 111(1)(e) limited-partnership-loss claim
|
|
7259
|
+
* attributable to those amounts
|
|
7260
|
+
*
|
|
7261
|
+
* ── C — the reductions ──────────────────────────────────────────────────────
|
|
7262
|
+
*
|
|
7263
|
+
* (a) interest and financing revenues
|
|
7264
|
+
* (b) recapture — subsection 13(1)
|
|
7265
|
+
* (c) the taxpayer's share of a partnership's 13(1) inclusion
|
|
7266
|
+
* (d) resource inclusions — subsections 59(1), 59(3.2), paragraph 59.1(b)
|
|
7267
|
+
* (e) for a corporation, a grossed-up foreign tax credit amount:
|
|
7268
|
+
* **100/28** of what would be deductible under s.126(1), and
|
|
7269
|
+
* the s.126(2) amounts times the relevant factor
|
|
7270
|
+
*
|
|
7271
|
+
* ── Not modelled ────────────────────────────────────────────────────────────
|
|
7272
|
+
*
|
|
7273
|
+
* The trust variant of C(e), and the later paragraphs of B and C dealing with
|
|
7274
|
+
* foreign affiliate income and exempt interest. Each is available as an explicit
|
|
7275
|
+
* `otherAdditions` / `otherReductions` input rather than silently omitted, so a
|
|
7276
|
+
* preparer with one of those amounts can still arrive at the right figure and the
|
|
7277
|
+
* engine does not pretend the definition is shorter than it is.
|
|
7278
|
+
*
|
|
7279
|
+
* Source: `research/sources/legislation/ITA-section-18.2-EIFEL.txt`.
|
|
7280
|
+
*
|
|
7281
|
+
* Pure, whole dollars.
|
|
7282
|
+
*/
|
|
7283
|
+
/** C(e)(i) — s.126(1) amounts are grossed up by 100/28. */
|
|
7284
|
+
const FOREIGN_TAX_CREDIT_GROSS_UP = 100 / 28;
|
|
7285
|
+
const nn$19 = (v) => Math.max(0, Math.round(v ?? 0));
|
|
7286
|
+
function computeAdjustedTaxableIncome(input) {
|
|
7287
|
+
const issues = [];
|
|
7288
|
+
const e = nn$19(input.nonCapitalLossForYear) + nn$19(input.lossClaimNotReducingTaxableIncome) + nn$19(input.foreignAccrualPropertyLossComponent);
|
|
7289
|
+
const incomeBase = Math.round(input.taxableIncome) - e;
|
|
7290
|
+
const totalAdditions = nn$19(input.interestAndFinancingExpenses) + nn$19(input.capitalCostAllowance) + nn$19(input.resourceDeductions) + nn$19(input.terminalLoss) + nn$19(input.partnershipCapitalAndTerminalShare) + nn$19(input.limitedPartnershipLossPortion) + nn$19(input.partVI1TaxDeduction) + nn$19(input.lossPortionDerivedFromIfe) + nn$19(input.exemptIfeActivityLoss) + nn$19(input.otherAdditions);
|
|
7291
|
+
const totalReductions = nn$19(input.interestAndFinancingRevenues) + nn$19(input.recapture) + nn$19(input.partnershipRecaptureShare) + nn$19(input.resourceInclusions) + Math.round(FOREIGN_TAX_CREDIT_GROSS_UP * nn$19(input.section126_1ForeignTaxCredits)) + nn$19(input.section126_2GrossedUp) + nn$19(input.exemptIfeActivityIncome) + nn$19(input.otherReductions);
|
|
7292
|
+
const adjustedTaxableIncome = incomeBase + totalAdditions - totalReductions;
|
|
7293
|
+
if (adjustedTaxableIncome < 0) issues.push(`EIFEL: adjusted taxable income is negative (${adjustedTaxableIncome}), so the ceiling is nil and every interest and financing expense is denied. Check that the loss and add-back figures are complete before filing on that basis.`);
|
|
7294
|
+
if (input.interestAndFinancingExpenses === void 0) issues.push("EIFEL: no interest and financing expenses were added back to adjusted taxable income. They are paragraph (a) of the add-backs, and omitting them understates the ceiling — which denies more expense than the rules require.");
|
|
7295
|
+
return {
|
|
7296
|
+
incomeBase,
|
|
7297
|
+
totalAdditions,
|
|
7298
|
+
totalReductions,
|
|
7299
|
+
adjustedTaxableIncome,
|
|
7300
|
+
issues
|
|
7301
|
+
};
|
|
7302
|
+
}
|
|
7303
|
+
//#endregion
|
|
7304
|
+
//#region src/t2/schedules/eifel-capacity.ts
|
|
7305
|
+
const nn$18 = (v) => Math.max(0, Math.round(v ?? 0));
|
|
7306
|
+
/**
|
|
7307
|
+
* Part 2O on its own — the total of lines 159 to 162.
|
|
7308
|
+
*
|
|
7309
|
+
* Exported separately because of the order the form imposes: line 159 is the
|
|
7310
|
+
* denial from Part 2L, which cannot be computed until Parts 2G-2J have supplied
|
|
7311
|
+
* `excessReceivedCapacity` and `absorbedCapacity` to Part 2K. A caller running
|
|
7312
|
+
* the whole chain therefore computes capacity, then the limitation, then calls
|
|
7313
|
+
* this — rather than computing capacity twice.
|
|
7314
|
+
*/
|
|
7315
|
+
function computeRifeUnderSubsection111_8(input) {
|
|
7316
|
+
return nn$18(input.excessInterestAndFinancingExpenses) + nn$18(input.partnershipIfeAddBack) + nn$18(input.clause95FapiAmountI) + nn$18(input.clause95FapiAmountII);
|
|
7317
|
+
}
|
|
7318
|
+
function computeEifelCapacity(input) {
|
|
7319
|
+
const issues = [];
|
|
7320
|
+
const ati = Math.round(input.adjustedTaxableIncome);
|
|
7321
|
+
const atiFloored = Math.max(0, ati);
|
|
7322
|
+
const ife = nn$18(input.interestAndFinancingExpenses);
|
|
7323
|
+
const ifr = nn$18(input.interestAndFinancingRevenues);
|
|
7324
|
+
const ratio = input.ratioOfPermissibleExpenses;
|
|
7325
|
+
const usedGroupRatio = input.hasGroupRatioElection === true;
|
|
7326
|
+
const receivedCapacity = (input.receivedCapacity ?? []).reduce((s, r) => s + nn$18(r.amount), 0);
|
|
7327
|
+
const permittedAmount = usedGroupRatio ? 0 : Math.round(atiFloored * ratio);
|
|
7328
|
+
const revenueOverExpense = usedGroupRatio ? 0 : Math.max(0, ifr - ife);
|
|
7329
|
+
const negativeAtiAbsolute = usedGroupRatio ? 0 : ati < 0 ? Math.abs(ati) : 0;
|
|
7330
|
+
const negativeAtiOffset = Math.min(revenueOverExpense, negativeAtiAbsolute);
|
|
7331
|
+
const negativeAtiOffsetAtRatio = Math.round(negativeAtiOffset * ratio);
|
|
7332
|
+
const revenueCapacity = usedGroupRatio ? 0 : Math.max(0, ifr - negativeAtiOffsetAtRatio);
|
|
7333
|
+
const totalCapacityBeforeExpenses = permittedAmount + revenueCapacity;
|
|
7334
|
+
const excessCapacityBeforeRife = usedGroupRatio ? 0 : Math.max(0, totalCapacityBeforeExpenses - ife);
|
|
7335
|
+
const rifeFromPreviousYears = nn$18(input.rifeFromPreviousYears);
|
|
7336
|
+
const rifeCapacityAvailable = excessCapacityBeforeRife + receivedCapacity;
|
|
7337
|
+
const rifeDeductible = Math.min(rifeFromPreviousYears, rifeCapacityAvailable);
|
|
7338
|
+
const excessCapacityForYear = Math.max(0, excessCapacityBeforeRife - rifeDeductible);
|
|
7339
|
+
const vintages = input.priorYearExcessCapacity ?? [];
|
|
7340
|
+
for (const v of vintages) if (v.yearsAgo < 1 || v.yearsAgo > 3) issues.push(`EIFEL: an excess-capacity vintage was supplied for ${v.yearsAgo} year(s) ago, but Schedule 130 Part 2I only carries the three immediately preceding years. It was ignored.`);
|
|
7341
|
+
const priorYearUnusedCapacity = vintages.filter((v) => v.yearsAgo >= 1 && v.yearsAgo <= 3).reduce((s, v) => s + Math.max(0, nn$18(v.excessCapacity) - nn$18(v.previouslyTransferred) - nn$18(v.previouslyAbsorbed)), 0);
|
|
7342
|
+
const cumulativeUnusedExcessCapacityBeforeAbsorption = priorYearUnusedCapacity + excessCapacityForYear;
|
|
7343
|
+
const absorbedShelter = (usedGroupRatio ? nn$18(input.groupRatioAmount) : Math.round(atiFloored * ratio)) + ifr;
|
|
7344
|
+
const absorbedRoom = Math.max(0, ife - absorbedShelter);
|
|
7345
|
+
const absorbedCapacity = Math.min(cumulativeUnusedExcessCapacityBeforeAbsorption, absorbedRoom);
|
|
7346
|
+
const cumulativeUnusedExcessCapacity = Math.max(0, cumulativeUnusedExcessCapacityBeforeAbsorption - absorbedCapacity);
|
|
7347
|
+
const excessReceivedCapacity = Math.max(0, receivedCapacity - rifeDeductible);
|
|
7348
|
+
const rifeForYear = computeRifeUnderSubsection111_8(input);
|
|
7349
|
+
if (usedGroupRatio && input.groupRatioAmount === void 0) issues.push("EIFEL: a group ratio election under subsection 18.21(2) was declared but no allocated group ratio amount was supplied, so absorbed capacity was computed with nil group ratio shelter — which absorbs more capacity than the election allows.");
|
|
7350
|
+
return {
|
|
7351
|
+
receivedCapacity,
|
|
7352
|
+
permittedAmount,
|
|
7353
|
+
revenueOverExpense,
|
|
7354
|
+
negativeAtiAbsolute,
|
|
7355
|
+
negativeAtiOffset,
|
|
7356
|
+
negativeAtiOffsetAtRatio,
|
|
7357
|
+
revenueCapacity,
|
|
7358
|
+
totalCapacityBeforeExpenses,
|
|
7359
|
+
excessCapacityBeforeRife,
|
|
7360
|
+
excessCapacityForYear,
|
|
7361
|
+
rifeCapacityAvailable,
|
|
7362
|
+
rifeDeductible,
|
|
7363
|
+
priorYearUnusedCapacity,
|
|
7364
|
+
cumulativeUnusedExcessCapacityBeforeAbsorption,
|
|
7365
|
+
cumulativeUnusedExcessCapacity,
|
|
7366
|
+
absorbedCapacity,
|
|
7367
|
+
excessReceivedCapacity,
|
|
7368
|
+
rifeForYear,
|
|
7369
|
+
issues
|
|
7370
|
+
};
|
|
7371
|
+
}
|
|
7372
|
+
//#endregion
|
|
6830
7373
|
//#region src/t2/schedules/eifel-excluded-entity.ts
|
|
6831
7374
|
/**
|
|
6832
7375
|
* EIFEL — excessive interest and financing expenses limitation (s.18.2, 18.21).
|
|
@@ -6888,7 +7431,7 @@ function assessEifel(input, thresholds) {
|
|
|
6888
7431
|
if (input.domesticExceptionApplies === true) return exclude("domestic");
|
|
6889
7432
|
const issues = [];
|
|
6890
7433
|
if (ife == null) issues.push("EIFEL: net interest and financing expenses were not provided, and the small-CCPC exception does not apply. The excluded-entity status cannot be established, so the return cannot be filed.");
|
|
6891
|
-
else issues.push(`EIFEL: the corporation is not an excluded entity (net interest and financing expenses of ${ife} exceed the de minimis threshold and no other exception applies). The
|
|
7434
|
+
else issues.push(`EIFEL: the corporation is not an excluded entity (net interest and financing expenses of ${ife} exceed the de minimis threshold and no other exception applies). The restriction under s.18.2 is computed — Schedule 130 Parts 2F-2L — but from figures that must be supplied rather than derived (gross IFE and IFR, received capacity, prior-year excess capacity, any group ratio amount), and several parts of the schedule are not modelled at all: exempt IFE, capitalized IFE, the partnership and controlled-foreign-affiliate components, and capacity transfers under s.18.2(4). Have this return reviewed by a qualified practitioner before filing.`);
|
|
6892
7435
|
return {
|
|
6893
7436
|
inForce: true,
|
|
6894
7437
|
isExcludedEntity: false,
|
|
@@ -6898,40 +7441,323 @@ function assessEifel(input, thresholds) {
|
|
|
6898
7441
|
};
|
|
6899
7442
|
}
|
|
6900
7443
|
//#endregion
|
|
6901
|
-
//#region src/t2/schedules/
|
|
6902
|
-
const
|
|
6903
|
-
|
|
6904
|
-
|
|
6905
|
-
|
|
6906
|
-
|
|
6907
|
-
|
|
6908
|
-
|
|
6909
|
-
|
|
6910
|
-
},
|
|
6911
|
-
{
|
|
6912
|
-
from: "2012-01-01",
|
|
6913
|
-
multiple: 3.5
|
|
6914
|
-
}
|
|
6915
|
-
];
|
|
6916
|
-
function utcDay$1(iso) {
|
|
6917
|
-
return Date.parse(`${iso.slice(0, 10)}T00:00:00Z`);
|
|
7444
|
+
//#region src/t2/schedules/eifel-ife.ts
|
|
7445
|
+
const nn$17 = (v) => Math.max(0, Math.round(v ?? 0));
|
|
7446
|
+
const sum = (rows, pick) => rows.reduce((s, r) => s + pick(r), 0);
|
|
7447
|
+
function computeExemptIfe(rows) {
|
|
7448
|
+
return {
|
|
7449
|
+
totalExemptIfe: sum(rows, (r) => nn$17(r.ifeIncurred)),
|
|
7450
|
+
incomeFromExemptActivities: sum(rows, (r) => nn$17(r.incomeFromFundedActivities)),
|
|
7451
|
+
lossFromExemptActivities: sum(rows, (r) => nn$17(r.lossFromFundedActivities))
|
|
7452
|
+
};
|
|
6918
7453
|
}
|
|
6919
|
-
|
|
6920
|
-
|
|
6921
|
-
|
|
6922
|
-
|
|
6923
|
-
|
|
6924
|
-
|
|
6925
|
-
return multiple;
|
|
7454
|
+
function computeBorrowings(rows) {
|
|
7455
|
+
return {
|
|
7456
|
+
interestPaidOrPayable: sum(rows, (r) => nn$17(r.interestPaidOrPayable)),
|
|
7457
|
+
fundingCostAmounts: sum(rows, (r) => nn$17(r.fundingCostAmounts)),
|
|
7458
|
+
costReducingAmounts: sum(rows, (r) => nn$17(r.costReducingAmounts))
|
|
7459
|
+
};
|
|
6926
7460
|
}
|
|
6927
|
-
|
|
6928
|
-
|
|
6929
|
-
|
|
6930
|
-
|
|
6931
|
-
|
|
6932
|
-
|
|
6933
|
-
|
|
6934
|
-
|
|
7461
|
+
function computeLoans(rows) {
|
|
7462
|
+
return {
|
|
7463
|
+
returnAmounts: sum(rows, (r) => nn$17(r.returnAmounts)),
|
|
7464
|
+
returnReducingAmounts: sum(rows, (r) => nn$17(r.returnReducingAmounts))
|
|
7465
|
+
};
|
|
7466
|
+
}
|
|
7467
|
+
function computePartnershipIfe(rows) {
|
|
7468
|
+
const computed = rows.map((r) => ({
|
|
7469
|
+
...r.partnershipName !== void 0 ? { partnershipName: r.partnershipName } : {},
|
|
7470
|
+
includedAmount: Math.max(0, nn$17(r.shareOfPartnershipIfe) - nn$17(r.portionUnderParagraph12_1_l1) - nn$17(r.portionDeniedBySubsection96_2_1))
|
|
7471
|
+
}));
|
|
7472
|
+
return {
|
|
7473
|
+
rows: computed,
|
|
7474
|
+
totalIncluded: sum(computed, (r) => r.includedAmount)
|
|
7475
|
+
};
|
|
7476
|
+
}
|
|
7477
|
+
function computeCapitalizedIfe(rows) {
|
|
7478
|
+
const issues = [];
|
|
7479
|
+
const computed = rows.map((r) => {
|
|
7480
|
+
const ifeInUcc = Math.max(0, nn$17(r.ifeInOpeningUcc) + Math.round(r.ifeInAcquisitionsAndDispositions ?? 0));
|
|
7481
|
+
const requested = nn$17(r.ifeInCca);
|
|
7482
|
+
if (requested > ifeInUcc) issues.push(`EIFEL: capitalized IFE in CCA${r.ccaClass ? ` for class ${r.ccaClass}` : ""} (${requested}) cannot exceed the IFE in the pool (${ifeInUcc}). Capped.`);
|
|
7483
|
+
const ifeInCca = Math.min(requested, ifeInUcc);
|
|
7484
|
+
return {
|
|
7485
|
+
...r.ccaClass !== void 0 ? { ccaClass: r.ccaClass } : {},
|
|
7486
|
+
ifeInUcc,
|
|
7487
|
+
ifeInCca,
|
|
7488
|
+
closingIfeInUcc: Math.max(0, ifeInUcc - ifeInCca)
|
|
7489
|
+
};
|
|
7490
|
+
});
|
|
7491
|
+
return {
|
|
7492
|
+
rows: computed,
|
|
7493
|
+
totalIfeInTerminalLoss: sum(rows, (r) => nn$17(r.ifeInTerminalLoss)),
|
|
7494
|
+
totalIfeInCca: sum(computed, (r) => r.ifeInCca),
|
|
7495
|
+
issues
|
|
7496
|
+
};
|
|
7497
|
+
}
|
|
7498
|
+
function computeResourceIfe(rows) {
|
|
7499
|
+
const issues = [];
|
|
7500
|
+
const computed = rows.map((r) => {
|
|
7501
|
+
const ifeAvailable = Math.max(0, nn$17(r.ifeInOpeningBalance) + Math.round(r.ifeAddedOrDeducted ?? 0));
|
|
7502
|
+
const requested = nn$17(r.ifeInCurrentYearClaim);
|
|
7503
|
+
if (requested > ifeAvailable) issues.push(`EIFEL: IFE claimed in the ${r.pool} pool (${requested}) cannot exceed the IFE available before the claim (${ifeAvailable}). Capped.`);
|
|
7504
|
+
const ifeClaimed = Math.min(requested, ifeAvailable);
|
|
7505
|
+
return {
|
|
7506
|
+
pool: r.pool,
|
|
7507
|
+
ifeAvailable,
|
|
7508
|
+
ifeClaimed,
|
|
7509
|
+
closing: Math.max(0, ifeAvailable - ifeClaimed)
|
|
7510
|
+
};
|
|
7511
|
+
});
|
|
7512
|
+
return {
|
|
7513
|
+
rows: computed,
|
|
7514
|
+
totalIfeInResourceClaims: sum(computed, (r) => r.ifeClaimed),
|
|
7515
|
+
issues
|
|
7516
|
+
};
|
|
7517
|
+
}
|
|
7518
|
+
function computeInterestAndFinancingExpenses(input) {
|
|
7519
|
+
const variableA = nn$17(input.interestOnBorrowings) + nn$17(input.otherInterest) + nn$17(input.subsection20_1_eAmounts) + nn$17(input.ifeInCca) + nn$17(input.ifeInResourceExpenses) + nn$17(input.ifeInTerminalLoss) + nn$17(input.fundingCostAmounts) + nn$17(input.fundingCostLoss) + nn$17(input.fundingCostCapitalLoss) + nn$17(input.feeGivingRiseToIfe) + nn$17(input.feeReducingIfe) + nn$17(input.leaseFinancingAmount) + nn$17(input.partnershipShare) + nn$17(input.reinstatedPartnershipLoss) + nn$17(input.affiliateRaife);
|
|
7520
|
+
const variableB = nn$17(input.costReducingAmounts) + nn$17(input.costReducingGain) + nn$17(input.costReducingPartnershipShare);
|
|
7521
|
+
return {
|
|
7522
|
+
variableA,
|
|
7523
|
+
variableB,
|
|
7524
|
+
totalIfe: Math.max(0, variableA - variableB)
|
|
7525
|
+
};
|
|
7526
|
+
}
|
|
7527
|
+
function computeInterestAndFinancingRevenues(input) {
|
|
7528
|
+
const variableA = nn$17(input.interestReceived) + nn$17(input.subsection12_9Amounts) + nn$17(input.guaranteeFees) + nn$17(input.returnAmounts) + nn$17(input.returnGain) + nn$17(input.leaseFinancingAmount) + nn$17(input.partnershipShare) + nn$17(input.affiliateRaifr);
|
|
7529
|
+
const variableB = nn$17(input.returnReducingAmounts) + nn$17(input.returnReducingLoss) + nn$17(input.returnReducingCapitalLoss) + nn$17(input.returnReducingPartnershipShare) + nn$17(input.shelteredByForeignTaxRelief) + nn$17(input.exemptFromPartITax);
|
|
7530
|
+
return {
|
|
7531
|
+
variableA,
|
|
7532
|
+
variableB,
|
|
7533
|
+
totalIfr: Math.max(0, variableA - variableB)
|
|
7534
|
+
};
|
|
7535
|
+
}
|
|
7536
|
+
function computeLossPortionFromIfe(rows) {
|
|
7537
|
+
const issues = [];
|
|
7538
|
+
const computed = rows.map((r) => {
|
|
7539
|
+
const loss = nn$17(r.nonCapitalLoss);
|
|
7540
|
+
const variableJ = Math.min(loss, nn$17(r.variableJSecondAmount));
|
|
7541
|
+
if (loss === 0) {
|
|
7542
|
+
if (nn$17(r.amountDeducted) > 0) issues.push(`EIFEL: a loss deducted under paragraph 111(1)(a)${r.taxYearOfOrigin ? ` from ${r.taxYearOfOrigin}` : ""} was supplied with a nil non-capital loss for that year, so the IFE-attributable portion cannot be apportioned. It contributed nothing.`);
|
|
7543
|
+
return {
|
|
7544
|
+
...r.taxYearOfOrigin !== void 0 ? { taxYearOfOrigin: r.taxYearOfOrigin } : {},
|
|
7545
|
+
variableJ,
|
|
7546
|
+
attributableToIfe: 0
|
|
7547
|
+
};
|
|
7548
|
+
}
|
|
7549
|
+
return {
|
|
7550
|
+
...r.taxYearOfOrigin !== void 0 ? { taxYearOfOrigin: r.taxYearOfOrigin } : {},
|
|
7551
|
+
variableJ,
|
|
7552
|
+
attributableToIfe: Math.round(nn$17(r.amountDeducted) * variableJ / loss)
|
|
7553
|
+
};
|
|
7554
|
+
});
|
|
7555
|
+
return {
|
|
7556
|
+
rows: computed,
|
|
7557
|
+
totalAttributableToIfe: sum(computed, (r) => r.attributableToIfe),
|
|
7558
|
+
issues
|
|
7559
|
+
};
|
|
7560
|
+
}
|
|
7561
|
+
/**
|
|
7562
|
+
* The amount actually denied, and the amount actually added back on Schedule 1
|
|
7563
|
+
* line 251.
|
|
7564
|
+
*
|
|
7565
|
+
* This is NOT simply "the shortfall". Part 2K computes a **proportion** (amount
|
|
7566
|
+
* G) and Part 2L applies it to a base that deliberately excludes two things
|
|
7567
|
+
* already counted elsewhere:
|
|
7568
|
+
*
|
|
7569
|
+
* 141 variable A of IFE
|
|
7570
|
+
* 142 less the partnership share (Part 1E amount A) — denied instead through
|
|
7571
|
+
* the paragraph 12(1)(l.2) add-back in Part 2N
|
|
7572
|
+
* 143 less a CFA's relevant affiliate IFE — denied instead through
|
|
7573
|
+
* clause 95(2)(f.11)(ii)(D) in Part 2M
|
|
7574
|
+
*
|
|
7575
|
+
* With neither of those present the base is variable A and the result equals
|
|
7576
|
+
* the raw shortfall, which is why a simple corporation sees no difference. With
|
|
7577
|
+
* either present, using the shortfall directly double-counts the denial.
|
|
7578
|
+
*/
|
|
7579
|
+
function computeExcessIfe(input) {
|
|
7580
|
+
const base = Math.max(0, nn$17(input.variableAOfIfe) - nn$17(input.partnershipShare) - nn$17(input.affiliateRaife));
|
|
7581
|
+
return {
|
|
7582
|
+
base,
|
|
7583
|
+
excessIfe: Math.round(base * Math.max(0, input.deniedProportion))
|
|
7584
|
+
};
|
|
7585
|
+
}
|
|
7586
|
+
/**
|
|
7587
|
+
* Part 2N line 158 — the partnership IFE add-back under paragraph 12(1)(l.2):
|
|
7588
|
+
* the Part 1E total (line 156) at the Part 2K proportion (line 157). Feeds
|
|
7589
|
+
* Schedule 1 **line 252** and Part 2O **line 160**.
|
|
7590
|
+
*/
|
|
7591
|
+
function computePartnershipIfeAddBack(partnershipShare, deniedProportion) {
|
|
7592
|
+
return Math.round(nn$17(partnershipShare) * Math.max(0, deniedProportion));
|
|
7593
|
+
}
|
|
7594
|
+
/**
|
|
7595
|
+
* @param deniedProportion Amount G from Part 2K — the proportion of each
|
|
7596
|
+
* expense denied under subsection 18.2(2). This is why Part 2M runs after the
|
|
7597
|
+
* limitation rather than before it.
|
|
7598
|
+
*/
|
|
7599
|
+
function computeClause95Amounts(denied, included, deniedProportion) {
|
|
7600
|
+
return {
|
|
7601
|
+
deniedUnderSubclauseI: sum(denied, (r) => Math.round(nn$17(r.variableAForAffiliate) * deniedProportion * (r.specifiedParticipatingPercentage ?? 0))),
|
|
7602
|
+
includedUnderSubclauseII: sum(included, (r) => Math.round(nn$17(r.amountInAffiliateFapi) * (r.specifiedParticipatingPercentage ?? 0)))
|
|
7603
|
+
};
|
|
7604
|
+
}
|
|
7605
|
+
//#endregion
|
|
7606
|
+
//#region src/t2/schedules/eifel-limitation.ts
|
|
7607
|
+
/**
|
|
7608
|
+
* ITA subsection 18.2(2) — the excessive interest and financing expenses
|
|
7609
|
+
* limitation itself.
|
|
7610
|
+
*
|
|
7611
|
+
* `eifel-excluded-entity.ts` decides **whether** the regime applies. This decides
|
|
7612
|
+
* **how much** it denies, which was previously left unbuilt on the grounds that
|
|
7613
|
+
* computing it from an unbuilt definition would be confidently wrong.
|
|
7614
|
+
*
|
|
7615
|
+
* ── The provision ───────────────────────────────────────────────────────────
|
|
7616
|
+
*
|
|
7617
|
+
* s.18.2(2) denies a *proportion* of each interest and financing expense:
|
|
7618
|
+
*
|
|
7619
|
+
* (A − (B + C + D + E)) ÷ F
|
|
7620
|
+
*
|
|
7621
|
+
* A the taxpayer's interest and financing expenses for the year
|
|
7622
|
+
* B the group-ratio amount under s.18.21(2) where that applies, otherwise
|
|
7623
|
+
* **G × H** — the ratio of permissible expenses times adjusted taxable income
|
|
7624
|
+
* C the taxpayer's interest and financing revenues for the year
|
|
7625
|
+
* D received capacity, to the extent it exceeds the amount deductible under
|
|
7626
|
+
* paragraph 111(1)(a.1)
|
|
7627
|
+
* E absorbed capacity
|
|
7628
|
+
* F ordinarily the same figure as A
|
|
7629
|
+
*
|
|
7630
|
+
* Because F is A in the ordinary case, the *amount* denied is simply
|
|
7631
|
+
*
|
|
7632
|
+
* denied = A − (B + C + D + E), floored at nil
|
|
7633
|
+
*
|
|
7634
|
+
* which is the form this module computes, while still reporting the proportion —
|
|
7635
|
+
* the statute denies a fraction of *each* expense, and a preparer allocating the
|
|
7636
|
+
* denial across expense lines needs the fraction rather than the total.
|
|
7637
|
+
*
|
|
7638
|
+
* ── The ratio of permissible expenses ───────────────────────────────────────
|
|
7639
|
+
*
|
|
7640
|
+
* Keyed off when the taxation year **BEGINS**, not when it ends:
|
|
7641
|
+
*
|
|
7642
|
+
* begins on or after 2023-10-01 and before 2024-01-01 → **40%**
|
|
7643
|
+
* begins on or after 2024-01-01 → **30%**
|
|
7644
|
+
*
|
|
7645
|
+
* The 40% band is transitional and narrow — one quarter — and it does **not**
|
|
7646
|
+
* apply when determining cumulative unused excess capacity for a year beginning
|
|
7647
|
+
* on or after 1 January 2024. That carve-out is not modelled; excess-capacity
|
|
7648
|
+
* carry-forward is a separate mechanism this module does not compute.
|
|
7649
|
+
*
|
|
7650
|
+
* ── What this module does NOT compute ───────────────────────────────────────
|
|
7651
|
+
*
|
|
7652
|
+
* **Adjusted taxable income** is an input to THIS module, not a derivation — it
|
|
7653
|
+
* is a build-up from taxable income through a dozen add-backs and reductions,
|
|
7654
|
+
* and deriving it partially here would produce a plausible number from an
|
|
7655
|
+
* incomplete definition. It is therefore **required**, and an absent one denies
|
|
7656
|
+
* nothing while saying so. `eifel-adjusted-taxable-income.ts` derives it
|
|
7657
|
+
* (Schedule 130 Part 2F), and `computeFederalT2` feeds that result in.
|
|
7658
|
+
*
|
|
7659
|
+
* Likewise the received and absorbed capacity amounts, which come from the
|
|
7660
|
+
* excess-capacity regime — `eifel-capacity.ts` computes those (Parts 1A and
|
|
7661
|
+
* 2G-2J), and the engine threads them in as `excessReceivedCapacity` (Part 2K
|
|
7662
|
+
* amount C) and `absorbedCapacity` (Part 2H amount D). The group-ratio election
|
|
7663
|
+
* under s.18.21 remains a preparer assertion.
|
|
7664
|
+
*
|
|
7665
|
+
* Source: `research/sources/legislation/ITA-section-18.2-EIFEL.txt`.
|
|
7666
|
+
*
|
|
7667
|
+
* Pure, whole dollars.
|
|
7668
|
+
*/
|
|
7669
|
+
/** The ratio bands, keyed off the taxation year START. */
|
|
7670
|
+
const EIFEL_TRANSITIONAL_RATIO = .4;
|
|
7671
|
+
const EIFEL_STANDARD_RATIO = .3;
|
|
7672
|
+
/** The regime's first day — years beginning before this are outside it. */
|
|
7673
|
+
const EIFEL_FIRST_YEAR_START = "2023-10-01";
|
|
7674
|
+
/** The transitional 40% band ends when years beginning in 2024 start. */
|
|
7675
|
+
const EIFEL_STANDARD_RATIO_FROM = "2024-01-01";
|
|
7676
|
+
const nn$16 = (v) => Math.max(0, Math.round(v ?? 0));
|
|
7677
|
+
function utcDay$1(iso) {
|
|
7678
|
+
return Date.parse(`${iso.slice(0, 10)}T00:00:00Z`);
|
|
7679
|
+
}
|
|
7680
|
+
/**
|
|
7681
|
+
* The ratio of permissible expenses for a year beginning on `taxYearStart`.
|
|
7682
|
+
* Returns 0 for a year beginning before the regime applies at all.
|
|
7683
|
+
*/
|
|
7684
|
+
function ratioOfPermissibleExpenses(taxYearStart) {
|
|
7685
|
+
const start = utcDay$1(taxYearStart);
|
|
7686
|
+
if (Number.isNaN(start) || start < utcDay$1("2023-10-01")) return 0;
|
|
7687
|
+
return start < utcDay$1("2024-01-01") ? EIFEL_TRANSITIONAL_RATIO : EIFEL_STANDARD_RATIO;
|
|
7688
|
+
}
|
|
7689
|
+
function computeEifelLimitation(input) {
|
|
7690
|
+
const issues = [];
|
|
7691
|
+
const ife = nn$16(input.interestAndFinancingExpenses);
|
|
7692
|
+
const nil = (ratio) => ({
|
|
7693
|
+
ratioOfPermissibleExpenses: ratio,
|
|
7694
|
+
permittedAmount: 0,
|
|
7695
|
+
usedGroupRatio: false,
|
|
7696
|
+
totalShelter: 0,
|
|
7697
|
+
deniedAmount: 0,
|
|
7698
|
+
deniedProportion: 0,
|
|
7699
|
+
deductibleAmount: ife,
|
|
7700
|
+
issues
|
|
7701
|
+
});
|
|
7702
|
+
const ratio = ratioOfPermissibleExpenses(input.taxYearStart);
|
|
7703
|
+
if (ratio === 0) {
|
|
7704
|
+
issues.push(`EIFEL: the taxation year beginning ${input.taxYearStart} is before the regime applies (${EIFEL_FIRST_YEAR_START}), so nothing is denied.`);
|
|
7705
|
+
return nil(0);
|
|
7706
|
+
}
|
|
7707
|
+
const usedGroupRatio = input.groupRatioAmount !== void 0;
|
|
7708
|
+
if (!usedGroupRatio && input.adjustedTaxableIncome === void 0) {
|
|
7709
|
+
issues.push("EIFEL: adjusted taxable income was not supplied, so no interest and financing expense was denied. The limitation cannot be computed without it — the figure is a build-up from taxable income that this engine does not derive, and it must be supplied or the return reviewed by hand.");
|
|
7710
|
+
return nil(ratio);
|
|
7711
|
+
}
|
|
7712
|
+
const permittedAmount = usedGroupRatio ? nn$16(input.groupRatioAmount) : Math.round(ratio * Math.max(0, input.adjustedTaxableIncome ?? 0));
|
|
7713
|
+
const totalShelter = permittedAmount + nn$16(input.interestAndFinancingRevenues) + nn$16(input.excessReceivedCapacity) + nn$16(input.absorbedCapacity);
|
|
7714
|
+
const deniedAmount = Math.max(0, ife - totalShelter);
|
|
7715
|
+
return {
|
|
7716
|
+
ratioOfPermissibleExpenses: ratio,
|
|
7717
|
+
permittedAmount,
|
|
7718
|
+
usedGroupRatio,
|
|
7719
|
+
totalShelter,
|
|
7720
|
+
deniedAmount,
|
|
7721
|
+
deniedProportion: ife > 0 ? deniedAmount / ife : 0,
|
|
7722
|
+
deductibleAmount: ife - deniedAmount,
|
|
7723
|
+
issues
|
|
7724
|
+
};
|
|
7725
|
+
}
|
|
7726
|
+
//#endregion
|
|
7727
|
+
//#region src/t2/schedules/part-vi-1-deduction.ts
|
|
7728
|
+
const PART_VI_1_DEDUCTION_BANDS = [
|
|
7729
|
+
{
|
|
7730
|
+
from: "0000-01-01",
|
|
7731
|
+
multiple: 3
|
|
7732
|
+
},
|
|
7733
|
+
{
|
|
7734
|
+
from: "2010-01-01",
|
|
7735
|
+
multiple: 3.2
|
|
7736
|
+
},
|
|
7737
|
+
{
|
|
7738
|
+
from: "2012-01-01",
|
|
7739
|
+
multiple: 3.5
|
|
7740
|
+
}
|
|
7741
|
+
];
|
|
7742
|
+
function utcDay(iso) {
|
|
7743
|
+
return Date.parse(`${iso.slice(0, 10)}T00:00:00Z`);
|
|
7744
|
+
}
|
|
7745
|
+
/** The multiple in force for a taxation year ending on `taxYearEnd`. */
|
|
7746
|
+
function partVI1DeductionMultiple(taxYearEnd, bands = PART_VI_1_DEDUCTION_BANDS) {
|
|
7747
|
+
const end = utcDay(taxYearEnd);
|
|
7748
|
+
if (Number.isNaN(end)) return 0;
|
|
7749
|
+
let multiple = 0;
|
|
7750
|
+
for (const band of [...bands].sort((a, b) => utcDay(a.from) - utcDay(b.from))) if (end >= utcDay(band.from)) multiple = band.multiple;
|
|
7751
|
+
return multiple;
|
|
7752
|
+
}
|
|
7753
|
+
/**
|
|
7754
|
+
* The paragraph 110(1)(k) deduction.
|
|
7755
|
+
*
|
|
7756
|
+
* An unreadable year end yields nil and says so, rather than defaulting to the
|
|
7757
|
+
* current multiple — guessing the year would misstate taxable income, and this
|
|
7758
|
+
* deduction is large relative to the tax it follows.
|
|
7759
|
+
*/
|
|
7760
|
+
function computePartVI1Deduction(partVI1Tax, taxYearEnd, bands = PART_VI_1_DEDUCTION_BANDS) {
|
|
6935
7761
|
const issues = [];
|
|
6936
7762
|
const tax = Math.max(0, Math.round(partVI1Tax));
|
|
6937
7763
|
const multiple = partVI1DeductionMultiple(taxYearEnd, bands);
|
|
@@ -7080,10 +7906,10 @@ function assertSchedule1Fileable(result) {
|
|
|
7080
7906
|
}
|
|
7081
7907
|
//#endregion
|
|
7082
7908
|
//#region src/t2/schedules/schedule2-donations.ts
|
|
7083
|
-
const nn$
|
|
7909
|
+
const nn$15 = (v) => Math.max(0, v ?? 0);
|
|
7084
7910
|
function computeSchedule2(input, rates) {
|
|
7085
|
-
const openingDonationPool = nn$
|
|
7086
|
-
const currentYearDonations = nn$
|
|
7911
|
+
const openingDonationPool = nn$15(input.openingDonationPool);
|
|
7912
|
+
const currentYearDonations = nn$15(input.currentYearDonations);
|
|
7087
7913
|
const available = openingDonationPool + currentYearDonations;
|
|
7088
7914
|
const deductionLimit = Math.max(0, Math.round(rates.DONATION_INCOME_LIMIT_RATE * input.netIncomeForTax));
|
|
7089
7915
|
const donationsClaimed = Math.min(available, deductionLimit);
|
|
@@ -7122,25 +7948,25 @@ function computeSchedule2(input, rates) {
|
|
|
7122
7948
|
const PART_IV_RATE = 115 / 300;
|
|
7123
7949
|
/** 30⅔% — the refundable portion of Part I tax on aggregate investment income. */
|
|
7124
7950
|
const REFUNDABLE_PART_I_RATE = 92 / 300;
|
|
7125
|
-
const nn$
|
|
7951
|
+
const nn$14 = (v) => Math.max(0, v ?? 0);
|
|
7126
7952
|
const DEFAULT_PART4_RATES = {
|
|
7127
7953
|
PART_IV_RATE,
|
|
7128
7954
|
REFUNDABLE_PART_I_RATE
|
|
7129
7955
|
};
|
|
7130
7956
|
function computePart4Rdtoh(input, rates = DEFAULT_PART4_RATES) {
|
|
7131
|
-
const portfolio = nn$
|
|
7132
|
-
const eligible = Math.min(portfolio, nn$
|
|
7957
|
+
const portfolio = nn$14(input.portfolioDividendsReceived);
|
|
7958
|
+
const eligible = Math.min(portfolio, nn$14(input.eligiblePortfolioDividends));
|
|
7133
7959
|
const nonEligible = portfolio - eligible;
|
|
7134
|
-
const aaii = nn$
|
|
7960
|
+
const aaii = nn$14(input.aggregateInvestmentIncome);
|
|
7135
7961
|
const partIvOnEligible = Math.round(eligible * rates.PART_IV_RATE);
|
|
7136
7962
|
const partIvOnNonEligible = Math.round(nonEligible * rates.PART_IV_RATE);
|
|
7137
7963
|
const partIvTax = partIvOnEligible + partIvOnNonEligible;
|
|
7138
7964
|
const refundablePartI = Math.round(aaii * rates.REFUNDABLE_PART_I_RATE);
|
|
7139
7965
|
const erdtohAddition = partIvOnEligible;
|
|
7140
7966
|
const nerdtohAddition = partIvOnNonEligible + refundablePartI;
|
|
7141
|
-
const erdtohClosing = nn$
|
|
7142
|
-
const nerdtohClosing = nn$
|
|
7143
|
-
const refundClaim = Math.round(nn$
|
|
7967
|
+
const erdtohClosing = nn$14(input.openingErdtoh) + erdtohAddition;
|
|
7968
|
+
const nerdtohClosing = nn$14(input.openingNerdtoh) + nerdtohAddition;
|
|
7969
|
+
const refundClaim = Math.round(nn$14(input.taxableDividendsPaid) * PART_IV_RATE);
|
|
7144
7970
|
return {
|
|
7145
7971
|
partIvTax,
|
|
7146
7972
|
refundablePartI,
|
|
@@ -7304,7 +8130,7 @@ const PROVINCE_NAMES = {
|
|
|
7304
8130
|
AB: "Alberta",
|
|
7305
8131
|
QC: "Quebec"
|
|
7306
8132
|
};
|
|
7307
|
-
const nn$
|
|
8133
|
+
const nn$13 = (v) => Math.max(0, v ?? 0);
|
|
7308
8134
|
function computeProvincialAllocation(input, rates = PROVINCE_RATES_2024) {
|
|
7309
8135
|
const byProvince = /* @__PURE__ */ new Map();
|
|
7310
8136
|
for (const pe of input.permanentEstablishments) {
|
|
@@ -7313,8 +8139,8 @@ function computeProvincialAllocation(input, rates = PROVINCE_RATES_2024) {
|
|
|
7313
8139
|
grossRevenue: 0,
|
|
7314
8140
|
salariesWages: 0
|
|
7315
8141
|
};
|
|
7316
|
-
cur.grossRevenue += nn$
|
|
7317
|
-
cur.salariesWages += nn$
|
|
8142
|
+
cur.grossRevenue += nn$13(pe.grossRevenue);
|
|
8143
|
+
cur.salariesWages += nn$13(pe.salariesWages);
|
|
7318
8144
|
byProvince.set(key, cur);
|
|
7319
8145
|
}
|
|
7320
8146
|
const totalRevenue = [...byProvince.values()].reduce((s, p) => s + p.grossRevenue, 0);
|
|
@@ -7458,7 +8284,7 @@ function computeSchedule6(dispositions, inclusionRate) {
|
|
|
7458
8284
|
*
|
|
7459
8285
|
* Whole dollars, pure functions, no I/O.
|
|
7460
8286
|
*/
|
|
7461
|
-
const nn$
|
|
8287
|
+
const nn$12 = (v) => Math.max(0, v ?? 0);
|
|
7462
8288
|
const round = (v) => Math.round(v);
|
|
7463
8289
|
/** CDE/CCOGPE-style short-tax-year proration: full rate at ≥357 days, else rate × days/365. */
|
|
7464
8290
|
function stepYearFactor(daysInTaxYear) {
|
|
@@ -7493,13 +8319,13 @@ function forcedOrCappedClaim(requested, subtotal, issues, label) {
|
|
|
7493
8319
|
}
|
|
7494
8320
|
function computeDepletion(input = {}) {
|
|
7495
8321
|
const issues = [];
|
|
7496
|
-
const edaRegularPool = nn$
|
|
8322
|
+
const edaRegularPool = nn$12(input.edaRegularOpening);
|
|
7497
8323
|
const edaRegularClaim = claimUpToCap(input.edaRegularClaim, edaRegularPool, issues, "Schedule 12 EDA regular (115)");
|
|
7498
8324
|
const edaRegularClosing = edaRegularPool - edaRegularClaim;
|
|
7499
|
-
const edaSuccessorPool = nn$
|
|
8325
|
+
const edaSuccessorPool = nn$12(input.edaSuccessorOpening);
|
|
7500
8326
|
const edaSuccessorClaim = claimUpToCap(input.edaSuccessorClaim, edaSuccessorPool, issues, "Schedule 12 EDA successor (140)");
|
|
7501
8327
|
const edaSuccessorClosing = edaSuccessorPool - edaSuccessorClaim;
|
|
7502
|
-
const cmedbPool = nn$
|
|
8328
|
+
const cmedbPool = nn$12(input.cmedbOpening);
|
|
7503
8329
|
const cmedbClaim = claimUpToCap(input.cmedbClaim, cmedbPool, issues, "Schedule 12 CMEDB (170)");
|
|
7504
8330
|
return {
|
|
7505
8331
|
edaRegularPool,
|
|
@@ -7517,10 +8343,10 @@ function computeDepletion(input = {}) {
|
|
|
7517
8343
|
}
|
|
7518
8344
|
function computeCee(input = {}) {
|
|
7519
8345
|
const issues = [];
|
|
7520
|
-
const regularSubtotal = nn$
|
|
8346
|
+
const regularSubtotal = nn$12(input.regularOpening) + nn$12(input.regularCurrentYearExpenses) + nn$12(input.regularOtherAdditions) - nn$12(input.regularGovernmentAssistance) - nn$12(input.regularOtherDeductions);
|
|
7521
8347
|
const regularClaim = forcedOrCappedClaim(input.regularClaim, regularSubtotal, issues, "Schedule 12 CEE regular (245)");
|
|
7522
8348
|
const regularClosing = regularSubtotal > 0 ? regularSubtotal - regularClaim : 0;
|
|
7523
|
-
const successorSubtotal = nn$
|
|
8349
|
+
const successorSubtotal = nn$12(input.successorOpening) - nn$12(input.successorOtherDeductions);
|
|
7524
8350
|
const successorClaim = forcedOrCappedClaim(input.successorClaim, successorSubtotal, issues, "Schedule 12 CEE successor (295)");
|
|
7525
8351
|
return {
|
|
7526
8352
|
regularSubtotal,
|
|
@@ -7542,15 +8368,15 @@ function computeCde(input = {}, daysInTaxYear, cogpe = {
|
|
|
7542
8368
|
successorSubtotal: 0
|
|
7543
8369
|
}) {
|
|
7544
8370
|
const issues = [];
|
|
7545
|
-
const regularCreditBalance = cogpe.regularSubtotal < 0 ? round(cogpe.regularSubtotal) : nn$
|
|
7546
|
-
const regularSubtotal = nn$
|
|
7547
|
-
const rcdePortion = Math.min(nn$
|
|
8371
|
+
const regularCreditBalance = cogpe.regularSubtotal < 0 ? round(cogpe.regularSubtotal) : nn$12(input.regularCreditBalanceInCogpePool);
|
|
8372
|
+
const regularSubtotal = nn$12(input.regularOpening) + nn$12(input.regularCurrentYearExpenses) + nn$12(input.regularOtherAdditions) - nn$12(input.regularGovernmentAssistance) - nn$12(input.regularReceivableOnDisposition) - regularCreditBalance - nn$12(input.regularOtherDeductions);
|
|
8373
|
+
const rcdePortion = Math.min(nn$12(input.regularCurrentYearExpenses), Math.max(0, regularSubtotal));
|
|
7548
8374
|
const regularCap = CDE_BASE_RATE * stepYearFactor(daysInTaxYear) * regularSubtotal + CDE_RCDE_BONUS_RATE * stepYearFactor(daysInTaxYear) * rcdePortion;
|
|
7549
8375
|
const regularClaim = regularSubtotal > 0 ? claimUpToCap(input.regularClaim, regularCap, issues, "Schedule 12 CDE regular (345)") : 0;
|
|
7550
8376
|
const regularClosing = Math.max(0, regularSubtotal - regularClaim);
|
|
7551
8377
|
if (regularSubtotal < 0) issues.push("Schedule 12 CDE regular (345): the pool subtotal is negative — per the form, include it as income in \"Other additions\" on Schedule 1 (this module does not auto-apply that; add a manual Schedule 1 addition for the negative amount).");
|
|
7552
|
-
const successorCreditBalance = cogpe.successorSubtotal < 0 ? round(cogpe.successorSubtotal) : nn$
|
|
7553
|
-
const successorSubtotal = nn$
|
|
8378
|
+
const successorCreditBalance = cogpe.successorSubtotal < 0 ? round(cogpe.successorSubtotal) : nn$12(input.successorCreditBalanceInCogpePool);
|
|
8379
|
+
const successorSubtotal = nn$12(input.successorOpening) - successorCreditBalance - nn$12(input.successorOtherDeductions);
|
|
7554
8380
|
const successorCap = CDE_BASE_RATE * stepYearFactor(daysInTaxYear) * successorSubtotal;
|
|
7555
8381
|
const successorClaim = successorSubtotal > 0 ? claimUpToCap(input.successorClaim, successorCap, issues, "Schedule 12 CDE successor (395)") : 0;
|
|
7556
8382
|
return {
|
|
@@ -7570,13 +8396,13 @@ const COGPE_BASE_RATE = .1;
|
|
|
7570
8396
|
const COGPE_RCOGPE_BONUS_RATE = .05;
|
|
7571
8397
|
function computeCogpe(input = {}, daysInTaxYear) {
|
|
7572
8398
|
const issues = [];
|
|
7573
|
-
const regularSubtotal = nn$
|
|
7574
|
-
const rcogpePortion = Math.min(nn$
|
|
8399
|
+
const regularSubtotal = nn$12(input.regularOpening) + nn$12(input.regularCurrentYearExpenses) + nn$12(input.regularOtherAdditions) - nn$12(input.regularReceivableOnDisposition) - nn$12(input.regularGovernmentAssistance) - nn$12(input.regularOtherDeductions);
|
|
8400
|
+
const rcogpePortion = Math.min(nn$12(input.regularCurrentYearExpenses), Math.max(0, regularSubtotal));
|
|
7575
8401
|
const regularCap = COGPE_BASE_RATE * stepYearFactor(daysInTaxYear) * regularSubtotal + COGPE_RCOGPE_BONUS_RATE * stepYearFactor(daysInTaxYear) * rcogpePortion;
|
|
7576
8402
|
const regularClaim = regularSubtotal > 0 ? claimUpToCap(input.regularClaim, regularCap, issues, "Schedule 12 COGPE regular (445)") : 0;
|
|
7577
8403
|
const regularClosing = regularSubtotal > 0 ? regularSubtotal - regularClaim : 0;
|
|
7578
8404
|
if (regularSubtotal < 0) issues.push("Schedule 12 COGPE regular (445): the pool subtotal is negative. Per the form this carries to CDE regular line 330 (no s.66.7(4)(a)(iii) designation) or CDE successor line 380 (with a designation) — computeCde auto-applies the 330 route unconditionally when this subtotal is negative; confirm the designation status before relying on that routing.");
|
|
7579
|
-
const successorSubtotal = nn$
|
|
8405
|
+
const successorSubtotal = nn$12(input.successorOpening) - nn$12(input.successorReceivableOnDisposition) - nn$12(input.successorOtherDeductions);
|
|
7580
8406
|
const successorCap = COGPE_BASE_RATE * stepYearFactor(daysInTaxYear) * successorSubtotal;
|
|
7581
8407
|
const successorClaim = successorSubtotal > 0 ? claimUpToCap(input.successorClaim, successorCap, issues, "Schedule 12 COGPE successor (495)") : 0;
|
|
7582
8408
|
const successorClosing = Math.max(0, successorSubtotal - successorClaim);
|
|
@@ -7595,18 +8421,18 @@ function computeCogpe(input = {}, daysInTaxYear) {
|
|
|
7595
8421
|
/** Part 7 — Foreign exploration and development expenses (pre-2001 tax years; still a real, if rare, carryforward). */
|
|
7596
8422
|
function computeForeignExploration(input = {}, daysInTaxYear) {
|
|
7597
8423
|
const issues = [];
|
|
7598
|
-
const regularPool = nn$
|
|
8424
|
+
const regularPool = nn$12(input.regularOpening) - nn$12(input.regularOtherDeductions);
|
|
7599
8425
|
let regularClaim = 0;
|
|
7600
8426
|
if (regularPool < 0) issues.push("Schedule 12 FEDE regular (520): the pool balance is negative — include it as income in \"Other additions\" on Schedule 1 (not auto-applied by this module).");
|
|
7601
8427
|
else if (regularPool > 0) {
|
|
7602
|
-
const cap = Math.max(COGPE_BASE_RATE * stepYearFactor(daysInTaxYear) * regularPool, nn$
|
|
8428
|
+
const cap = Math.max(COGPE_BASE_RATE * stepYearFactor(daysInTaxYear) * regularPool, nn$12(input.regularForeignResourceIncome));
|
|
7603
8429
|
regularClaim = claimUpToCap(input.regularClaim, Math.min(regularPool, cap), issues, "Schedule 12 FEDE regular (520)");
|
|
7604
8430
|
}
|
|
7605
8431
|
const regularClosing = regularPool - regularClaim;
|
|
7606
|
-
const successorPool = nn$
|
|
8432
|
+
const successorPool = nn$12(input.successorOpening) - nn$12(input.successorOtherDeductions);
|
|
7607
8433
|
let successorClaim = 0;
|
|
7608
8434
|
if (successorPool < 0) issues.push("Schedule 12 FEDE successor (570): the pool balance is negative — include it as income in \"Other additions\" on Schedule 1 (not auto-applied by this module).");
|
|
7609
|
-
else if (successorPool > 0) successorClaim = claimUpToCap(input.successorClaim, Math.min(successorPool, nn$
|
|
8435
|
+
else if (successorPool > 0) successorClaim = claimUpToCap(input.successorClaim, Math.min(successorPool, nn$12(input.successorForeignResourceIncome)), issues, "Schedule 12 FEDE successor (570)");
|
|
7610
8436
|
const successorClosing = successorPool - successorClaim;
|
|
7611
8437
|
return {
|
|
7612
8438
|
regularPool,
|
|
@@ -7621,10 +8447,10 @@ function computeForeignExploration(input = {}, daysInTaxYear) {
|
|
|
7621
8447
|
/** Part 8 — specified foreign exploration/development, regular OR successor (call once per column; rates are identical). */
|
|
7622
8448
|
function computeSpecifiedForeignExploration(input = {}, label) {
|
|
7623
8449
|
const issues = [];
|
|
7624
|
-
const pool = nn$
|
|
8450
|
+
const pool = nn$12(input.openingBalance) - nn$12(input.otherDeductions);
|
|
7625
8451
|
let claim = 0;
|
|
7626
8452
|
if (pool < 0) issues.push(`${label}: a country-level pool is negative — include it as income on Schedule 1 manually.`);
|
|
7627
|
-
else if (pool > 0) claim = claimUpToCap(input.claim, Math.min(pool, Math.max(nn$
|
|
8453
|
+
else if (pool > 0) claim = claimUpToCap(input.claim, Math.min(pool, Math.max(nn$12(input.foreignResourceIncome), pool)), issues, label);
|
|
7628
8454
|
return {
|
|
7629
8455
|
pool,
|
|
7630
8456
|
claim,
|
|
@@ -7635,12 +8461,12 @@ function computeSpecifiedForeignExploration(input = {}, label) {
|
|
|
7635
8461
|
/** Part 9 — cumulative foreign resource expenses, regular OR successor. */
|
|
7636
8462
|
function computeCumulativeForeignResource(input = {}, daysInTaxYear, label) {
|
|
7637
8463
|
const issues = [];
|
|
7638
|
-
const pool = nn$
|
|
8464
|
+
const pool = nn$12(input.openingBalance) + nn$12(input.currentYearExpenses) - nn$12(input.otherDeductions);
|
|
7639
8465
|
let claim = 0;
|
|
7640
8466
|
if (pool < 0) issues.push(`${label}: a country-level pool is negative — include it as income on Schedule 1 manually.`);
|
|
7641
8467
|
else if (pool > 0) {
|
|
7642
|
-
const a = Math.max(.1 * stepYearFactor(daysInTaxYear) * pool, Math.min(.3 * stepYearFactor(daysInTaxYear) * pool, nn$
|
|
7643
|
-
const cap = a + Math.min(pool - a, nn$
|
|
8468
|
+
const a = Math.max(.1 * stepYearFactor(daysInTaxYear) * pool, Math.min(.3 * stepYearFactor(daysInTaxYear) * pool, nn$12(input.foreignResourceIncome)));
|
|
8469
|
+
const cap = a + Math.min(pool - a, nn$12(input.foreignResourceIncome));
|
|
7644
8470
|
claim = claimUpToCap(input.claim, Math.min(pool, cap), issues, label);
|
|
7645
8471
|
}
|
|
7646
8472
|
return {
|
|
@@ -7694,15 +8520,15 @@ function computeSchedule12ResourceDeductions(input) {
|
|
|
7694
8520
|
}
|
|
7695
8521
|
//#endregion
|
|
7696
8522
|
//#region src/t2/schedules/schedule13-reserves.ts
|
|
7697
|
-
const nn$
|
|
8523
|
+
const nn$11 = (v) => Math.max(0, Math.round(v ?? 0));
|
|
7698
8524
|
function computeSchedule13(rows = []) {
|
|
7699
8525
|
let totalOpening = 0;
|
|
7700
8526
|
let totalTransfer = 0;
|
|
7701
8527
|
let totalClosing = 0;
|
|
7702
8528
|
for (const r of rows) {
|
|
7703
|
-
totalOpening += nn$
|
|
7704
|
-
totalTransfer += nn$
|
|
7705
|
-
totalClosing += nn$
|
|
8529
|
+
totalOpening += nn$11(r.opening);
|
|
8530
|
+
totalTransfer += nn$11(r.transfer);
|
|
8531
|
+
totalClosing += nn$11(r.closing);
|
|
7706
8532
|
}
|
|
7707
8533
|
const schedule1Addition = totalOpening + totalTransfer;
|
|
7708
8534
|
const schedule1Deduction = totalClosing;
|
|
@@ -7717,15 +8543,15 @@ function computeSchedule13(rows = []) {
|
|
|
7717
8543
|
}
|
|
7718
8544
|
//#endregion
|
|
7719
8545
|
//#region src/t2/schedules/schedule21-foreign-tax-credit.ts
|
|
7720
|
-
const nn$
|
|
8546
|
+
const nn$10 = (v) => Math.max(0, v ?? 0);
|
|
7721
8547
|
function computeSchedule21(input) {
|
|
7722
8548
|
const taxableIncome = input.taxableIncome;
|
|
7723
|
-
const partITax = nn$
|
|
7724
|
-
const fNonBizIncome = nn$
|
|
7725
|
-
const fNonBizTax = nn$
|
|
7726
|
-
const fBizIncome = nn$
|
|
7727
|
-
const fBizTax = nn$
|
|
7728
|
-
const openingPool = nn$
|
|
8549
|
+
const partITax = nn$10(input.partITax);
|
|
8550
|
+
const fNonBizIncome = nn$10(input.foreignNonBusinessIncome);
|
|
8551
|
+
const fNonBizTax = nn$10(input.foreignNonBusinessTaxPaid);
|
|
8552
|
+
const fBizIncome = nn$10(input.foreignBusinessIncome);
|
|
8553
|
+
const fBizTax = nn$10(input.foreignBusinessTaxPaid);
|
|
8554
|
+
const openingPool = nn$10(input.openingBusinessFtcPool);
|
|
7729
8555
|
if (taxableIncome <= 0 || partITax <= 0) return {
|
|
7730
8556
|
nonBusinessFtc: 0,
|
|
7731
8557
|
businessFtc: 0,
|
|
@@ -7795,11 +8621,11 @@ function allocateEvenly(count, totalLimit = DEFAULT_BUSINESS_LIMIT) {
|
|
|
7795
8621
|
}
|
|
7796
8622
|
//#endregion
|
|
7797
8623
|
//#region src/t2/schedules/schedule27-zetm.ts
|
|
7798
|
-
const nn$
|
|
8624
|
+
const nn$9 = (v) => Math.max(0, v ?? 0);
|
|
7799
8625
|
function computeZetm(input, rates) {
|
|
7800
|
-
const sbdIncome = nn$
|
|
7801
|
-
const generalRateIncome = nn$
|
|
7802
|
-
const zetmIncome = Math.min(nn$
|
|
8626
|
+
const sbdIncome = nn$9(input.sbdIncome);
|
|
8627
|
+
const generalRateIncome = nn$9(input.generalRateIncome);
|
|
8628
|
+
const zetmIncome = Math.min(nn$9(input.zetmIncome), sbdIncome + generalRateIncome);
|
|
7803
8629
|
const zetmSbdIncome = Math.min(zetmIncome, sbdIncome);
|
|
7804
8630
|
const zetmGeneralIncome = Math.min(zetmIncome - zetmSbdIncome, generalRateIncome);
|
|
7805
8631
|
const sbdDifferential = Math.max(0, input.sbdEffectiveRate - rates.ZETM_SBD_RATE);
|
|
@@ -7872,13 +8698,13 @@ function computeZetm(input, rates) {
|
|
|
7872
8698
|
*/
|
|
7873
8699
|
/** s.127(27)-(29) — the recapture window. */
|
|
7874
8700
|
const ITC_RECAPTURE_PERIOD_YEARS = 20;
|
|
7875
|
-
const nn$
|
|
8701
|
+
const nn$8 = (v) => Math.max(0, Math.round(v ?? 0));
|
|
7876
8702
|
function computeItcRecapture(items) {
|
|
7877
8703
|
const issues = [];
|
|
7878
8704
|
const results = items.map((item) => {
|
|
7879
8705
|
const label = item.description ? ` (${item.description})` : "";
|
|
7880
8706
|
const usedFairMarketValue = item.armsLengthProceeds === void 0;
|
|
7881
|
-
const dispositionValue = usedFairMarketValue ? nn$
|
|
8707
|
+
const dispositionValue = usedFairMarketValue ? nn$8(item.fairMarketValue) : nn$8(item.armsLengthProceeds);
|
|
7882
8708
|
if (usedFairMarketValue && item.fairMarketValue === void 0) issues.push(`ITC recapture${label}: neither arm's length proceeds nor a fair market value was supplied, so the recapture computed as nil. A disposition or conversion needs one of the two.`);
|
|
7883
8709
|
const outsideRecapturePeriod = item.yearsSinceCredit !== void 0 && item.yearsSinceCredit > 20;
|
|
7884
8710
|
const base = {
|
|
@@ -7891,12 +8717,12 @@ function computeItcRecapture(items) {
|
|
|
7891
8717
|
outsideRecapturePeriod
|
|
7892
8718
|
};
|
|
7893
8719
|
if (outsideRecapturePeriod) return base;
|
|
7894
|
-
const ownRecapture = Math.min(nn$
|
|
8720
|
+
const ownRecapture = Math.min(nn$8(item.itcEarned), Math.round(Math.max(0, item.itcRate) * dispositionValue));
|
|
7895
8721
|
let transferredRecapture = 0;
|
|
7896
8722
|
if (item.transferred) {
|
|
7897
8723
|
const t = item.transferred;
|
|
7898
|
-
const formula = Math.round(Math.max(0, t.transfereeItcRate) * dispositionValue) - nn$
|
|
7899
|
-
transferredRecapture = Math.max(0, Math.min(nn$
|
|
8724
|
+
const formula = Math.round(Math.max(0, t.transfereeItcRate) * dispositionValue) - nn$8(t.alreadyRecaptured);
|
|
8725
|
+
transferredRecapture = Math.max(0, Math.min(nn$8(t.transfereeItcEarned), formula));
|
|
7900
8726
|
}
|
|
7901
8727
|
return {
|
|
7902
8728
|
...base,
|
|
@@ -7913,9 +8739,9 @@ function computeItcRecapture(items) {
|
|
|
7913
8739
|
}
|
|
7914
8740
|
//#endregion
|
|
7915
8741
|
//#region src/t2/schedules/schedule31-sred-itc.ts
|
|
7916
|
-
const nn$
|
|
8742
|
+
const nn$7 = (v) => Math.max(0, v ?? 0);
|
|
7917
8743
|
function computeSchedule31(input, rates) {
|
|
7918
|
-
const qualifiedExpenditures = nn$
|
|
8744
|
+
const qualifiedExpenditures = nn$7(input.qualifiedExpenditures);
|
|
7919
8745
|
const isCcpc = input.isCcpc ?? false;
|
|
7920
8746
|
const expenditureLimit = input.expenditureLimit ?? rates.SRED_EXPENDITURE_LIMIT;
|
|
7921
8747
|
const enhancedBase = isCcpc ? Math.min(qualifiedExpenditures, expenditureLimit) : 0;
|
|
@@ -7924,8 +8750,8 @@ function computeSchedule31(input, rates) {
|
|
|
7924
8750
|
const basicItc = Math.round(rates.SRED_ITC_BASIC_RATE * basicBase);
|
|
7925
8751
|
const itcEarned = enhancedItc + basicItc;
|
|
7926
8752
|
const refundableItc = enhancedItc;
|
|
7927
|
-
const availableNonRefundable = basicItc + nn$
|
|
7928
|
-
const itcAppliedAgainstTax = Math.min(availableNonRefundable, nn$
|
|
8753
|
+
const availableNonRefundable = basicItc + nn$7(input.openingItcPool);
|
|
8754
|
+
const itcAppliedAgainstTax = Math.min(availableNonRefundable, nn$7(input.partITaxAvailable));
|
|
7929
8755
|
return {
|
|
7930
8756
|
qualifiedExpenditures,
|
|
7931
8757
|
expenditureLimit,
|
|
@@ -7964,17 +8790,17 @@ function computeSchedule31(input, rates) {
|
|
|
7964
8790
|
/** The large-corporation filing / grind threshold (s.181.5, s.125(5.1)). */
|
|
7965
8791
|
const LARGE_CORPORATION_THRESHOLD = 1e7;
|
|
7966
8792
|
const n$1 = (v) => Math.round(v ?? 0);
|
|
7967
|
-
const nn$
|
|
8793
|
+
const nn$6 = (v) => Math.max(0, Math.round(v ?? 0));
|
|
7968
8794
|
function computeTaxableCapital(input = {}) {
|
|
7969
|
-
const additions = nn$
|
|
7970
|
-
const deductions = nn$
|
|
8795
|
+
const additions = nn$6(input.reservesNotDeducted) + nn$6(input.capitalStock) + n$1(input.retainedEarnings) + nn$6(input.contributedSurplus) + nn$6(input.otherSurpluses) + nn$6(input.deferredForexGains) + nn$6(input.loansAndAdvances) + nn$6(input.bondsAndDebentures) + nn$6(input.dividendsDeclaredUnpaid) + nn$6(input.otherLongTermDebt) + nn$6(input.partnershipInterest);
|
|
8796
|
+
const deductions = nn$6(input.deferredTaxDebit) + nn$6(input.deficitInEquity) + nn$6(input.patronageDeducted) + nn$6(input.deferredForexLosses);
|
|
7971
8797
|
const capital = Math.max(0, additions - deductions);
|
|
7972
|
-
const investmentAllowance = nn$
|
|
8798
|
+
const investmentAllowance = nn$6(input.sharesOfOtherCorporations) + nn$6(input.loansToOtherCorporations) + nn$6(input.bondsOfOtherCorporations) + nn$6(input.longTermDebtOfFinancialInstitution) + nn$6(input.dividendsReceivable) + nn$6(input.partnershipObligations) + nn$6(input.partnershipInterestAsset);
|
|
7973
8799
|
const taxableCapital = Math.max(0, capital - investmentAllowance);
|
|
7974
8800
|
let ratio = 1;
|
|
7975
8801
|
if (input.taxableIncomeEarnedInCanada !== void 0 && input.taxableIncome !== void 0) {
|
|
7976
8802
|
const denom = input.taxableIncome > 0 ? input.taxableIncome : 1e3;
|
|
7977
|
-
ratio = Math.max(0, Math.min(1, nn$
|
|
8803
|
+
ratio = Math.max(0, Math.min(1, nn$6(input.taxableIncomeEarnedInCanada) / denom));
|
|
7978
8804
|
}
|
|
7979
8805
|
const taxableCapitalEmployedInCanada = Math.round(taxableCapital * ratio);
|
|
7980
8806
|
return {
|
|
@@ -7987,18 +8813,18 @@ function computeTaxableCapital(input = {}) {
|
|
|
7987
8813
|
}
|
|
7988
8814
|
//#endregion
|
|
7989
8815
|
//#region src/t2/schedules/schedule43-part6-1.ts
|
|
7990
|
-
const nn$
|
|
8816
|
+
const nn$5 = (v) => Math.max(0, v ?? 0);
|
|
7991
8817
|
function computeSchedule43(input, rates) {
|
|
7992
|
-
const shortTerm = nn$
|
|
7993
|
-
const other = nn$
|
|
8818
|
+
const shortTerm = nn$5(input.shortTermPreferredDividends);
|
|
8819
|
+
const other = nn$5(input.otherPreferredDividends);
|
|
7994
8820
|
const issues = [];
|
|
7995
8821
|
let dividendAllowance;
|
|
7996
8822
|
if (input.isAssociated === true) if (input.allocatedAllowance == null) {
|
|
7997
8823
|
dividendAllowance = 0;
|
|
7998
8824
|
if (shortTerm + other > 0) issues.push("Associated corporation: the Part VI.1 dividend allowance is nil unless the group files an allocation agreement (s.191.1(3)). Enter the allocated amount or the full dividend is taxable.");
|
|
7999
|
-
} else dividendAllowance = Math.min(nn$
|
|
8825
|
+
} else dividendAllowance = Math.min(nn$5(input.allocatedAllowance), rates.DIVIDEND_ALLOWANCE);
|
|
8000
8826
|
else dividendAllowance = rates.DIVIDEND_ALLOWANCE;
|
|
8001
|
-
const priorExcess = Math.max(0, nn$
|
|
8827
|
+
const priorExcess = Math.max(0, nn$5(input.priorYearPreferredDividends) - rates.ALLOWANCE_GRIND_THRESHOLD);
|
|
8002
8828
|
dividendAllowance = Math.max(0, dividendAllowance - priorExcess);
|
|
8003
8829
|
const shortTermTaxable = Math.max(0, shortTerm - dividendAllowance);
|
|
8004
8830
|
const allowanceLeft = Math.max(0, dividendAllowance - shortTerm);
|
|
@@ -8021,12 +8847,12 @@ function computeSchedule43(input, rates) {
|
|
|
8021
8847
|
}
|
|
8022
8848
|
//#endregion
|
|
8023
8849
|
//#region src/t2/schedules/schedule53-grip.ts
|
|
8024
|
-
const nn$
|
|
8850
|
+
const nn$4 = (v) => Math.max(0, v ?? 0);
|
|
8025
8851
|
function computeGrip(input, gripFactor = .72) {
|
|
8026
|
-
const openingGrip = nn$
|
|
8852
|
+
const openingGrip = nn$4(input.openingGrip);
|
|
8027
8853
|
const generalRateAddition = Math.round(gripFactor * Math.max(0, input.generalRateIncome));
|
|
8028
|
-
const eligibleDividendsReceived = nn$
|
|
8029
|
-
const eligibleDividendsDesignated = nn$
|
|
8854
|
+
const eligibleDividendsReceived = nn$4(input.eligibleDividendsReceived);
|
|
8855
|
+
const eligibleDividendsDesignated = nn$4(input.eligibleDividendsDesignated);
|
|
8030
8856
|
const gripBeforeDesignation = openingGrip + generalRateAddition + eligibleDividendsReceived;
|
|
8031
8857
|
const excessiveDesignation = Math.max(0, eligibleDividendsDesignated - gripBeforeDesignation);
|
|
8032
8858
|
return {
|
|
@@ -8128,24 +8954,24 @@ function computeGrip(input, gripFactor = .72) {
|
|
|
8128
8954
|
const LRIP_INVESTMENT_INCOME_FACTOR = .8;
|
|
8129
8955
|
/** Line 160 — the investment corporation deduction enters the pool at four times its value. */
|
|
8130
8956
|
const LRIP_INVESTMENT_CORPORATION_MULTIPLE = 4;
|
|
8131
|
-
const nn$
|
|
8957
|
+
const nn$3 = (v) => Math.max(0, Math.round(v ?? 0));
|
|
8132
8958
|
const sn = (v) => Math.round(v ?? 0);
|
|
8133
8959
|
function computeSchedule54(input) {
|
|
8134
8960
|
const issues = [];
|
|
8135
|
-
const openingLrip = nn$
|
|
8136
|
-
const investmentIncomeAddition = Math.round(LRIP_INVESTMENT_INCOME_FACTOR * nn$
|
|
8137
|
-
const investmentCorporationAddition = 4 * nn$
|
|
8961
|
+
const openingLrip = nn$3(input.openingLrip);
|
|
8962
|
+
const investmentIncomeAddition = Math.round(LRIP_INVESTMENT_INCOME_FACTOR * nn$3(input.priorYearAggregateInvestmentIncome));
|
|
8963
|
+
const investmentCorporationAddition = 4 * nn$3(input.priorYearInvestmentCorporationDeduction);
|
|
8138
8964
|
const lripBeforeDividends = openingLrip + investmentIncomeAddition + investmentCorporationAddition;
|
|
8139
8965
|
const ordered = [...input.dividendEvents ?? []].sort((a, b) => a.date.localeCompare(b.date));
|
|
8140
8966
|
const events = [];
|
|
8141
8967
|
let designationsSoFar = 0;
|
|
8142
8968
|
for (const e of ordered) {
|
|
8143
|
-
const poolBeforeReductions = lripBeforeDividends + nn$
|
|
8969
|
+
const poolBeforeReductions = lripBeforeDividends + nn$3(e.dividendsReceivableBefore) + sn(e.adjustmentsBefore);
|
|
8144
8970
|
const derivedPrior = designationsSoFar;
|
|
8145
|
-
const excessiveDesignationsBefore = e.excessiveDesignationsBefore !== void 0 ? nn$
|
|
8146
|
-
if (e.excessiveDesignationsBefore !== void 0 && nn$
|
|
8147
|
-
const lripAtDate = Math.max(0, poolBeforeReductions - nn$
|
|
8148
|
-
const eligibleDividendsPaid = nn$
|
|
8971
|
+
const excessiveDesignationsBefore = e.excessiveDesignationsBefore !== void 0 ? nn$3(e.excessiveDesignationsBefore) : derivedPrior;
|
|
8972
|
+
if (e.excessiveDesignationsBefore !== void 0 && nn$3(e.excessiveDesignationsBefore) !== derivedPrior) issues.push(`Schedule 54: for the dividend dated ${e.date}, line 250 was given as ${nn$3(e.excessiveDesignationsBefore)} but the earlier rows of this schedule total ${derivedPrior}. The supplied figure has been used; confirm which is right before filing, because line 250 feeds every later row.`);
|
|
8973
|
+
const lripAtDate = Math.max(0, poolBeforeReductions - nn$3(e.dividendsPayableBefore) - excessiveDesignationsBefore);
|
|
8974
|
+
const eligibleDividendsPaid = nn$3(e.eligibleDividendsPaid);
|
|
8149
8975
|
const excessiveDesignation = Math.max(0, Math.min(lripAtDate, eligibleDividendsPaid));
|
|
8150
8976
|
events.push({
|
|
8151
8977
|
date: e.date,
|
|
@@ -8158,8 +8984,8 @@ function computeSchedule54(input) {
|
|
|
8158
8984
|
designationsSoFar += excessiveDesignation;
|
|
8159
8985
|
}
|
|
8160
8986
|
const totalExcessiveDesignation = events.reduce((s, e) => s + e.excessiveDesignation, 0);
|
|
8161
|
-
const poolIncludingReceipts = lripBeforeDividends + nn$
|
|
8162
|
-
const totalReductions = nn$
|
|
8987
|
+
const poolIncludingReceipts = lripBeforeDividends + nn$3(input.dividendsReceivableInYear) + sn(input.adjustmentsInYear);
|
|
8988
|
+
const totalReductions = nn$3(input.dividendsPayableInYear) + totalExcessiveDesignation;
|
|
8163
8989
|
const closingLrip = Math.max(0, poolIncludingReceipts - totalReductions);
|
|
8164
8990
|
if (totalExcessiveDesignation > 0) issues.push(`Schedule 54: ${totalExcessiveDesignation} of eligible dividends were designated while low rate income pool remained, so they are excessive eligible dividend designations. Carry this to amount C of Schedule 55, where it bears Part III.1 tax at 20% unless an election under subsection 185.1(2) is made.`);
|
|
8165
8991
|
return {
|
|
@@ -8177,7 +9003,7 @@ function computeSchedule54(input) {
|
|
|
8177
9003
|
}
|
|
8178
9004
|
//#endregion
|
|
8179
9005
|
//#region src/t2/schedules/schedule55-part3-1.ts
|
|
8180
|
-
const nn$
|
|
9006
|
+
const nn$2 = (v) => Math.max(0, v ?? 0);
|
|
8181
9007
|
/**
|
|
8182
9008
|
* Compute Part III.1 tax.
|
|
8183
9009
|
*
|
|
@@ -8186,10 +9012,10 @@ const nn$4 = (v) => Math.max(0, v ?? 0);
|
|
|
8186
9012
|
*/
|
|
8187
9013
|
function computeSchedule55(input, baseRate = .2, paragraphCRate = .1) {
|
|
8188
9014
|
const issues = [];
|
|
8189
|
-
const excessiveDesignation = nn$
|
|
9015
|
+
const excessiveDesignation = nn$2(input.excessiveDesignation);
|
|
8190
9016
|
const arisesUnderParagraphC = input.arisesUnderParagraphC === true;
|
|
8191
9017
|
const electionAvailable = !arisesUnderParagraphC;
|
|
8192
|
-
const claimed = input.electedAmount !== void 0 ? nn$
|
|
9018
|
+
const claimed = input.electedAmount !== void 0 ? nn$2(input.electedAmount) : input.electsMaximum === true ? excessiveDesignation : 0;
|
|
8193
9019
|
if (claimed > 0 && !electionAvailable) issues.push(`Part III.1: a subsection 185.1(2) election of ${claimed} was claimed, but the election is not available where the excess arises under paragraph (c) of the section 89(1) definition. The full ${excessiveDesignation} remains taxable at ${(baseRate + paragraphCRate) * 100}%.`);
|
|
8194
9020
|
let reclassifiedAsOrdinary = electionAvailable ? Math.min(claimed, excessiveDesignation) : 0;
|
|
8195
9021
|
if (electionAvailable && claimed > excessiveDesignation) {
|
|
@@ -8456,76 +9282,266 @@ function computeFederalT2(input) {
|
|
|
8456
9282
|
ref: "s.66(4)/66.7(2)"
|
|
8457
9283
|
});
|
|
8458
9284
|
}
|
|
8459
|
-
|
|
8460
|
-
|
|
8461
|
-
|
|
8462
|
-
|
|
8463
|
-
|
|
8464
|
-
|
|
8465
|
-
|
|
8466
|
-
|
|
8467
|
-
|
|
8468
|
-
|
|
8469
|
-
|
|
8470
|
-
|
|
8471
|
-
|
|
8472
|
-
|
|
8473
|
-
|
|
8474
|
-
|
|
8475
|
-
|
|
8476
|
-
|
|
8477
|
-
|
|
8478
|
-
|
|
8479
|
-
|
|
8480
|
-
|
|
8481
|
-
|
|
8482
|
-
|
|
8483
|
-
|
|
8484
|
-
|
|
8485
|
-
|
|
8486
|
-
|
|
8487
|
-
|
|
8488
|
-
|
|
8489
|
-
|
|
8490
|
-
|
|
8491
|
-
|
|
8492
|
-
|
|
8493
|
-
|
|
8494
|
-
|
|
8495
|
-
|
|
8496
|
-
|
|
8497
|
-
|
|
8498
|
-
|
|
8499
|
-
|
|
8500
|
-
|
|
8501
|
-
|
|
8502
|
-
|
|
8503
|
-
|
|
8504
|
-
|
|
8505
|
-
|
|
8506
|
-
|
|
8507
|
-
|
|
8508
|
-
|
|
8509
|
-
|
|
8510
|
-
|
|
8511
|
-
|
|
8512
|
-
|
|
8513
|
-
|
|
8514
|
-
|
|
8515
|
-
|
|
8516
|
-
|
|
8517
|
-
|
|
8518
|
-
|
|
8519
|
-
|
|
8520
|
-
|
|
9285
|
+
/**
|
|
9286
|
+
* Schedule 1 → net income → Division C → taxable income → Schedule 33, as a
|
|
9287
|
+
* closure, because EIFEL makes it run **twice**.
|
|
9288
|
+
*
|
|
9289
|
+
* Subsection 18.2(1) defines adjusted taxable income from taxable income
|
|
9290
|
+
* "determined without regard to subsection 18.2(2), paragraphs 12(1)(l.2)
|
|
9291
|
+
* and 111(1)(a.1)" — and those three are exactly the three adjustments the
|
|
9292
|
+
* EIFEL computation produces (Schedule 1 lines 251 and 252, and the jacket
|
|
9293
|
+
* line 336 deduction). So the limitation cannot be an input to the base it
|
|
9294
|
+
* is computed from: the first pass supplies that base, the EIFEL chain runs
|
|
9295
|
+
* on it, and the second pass applies the three adjustments it produced.
|
|
9296
|
+
*
|
|
9297
|
+
* Every step in here is a pure function of its arguments, so running it
|
|
9298
|
+
* twice costs only arithmetic and cannot drift between the passes — which
|
|
9299
|
+
* is the reason it is one closure rather than two copies of the sequence.
|
|
9300
|
+
*/
|
|
9301
|
+
const runIncomeSequence = (eifelAdjustments) => {
|
|
9302
|
+
const passAdditions = eifelAdjustments ? [...schedule1Additions, ...eifelAdjustments.additions] : schedule1Additions;
|
|
9303
|
+
const schedule1 = computeSchedule1({
|
|
9304
|
+
bookNetIncome: input.bookNetIncome,
|
|
9305
|
+
...passAdditions.length ? { additions: passAdditions } : {},
|
|
9306
|
+
...schedule1Deductions.length ? { deductions: schedule1Deductions } : {}
|
|
9307
|
+
});
|
|
9308
|
+
const partVI1 = input.preferredShareDividends && ((input.preferredShareDividends.shortTermPreferredDividends ?? 0) > 0 || (input.preferredShareDividends.otherPreferredDividends ?? 0) > 0) ? computeSchedule43(input.preferredShareDividends, {
|
|
9309
|
+
SHORT_TERM_RATE: rates.PART_VI_1_SHORT_TERM_RATE,
|
|
9310
|
+
ELECTED_RATE: rates.PART_VI_1_ELECTED_RATE,
|
|
9311
|
+
BASE_RATE: rates.PART_VI_1_BASE_RATE,
|
|
9312
|
+
DIVIDEND_ALLOWANCE: rates.PART_VI_1_DIVIDEND_ALLOWANCE,
|
|
9313
|
+
ALLOWANCE_GRIND_THRESHOLD: rates.PART_VI_1_ALLOWANCE_GRIND_THRESHOLD
|
|
9314
|
+
}) : void 0;
|
|
9315
|
+
const partVI1Deduction = partVI1 ? computePartVI1Deduction(partVI1.partVI1Tax, isoDay(input.periodEnd)) : void 0;
|
|
9316
|
+
const donations = input.charitableDonations !== void 0 || input.openingDonationPool !== void 0 ? computeSchedule2({
|
|
9317
|
+
...input.openingDonationPool !== void 0 ? { openingDonationPool: input.openingDonationPool } : {},
|
|
9318
|
+
...input.charitableDonations !== void 0 ? { currentYearDonations: input.charitableDonations } : {},
|
|
9319
|
+
netIncomeForTax: schedule1.netIncomeForTax
|
|
9320
|
+
}, rates) : void 0;
|
|
9321
|
+
const culturalEcologicalGiftsClaimed = Math.max(0, input.culturalEcologicalGifts ?? 0);
|
|
9322
|
+
const divisionCDeductions = [
|
|
9323
|
+
...donations && donations.donationsClaimed > 0 ? [{
|
|
9324
|
+
line: "112",
|
|
9325
|
+
label: "Charitable donations and gifts from Schedule 2",
|
|
9326
|
+
amount: donations.donationsClaimed,
|
|
9327
|
+
ref: "s.110.1"
|
|
9328
|
+
}] : [],
|
|
9329
|
+
...culturalEcologicalGiftsClaimed > 0 ? [{
|
|
9330
|
+
line: "112",
|
|
9331
|
+
label: "Gifts of certified cultural property and ecologically sensitive land from Schedule 2",
|
|
9332
|
+
amount: culturalEcologicalGiftsClaimed,
|
|
9333
|
+
ref: "s.110.1(1)(b)/(c) — not subject to the 75% income limit"
|
|
9334
|
+
}] : [],
|
|
9335
|
+
...partVI1Deduction && partVI1Deduction.deduction > 0 ? [{
|
|
9336
|
+
line: "325",
|
|
9337
|
+
label: "Part VI.1 tax deduction",
|
|
9338
|
+
amount: partVI1Deduction.deduction,
|
|
9339
|
+
ref: `s.110(1)(k) — ${partVI1Deduction.multiple}× Part VI.1 tax payable`
|
|
9340
|
+
}] : [],
|
|
9341
|
+
...input.divisionCDeductions ?? [],
|
|
9342
|
+
...eifelAdjustments?.deductions ?? []
|
|
9343
|
+
];
|
|
9344
|
+
const taxableIncomeCalc = computeTaxableIncome({
|
|
9345
|
+
netIncomeForTax: schedule1.netIncomeForTax,
|
|
9346
|
+
...divisionCDeductions.length ? { deductions: divisionCDeductions } : {}
|
|
9347
|
+
});
|
|
9348
|
+
const currentYearNonCapitalLoss = Math.max(0, -schedule1.netIncomeForTax);
|
|
9349
|
+
const lossCarryback = input.lossCarrybacks?.length ? computeLossCarryback({
|
|
9350
|
+
currentYearLoss: currentYearNonCapitalLoss,
|
|
9351
|
+
carrybacks: input.lossCarrybacks
|
|
9352
|
+
}) : void 0;
|
|
9353
|
+
const nonCapitalCarriedBack = lossCarryback ? lossCarryback.totalCarriedBack : input.nonCapitalLossCarriedBack;
|
|
9354
|
+
const losses = computeSchedule4Losses({
|
|
9355
|
+
...input.openingNonCapitalLoss !== void 0 ? { openingNonCapitalLoss: input.openingNonCapitalLoss } : {},
|
|
9356
|
+
...input.openingNetCapitalLoss !== void 0 ? { openingNetCapitalLoss: input.openingNetCapitalLoss } : {},
|
|
9357
|
+
netIncomeForTax: schedule1.netIncomeForTax,
|
|
9358
|
+
taxableIncomeBeforeLosses: taxableIncomeCalc.taxableIncome,
|
|
9359
|
+
...capitalGains ? { taxableCapitalGains: capitalGains.taxableCapitalGain } : input.taxableCapitalGains !== void 0 ? { taxableCapitalGains: input.taxableCapitalGains } : {},
|
|
9360
|
+
...input.nonCapitalLossToApply !== void 0 ? { nonCapitalLossToApply: input.nonCapitalLossToApply } : {},
|
|
9361
|
+
...input.netCapitalLossToApply !== void 0 ? { netCapitalLossToApply: input.netCapitalLossToApply } : {},
|
|
9362
|
+
...nonCapitalCarriedBack !== void 0 ? { nonCapitalCarriedBack } : {},
|
|
9363
|
+
...input.nonCapitalLossExpired !== void 0 ? { nonCapitalExpired: input.nonCapitalLossExpired } : {},
|
|
9364
|
+
...input.netCapitalLossExpired !== void 0 ? { netCapitalExpired: input.netCapitalLossExpired } : {},
|
|
9365
|
+
...capitalGains && capitalGains.currentYearNetCapitalLoss > 0 ? { currentYearNetCapitalLoss: capitalGains.currentYearNetCapitalLoss } : input.currentYearNetCapitalLoss !== void 0 ? { currentYearNetCapitalLoss: input.currentYearNetCapitalLoss } : {}
|
|
9366
|
+
});
|
|
9367
|
+
const taxableIncome = Math.max(0, taxableIncomeCalc.taxableIncome - losses.totalApplied);
|
|
9368
|
+
const associatedAllocation = input.associatedMembers ? computeBusinessLimitAllocation({ members: input.associatedMembers }) : void 0;
|
|
9369
|
+
const taxableCapitalSchedule = input.taxableCapitalDetail ? computeTaxableCapital({
|
|
9370
|
+
...input.taxableCapitalDetail,
|
|
9371
|
+
...input.taxableCapitalDetail.taxableIncome === void 0 ? { taxableIncome } : {}
|
|
9372
|
+
}) : void 0;
|
|
9373
|
+
return {
|
|
9374
|
+
schedule1,
|
|
9375
|
+
partVI1,
|
|
9376
|
+
partVI1Deduction,
|
|
9377
|
+
donations,
|
|
9378
|
+
culturalEcologicalGiftsClaimed,
|
|
9379
|
+
divisionCDeductions,
|
|
9380
|
+
taxableIncomeCalc,
|
|
9381
|
+
currentYearNonCapitalLoss,
|
|
9382
|
+
lossCarryback,
|
|
9383
|
+
nonCapitalCarriedBack,
|
|
9384
|
+
losses,
|
|
9385
|
+
taxableIncome,
|
|
9386
|
+
associatedAllocation,
|
|
9387
|
+
taxableCapitalSchedule,
|
|
9388
|
+
grindTaxableCapital: input.taxableCapital ?? taxableCapitalSchedule?.taxableCapitalEmployedInCanada
|
|
9389
|
+
};
|
|
9390
|
+
};
|
|
9391
|
+
const provisional = runIncomeSequence();
|
|
9392
|
+
const eifel = assessEifel({
|
|
9393
|
+
taxYearStart: isoDay(input.periodStart ?? input.period?.start),
|
|
9394
|
+
...(input.eifel?.isCcpc ?? input.isCcpc) !== void 0 ? { isCcpc: input.eifel?.isCcpc ?? input.isCcpc } : {},
|
|
9395
|
+
...(() => {
|
|
9396
|
+
const tc = input.eifel?.groupTaxableCapital ?? provisional.taxableCapitalSchedule?.taxableCapitalEmployedInCanada ?? input.taxableCapital;
|
|
9397
|
+
return tc !== void 0 ? { groupTaxableCapital: tc } : {};
|
|
9398
|
+
})(),
|
|
9399
|
+
...input.eifel?.netInterestAndFinancingExpenses !== void 0 ? { netInterestAndFinancingExpenses: input.eifel.netInterestAndFinancingExpenses } : {},
|
|
9400
|
+
...input.eifel?.domesticExceptionApplies !== void 0 ? { domesticExceptionApplies: input.eifel.domesticExceptionApplies } : {}
|
|
9401
|
+
}, {
|
|
9402
|
+
SMALL_CCPC_TAXABLE_CAPITAL: rates.EIFEL_SMALL_CCPC_TAXABLE_CAPITAL,
|
|
9403
|
+
DE_MINIMIS_NET_IFE: rates.EIFEL_DE_MINIMIS_NET_IFE
|
|
8521
9404
|
});
|
|
8522
|
-
const
|
|
8523
|
-
|
|
8524
|
-
|
|
8525
|
-
|
|
8526
|
-
|
|
8527
|
-
|
|
8528
|
-
|
|
9405
|
+
const eifelChain = (() => {
|
|
9406
|
+
if (!eifel.requiresLimitation) return null;
|
|
9407
|
+
const e = input.eifel;
|
|
9408
|
+
const taxYearStart = isoDay(input.periodStart ?? input.period?.start);
|
|
9409
|
+
const exemptIfe = computeExemptIfe(e?.exemptIfe ?? []);
|
|
9410
|
+
const borrowings = computeBorrowings(e?.borrowings ?? []);
|
|
9411
|
+
const loans = computeLoans(e?.loans ?? []);
|
|
9412
|
+
const partnership = computePartnershipIfe(e?.partnershipIfe ?? []);
|
|
9413
|
+
const capitalized = computeCapitalizedIfe(e?.capitalizedIfe ?? []);
|
|
9414
|
+
const resourceIfe = computeResourceIfe(e?.resourceIfe ?? []);
|
|
9415
|
+
const lossPortion = computeLossPortionFromIfe(e?.lossPortionFromIfe ?? []);
|
|
9416
|
+
const ife = computeInterestAndFinancingExpenses({
|
|
9417
|
+
...e?.ifeDetail ?? {},
|
|
9418
|
+
interestOnBorrowings: borrowings.interestPaidOrPayable,
|
|
9419
|
+
ifeInCca: capitalized.totalIfeInCca,
|
|
9420
|
+
ifeInResourceExpenses: resourceIfe.totalIfeInResourceClaims,
|
|
9421
|
+
ifeInTerminalLoss: capitalized.totalIfeInTerminalLoss,
|
|
9422
|
+
fundingCostAmounts: borrowings.fundingCostAmounts,
|
|
9423
|
+
partnershipShare: partnership.totalIncluded,
|
|
9424
|
+
costReducingAmounts: borrowings.costReducingAmounts
|
|
9425
|
+
});
|
|
9426
|
+
const ifr = computeInterestAndFinancingRevenues({
|
|
9427
|
+
...e?.ifrDetail ?? {},
|
|
9428
|
+
returnAmounts: loans.returnAmounts,
|
|
9429
|
+
returnReducingAmounts: loans.returnReducingAmounts
|
|
9430
|
+
});
|
|
9431
|
+
const eifelIfe = e?.interestAndFinancingExpenses ?? ife.totalIfe;
|
|
9432
|
+
const eifelIfr = e?.interestAndFinancingRevenues ?? ifr.totalIfr;
|
|
9433
|
+
const ati = computeAdjustedTaxableIncome({
|
|
9434
|
+
...e?.adjustedTaxableIncomeDetail ?? {},
|
|
9435
|
+
taxableIncome: provisional.taxableIncome,
|
|
9436
|
+
nonCapitalLossForYear: provisional.currentYearNonCapitalLoss,
|
|
9437
|
+
lossClaimNotReducingTaxableIncome: Math.max(0, provisional.losses.totalApplied - Math.max(0, provisional.taxableIncomeCalc.taxableIncome)),
|
|
9438
|
+
interestAndFinancingExpenses: eifelIfe,
|
|
9439
|
+
capitalCostAllowance: cca?.totalCca ?? 0,
|
|
9440
|
+
resourceDeductions: resourceDeductions ? resourceDeductions.depletionClaim + resourceDeductions.ceeClaim + resourceDeductions.cdeClaim + resourceDeductions.cogpeClaim + resourceDeductions.foreignClaim : 0,
|
|
9441
|
+
terminalLoss: cca?.totalTerminalLoss ?? 0,
|
|
9442
|
+
partVI1TaxDeduction: provisional.partVI1Deduction?.deduction ?? 0,
|
|
9443
|
+
lossPortionDerivedFromIfe: lossPortion.totalAttributableToIfe,
|
|
9444
|
+
exemptIfeActivityLoss: exemptIfe.lossFromExemptActivities,
|
|
9445
|
+
exemptIfeActivityIncome: exemptIfe.incomeFromExemptActivities,
|
|
9446
|
+
interestAndFinancingRevenues: eifelIfr,
|
|
9447
|
+
recapture: cca?.totalRecapture ?? 0
|
|
9448
|
+
});
|
|
9449
|
+
const resolvedAti = e?.adjustedTaxableIncome ?? ati.adjustedTaxableIncome;
|
|
9450
|
+
const capacityBase = computeEifelCapacity({
|
|
9451
|
+
adjustedTaxableIncome: resolvedAti,
|
|
9452
|
+
interestAndFinancingExpenses: eifelIfe,
|
|
9453
|
+
interestAndFinancingRevenues: eifelIfr,
|
|
9454
|
+
ratioOfPermissibleExpenses: ratioOfPermissibleExpenses(taxYearStart),
|
|
9455
|
+
...e?.hasGroupRatioElection !== void 0 ? { hasGroupRatioElection: e.hasGroupRatioElection } : {},
|
|
9456
|
+
...e?.groupRatioAmount !== void 0 ? { groupRatioAmount: e.groupRatioAmount } : {},
|
|
9457
|
+
...e?.receivedCapacity ? { receivedCapacity: e.receivedCapacity } : {},
|
|
9458
|
+
...e?.rifeFromPreviousYears !== void 0 ? { rifeFromPreviousYears: e.rifeFromPreviousYears } : {},
|
|
9459
|
+
...e?.priorYearExcessCapacity ? { priorYearExcessCapacity: e.priorYearExcessCapacity } : {}
|
|
9460
|
+
});
|
|
9461
|
+
const limitation = computeEifelLimitation({
|
|
9462
|
+
interestAndFinancingExpenses: eifelIfe,
|
|
9463
|
+
adjustedTaxableIncome: resolvedAti,
|
|
9464
|
+
interestAndFinancingRevenues: eifelIfr,
|
|
9465
|
+
excessReceivedCapacity: capacityBase.excessReceivedCapacity,
|
|
9466
|
+
absorbedCapacity: capacityBase.absorbedCapacity,
|
|
9467
|
+
...e?.hasGroupRatioElection && e?.groupRatioAmount !== void 0 ? { groupRatioAmount: e.groupRatioAmount } : {},
|
|
9468
|
+
taxYearStart
|
|
9469
|
+
});
|
|
9470
|
+
const { excessIfe } = computeExcessIfe({
|
|
9471
|
+
variableAOfIfe: e?.interestAndFinancingExpenses ?? ife.variableA,
|
|
9472
|
+
partnershipShare: partnership.totalIncluded,
|
|
9473
|
+
...e?.ifeDetail?.affiliateRaife !== void 0 ? { affiliateRaife: e.ifeDetail.affiliateRaife } : {},
|
|
9474
|
+
deniedProportion: limitation.deniedProportion
|
|
9475
|
+
});
|
|
9476
|
+
const partnershipIfeAddBack = e?.partnershipIfeAddBack ?? computePartnershipIfeAddBack(partnership.totalIncluded, limitation.deniedProportion);
|
|
9477
|
+
const clause95 = computeClause95Amounts(e?.clause95Denied ?? [], e?.clause95Included ?? [], limitation.deniedProportion);
|
|
9478
|
+
return {
|
|
9479
|
+
ati,
|
|
9480
|
+
limitation,
|
|
9481
|
+
capacity: {
|
|
9482
|
+
...capacityBase,
|
|
9483
|
+
rifeForYear: computeRifeUnderSubsection111_8({
|
|
9484
|
+
excessInterestAndFinancingExpenses: excessIfe,
|
|
9485
|
+
partnershipIfeAddBack,
|
|
9486
|
+
clause95FapiAmountI: e?.clause95FapiAmountI ?? clause95.deniedUnderSubclauseI,
|
|
9487
|
+
clause95FapiAmountII: e?.clause95FapiAmountII ?? clause95.includedUnderSubclauseII
|
|
9488
|
+
}),
|
|
9489
|
+
issues: [
|
|
9490
|
+
...capacityBase.issues,
|
|
9491
|
+
...capitalized.issues,
|
|
9492
|
+
...resourceIfe.issues,
|
|
9493
|
+
...lossPortion.issues
|
|
9494
|
+
]
|
|
9495
|
+
},
|
|
9496
|
+
ife,
|
|
9497
|
+
ifr,
|
|
9498
|
+
excessIfe,
|
|
9499
|
+
partnershipIfeAddBack
|
|
9500
|
+
};
|
|
9501
|
+
})();
|
|
9502
|
+
/**
|
|
9503
|
+
* A return inside the regime that never supplied its GROSS interest and
|
|
9504
|
+
* financing expenses computes a denial of nil — which looks like "nothing was
|
|
9505
|
+
* restricted" and is really "nothing was measured". The group NET figure that
|
|
9506
|
+
* settled the de-minimis test above is not a substitute: it is a different
|
|
9507
|
+
* figure, for a different purpose, at group level.
|
|
9508
|
+
*/
|
|
9509
|
+
const eifelWithIssues = eifel.requiresLimitation && !((eifelChain?.ife.totalIfe ?? 0) > 0) ? {
|
|
9510
|
+
...eifel,
|
|
9511
|
+
issues: [...eifel.issues, "EIFEL: the corporation is inside the regime but its gross interest and financing expenses (Schedule 130 Part 2A line 045) were not supplied, so the limitation measured nothing and denied nothing. Supply that figure — the group net figure used for the de minimis test is not the same amount."]
|
|
9512
|
+
} : eifel;
|
|
9513
|
+
/**
|
|
9514
|
+
* The three adjustments the EIFEL computation produces, on the lines the
|
|
9515
|
+
* forms name for them:
|
|
9516
|
+
*
|
|
9517
|
+
* Schedule 1 line 251 the denial under s.18.2(2) (Part 2L amount B)
|
|
9518
|
+
* Schedule 1 line 252 the 12(1)(l.2) partnership add-back (Part 2N)
|
|
9519
|
+
* jacket line 336 the 111(1)(a.1) RIFE deduction (Part 2J amount B)
|
|
9520
|
+
*
|
|
9521
|
+
* Each is one of the three things adjusted taxable income is defined to
|
|
9522
|
+
* disregard, which is why applying them needs the second pass below rather
|
|
9523
|
+
* than being folded into the first.
|
|
9524
|
+
*/
|
|
9525
|
+
const eifelAdjustments = eifelChain ? {
|
|
9526
|
+
additions: [...eifelChain.excessIfe > 0 ? [{
|
|
9527
|
+
line: "251",
|
|
9528
|
+
label: "Excess IFE under subsection 18.2(2) from Schedule 130",
|
|
9529
|
+
amount: eifelChain.excessIfe,
|
|
9530
|
+
ref: "s.18.2(2)"
|
|
9531
|
+
}] : [], ...eifelChain.partnershipIfeAddBack > 0 ? [{
|
|
9532
|
+
line: "252",
|
|
9533
|
+
label: "Partnership IFE add-back under paragraph 12(1)(l.2) from Schedule 130",
|
|
9534
|
+
amount: eifelChain.partnershipIfeAddBack,
|
|
9535
|
+
ref: "s.12(1)(l.2)"
|
|
9536
|
+
}] : []],
|
|
9537
|
+
deductions: eifelChain.capacity.rifeDeductible > 0 ? [{
|
|
9538
|
+
line: "336",
|
|
9539
|
+
label: "Restricted interest and financing expenses from Schedule 4",
|
|
9540
|
+
amount: eifelChain.capacity.rifeDeductible,
|
|
9541
|
+
ref: "s.111(1)(a.1)"
|
|
9542
|
+
}] : []
|
|
9543
|
+
} : void 0;
|
|
9544
|
+
const { schedule1, partVI1, partVI1Deduction, donations, taxableIncomeCalc, lossCarryback, losses, taxableIncome, associatedAllocation, taxableCapitalSchedule, grindTaxableCapital } = ((eifelAdjustments?.additions.length ?? 0) > 0 || (eifelAdjustments?.deductions.length ?? 0) > 0) && eifelAdjustments ? runIncomeSequence(eifelAdjustments) : provisional;
|
|
8529
9545
|
const adjustedAggregateInvestmentIncomeSchedule = input.adjustedAggregateInvestmentIncomeDetail ? computeAdjustedAggregateInvestmentIncome(input.adjustedAggregateInvestmentIncomeDetail) : void 0;
|
|
8530
9546
|
const resolvedAaii = input.aaii ?? adjustedAggregateInvestmentIncomeSchedule?.adjustedAggregateInvestmentIncome;
|
|
8531
9547
|
const aggregateInvestmentIncomeSchedule = input.aggregateInvestmentIncomeDetail ? computeAggregateInvestmentIncome(input.aggregateInvestmentIncomeDetail) : void 0;
|
|
@@ -8617,19 +9633,6 @@ function computeFederalT2(input) {
|
|
|
8617
9633
|
...input.provincialAllocationFactor !== void 0 ? { allocationFactor: input.provincialAllocationFactor } : {}
|
|
8618
9634
|
}, provinceRates) : void 0;
|
|
8619
9635
|
const totalTax = totalFederalTax + (provincialAllocation?.totalProvincialTax ?? provincial?.provincialTax ?? 0);
|
|
8620
|
-
const eifel = assessEifel({
|
|
8621
|
-
taxYearStart: isoDay(input.periodStart ?? input.period?.start),
|
|
8622
|
-
...(input.eifel?.isCcpc ?? input.isCcpc) !== void 0 ? { isCcpc: input.eifel?.isCcpc ?? input.isCcpc } : {},
|
|
8623
|
-
...(() => {
|
|
8624
|
-
const tc = input.eifel?.groupTaxableCapital ?? taxableCapitalSchedule?.taxableCapitalEmployedInCanada ?? input.taxableCapital;
|
|
8625
|
-
return tc !== void 0 ? { groupTaxableCapital: tc } : {};
|
|
8626
|
-
})(),
|
|
8627
|
-
...input.eifel?.netInterestAndFinancingExpenses !== void 0 ? { netInterestAndFinancingExpenses: input.eifel.netInterestAndFinancingExpenses } : {},
|
|
8628
|
-
...input.eifel?.domesticExceptionApplies !== void 0 ? { domesticExceptionApplies: input.eifel.domesticExceptionApplies } : {}
|
|
8629
|
-
}, {
|
|
8630
|
-
SMALL_CCPC_TAXABLE_CAPITAL: rates.EIFEL_SMALL_CCPC_TAXABLE_CAPITAL,
|
|
8631
|
-
DE_MINIMIS_NET_IFE: rates.EIFEL_DE_MINIMIS_NET_IFE
|
|
8632
|
-
});
|
|
8633
9636
|
const internetBusiness = input.internetBusiness ? normalizeSchedule88(input.internetBusiness) : void 0;
|
|
8634
9637
|
const firstReturn = input.firstReturn ? computeSchedule101(input.firstReturn) : void 0;
|
|
8635
9638
|
return {
|
|
@@ -8657,7 +9660,14 @@ function computeFederalT2(input) {
|
|
|
8657
9660
|
...partIII1 ? { partIII1 } : {},
|
|
8658
9661
|
...partVI1 ? { partVI1 } : {},
|
|
8659
9662
|
...partVI1Deduction ? { partVI1Deduction } : {},
|
|
8660
|
-
eifel,
|
|
9663
|
+
eifel: eifelWithIssues,
|
|
9664
|
+
...eifelChain ? {
|
|
9665
|
+
eifelAdjustedTaxableIncome: eifelChain.ati,
|
|
9666
|
+
eifelLimitation: eifelChain.limitation,
|
|
9667
|
+
eifelCapacity: eifelChain.capacity,
|
|
9668
|
+
eifelIfe: eifelChain.ife,
|
|
9669
|
+
eifelIfr: eifelChain.ifr
|
|
9670
|
+
} : {},
|
|
8661
9671
|
...internetBusiness ? { internetBusiness } : {},
|
|
8662
9672
|
...firstReturn ? { firstReturn } : {},
|
|
8663
9673
|
...sredItc ? { sredItc } : {},
|
|
@@ -8672,7 +9682,20 @@ function computeFederalT2(input) {
|
|
|
8672
9682
|
taxableIncome,
|
|
8673
9683
|
federalTaxPayable: partI.partITaxPayable,
|
|
8674
9684
|
totalFederalTax,
|
|
8675
|
-
totalTax
|
|
9685
|
+
totalTax,
|
|
9686
|
+
schedulePayloads: federalSchedulePayloads({
|
|
9687
|
+
schedule1,
|
|
9688
|
+
netIncomeForTax: schedule1.netIncomeForTax,
|
|
9689
|
+
taxableIncome,
|
|
9690
|
+
totalFederalTax,
|
|
9691
|
+
...donations ? { donations } : {},
|
|
9692
|
+
...adjustedAggregateInvestmentIncomeSchedule ? { adjustedAggregateInvestmentIncomeSchedule } : {},
|
|
9693
|
+
...cca ? { cca } : {},
|
|
9694
|
+
...foreignTaxCredit ? { foreignTaxCredit } : {},
|
|
9695
|
+
...taxableCapitalSchedule ? { taxableCapitalSchedule } : {},
|
|
9696
|
+
...grip ? { grip } : {},
|
|
9697
|
+
...partIII1 ? { partIII1 } : {}
|
|
9698
|
+
})
|
|
8676
9699
|
};
|
|
8677
9700
|
}
|
|
8678
9701
|
//#endregion
|
|
@@ -8910,7 +9933,7 @@ function computeQuebecTax(input, rates = QC_TAX_2024) {
|
|
|
8910
9933
|
}
|
|
8911
9934
|
//#endregion
|
|
8912
9935
|
//#region src/t2/co17/schedules/quebec-allocation.ts
|
|
8913
|
-
const nn$
|
|
9936
|
+
const nn$1 = (v) => Math.max(0, v ?? 0);
|
|
8914
9937
|
function computeQuebecAllocationFactor(establishments, quebecCode = "QC") {
|
|
8915
9938
|
let quebecRevenue = 0;
|
|
8916
9939
|
let totalRevenue = 0;
|
|
@@ -8919,8 +9942,8 @@ function computeQuebecAllocationFactor(establishments, quebecCode = "QC") {
|
|
|
8919
9942
|
let quebecCount = 0;
|
|
8920
9943
|
const total = establishments.length;
|
|
8921
9944
|
for (const pe of establishments) {
|
|
8922
|
-
const rev = nn$
|
|
8923
|
-
const pay = nn$
|
|
9945
|
+
const rev = nn$1(pe.grossRevenue);
|
|
9946
|
+
const pay = nn$1(pe.salariesWages);
|
|
8924
9947
|
totalRevenue += rev;
|
|
8925
9948
|
totalSalaries += pay;
|
|
8926
9949
|
if (pe.province === quebecCode) {
|
|
@@ -9408,215 +10431,6 @@ function computeT2Settlement(input) {
|
|
|
9408
10431
|
};
|
|
9409
10432
|
}
|
|
9410
10433
|
//#endregion
|
|
9411
|
-
//#region src/t2/schedules/eifel-adjusted-taxable-income.ts
|
|
9412
|
-
/**
|
|
9413
|
-
* ITA subsection 18.2(1) — **adjusted taxable income**, the base the EIFEL
|
|
9414
|
-
* ceiling is computed on.
|
|
9415
|
-
*
|
|
9416
|
-
* `eifel-limitation.ts` took this as a required input because deriving it
|
|
9417
|
-
* partially would produce a plausible figure from an incomplete definition. This
|
|
9418
|
-
* derives it, and is explicit about the components it does and does not cover.
|
|
9419
|
-
*
|
|
9420
|
-
* ── What it is ──────────────────────────────────────────────────────────────
|
|
9421
|
-
*
|
|
9422
|
-
* An EBITDA-like measure, built from taxable income by adding back the things the
|
|
9423
|
-
* regime is measuring against and removing the things that would double-count.
|
|
9424
|
-
*
|
|
9425
|
-
* ATI = A + B − C
|
|
9426
|
-
*
|
|
9427
|
-
* A = D − E the income base
|
|
9428
|
-
* B the ADD-BACKS
|
|
9429
|
-
* C the REDUCTIONS
|
|
9430
|
-
*
|
|
9431
|
-
* **The add-backs include the interest and financing expenses themselves.** That
|
|
9432
|
-
* is the point of the measure and the thing to hold on to: the ceiling is a
|
|
9433
|
-
* percentage of income computed *before* the very expenses being limited, so a
|
|
9434
|
-
* corporation cannot shrink its own ceiling by borrowing more.
|
|
9435
|
-
*
|
|
9436
|
-
* ── A — the income base (D − E) ─────────────────────────────────────────────
|
|
9437
|
-
*
|
|
9438
|
-
* **D** is taxable income for the year, determined **without regard to** s.18.2(2)
|
|
9439
|
-
* itself, paragraphs 12(1)(l.2) and 111(1)(a.1), and clause 95(2)(f.11)(ii)(D) —
|
|
9440
|
-
* a non-resident uses taxable income earned in Canada on the same basis. The
|
|
9441
|
-
* circularity is deliberate: the limitation cannot be an input to its own base.
|
|
9442
|
-
*
|
|
9443
|
-
* **E** subtracts the year's non-capital loss on the same basis, any amount
|
|
9444
|
-
* claimed under paragraph 111(1)(a) that did not actually reduce taxable income,
|
|
9445
|
-
* and a controlled-foreign-affiliate component (`T × U ÷ V`).
|
|
9446
|
-
*
|
|
9447
|
-
* ── B — the add-backs ───────────────────────────────────────────────────────
|
|
9448
|
-
*
|
|
9449
|
-
* (a) interest and financing expenses for the year
|
|
9450
|
-
* (b) capital cost allowance and resource deductions — paragraph 20(1)(a),
|
|
9451
|
-
* 59.1(a) and subsections 66(4), 66.1(2)/(3), 66.2(2), 66.21(4), 66.4(2),
|
|
9452
|
-
* 66.7(1)-(5)
|
|
9453
|
-
* (c) terminal losses — subsection 20(16)
|
|
9454
|
-
* (d) the taxpayer's share of a partnership's 20(1)(a) and 20(16) deductions
|
|
9455
|
-
* (e) the portion of a paragraph 111(1)(e) limited-partnership-loss claim
|
|
9456
|
-
* attributable to those amounts
|
|
9457
|
-
*
|
|
9458
|
-
* ── C — the reductions ──────────────────────────────────────────────────────
|
|
9459
|
-
*
|
|
9460
|
-
* (a) interest and financing revenues
|
|
9461
|
-
* (b) recapture — subsection 13(1)
|
|
9462
|
-
* (c) the taxpayer's share of a partnership's 13(1) inclusion
|
|
9463
|
-
* (d) resource inclusions — subsections 59(1), 59(3.2), paragraph 59.1(b)
|
|
9464
|
-
* (e) for a corporation, a grossed-up foreign tax credit amount:
|
|
9465
|
-
* **100/28** of what would be deductible under s.126(1), and
|
|
9466
|
-
* the s.126(2) amounts times the relevant factor
|
|
9467
|
-
*
|
|
9468
|
-
* ── Not modelled ────────────────────────────────────────────────────────────
|
|
9469
|
-
*
|
|
9470
|
-
* The trust variant of C(e), and the later paragraphs of B and C dealing with
|
|
9471
|
-
* foreign affiliate income and exempt interest. Each is available as an explicit
|
|
9472
|
-
* `otherAdditions` / `otherReductions` input rather than silently omitted, so a
|
|
9473
|
-
* preparer with one of those amounts can still arrive at the right figure and the
|
|
9474
|
-
* engine does not pretend the definition is shorter than it is.
|
|
9475
|
-
*
|
|
9476
|
-
* Source: `research/sources/legislation/ITA-section-18.2-EIFEL.txt`.
|
|
9477
|
-
*
|
|
9478
|
-
* Pure, whole dollars.
|
|
9479
|
-
*/
|
|
9480
|
-
/** C(e)(i) — s.126(1) amounts are grossed up by 100/28. */
|
|
9481
|
-
const FOREIGN_TAX_CREDIT_GROSS_UP = 100 / 28;
|
|
9482
|
-
const nn$2 = (v) => Math.max(0, Math.round(v ?? 0));
|
|
9483
|
-
function computeAdjustedTaxableIncome(input) {
|
|
9484
|
-
const issues = [];
|
|
9485
|
-
const e = nn$2(input.nonCapitalLossForYear) + nn$2(input.lossClaimNotReducingTaxableIncome) + nn$2(input.foreignAccrualPropertyLossComponent);
|
|
9486
|
-
const incomeBase = Math.round(input.taxableIncome) - e;
|
|
9487
|
-
const totalAdditions = nn$2(input.interestAndFinancingExpenses) + nn$2(input.capitalCostAllowance) + nn$2(input.resourceDeductions) + nn$2(input.terminalLoss) + nn$2(input.partnershipCapitalAndTerminalShare) + nn$2(input.limitedPartnershipLossPortion) + nn$2(input.otherAdditions);
|
|
9488
|
-
const totalReductions = nn$2(input.interestAndFinancingRevenues) + nn$2(input.recapture) + nn$2(input.partnershipRecaptureShare) + nn$2(input.resourceInclusions) + Math.round(FOREIGN_TAX_CREDIT_GROSS_UP * nn$2(input.section126_1ForeignTaxCredits)) + nn$2(input.section126_2GrossedUp) + nn$2(input.otherReductions);
|
|
9489
|
-
const adjustedTaxableIncome = incomeBase + totalAdditions - totalReductions;
|
|
9490
|
-
if (adjustedTaxableIncome < 0) issues.push(`EIFEL: adjusted taxable income is negative (${adjustedTaxableIncome}), so the ceiling is nil and every interest and financing expense is denied. Check that the loss and add-back figures are complete before filing on that basis.`);
|
|
9491
|
-
if (input.interestAndFinancingExpenses === void 0) issues.push("EIFEL: no interest and financing expenses were added back to adjusted taxable income. They are paragraph (a) of the add-backs, and omitting them understates the ceiling — which denies more expense than the rules require.");
|
|
9492
|
-
return {
|
|
9493
|
-
incomeBase,
|
|
9494
|
-
totalAdditions,
|
|
9495
|
-
totalReductions,
|
|
9496
|
-
adjustedTaxableIncome,
|
|
9497
|
-
issues
|
|
9498
|
-
};
|
|
9499
|
-
}
|
|
9500
|
-
//#endregion
|
|
9501
|
-
//#region src/t2/schedules/eifel-limitation.ts
|
|
9502
|
-
/**
|
|
9503
|
-
* ITA subsection 18.2(2) — the excessive interest and financing expenses
|
|
9504
|
-
* limitation itself.
|
|
9505
|
-
*
|
|
9506
|
-
* `eifel-excluded-entity.ts` decides **whether** the regime applies. This decides
|
|
9507
|
-
* **how much** it denies, which was previously left unbuilt on the grounds that
|
|
9508
|
-
* computing it from an unbuilt definition would be confidently wrong.
|
|
9509
|
-
*
|
|
9510
|
-
* ── The provision ───────────────────────────────────────────────────────────
|
|
9511
|
-
*
|
|
9512
|
-
* s.18.2(2) denies a *proportion* of each interest and financing expense:
|
|
9513
|
-
*
|
|
9514
|
-
* (A − (B + C + D + E)) ÷ F
|
|
9515
|
-
*
|
|
9516
|
-
* A the taxpayer's interest and financing expenses for the year
|
|
9517
|
-
* B the group-ratio amount under s.18.21(2) where that applies, otherwise
|
|
9518
|
-
* **G × H** — the ratio of permissible expenses times adjusted taxable income
|
|
9519
|
-
* C the taxpayer's interest and financing revenues for the year
|
|
9520
|
-
* D received capacity, to the extent it exceeds the amount deductible under
|
|
9521
|
-
* paragraph 111(1)(a.1)
|
|
9522
|
-
* E absorbed capacity
|
|
9523
|
-
* F ordinarily the same figure as A
|
|
9524
|
-
*
|
|
9525
|
-
* Because F is A in the ordinary case, the *amount* denied is simply
|
|
9526
|
-
*
|
|
9527
|
-
* denied = A − (B + C + D + E), floored at nil
|
|
9528
|
-
*
|
|
9529
|
-
* which is the form this module computes, while still reporting the proportion —
|
|
9530
|
-
* the statute denies a fraction of *each* expense, and a preparer allocating the
|
|
9531
|
-
* denial across expense lines needs the fraction rather than the total.
|
|
9532
|
-
*
|
|
9533
|
-
* ── The ratio of permissible expenses ───────────────────────────────────────
|
|
9534
|
-
*
|
|
9535
|
-
* Keyed off when the taxation year **BEGINS**, not when it ends:
|
|
9536
|
-
*
|
|
9537
|
-
* begins on or after 2023-10-01 and before 2024-01-01 → **40%**
|
|
9538
|
-
* begins on or after 2024-01-01 → **30%**
|
|
9539
|
-
*
|
|
9540
|
-
* The 40% band is transitional and narrow — one quarter — and it does **not**
|
|
9541
|
-
* apply when determining cumulative unused excess capacity for a year beginning
|
|
9542
|
-
* on or after 1 January 2024. That carve-out is not modelled; excess-capacity
|
|
9543
|
-
* carry-forward is a separate mechanism this module does not compute.
|
|
9544
|
-
*
|
|
9545
|
-
* ── What this module does NOT compute ───────────────────────────────────────
|
|
9546
|
-
*
|
|
9547
|
-
* **Adjusted taxable income** is an input, not a derivation. Its definition is a
|
|
9548
|
-
* build-up from taxable income through a dozen add-backs and reductions —
|
|
9549
|
-
* interest and financing expenses, capital cost allowance, resource deductions,
|
|
9550
|
-
* loss claims with their own nested formulas — each with its own defined term. A
|
|
9551
|
-
* partial implementation would produce a plausible number from an incomplete
|
|
9552
|
-
* definition, which is precisely the failure this module was deferred to avoid.
|
|
9553
|
-
* It is therefore **required**, and an absent one denies nothing while saying so.
|
|
9554
|
-
*
|
|
9555
|
-
* Likewise the group-ratio election under s.18.21, and the received/absorbed
|
|
9556
|
-
* capacity amounts, which come from the excess-capacity regime.
|
|
9557
|
-
*
|
|
9558
|
-
* Source: `research/sources/legislation/ITA-section-18.2-EIFEL.txt`.
|
|
9559
|
-
*
|
|
9560
|
-
* Pure, whole dollars.
|
|
9561
|
-
*/
|
|
9562
|
-
/** The ratio bands, keyed off the taxation year START. */
|
|
9563
|
-
const EIFEL_TRANSITIONAL_RATIO = .4;
|
|
9564
|
-
const EIFEL_STANDARD_RATIO = .3;
|
|
9565
|
-
/** The regime's first day — years beginning before this are outside it. */
|
|
9566
|
-
const EIFEL_FIRST_YEAR_START = "2023-10-01";
|
|
9567
|
-
/** The transitional 40% band ends when years beginning in 2024 start. */
|
|
9568
|
-
const EIFEL_STANDARD_RATIO_FROM = "2024-01-01";
|
|
9569
|
-
const nn$1 = (v) => Math.max(0, Math.round(v ?? 0));
|
|
9570
|
-
function utcDay(iso) {
|
|
9571
|
-
return Date.parse(`${iso.slice(0, 10)}T00:00:00Z`);
|
|
9572
|
-
}
|
|
9573
|
-
/**
|
|
9574
|
-
* The ratio of permissible expenses for a year beginning on `taxYearStart`.
|
|
9575
|
-
* Returns 0 for a year beginning before the regime applies at all.
|
|
9576
|
-
*/
|
|
9577
|
-
function ratioOfPermissibleExpenses(taxYearStart) {
|
|
9578
|
-
const start = utcDay(taxYearStart);
|
|
9579
|
-
if (Number.isNaN(start) || start < utcDay("2023-10-01")) return 0;
|
|
9580
|
-
return start < utcDay("2024-01-01") ? EIFEL_TRANSITIONAL_RATIO : EIFEL_STANDARD_RATIO;
|
|
9581
|
-
}
|
|
9582
|
-
function computeEifelLimitation(input) {
|
|
9583
|
-
const issues = [];
|
|
9584
|
-
const ife = nn$1(input.interestAndFinancingExpenses);
|
|
9585
|
-
const nil = (ratio) => ({
|
|
9586
|
-
ratioOfPermissibleExpenses: ratio,
|
|
9587
|
-
permittedAmount: 0,
|
|
9588
|
-
usedGroupRatio: false,
|
|
9589
|
-
totalShelter: 0,
|
|
9590
|
-
deniedAmount: 0,
|
|
9591
|
-
deniedProportion: 0,
|
|
9592
|
-
deductibleAmount: ife,
|
|
9593
|
-
issues
|
|
9594
|
-
});
|
|
9595
|
-
const ratio = ratioOfPermissibleExpenses(input.taxYearStart);
|
|
9596
|
-
if (ratio === 0) {
|
|
9597
|
-
issues.push(`EIFEL: the taxation year beginning ${input.taxYearStart} is before the regime applies (${EIFEL_FIRST_YEAR_START}), so nothing is denied.`);
|
|
9598
|
-
return nil(0);
|
|
9599
|
-
}
|
|
9600
|
-
const usedGroupRatio = input.groupRatioAmount !== void 0;
|
|
9601
|
-
if (!usedGroupRatio && input.adjustedTaxableIncome === void 0) {
|
|
9602
|
-
issues.push("EIFEL: adjusted taxable income was not supplied, so no interest and financing expense was denied. The limitation cannot be computed without it — the figure is a build-up from taxable income that this engine does not derive, and it must be supplied or the return reviewed by hand.");
|
|
9603
|
-
return nil(ratio);
|
|
9604
|
-
}
|
|
9605
|
-
const permittedAmount = usedGroupRatio ? nn$1(input.groupRatioAmount) : Math.round(ratio * Math.max(0, input.adjustedTaxableIncome ?? 0));
|
|
9606
|
-
const totalShelter = permittedAmount + nn$1(input.interestAndFinancingRevenues) + nn$1(input.excessReceivedCapacity) + nn$1(input.absorbedCapacity);
|
|
9607
|
-
const deniedAmount = Math.max(0, ife - totalShelter);
|
|
9608
|
-
return {
|
|
9609
|
-
ratioOfPermissibleExpenses: ratio,
|
|
9610
|
-
permittedAmount,
|
|
9611
|
-
usedGroupRatio,
|
|
9612
|
-
totalShelter,
|
|
9613
|
-
deniedAmount,
|
|
9614
|
-
deniedProportion: ife > 0 ? deniedAmount / ife : 0,
|
|
9615
|
-
deductibleAmount: ife - deniedAmount,
|
|
9616
|
-
issues
|
|
9617
|
-
};
|
|
9618
|
-
}
|
|
9619
|
-
//#endregion
|
|
9620
10434
|
//#region src/t2/schedules/schedule27-mp.ts
|
|
9621
10435
|
/**
|
|
9622
10436
|
* T2 Schedule 27 — Canadian Manufacturing and Processing Profits Deduction
|
|
@@ -9794,4 +10608,4 @@ function computeMpDeduction(input, rates = MP_RATES_2024) {
|
|
|
9794
10608
|
};
|
|
9795
10609
|
}
|
|
9796
10610
|
//#endregion
|
|
9797
|
-
export {
|
|
10611
|
+
export { computeSchedule6 as $, schedule21Values$1 as $i, resolveCcaRates as $n, computeIegReductionFactor as $r, dividendsDeductibleS112 as $t, LRIP_INVESTMENT_CORPORATION_MULTIPLE as A, computeAlbertaSchedule6 as Ai, AT1_RESERVE_LINES as An, renderRsiHeader as Ar, computeExcessIfe as At, computeZetm as B, computeAt4970 as Bi, CLASS_14_1_MINIMUM_DEDUCTION as Bn, assertCriticalFields as Br, assessEifel as Bt, runConformance as C, computeAlbertaSchedule9 as Ci, AT1_DONATION_INCOME_RATE as Cn, RSI_NEGATIVE_PREFIX as Cr, EIFEL_STANDARD_RATIO_FROM as Ct, SCHEDULE_88_MAX_URLS as D, schedule8Values$1 as Di, SECTION_34_2_GROSS_UP as Dn, formatRsiDate as Dr, computeBorrowings as Dt, computeSchedule101 as E, computeSchedule8$1 as Ei, AT1_DISPOSITION_CATEGORIES as En, formatRsiAmount as Er, ratioOfPermissibleExpenses as Et, LARGE_CORPORATION_THRESHOLD as F, schedule4Values as Fi, computeAlbertaSchedule13 as Fn, At1MandatoryFieldMissingError as Fr, computeLossPortionFromIfe as Ft, computeCde as G, schedule12LossDeductions as Gi, computeClass13 as Gn, computeAlbertaReturn as Gr, PROVINCE_RATES_2024 as Gt, computeBusinessLimitAllocation as H, AT1_SCHEDULES_WITH_BUILDERS as Hi, CLASS_14_1_TRANSITIONAL_RATE as Hn, at1YesNo as Hr, computeRifeUnderSubsection111_8 as Ht, computeTaxableCapital as I, computeSchedule3 as Ii, UnsupportedCcaClassError as In, At1TaxPayableMismatchError as Ir, computePartnershipIfe as It, computeCumulativeForeignResource as J, schedule16Values as Ji, computeClass141RecaptureReduction as Jn, computeIegAgreement as Jr, resolveProvinceRates as Jt, computeCee as K, schedule12Values as Ki, computeClass14 as Kn, allocateIegEvenly as Kr, PROVINCE_RATE_BOOK as Kt, computeSchedule31 as L, schedule3Values as Li, computeCcaClass as Ln, albertaBalanceUnpaid as Lr, computePartnershipIfeAddBack as Lt, computeSchedule54 as M, computeAlbertaSchedule5 as Mi, computeAlbertaSchedule17 as Mn, renderAt1NetFile as Mr, computeInterestAndFinancingExpenses as Mt, computeGrip as N, schedule5Values as Ni, assistanceFrom as Nn, AT1_CRITICAL_MANDATORY_FIELDS as Nr, computeInterestAndFinancingRevenues as Nt, normalizeSchedule88 as O, computeAlbertaSchedule7 as Oi, computeAlbertaSchedule18 as On, formatRsiText as Or, computeCapitalizedIfe as Ot, computeSchedule43 as P, computeSchedule4 as Pi, computeAlbertaSchedule16 as Pn, At1CriticalFieldMissingError as Pr, computeLoans as Pt, computeSpecifiedForeignExploration as Q, schedule20Values as Qi, isDecliningBalanceClass as Qn, computeIegBaseAmount as Qr, computeTaxableIncome as Qt, ITC_RECAPTURE_PERIOD_YEARS as R, SINGLE_JURISDICTION_ALBERTA_FACTOR as Ri, computeCcaSchedule as Rn, assertAt1MandatoryComplete as Rr, computeResourceIfe as Rt, formatConformanceReport as S, allocateSchedule9ExpenditureLimit as Si, AT1_DONATION_GAIN_RATE as Sn, RSI_DELIMITER as Sr, EIFEL_STANDARD_RATIO as St, computeFederalT2 as T, schedule9Values as Ti, computeSchedule20 as Tn, RsiLineItemError as Tr, computeEifelLimitation as Tt, computeSchedule21 as U, at1LineItemId as Ui, MAX_LEASEHOLD_PERIODS as Un, xmlEscape as Ur, FOREIGN_TAX_CREDIT_GROSS_UP as Ut, allocateEvenly as V, AT1_SCHEDULES_WITHOUT_BUILDERS as Vi, CLASS_14_1_RECAPTURE_REDUCTION_RATE as Vn, at1TaxPayableDeductions as Vr, computeEifelCapacity as Vt, computeSchedule13 as W, schedule10Values as Wi, MIN_LEASEHOLD_PERIODS as Wn, at1Engine as Wr, computeAdjustedTaxableIncome as Wt, computeForeignExploration as X, schedule18Values as Xi, CCA_DECLINING_BALANCE_RATES_2024 as Xn, IEG_2024 as Xr, dayWeightedRate as Xt, computeDepletion as Y, schedule17Values as Yi, leaseholdPeriods as Yn, computeIegGroupFigures as Yr, blendProvinceRateTable as Yt, computeSchedule12ResourceDeductions as Z, schedule1Values$1 as Zi, CCA_RATE_BOOK as Zn, computeIeg as Zr, charitableDonationsDeduction as Zt, QC_TAX_2024 as _, computeSfedeCountrySuccessor as _i, computeRifeContinuity as _n, toRsiHeader as _r, terminalLossDeduction as _t, computeCanadianMPProfits as a, AB_GENERAL_RATE_BANDS as aa, computeCdeRegular as ai, computeAggregateInvestmentIncome as an, albertaDispositionAdjustments as ar, computePart4Rdtoh as at, T2_LINE_META as b, ALBERTA_SRED_PROGRAM_START as bi, computeLimitedPartnershipLossRow as bn, toRsiSchedule as br, partVI1DeductionMultiple as bt, computeSmallManufacturerTest as c, AB_TAX_RATE_BOOK as ca, computeCeeSuccessor as ci, CORP_TAX_2024 as cn, albertaResourceDeductionDifference as cr, amortizationAddBack as ct, t2Engine as d, extendRateBook as da, computeCmedb as di, federalSchedulePayloads as dn, reconcileAlbertaNetIncome as dr, computeSchedule1 as dt, schedule29Values as ea, computeIegEligibleExpenditures as ei, netCapitalLossApplied as en, albertaAbilDifference as er, computeProvincialAllocation as et, renderCo17DraftReturn as f, hasExactRateYear as fa, computeEdaRegular as fi, parseT2LineItemId as fn, LossCarrybackError as fr, deferredIncomeTaxProvisionAddBack as ft, computeQuebecTax as g, computeSfedeCountryRegular as gi, computeOtherLossByYearOfOrigin as gn, validateAt1Transmitter as gr, recaptureAddBack as gt, computeQuebecAllocationFactor as h, computeFedeSuccessor as hi, computeNonCapitalLossByYearOfOrigin as hn, assertAt1TransmitterValid as hr, mealsAndEntertainmentAddBack as ht, SMALL_MANUFACTURER_INCOME_THRESHOLD as i, computeAlbertaSbd as ia, computeCcogpeSuccessor as ii, computeAdjustedAggregateInvestmentIncome as in, albertaCurrentYearLoss as ir, REFUNDABLE_PART_I_RATE as it, LRIP_INVESTMENT_INCOME_FACTOR as j, schedule6Values as ji, AT1_RESERVE_TOTAL_LINES as jn, renderRsiLineItem as jr, computeExemptIfe as jt, computeSchedule55 as k, schedule7Values$1 as ki, AT1_RESERVE_KINDS as kn, renderAt1Rsi as kr, computeClause95Amounts as kt, computeT2Settlement as l, resolveAlbertaTaxRates as la, computeCfreRegular as li, CORP_TAX_RATE_BOOK as ln, albertaTerminalLossDifference as lr, assertSchedule1Fileable as lt, computeQuebecReturn as m, resolveRates as ma, computeFedeRegular as mi, T2_CERTIFICATION_FIXTURES as mn, At1TransmitterInvalidError as mr, incomeTaxProvisionAddBack as mt, MP_GROSS_REVENUE_THRESHOLD as n, schedule4970Values as na, computeAlbertaSchedule15 as ni, computeCcpcActiveBusinessTax as nn, albertaCcaDifference as nr, computeSchedule4Losses as nt, computeMpDeduction as o, computeDayWeightedGeneralTax as oa, computeCdeSuccessor as oi, computeBusinessLimit as on, albertaRecaptureDifference as or, computeSchedule2 as ot, co17Engine as p, latestRateYear as pa, computeEdaSuccessor as pi, t2LineItemId as pn, computeLossCarryback as pr, findSchedule1LineDefects as pt, computeCogpe as q, schedule13Values as qi, computeClass141AdditionalAllowance as qn, allocateIegExpenditureLimit as qr, isSchedule5Province as qt, MP_RATES_2024 as r, computeAlbertaTax as ra, computeCcogpeRegular as ri, computePartITax as rn, albertaCcaScheduleAdjustments as rr, PART_IV_RATE as rt, computePart2MPProfits as s, AB_TAX_2024 as sa, computeCeeRegular as si, computeSBD as sn, albertaReserveDifference as sr, Schedule1NotFileableError as st, MP_EXCLUDED_ACTIVITIES as t, schedule2Values$1 as ta, iegT661SourceLine as ti, nonCapitalLossApplied as tn, albertaCapitalGainDifference as tr, computeSchedule5 as tt, renderT2DraftReturn as u, earliestRateYear as ua, computeCfreSuccessor as ui, resolveCorpTaxRates as un, computeSchedule12 as ur, ccaDeduction as ut, QC_TAX_RATE_BOOK as v, schedule15Values as vi, computeLossSchedule as vn, toRsiJacketSchedules as vr, PART_VI_1_DEDUCTION_BANDS as vt, runConformanceSuite as w, computeSchedule9MaximumExpenditureLimit as wi, computeDonationMaximum as wn, RSI_WORD_GAP as wr, EIFEL_TRANSITIONAL_RATIO as wt, foldT2Lines as x, ALBERTA_SRED_TAX_CREDIT_RATE as xi, computeLimitedPartnershipLosses as xn, RSI_COLUMN_GAP as xr, EIFEL_FIRST_YEAR_START as xt, resolveQuebecTaxRates as y, ALBERTA_SRED_EXPENDITURE_CUTOFF as yi, computeLossContinuity as yn, toRsiLineItems as yr, computePartVI1Deduction as yt, computeItcRecapture as z, computeAllocationFactor as zi, computeSchedule8 as zn, assertAt1TaxPayableReconciles as zr, EIFEL_EFFECTIVE_FROM as zt };
|