@classytic/ca-tax 0.0.14 → 0.0.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +96 -0
- package/dist/forms/index.d.mts +2 -2
- package/dist/forms/index.mjs +2 -2
- package/dist/forms.mjs +7980 -7862
- package/dist/index.d.mts +83 -5
- package/dist/index.mjs +3 -3
- package/dist/index3.d.mts +855 -479
- 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 +853 -462
- package/package.json +1 -1
package/dist/t2.mjs
CHANGED
|
@@ -262,7 +262,6 @@ const AT1_SCHEDULES_WITH_BUILDERS = Object.freeze([
|
|
|
262
262
|
"008",
|
|
263
263
|
"009",
|
|
264
264
|
"010",
|
|
265
|
-
"011",
|
|
266
265
|
"012",
|
|
267
266
|
"013",
|
|
268
267
|
"015",
|
|
@@ -275,18 +274,20 @@ const AT1_SCHEDULES_WITH_BUILDERS = Object.freeze([
|
|
|
275
274
|
"4970"
|
|
276
275
|
]);
|
|
277
276
|
/**
|
|
278
|
-
* Schedules the engine computes but cannot yet file.
|
|
279
|
-
*
|
|
280
|
-
*
|
|
281
|
-
*
|
|
282
|
-
*
|
|
283
|
-
*
|
|
284
|
-
*
|
|
285
|
-
*
|
|
286
|
-
* Every
|
|
287
|
-
* form.
|
|
277
|
+
* Schedules the engine computes but cannot yet file — currently empty.
|
|
278
|
+
*
|
|
279
|
+
* Its one member, Schedule 14 (cumulative eligible capital), was removed
|
|
280
|
+
* entirely rather than left here: it had no server wiring and no UI to begin
|
|
281
|
+
* with, and applies only to a corporation whose tax year straddles
|
|
282
|
+
* 2016-12-31 (eligible capital property's repeal date) — see
|
|
283
|
+
* `research/findings/alberta/AT1-schedule14-cec.md`.
|
|
284
|
+
*
|
|
285
|
+
* Every implemented schedule has been verified line by line against the live
|
|
286
|
+
* certified form. Kept as a named, tested concept (not deleted outright)
|
|
287
|
+
* since a future schedule may legitimately land here again before its
|
|
288
|
+
* builder does.
|
|
288
289
|
*/
|
|
289
|
-
const AT1_SCHEDULES_WITHOUT_BUILDERS = Object.freeze([
|
|
290
|
+
const AT1_SCHEDULES_WITHOUT_BUILDERS = Object.freeze([]);
|
|
290
291
|
/** `SSSFFFOOO` — schedule id, field id, occurrence. Occurrence is 1-based. */
|
|
291
292
|
function at1LineItemId(scheduleId, fieldId, occurrence = 1) {
|
|
292
293
|
return `${scheduleId}${fieldId}${String(occurrence).padStart(3, "0")}`;
|
|
@@ -304,6 +305,8 @@ function schedule13Values(result) {
|
|
|
304
305
|
value
|
|
305
306
|
});
|
|
306
307
|
put("001", c.ccaClass);
|
|
308
|
+
put("035", c.alberta.aiipEnhancement);
|
|
309
|
+
put("037", c.alberta.halfYearAdjustment);
|
|
307
310
|
put("019", c.alberta.ccaClaimed);
|
|
308
311
|
put("015", c.alberta.recapture);
|
|
309
312
|
put("017", c.alberta.terminalLoss);
|
|
@@ -512,6 +515,7 @@ function schedule29Values(result, agreement, eligible, primaryFieldCode) {
|
|
|
512
515
|
put("031", eligible.totalEligibleExpenditures);
|
|
513
516
|
}
|
|
514
517
|
if (primaryFieldCode !== void 0) put("040", primaryFieldCode);
|
|
518
|
+
put("100", agreement ? 1 : 2);
|
|
515
519
|
put("110", result.creditAtBaseRate);
|
|
516
520
|
put(result.enhancedRateBasis === "associated" ? "125" : "112", result.creditAtEnhancedRate);
|
|
517
521
|
put("126", result.taxableCapital);
|
|
@@ -673,13 +677,26 @@ function schedule12Values(input) {
|
|
|
673
677
|
pair("004", "005", input.cca);
|
|
674
678
|
pair("006", "007", input.recapture);
|
|
675
679
|
pair("008", "009", input.terminalLoss);
|
|
680
|
+
pair("022", "023", input.depletion);
|
|
681
|
+
pair("026", "027", input.cee);
|
|
682
|
+
pair("028", "029", input.cde);
|
|
683
|
+
pair("030", "031", input.foreignExploration);
|
|
684
|
+
pair("032", "033", input.cogpe);
|
|
676
685
|
pair("036", "037", input.reservesDeductedPriorYear);
|
|
677
686
|
pair("038", "039", input.reservesClaimedCurrentYear);
|
|
687
|
+
const alwaysPair = (albertaField, federalField, p) => {
|
|
688
|
+
if (!p) return;
|
|
689
|
+
put(albertaField, p.alberta);
|
|
690
|
+
put(federalField, p.federal);
|
|
691
|
+
};
|
|
678
692
|
const d = input.lossDeductions;
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
693
|
+
alwaysPair("064", "065", d?.nonCapital);
|
|
694
|
+
alwaysPair("066", "067", d?.netCapital);
|
|
695
|
+
alwaysPair("068", "069", d?.restrictedFarm);
|
|
696
|
+
alwaysPair("070", "071", d?.farm);
|
|
697
|
+
alwaysPair("072", "073", d?.limitedPartnership);
|
|
698
|
+
alwaysPair("056", "057", input.donations?.charitable);
|
|
699
|
+
alwaysPair("058", "059", input.donations?.gifts);
|
|
683
700
|
put("054", input.albertaNetIncomeForTax);
|
|
684
701
|
return {
|
|
685
702
|
scheduleId: "012",
|
|
@@ -816,7 +833,6 @@ function schedule1Values(input) {
|
|
|
816
833
|
lineItemId: at1LineItemId("001", fieldId, occurrence),
|
|
817
834
|
value
|
|
818
835
|
});
|
|
819
|
-
if (input.isAssociated !== void 0) put("001", input.isAssociated ? 1 : 2);
|
|
820
836
|
const abi = Math.max(0, input.activeBusinessIncome ?? 0);
|
|
821
837
|
const taxable = Math.max(0, input.albertaTaxableIncome ?? 0);
|
|
822
838
|
const royalty = Math.max(0, input.royaltyTaxDeduction ?? 0);
|
|
@@ -2196,130 +2212,6 @@ function schedule9Values(result, group) {
|
|
|
2196
2212
|
};
|
|
2197
2213
|
}
|
|
2198
2214
|
//#endregion
|
|
2199
|
-
//#region src/t2/at1/schedules/schedule11-manufacturing-processing.ts
|
|
2200
|
-
const nn$26 = (v) => Math.max(0, Math.round(v ?? 0));
|
|
2201
|
-
function computeSchedule11(input) {
|
|
2202
|
-
const issues = [];
|
|
2203
|
-
const dateEligible = input.taxYearStart < "2001-04-01";
|
|
2204
|
-
if (!dateEligible) issues.push(`Schedule 11: the Alberta Manufacturing and Processing Profits Deduction applies only where the tax year begins before 2001-04-01 (TRA-spec lines 9135-9146). This tax year begins ${input.taxYearStart}, so no deduction applies; line 011042 is reported as nil regardless of the workings below.`);
|
|
2205
|
-
let grossRevenueRatio;
|
|
2206
|
-
let revenueEligible = true;
|
|
2207
|
-
if (dateEligible) if (input.manufacturingGrossRevenue == null || input.totalGrossRevenue == null) {
|
|
2208
|
-
revenueEligible = false;
|
|
2209
|
-
issues.push("Schedule 11: the 10% manufacturing gross-revenue test (TRA-spec lines 9138-9142) could not be run because gross revenue figures were not supplied, so form 011 is treated as not applicable.");
|
|
2210
|
-
} else {
|
|
2211
|
-
const total = nn$26(input.totalGrossRevenue);
|
|
2212
|
-
grossRevenueRatio = total > 0 ? nn$26(input.manufacturingGrossRevenue) / total : 0;
|
|
2213
|
-
if (grossRevenueRatio < .1) {
|
|
2214
|
-
revenueEligible = false;
|
|
2215
|
-
issues.push(`Schedule 11: manufacturing gross revenue is ${(grossRevenueRatio * 100).toFixed(1)}% of total gross revenue, below the 10% threshold in the AT1 spec, so form 011 is not applicable.`);
|
|
2216
|
-
}
|
|
2217
|
-
}
|
|
2218
|
-
const eligible = dateEligible && revenueEligible;
|
|
2219
|
-
let albertaAdjubi;
|
|
2220
|
-
if (input.albertaAdjubiFromSchedule12) albertaAdjubi = Math.max(0, Math.round(input.albertaAdjubiFromSchedule12.line112 + input.albertaAdjubiFromSchedule12.line114));
|
|
2221
|
-
else {
|
|
2222
|
-
albertaAdjubi = nn$26(input.federalAdjubi);
|
|
2223
|
-
if (input.federalAdjubi == null && eligible) issues.push("Schedule 11: neither `federalAdjubi` (fed 027130) nor `albertaAdjubiFromSchedule12` was supplied; line 011001 defaults to nil.");
|
|
2224
|
-
}
|
|
2225
|
-
let aggregateInvestmentIncome;
|
|
2226
|
-
if (input.isCcpc) if (input.schedule12Exists) aggregateInvestmentIncome = nn$26(input.albertaAggregateInvestmentIncome);
|
|
2227
|
-
else {
|
|
2228
|
-
aggregateInvestmentIncome = nn$26(input.federalAggregateInvestmentIncome);
|
|
2229
|
-
if (input.federalAggregateInvestmentIncome == null) issues.push("Schedule 11: the corp is a CCPC and no Alberta Schedule 12 exists, so line 011013 must equal fed 200440, but `federalAggregateInvestmentIncome` was not supplied; line 011013 defaults to nil.");
|
|
2230
|
-
}
|
|
2231
|
-
const isSmallManufacturingCorp = input.isSmallManufacturingCorp ?? false;
|
|
2232
|
-
let costOfCapital = 0;
|
|
2233
|
-
let albertaCostOfCapital = 0;
|
|
2234
|
-
let costOfLabour = 0;
|
|
2235
|
-
let albertaCostOfLabour = 0;
|
|
2236
|
-
let albertaManufacturingProcessingProfits = 0;
|
|
2237
|
-
if (isSmallManufacturingCorp) {
|
|
2238
|
-
if (input.costOfCapital != null || input.albertaCostOfCapital != null || input.costOfLabour != null || input.albertaCostOfLabour != null) issues.push("Schedule 11: lines 011031-011039 must not exist for a small manufacturing corp, but capital/labour figures were supplied; they are ignored for line 011042.");
|
|
2239
|
-
if (input.smallManufacturerAmpp != null) albertaManufacturingProcessingProfits = nn$26(input.smallManufacturerAmpp);
|
|
2240
|
-
else if (eligible) issues.push("Schedule 11: the small-manufacturing-corp formula for line 011042 is not stated in the transcribed spec range (TRA-spec lines 9082-9397); supply `smallManufacturerAmpp` directly per the AT1 Guide criteria. Line 011042 defaults to nil.");
|
|
2241
|
-
} else {
|
|
2242
|
-
costOfCapital = nn$26(input.costOfCapital);
|
|
2243
|
-
albertaCostOfCapital = nn$26(input.albertaCostOfCapital);
|
|
2244
|
-
costOfLabour = nn$26(input.costOfLabour);
|
|
2245
|
-
albertaCostOfLabour = nn$26(input.albertaCostOfLabour);
|
|
2246
|
-
if (albertaCostOfCapital > costOfCapital) {
|
|
2247
|
-
issues.push(`Schedule 11: line 011033 (Alberta Cost of Manufacturing and Processing Capital, ${albertaCostOfCapital}) exceeds line 011031 (Cost of Capital, ${costOfCapital}); the AT1 spec requires 011033 ≤ 011031. Clamped to ${costOfCapital}.`);
|
|
2248
|
-
albertaCostOfCapital = costOfCapital;
|
|
2249
|
-
}
|
|
2250
|
-
if (albertaCostOfLabour > costOfLabour) {
|
|
2251
|
-
issues.push(`Schedule 11: line 011039 (Alberta Cost of Manufacturing and Processing Labour, ${albertaCostOfLabour}) exceeds line 011037 (Cost of Labour, ${costOfLabour}); the AT1 spec requires 011039 ≤ 011037. Clamped to ${costOfLabour}.`);
|
|
2252
|
-
albertaCostOfLabour = costOfLabour;
|
|
2253
|
-
}
|
|
2254
|
-
const denominator = costOfCapital + costOfLabour;
|
|
2255
|
-
if (denominator === 0) {
|
|
2256
|
-
if (albertaAdjubi > 0 && eligible) issues.push("Schedule 11: Cost of Capital (011031) and Cost of Labour (011037) are both nil, so the line 011042 proration cannot be computed; supply them. Line 011042 defaults to nil.");
|
|
2257
|
-
} else {
|
|
2258
|
-
const factor = (Math.min(albertaCostOfCapital * 100 / 85, costOfCapital) + Math.min(albertaCostOfLabour * 100 / 75, costOfLabour)) / denominator;
|
|
2259
|
-
albertaManufacturingProcessingProfits = Math.round(albertaAdjubi * factor);
|
|
2260
|
-
}
|
|
2261
|
-
}
|
|
2262
|
-
if (!eligible && albertaManufacturingProcessingProfits > 0) issues.push(`Schedule 11: the workings above yield ${albertaManufacturingProcessingProfits}, but the deduction is not applicable this year (see the eligibility issue above); line 011042 is reported as nil.`);
|
|
2263
|
-
if (!eligible) albertaManufacturingProcessingProfits = 0;
|
|
2264
|
-
return {
|
|
2265
|
-
eligible,
|
|
2266
|
-
isSmallManufacturingCorp,
|
|
2267
|
-
albertaAdjubi,
|
|
2268
|
-
...aggregateInvestmentIncome !== void 0 ? { aggregateInvestmentIncome } : {},
|
|
2269
|
-
costOfCapital,
|
|
2270
|
-
albertaCostOfCapital,
|
|
2271
|
-
costOfLabour,
|
|
2272
|
-
albertaCostOfLabour,
|
|
2273
|
-
albertaManufacturingProcessingProfits,
|
|
2274
|
-
...grossRevenueRatio !== void 0 ? { grossRevenueRatio } : {},
|
|
2275
|
-
issues
|
|
2276
|
-
};
|
|
2277
|
-
}
|
|
2278
|
-
function schedule11LineItemId(fieldId, occurrence = 1) {
|
|
2279
|
-
return `011${fieldId}${String(occurrence).padStart(3, "0")}`;
|
|
2280
|
-
}
|
|
2281
|
-
/**
|
|
2282
|
-
* Field ids per the spec transcription above: 001 (AMPPD/ADJUBI), 013 (CCPC
|
|
2283
|
-
* aggregate investment income), 031/033/037/039 (cost of capital/labour, both
|
|
2284
|
-
* jurisdictions) and 042 (Alberta M&P Profits).
|
|
2285
|
-
*
|
|
2286
|
-
* Line 042 is ALWAYS emitted, including when the historical-eligibility gate
|
|
2287
|
-
* (pre-2001-04-01 tax year AND the 10% gross-revenue test) has forced it to
|
|
2288
|
-
* nil — an ineligible year still has a line 011042 on the form, and it reads
|
|
2289
|
-
* nil, so this files nil rather than omitting the line entirely. The REASON
|
|
2290
|
-
* it is nil (a `Schedule 11: … applies only where the tax year begins before
|
|
2291
|
-
* 2001-04-01 …` / `… below the 10% threshold …` entry) lives on
|
|
2292
|
-
* `result.issues`, which this builder does not carry onto the wire itself —
|
|
2293
|
-
* the caller already has `result` (this function's own input) and so already
|
|
2294
|
-
* has `result.issues` sitting beside whatever this returns; duplicating it
|
|
2295
|
-
* onto `At1ScheduleDataLike`, which has no field for prose, would only be
|
|
2296
|
-
* losing information conversion by not adding any.
|
|
2297
|
-
*
|
|
2298
|
-
* Line 013 (CCPC aggregate investment income) is the one line legitimately
|
|
2299
|
-
* OMITTED rather than filed as nil: it is undefined, not zero, for a non-CCPC
|
|
2300
|
-
* corporation — the spec's own business rule gates it on `000029 = 1 or 2`,
|
|
2301
|
-
* so a non-CCPC has no box to fill here at all, unlike line 042's "nil is a
|
|
2302
|
-
* real answer" case above.
|
|
2303
|
-
*/
|
|
2304
|
-
function schedule11Values(result) {
|
|
2305
|
-
const values = [];
|
|
2306
|
-
const put = (fieldId, value) => values.push({
|
|
2307
|
-
lineItemId: schedule11LineItemId(fieldId),
|
|
2308
|
-
value
|
|
2309
|
-
});
|
|
2310
|
-
put("001", result.albertaAdjubi);
|
|
2311
|
-
if (result.aggregateInvestmentIncome !== void 0) put("013", result.aggregateInvestmentIncome);
|
|
2312
|
-
put("031", result.costOfCapital);
|
|
2313
|
-
put("033", result.albertaCostOfCapital);
|
|
2314
|
-
put("037", result.costOfLabour);
|
|
2315
|
-
put("039", result.albertaCostOfLabour);
|
|
2316
|
-
put("042", result.albertaManufacturingProcessingProfits);
|
|
2317
|
-
return {
|
|
2318
|
-
scheduleId: "011",
|
|
2319
|
-
values
|
|
2320
|
-
};
|
|
2321
|
-
}
|
|
2322
|
-
//#endregion
|
|
2323
2215
|
//#region src/t2/at1/schedules/schedule15-resource-related-deductions.ts
|
|
2324
2216
|
/**
|
|
2325
2217
|
* Alberta AT1 Schedule 15 — Alberta Resource Related Deductions.
|
|
@@ -2466,9 +2358,9 @@ function schedule11Values(result) {
|
|
|
2466
2358
|
*
|
|
2467
2359
|
* Whole dollars, pure functions, no I/O.
|
|
2468
2360
|
*/
|
|
2469
|
-
const nn$
|
|
2361
|
+
const nn$26 = (v) => Math.max(0, v ?? 0);
|
|
2470
2362
|
const num$1 = (v) => v ?? 0;
|
|
2471
|
-
const round = (v) => Math.round(v);
|
|
2363
|
+
const round$1 = (v) => Math.round(v);
|
|
2472
2364
|
/** `override ?? federal`, tracking whether an Alberta-specific figure was actually entered. */
|
|
2473
2365
|
function reconcile(federal, override) {
|
|
2474
2366
|
return override !== void 0 ? {
|
|
@@ -2483,7 +2375,7 @@ function reconcile(federal, override) {
|
|
|
2483
2375
|
* CDE / CCOGPE style short-tax-year proration: the full rate applies with NO
|
|
2484
2376
|
* proration once the tax year reaches 357 days; below that, rate × days/365.
|
|
2485
2377
|
*/
|
|
2486
|
-
function stepYearFactor(daysInTaxYear) {
|
|
2378
|
+
function stepYearFactor$1(daysInTaxYear) {
|
|
2487
2379
|
const days = daysInTaxYear ?? 365;
|
|
2488
2380
|
return days >= 357 ? 1 : Math.max(0, days) / 365;
|
|
2489
2381
|
}
|
|
@@ -2492,18 +2384,18 @@ function linearYearFactor(daysInTaxYear) {
|
|
|
2492
2384
|
return Math.max(0, daysInTaxYear ?? 365) / 365;
|
|
2493
2385
|
}
|
|
2494
2386
|
/** A discretionary claim capped at `cap` (≥ 0), defaulting to the maximum (`cap`) when omitted. */
|
|
2495
|
-
function claimUpToCap(requested, cap, issues, label) {
|
|
2496
|
-
const c = Math.max(0, round(cap));
|
|
2387
|
+
function claimUpToCap$1(requested, cap, issues, label) {
|
|
2388
|
+
const c = Math.max(0, round$1(cap));
|
|
2497
2389
|
if (requested === void 0) return c;
|
|
2498
2390
|
if (requested < 0) {
|
|
2499
2391
|
issues.push(`${label}: a requested claim of ${requested} is negative; treated as 0.`);
|
|
2500
2392
|
return 0;
|
|
2501
2393
|
}
|
|
2502
|
-
if (round(requested) > c) {
|
|
2394
|
+
if (round$1(requested) > c) {
|
|
2503
2395
|
issues.push(`${label}: the requested claim of ${requested} exceeds the maximum allowable ${c} for the year; capped at ${c}.`);
|
|
2504
2396
|
return c;
|
|
2505
2397
|
}
|
|
2506
|
-
return round(requested);
|
|
2398
|
+
return round$1(requested);
|
|
2507
2399
|
}
|
|
2508
2400
|
/**
|
|
2509
2401
|
* CEE-style claim: when the pool subtotal is ≤ 0 the claim MUST equal that
|
|
@@ -2512,12 +2404,12 @@ function claimUpToCap(requested, cap, issues, label) {
|
|
|
2512
2404
|
* claim up to the subtotal (100% claimable, no percentage rate), defaulting
|
|
2513
2405
|
* to the maximum.
|
|
2514
2406
|
*/
|
|
2515
|
-
function forcedOrCappedClaim(requested, subtotal, issues, label) {
|
|
2407
|
+
function forcedOrCappedClaim$1(requested, subtotal, issues, label) {
|
|
2516
2408
|
if (subtotal <= 0) {
|
|
2517
|
-
if (requested !== void 0 && round(requested) !== round(subtotal)) issues.push(`${label}: the pool subtotal is ${subtotal} (≤ 0), so the claim must equal the subtotal (an income inclusion) — overriding the requested ${requested}.`);
|
|
2518
|
-
return round(subtotal);
|
|
2409
|
+
if (requested !== void 0 && round$1(requested) !== round$1(subtotal)) issues.push(`${label}: the pool subtotal is ${subtotal} (≤ 0), so the claim must equal the subtotal (an income inclusion) — overriding the requested ${requested}.`);
|
|
2410
|
+
return round$1(subtotal);
|
|
2519
2411
|
}
|
|
2520
|
-
return claimUpToCap(requested, subtotal, issues, label);
|
|
2412
|
+
return claimUpToCap$1(requested, subtotal, issues, label);
|
|
2521
2413
|
}
|
|
2522
2414
|
function computeEdaRegular(input) {
|
|
2523
2415
|
const issues = [];
|
|
@@ -2542,12 +2434,12 @@ function computeEdaRegular(input) {
|
|
|
2542
2434
|
}
|
|
2543
2435
|
/** A reconciled figure that is ALSO capped by a pool — the EDA/CMEDB claim shape (015007, 015019). */
|
|
2544
2436
|
function pool_cappedClaim(reconciled, pool, issues, label) {
|
|
2545
|
-
const cap = Math.max(0, round(pool));
|
|
2437
|
+
const cap = Math.max(0, round$1(pool));
|
|
2546
2438
|
if (pool <= 0) return {
|
|
2547
2439
|
value: 0,
|
|
2548
2440
|
differs: reconciled.differs
|
|
2549
2441
|
};
|
|
2550
|
-
if (round(reconciled.value) > cap) {
|
|
2442
|
+
if (round$1(reconciled.value) > cap) {
|
|
2551
2443
|
issues.push(`${label}: the entered claim ${reconciled.value} exceeds the pool ${cap}; capped.`);
|
|
2552
2444
|
return {
|
|
2553
2445
|
value: cap,
|
|
@@ -2555,7 +2447,7 @@ function pool_cappedClaim(reconciled, pool, issues, label) {
|
|
|
2555
2447
|
};
|
|
2556
2448
|
}
|
|
2557
2449
|
return {
|
|
2558
|
-
value: Math.max(0, round(reconciled.value)),
|
|
2450
|
+
value: Math.max(0, round$1(reconciled.value)),
|
|
2559
2451
|
differs: reconciled.differs
|
|
2560
2452
|
};
|
|
2561
2453
|
}
|
|
@@ -2591,7 +2483,7 @@ function computeCmedb(input) {
|
|
|
2591
2483
|
const other = reconcile(f.otherTransfer, o.otherTransfer);
|
|
2592
2484
|
const disposal = reconcile(f.disposalTransfer, o.disposalTransfer);
|
|
2593
2485
|
const poolBeforeClaim = opening.value + amalg.value + other.value - disposal.value;
|
|
2594
|
-
const claim = poolBeforeClaim <= 0 ? 0 : claimUpToCap(input.claimed, poolBeforeClaim, issues, "Schedule 15 CMEDB (015031)");
|
|
2486
|
+
const claim = poolBeforeClaim <= 0 ? 0 : claimUpToCap$1(input.claimed, poolBeforeClaim, issues, "Schedule 15 CMEDB (015031)");
|
|
2595
2487
|
const closingBalance = poolBeforeClaim - claim;
|
|
2596
2488
|
return {
|
|
2597
2489
|
openingBalance: opening.value,
|
|
@@ -2622,7 +2514,7 @@ function computeCeeRegular(input) {
|
|
|
2622
2514
|
const renouncedFlowThrough = num$1(f.renouncedFlowThrough);
|
|
2623
2515
|
const renouncedLookBack = num$1(f.renouncedLookBack);
|
|
2624
2516
|
const subtotal = opening.value + currentYearExpenses + lookBackExpenses + reclassifiedFromCde + amalg.value + renewableConservationExpenses + otherAdd.value - governmentAssistance - otherDed.value - renouncedFlowThrough - toSuccessor.value - renouncedLookBack;
|
|
2625
|
-
const claim = forcedOrCappedClaim(input.claimed, subtotal, issues, "Schedule 15 CEE regular (015061)");
|
|
2517
|
+
const claim = forcedOrCappedClaim$1(input.claimed, subtotal, issues, "Schedule 15 CEE regular (015061)");
|
|
2626
2518
|
const closingBalance = subtotal > 0 ? subtotal - claim : 0;
|
|
2627
2519
|
return {
|
|
2628
2520
|
openingBalance: opening.value,
|
|
@@ -2655,7 +2547,7 @@ function computeCeeSuccessor(input) {
|
|
|
2655
2547
|
const otherDed = reconcile(f.otherDeductions, o.otherDeductions);
|
|
2656
2548
|
const toSuccessor = reconcile(f.transferredToSuccessor, o.transferredToSuccessor);
|
|
2657
2549
|
const subtotal = opening.value + reclassified + amalg.value + other.value - otherDed.value - toSuccessor.value;
|
|
2658
|
-
const claim = forcedOrCappedClaim(input.claimed, subtotal, issues, "Schedule 15 CEE successor (015081)");
|
|
2550
|
+
const claim = forcedOrCappedClaim$1(input.claimed, subtotal, issues, "Schedule 15 CEE successor (015081)");
|
|
2659
2551
|
const closingBalance = subtotal - claim;
|
|
2660
2552
|
return {
|
|
2661
2553
|
openingBalance: opening.value,
|
|
@@ -2689,7 +2581,7 @@ function computeCdeRegular(input, ccogpeRegular) {
|
|
|
2689
2581
|
const receivable = reconcile(f.receivableOnDisposition, o.receivableOnDisposition);
|
|
2690
2582
|
const creditBalanceReconciled = reconcile(f.creditBalanceInCogpePool, o.creditBalanceInCogpePool);
|
|
2691
2583
|
const creditBalance = ccogpeRegular.subtotal < 0 ? {
|
|
2692
|
-
value: round(ccogpeRegular.subtotal),
|
|
2584
|
+
value: round$1(ccogpeRegular.subtotal),
|
|
2693
2585
|
differs: true
|
|
2694
2586
|
} : creditBalanceReconciled;
|
|
2695
2587
|
const otherDed = reconcile(f.otherDeductions, o.otherDeductions);
|
|
@@ -2698,7 +2590,7 @@ function computeCdeRegular(input, ccogpeRegular) {
|
|
|
2698
2590
|
const renouncedLookBack = num$1(f.renouncedLookBack);
|
|
2699
2591
|
const subtotal = opening.value + currentYearExpenses + lookBackExpenses + amalg.value + otherAdd.value - reclassified - governmentAssistance - receivable.value - creditBalance.value - otherDed.value - toSuccessor.value - renouncedFlowThrough - renouncedLookBack;
|
|
2700
2592
|
if (f.otherDeductions !== void 0 || o.otherDeductions !== void 0) issues.push("Schedule 15 CDE regular (015107): the spec's own business rule for this line adds \"If 015139 is negative, include the amount at 015107 as a positive value\" — line 015139 does not exist anywhere else in Schedule 15 as extracted from the source text (source lines 13681-13691). Not modelled; verify against the live TRA form, which has no PDF in this engine's sources for Schedule 15.");
|
|
2701
|
-
const claim = subtotal > 0 ? claimUpToCap(input.claimed, CDE_CLAIM_RATE * stepYearFactor(input.daysInTaxYear) * subtotal, issues, "Schedule 15 CDE regular (015115)") : 0;
|
|
2593
|
+
const claim = subtotal > 0 ? claimUpToCap$1(input.claimed, CDE_CLAIM_RATE * stepYearFactor$1(input.daysInTaxYear) * subtotal, issues, "Schedule 15 CDE regular (015115)") : 0;
|
|
2702
2594
|
const closingBalance = Math.max(0, subtotal - claim);
|
|
2703
2595
|
return {
|
|
2704
2596
|
openingBalance: opening.value,
|
|
@@ -2731,14 +2623,14 @@ function computeCdeSuccessor(input, ccogpeSuccessor) {
|
|
|
2731
2623
|
const reclassified = num$1(f.reclassifiedFromCee);
|
|
2732
2624
|
const creditBalanceReconciled = reconcile(f.creditBalanceInCogpePool, o.creditBalanceInCogpePool);
|
|
2733
2625
|
const creditBalance = ccogpeSuccessor.subtotal < 0 ? {
|
|
2734
|
-
value: round(ccogpeSuccessor.subtotal),
|
|
2626
|
+
value: round$1(ccogpeSuccessor.subtotal),
|
|
2735
2627
|
differs: true
|
|
2736
2628
|
} : creditBalanceReconciled;
|
|
2737
2629
|
if (creditBalance.value !== 0) issues.push("Schedule 15 CDE successor (015133): the \"value may not exceed amount A\" wording (source lines 13945-13962) is ambiguous — this module treats it as \"value = A\" (matching line 015105's unconditional wording) whenever the CCOGPE-successor subtotal is negative. Verify against the live TRA form.");
|
|
2738
2630
|
const otherDed = reconcile(f.otherDeductions, o.otherDeductions);
|
|
2739
2631
|
const toSuccessor = reconcile(f.transferredToSuccessor, o.transferredToSuccessor);
|
|
2740
2632
|
const subtotal = opening.value + amalg.value + other.value - reclassified - creditBalance.value - otherDed.value - toSuccessor.value;
|
|
2741
|
-
const claim = subtotal > 0 ? claimUpToCap(input.claimed, CDE_CLAIM_RATE * stepYearFactor(input.daysInTaxYear) * subtotal, issues, "Schedule 15 CDE successor (015141)") : 0;
|
|
2633
|
+
const claim = subtotal > 0 ? claimUpToCap$1(input.claimed, CDE_CLAIM_RATE * stepYearFactor$1(input.daysInTaxYear) * subtotal, issues, "Schedule 15 CDE successor (015141)") : 0;
|
|
2742
2634
|
const closingBalance = Math.max(0, subtotal - claim);
|
|
2743
2635
|
return {
|
|
2744
2636
|
openingBalance: opening.value,
|
|
@@ -2770,7 +2662,7 @@ function computeCcogpeRegular(input) {
|
|
|
2770
2662
|
const subtotal = opening.value + currentYearExpenses + amalg.value + otherAdd.value - receivable.value - governmentAssistance - toSuccessor.value - otherDed.value;
|
|
2771
2663
|
let claim = 0;
|
|
2772
2664
|
if (subtotal < 0) issues.push("Schedule 15 CCOGPE regular (015169): the pool subtotal is negative. Per source lines 14346-14359, this must be carried forward to line 015105 (CDE regular) if the corporation has made a designation under subparagraph 66.7(4)(a)(iii), or to line 015133 (CDE successor) if it has not. computeCdeRegular auto-applies the 015105 route unconditionally (see that function's doc comment) — confirm the designation status before relying on that routing when it should instead land on 015133.");
|
|
2773
|
-
else if (subtotal > 0) claim = claimUpToCap(input.claimed, CCOGPE_CLAIM_RATE * stepYearFactor(input.daysInTaxYear) * subtotal, issues, "Schedule 15 CCOGPE regular (015169)");
|
|
2665
|
+
else if (subtotal > 0) claim = claimUpToCap$1(input.claimed, CCOGPE_CLAIM_RATE * stepYearFactor$1(input.daysInTaxYear) * subtotal, issues, "Schedule 15 CCOGPE regular (015169)");
|
|
2774
2666
|
const closingBalance = subtotal > 0 ? subtotal - claim : 0;
|
|
2775
2667
|
return {
|
|
2776
2668
|
openingBalance: opening.value,
|
|
@@ -2801,7 +2693,7 @@ function computeCcogpeSuccessor(input) {
|
|
|
2801
2693
|
const subtotal = opening.value + amalg.value + other.value - receivable.value - toSuccessor.value - otherDed.value;
|
|
2802
2694
|
let claim = 0;
|
|
2803
2695
|
if (subtotal < 0) issues.push("Schedule 15 CCOGPE successor (015189): the pool subtotal is negative. Per source lines 14646-14660, this must be carried forward to line 015133 (CDE successor) if the corporation has made a designation under subparagraph 66.7(4)(a)(iii), or included in line 015167 (this SAME pool's own regular-side deduction line) if it has not. Neither route is auto-applied by this function; supply the appropriate override manually. See module doc comment.");
|
|
2804
|
-
else if (subtotal > 0) claim = claimUpToCap(input.claimed, CCOGPE_CLAIM_RATE * stepYearFactor(input.daysInTaxYear) * subtotal, issues, "Schedule 15 CCOGPE successor (015189)");
|
|
2696
|
+
else if (subtotal > 0) claim = claimUpToCap$1(input.claimed, CCOGPE_CLAIM_RATE * stepYearFactor$1(input.daysInTaxYear) * subtotal, issues, "Schedule 15 CCOGPE successor (015189)");
|
|
2805
2697
|
const closingBalance = Math.max(0, subtotal - claim);
|
|
2806
2698
|
return {
|
|
2807
2699
|
openingBalance: opening.value,
|
|
@@ -2830,7 +2722,7 @@ function computeFedeRegular(input) {
|
|
|
2830
2722
|
if (pool < 0) issues.push("Schedule 15 FEDE regular (015209): the pool balance is negative. Per source lines 14855-14858 this is included in federal T2 line 012040 — outside AT1 Schedule 15 and this engine's scope. Claim and closing balance are zeroed per the schedule's own instruction.");
|
|
2831
2723
|
else if (pool > 0) {
|
|
2832
2724
|
const cap = Math.max(CCOGPE_CLAIM_RATE * linearYearFactor(input.daysInTaxYear) * pool, foreignResourceIncome);
|
|
2833
|
-
claim = claimUpToCap(input.claimed, Math.min(pool, cap), issues, "Schedule 15 FEDE regular (015209)");
|
|
2725
|
+
claim = claimUpToCap$1(input.claimed, Math.min(pool, cap), issues, "Schedule 15 FEDE regular (015209)");
|
|
2834
2726
|
}
|
|
2835
2727
|
const closingBalance = pool - claim;
|
|
2836
2728
|
return {
|
|
@@ -2857,7 +2749,7 @@ function computeFedeSuccessor(input) {
|
|
|
2857
2749
|
const pool = opening.value + amalg.value + other.value - otherDed.value;
|
|
2858
2750
|
let claim = 0;
|
|
2859
2751
|
if (pool < 0) issues.push("Schedule 15 FEDE successor (015221): the pool balance is negative. Per source lines 14855-14858-style wording (successor variant, source lines ~15045-15048) this is included in federal T2 line 012040 — outside AT1 Schedule 15 and this engine's scope.");
|
|
2860
|
-
else if (pool > 0) claim = claimUpToCap(input.claimed, Math.min(pool, foreignResourceIncome), issues, "Schedule 15 FEDE successor (015221)");
|
|
2752
|
+
else if (pool > 0) claim = claimUpToCap$1(input.claimed, Math.min(pool, foreignResourceIncome), issues, "Schedule 15 FEDE successor (015221)");
|
|
2861
2753
|
const closingBalance = pool - claim;
|
|
2862
2754
|
return {
|
|
2863
2755
|
openingBalance: opening.value,
|
|
@@ -2886,7 +2778,7 @@ function computeSfedeCountryRegular(input) {
|
|
|
2886
2778
|
if (pool < 0) issues.push(`Schedule 15 SFEDE regular, country ${f.countryCode} (015253): the pool balance is negative. Per the schedule's pattern for foreign pools (source lines 15262-15265), this is included in federal T2 line 012040 — outside this engine's scope.`);
|
|
2887
2779
|
else if (pool > 0) {
|
|
2888
2780
|
const cap = Math.max(CCOGPE_CLAIM_RATE * linearYearFactor(input.daysInTaxYear) * pool, foreignResourceIncome);
|
|
2889
|
-
claim = claimUpToCap(input.claimed, Math.min(pool, cap), issues, `Schedule 15 SFEDE regular, country ${f.countryCode} (015253)`);
|
|
2781
|
+
claim = claimUpToCap$1(input.claimed, Math.min(pool, cap), issues, `Schedule 15 SFEDE regular, country ${f.countryCode} (015253)`);
|
|
2890
2782
|
}
|
|
2891
2783
|
const closingBalance = pool - claim;
|
|
2892
2784
|
return {
|
|
@@ -2915,7 +2807,7 @@ function computeSfedeCountrySuccessor(input) {
|
|
|
2915
2807
|
const pool = opening.value + amalg.value + other.value - otherDed.value;
|
|
2916
2808
|
let claim = 0;
|
|
2917
2809
|
if (pool < 0) issues.push(`Schedule 15 SFEDE successor, country ${f.countryCode} (015273): the pool balance is negative. Per the schedule's pattern for foreign pools this is included in federal T2 line 012040 — outside this engine's scope.`);
|
|
2918
|
-
else if (pool > 0) claim = claimUpToCap(input.claimed, Math.min(pool, foreignResourceIncome), issues, `Schedule 15 SFEDE successor, country ${f.countryCode} (015273)`);
|
|
2810
|
+
else if (pool > 0) claim = claimUpToCap$1(input.claimed, Math.min(pool, foreignResourceIncome), issues, `Schedule 15 SFEDE successor, country ${f.countryCode} (015273)`);
|
|
2919
2811
|
const closingBalance = pool - claim;
|
|
2920
2812
|
return {
|
|
2921
2813
|
countryCode: f.countryCode,
|
|
@@ -2970,8 +2862,8 @@ function computeCfreRegular(entries) {
|
|
|
2970
2862
|
const partA = Math.max(CCOGPE_CLAIM_RATE * linear * pool, Math.min(CDE_CLAIM_RATE * linear * pool, foreignResourceIncome, sumForeignResourceIncome));
|
|
2971
2863
|
const remainder = Math.max(0, pool - partA);
|
|
2972
2864
|
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).`);
|
|
2973
|
-
const partB = Math.min(remainder, nn$
|
|
2974
|
-
claim = claimUpToCap(e.claimed, partA + partB, issues, `Schedule 15 CFRE regular, country ${e.federal.countryCode} (015293)`);
|
|
2865
|
+
const partB = Math.min(remainder, nn$26(e.globalForeignResourceLimit));
|
|
2866
|
+
claim = claimUpToCap$1(e.claimed, partA + partB, issues, `Schedule 15 CFRE regular, country ${e.federal.countryCode} (015293)`);
|
|
2975
2867
|
}
|
|
2976
2868
|
const closingBalance = pool - claim;
|
|
2977
2869
|
return {
|
|
@@ -3116,7 +3008,7 @@ function computeCfreSuccessor(entries) {
|
|
|
3116
3008
|
if (pool < 0) issues.push(`Schedule 15 CFRE successor, country ${e.federal.countryCode} (015313): the pool balance is negative. Per the schedule's pattern for foreign pools this is included in federal T2 line 012040 — outside this engine's scope.`);
|
|
3117
3009
|
else if (pool > 0) {
|
|
3118
3010
|
const cap = Math.min(CDE_CLAIM_RATE * linearYearFactor(e.daysInTaxYear) * pool, sumForeignResourceIncome);
|
|
3119
|
-
claim = claimUpToCap(e.claimed, cap, issues, `Schedule 15 CFRE successor, country ${e.federal.countryCode} (015313)`);
|
|
3011
|
+
claim = claimUpToCap$1(e.claimed, cap, issues, `Schedule 15 CFRE successor, country ${e.federal.countryCode} (015313)`);
|
|
3120
3012
|
}
|
|
3121
3013
|
const closingBalance = pool - claim;
|
|
3122
3014
|
return {
|
|
@@ -3402,15 +3294,15 @@ function schedule15Values(result) {
|
|
|
3402
3294
|
function iegT661SourceLine(taxationYearEnd) {
|
|
3403
3295
|
return taxationYearEnd >= "2024-12-16" ? "557" : "559";
|
|
3404
3296
|
}
|
|
3405
|
-
const nn$
|
|
3297
|
+
const nn$25 = (v) => Math.round(v ?? 0);
|
|
3406
3298
|
/** Line 031 = 005 − 007 + 009 + 011 + 025. Every term but 005 defaults to nil. */
|
|
3407
3299
|
function computeIegEligibleExpenditures(input) {
|
|
3408
|
-
const federalAmount = nn$
|
|
3409
|
-
const albertaPortion = nn$
|
|
3410
|
-
const federalProxyAmount = nn$
|
|
3411
|
-
const albertaProxyAmount = nn$
|
|
3412
|
-
const iegReducingFederalExpenditure = nn$
|
|
3413
|
-
const repaymentOrContractPayment = nn$
|
|
3300
|
+
const federalAmount = nn$25(input.federalAmount);
|
|
3301
|
+
const albertaPortion = nn$25(input.albertaPortion);
|
|
3302
|
+
const federalProxyAmount = nn$25(input.federalProxyAmount);
|
|
3303
|
+
const albertaProxyAmount = nn$25(input.albertaProxyAmount);
|
|
3304
|
+
const iegReducingFederalExpenditure = nn$25(input.iegReducingFederalExpenditure);
|
|
3305
|
+
const repaymentOrContractPayment = nn$25(input.repaymentOrContractPayment);
|
|
3414
3306
|
return {
|
|
3415
3307
|
federalAmount,
|
|
3416
3308
|
albertaPortion,
|
|
@@ -3630,7 +3522,7 @@ function computeIeg(input) {
|
|
|
3630
3522
|
*
|
|
3631
3523
|
* Whole dollars, pure.
|
|
3632
3524
|
*/
|
|
3633
|
-
const nn$
|
|
3525
|
+
const nn$24 = (v) => Math.max(0, Math.round(v ?? 0));
|
|
3634
3526
|
/**
|
|
3635
3527
|
* The group's taxable capital and base level of spending, from every associated
|
|
3636
3528
|
* member's own figures.
|
|
@@ -3641,11 +3533,11 @@ const nn$23 = (v) => Math.max(0, Math.round(v ?? 0));
|
|
|
3641
3533
|
function computeIegGroupFigures(members, priorYears = IEG_2024.PRIOR_YEARS) {
|
|
3642
3534
|
const issues = [];
|
|
3643
3535
|
const detail = members.map((m) => {
|
|
3644
|
-
const priorYearAlbertaExpenditures = (m.priorYearAlbertaExpenditures ?? []).map(nn$
|
|
3536
|
+
const priorYearAlbertaExpenditures = (m.priorYearAlbertaExpenditures ?? []).map(nn$24);
|
|
3645
3537
|
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.`);
|
|
3646
3538
|
return {
|
|
3647
3539
|
name: m.name,
|
|
3648
|
-
taxableCapital: nn$
|
|
3540
|
+
taxableCapital: nn$24(m.taxableCapital),
|
|
3649
3541
|
priorYearAlbertaExpenditures,
|
|
3650
3542
|
priorYearTotal: priorYearAlbertaExpenditures.reduce((a, b) => a + b, 0)
|
|
3651
3543
|
};
|
|
@@ -3672,11 +3564,11 @@ function computeIegGroupFigures(members, priorYears = IEG_2024.PRIOR_YEARS) {
|
|
|
3672
3564
|
function allocateIegExpenditureLimit(groupExpenditureLimit, requested) {
|
|
3673
3565
|
const issues = [];
|
|
3674
3566
|
const limit = Math.max(0, Math.round(groupExpenditureLimit));
|
|
3675
|
-
const totalRequested = requested.reduce((s, a) => s + nn$
|
|
3567
|
+
const totalRequested = requested.reduce((s, a) => s + nn$24(a.allocated), 0);
|
|
3676
3568
|
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.`);
|
|
3677
3569
|
let remaining = limit;
|
|
3678
3570
|
const allocations = requested.map((a) => {
|
|
3679
|
-
const allocated = Math.min(nn$
|
|
3571
|
+
const allocated = Math.min(nn$24(a.allocated), remaining);
|
|
3680
3572
|
remaining -= allocated;
|
|
3681
3573
|
return {
|
|
3682
3574
|
name: a.name,
|
|
@@ -3710,10 +3602,10 @@ function allocateIegEvenly(groupExpenditureLimit, names) {
|
|
|
3710
3602
|
})));
|
|
3711
3603
|
}
|
|
3712
3604
|
function computeAgreementMember(m, index, issues) {
|
|
3713
|
-
const allocatedExpenditureLimit = nn$
|
|
3714
|
-
const currentYearExpenditures = nn$
|
|
3715
|
-
const priorYear1 = nn$
|
|
3716
|
-
const priorYear2 = nn$
|
|
3605
|
+
const allocatedExpenditureLimit = nn$24(m.allocatedExpenditureLimit);
|
|
3606
|
+
const currentYearExpenditures = nn$24(m.currentYearExpenditures);
|
|
3607
|
+
const priorYear1 = nn$24(m.priorYear1);
|
|
3608
|
+
const priorYear2 = nn$24(m.priorYear2);
|
|
3717
3609
|
const base = Math.round((priorYear1 + priorYear2) / 2);
|
|
3718
3610
|
const individualMaximumAllowedAmount = currentYearExpenditures - base;
|
|
3719
3611
|
const days = Math.max(0, Math.min(m.daysInTaxYear ?? 365, 366));
|
|
@@ -3732,7 +3624,7 @@ function computeAgreementMember(m, index, issues) {
|
|
|
3732
3624
|
currentYearExpenditures,
|
|
3733
3625
|
priorYear1,
|
|
3734
3626
|
priorYear2,
|
|
3735
|
-
taxableCapitalPriorYear: nn$
|
|
3627
|
+
taxableCapitalPriorYear: nn$24(m.taxableCapitalPriorYear),
|
|
3736
3628
|
hasAlbertaPermanentEstablishment,
|
|
3737
3629
|
individualMaximumAllowedAmount,
|
|
3738
3630
|
allocatedAllowedAmount
|
|
@@ -3893,10 +3785,6 @@ function computeAlbertaReturn(input) {
|
|
|
3893
3785
|
issues.push(...sched.sredTaxCredit.result.issues);
|
|
3894
3786
|
}
|
|
3895
3787
|
if (sched?.lossCarryback) schedulePayloads.push(schedule10Values(sched.lossCarryback));
|
|
3896
|
-
if (sched?.manufacturingProcessing) {
|
|
3897
|
-
schedulePayloads.push(schedule11Values(sched.manufacturingProcessing));
|
|
3898
|
-
issues.push(...sched.manufacturingProcessing.issues);
|
|
3899
|
-
}
|
|
3900
3788
|
if (sched?.reconciliation) schedulePayloads.push(schedule12Values(sched.reconciliation));
|
|
3901
3789
|
if (sched?.cca) {
|
|
3902
3790
|
schedulePayloads.push(schedule13Values(sched.cca));
|
|
@@ -3930,7 +3818,6 @@ function computeAlbertaReturn(input) {
|
|
|
3930
3818
|
issues.push(...sched.losses.otherLossesByYearOfOrigin?.issues ?? []);
|
|
3931
3819
|
}
|
|
3932
3820
|
if (ieg) schedulePayloads.push(schedule29Values(ieg, iegAgreement, iegEligibleExpenditures, input.ieg?.primaryFieldCode));
|
|
3933
|
-
if (at4970) schedulePayloads.push(schedule4970Values(at4970));
|
|
3934
3821
|
return {
|
|
3935
3822
|
allocationFactor,
|
|
3936
3823
|
albertaTax,
|
|
@@ -4057,8 +3944,7 @@ var At1MandatoryFieldMissingError = class extends Error {
|
|
|
4057
3944
|
* for Net File by the specification itself.
|
|
4058
3945
|
*/
|
|
4059
3946
|
const AT1_MANDATORY_WITHOUT_DEFAULT = Object.freeze([
|
|
4060
|
-
["
|
|
4061
|
-
["federalTaxableIncome", "000009 taxable income"],
|
|
3947
|
+
["associatedWithCcpcs", "000001 associated with CCPCs"],
|
|
4062
3948
|
["contactPerson", "000025 contact person"],
|
|
4063
3949
|
["contactTelephone", "000026 contact telephone"],
|
|
4064
3950
|
["natureOfBusiness", "000028 nature of business"],
|
|
@@ -4068,7 +3954,6 @@ const AT1_MANDATORY_WITHOUT_DEFAULT = Object.freeze([
|
|
|
4068
3954
|
["certificationDate", "000101 certification date"],
|
|
4069
3955
|
["certificationTelephone", "000103 certification telephone"],
|
|
4070
3956
|
["authorizedEmail", "000105 CIT authorized email"],
|
|
4071
|
-
["associatedWithCcpcs", "000001 associated with CCPCs"],
|
|
4072
3957
|
["windUpOfSubsidiary", "000031 wind-up of a subsidiary"],
|
|
4073
3958
|
["firstYearAfterAmalgamation", "000032 first year after amalgamation"],
|
|
4074
3959
|
["taxYearEndChanged", "000038 tax year end changed"],
|
|
@@ -4145,21 +4030,11 @@ const AT1_RETURN_LINE_ITEMS = [
|
|
|
4145
4030
|
get: (d) => at1YesNo(d.associatedWithCcpcs),
|
|
4146
4031
|
fmt: "text"
|
|
4147
4032
|
},
|
|
4148
|
-
{
|
|
4149
|
-
id: "000003001",
|
|
4150
|
-
get: (d) => d.activeBusinessIncome,
|
|
4151
|
-
fmt: "amount"
|
|
4152
|
-
},
|
|
4153
4033
|
{
|
|
4154
4034
|
id: "000005001",
|
|
4155
4035
|
get: (d) => d.softwareCertCode,
|
|
4156
4036
|
fmt: "text"
|
|
4157
4037
|
},
|
|
4158
|
-
{
|
|
4159
|
-
id: "000009001",
|
|
4160
|
-
get: (d) => d.federalTaxableIncome,
|
|
4161
|
-
fmt: "amount"
|
|
4162
|
-
},
|
|
4163
4038
|
{
|
|
4164
4039
|
id: "000010001",
|
|
4165
4040
|
get: (d) => d.legalName,
|
|
@@ -4651,7 +4526,7 @@ var RsiLineItemError = class extends Error {
|
|
|
4651
4526
|
}
|
|
4652
4527
|
};
|
|
4653
4528
|
/**
|
|
4654
|
-
* Render one line item: `##` + nine
|
|
4529
|
+
* Render one line item: `##` + nine characters + five spaces + value.
|
|
4655
4530
|
*
|
|
4656
4531
|
* §3.2.1.5 — *"For a Line Item to be considered complete and therefore allowed to
|
|
4657
4532
|
* be output to the AT1 RSI, it must contain both a Line Item ID and a Value"*. An
|
|
@@ -4659,7 +4534,7 @@ var RsiLineItemError = class extends Error {
|
|
|
4659
4534
|
* not a line item the reader can interpret.
|
|
4660
4535
|
*/
|
|
4661
4536
|
function renderRsiLineItem(item) {
|
|
4662
|
-
if (!/^\
|
|
4537
|
+
if (!/^\w{3}[0-9]{6}$/.test(item.lineItemId)) throw new RsiLineItemError(`AT1 RSI: line item id "${item.lineItemId}" must be a 3-character Schedule ID followed by six digits (Field ID + Occurrence ID).`);
|
|
4663
4538
|
if (item.value === "") throw new RsiLineItemError(`AT1 RSI: line item ${item.lineItemId} has no value. A line item must carry both an id and a value to be printed.`);
|
|
4664
4539
|
return `##${item.lineItemId}${RSI_COLUMN_GAP}${item.value}`;
|
|
4665
4540
|
}
|
|
@@ -4697,6 +4572,82 @@ function renderAt1Rsi(header, schedules, options = {}) {
|
|
|
4697
4572
|
return lines.join("\n");
|
|
4698
4573
|
}
|
|
4699
4574
|
//#endregion
|
|
4575
|
+
//#region src/t2/at1/filing/at1-rsi-adapter.ts
|
|
4576
|
+
/**
|
|
4577
|
+
* Bridge between the Net File shapes (`At1FilingData` / `At1ScheduleData`,
|
|
4578
|
+
* `at1-line-items.ts` / `at1-schedule-line-items.ts`) and the RSI print
|
|
4579
|
+
* renderer's own shapes (`RsiHeaderInput` / `RsiScheduleInput`,
|
|
4580
|
+
* `at1-rsi-renderer.ts`).
|
|
4581
|
+
*
|
|
4582
|
+
* The two formats share the same underlying data — the same computed return,
|
|
4583
|
+
* the same M/O/X-driven set of fields to emit — so this module does no new
|
|
4584
|
+
* arithmetic; it only reformats already-assembled values through
|
|
4585
|
+
* `at1-rsi-renderer.ts`'s own formatters (`formatRsiAmount`/`formatRsiText`/
|
|
4586
|
+
* `formatRsiDate`) instead of Net File's XML ones. Building the actual RSI
|
|
4587
|
+
* TEXT for a computed return is then `renderAt1Rsi(toRsiHeader(data),
|
|
4588
|
+
* [toRsiSchedule('000', AT1_RETURN_LINE_ITEMS, data), ...schedulePayloads.map(s
|
|
4589
|
+
* => toRsiScheduleData(s)), toRsiSchedule('EDI', AT1_EDI_LINE_ITEMS,
|
|
4590
|
+
* data.transmitter)])`.
|
|
4591
|
+
*/
|
|
4592
|
+
/**
|
|
4593
|
+
* §3.2.1.16 — "Value of Line Item IDs where percentages apply are to use the
|
|
4594
|
+
* number of significant digits specified in the Cross-reference Tables."
|
|
4595
|
+
* Not a dollar value, so the "no decimals" rule (§3.2.1.17) does not apply —
|
|
4596
|
+
* reuses Net File's own six-decimal, leading-zero-stripped convention
|
|
4597
|
+
* (`fmtFactor` in `at1-line-items.ts`) since the spec gives no different one.
|
|
4598
|
+
*/
|
|
4599
|
+
function formatRsiFactorValue(n) {
|
|
4600
|
+
const s = n.toFixed(6);
|
|
4601
|
+
return n >= 0 && n < 1 ? s.replace(/^0/, "") : s;
|
|
4602
|
+
}
|
|
4603
|
+
function formatByFmt(v, fmt) {
|
|
4604
|
+
if (v === void 0 || v === null) return void 0;
|
|
4605
|
+
if (fmt === "date") return formatRsiDate(v);
|
|
4606
|
+
if (fmt === "amount") return formatRsiAmount(v);
|
|
4607
|
+
if (fmt === "factor") return formatRsiFactorValue(v);
|
|
4608
|
+
return formatRsiText(String(v));
|
|
4609
|
+
}
|
|
4610
|
+
/** Convert one declarative line-item table (jacket or EDI) into RSI line items. */
|
|
4611
|
+
function toRsiLineItems(data, items) {
|
|
4612
|
+
const result = [];
|
|
4613
|
+
for (const li of items) {
|
|
4614
|
+
const value = formatByFmt(li.get(data), li.fmt);
|
|
4615
|
+
if (value !== void 0) result.push({
|
|
4616
|
+
lineItemId: li.id,
|
|
4617
|
+
value
|
|
4618
|
+
});
|
|
4619
|
+
}
|
|
4620
|
+
return result;
|
|
4621
|
+
}
|
|
4622
|
+
/** Convert an already-assembled supporting-schedule payload (Net File shape) to RSI shape. */
|
|
4623
|
+
function toRsiSchedule(schedule) {
|
|
4624
|
+
return {
|
|
4625
|
+
scheduleId: schedule.scheduleId,
|
|
4626
|
+
items: schedule.values.map((v) => ({
|
|
4627
|
+
lineItemId: v.lineItemId,
|
|
4628
|
+
value: typeof v.value === "number" ? formatRsiAmount(v.value) : formatRsiText(String(v.value))
|
|
4629
|
+
}))
|
|
4630
|
+
};
|
|
4631
|
+
}
|
|
4632
|
+
/** The AT1 jacket (schedule `000`) and the EDI transmitter block (schedule `EDI`), RSI-formatted. */
|
|
4633
|
+
function toRsiJacketSchedules(data) {
|
|
4634
|
+
return [{
|
|
4635
|
+
scheduleId: "000",
|
|
4636
|
+
items: toRsiLineItems(data, AT1_RETURN_LINE_ITEMS)
|
|
4637
|
+
}, {
|
|
4638
|
+
scheduleId: "EDI",
|
|
4639
|
+
items: toRsiLineItems(data.transmitter, AT1_EDI_LINE_ITEMS)
|
|
4640
|
+
}];
|
|
4641
|
+
}
|
|
4642
|
+
/** The RSI header identity fields (everything but pagination) from the same filing data Net File uses. */
|
|
4643
|
+
function toRsiHeader(data) {
|
|
4644
|
+
return {
|
|
4645
|
+
corporateAccountNumber: data.corporateAccountNumber,
|
|
4646
|
+
taxYearEnd: data.taxYearEnd,
|
|
4647
|
+
legalName: data.legalName
|
|
4648
|
+
};
|
|
4649
|
+
}
|
|
4650
|
+
//#endregion
|
|
4700
4651
|
//#region src/t2/schedules/loss-carryback.ts
|
|
4701
4652
|
var LossCarrybackError = class extends Error {
|
|
4702
4653
|
constructor(message) {
|
|
@@ -4963,6 +4914,42 @@ function albertaReserveDifference(albertaNetEffect, federalNetEffect) {
|
|
|
4963
4914
|
}
|
|
4964
4915
|
};
|
|
4965
4916
|
}
|
|
4917
|
+
/**
|
|
4918
|
+
* A resource-deduction pool (AT1 Schedule 15 vs federal Schedule 12) as a
|
|
4919
|
+
* Schedule 12 adjustment — same direction convention as CCA/reserves above:
|
|
4920
|
+
* a LARGER Alberta claim is a DEDUCTION (Alberta income lower), a smaller
|
|
4921
|
+
* one is an ADDITION. Shared across the five reconciling pairs Schedule 12
|
|
4922
|
+
* lines 022/023 (Depletion), 026/027 (CEE), 028/029 (CDE), 030/031
|
|
4923
|
+
* (Foreign exploration/development), 032/033 (COGPE) all follow — the
|
|
4924
|
+
* labels/refs differ per pool, everything else is identical, so this one
|
|
4925
|
+
* function replaces five near-duplicate hand-written diffs.
|
|
4926
|
+
*/
|
|
4927
|
+
function albertaResourceDeductionDifference(label, ref, albertaClaim, federalClaim) {
|
|
4928
|
+
const diff = albertaClaim - federalClaim;
|
|
4929
|
+
if (diff > 0) return {
|
|
4930
|
+
side: "deduction",
|
|
4931
|
+
line: {
|
|
4932
|
+
label: `${label} — additional claim for Alberta`,
|
|
4933
|
+
amount: diff,
|
|
4934
|
+
ref
|
|
4935
|
+
}
|
|
4936
|
+
};
|
|
4937
|
+
if (diff < 0) return {
|
|
4938
|
+
side: "addition",
|
|
4939
|
+
line: {
|
|
4940
|
+
label: `${label} — claimed federally but not for Alberta`,
|
|
4941
|
+
amount: -diff,
|
|
4942
|
+
ref
|
|
4943
|
+
}
|
|
4944
|
+
};
|
|
4945
|
+
return {
|
|
4946
|
+
side: "none",
|
|
4947
|
+
line: {
|
|
4948
|
+
label: `No ${label.toLowerCase()} difference`,
|
|
4949
|
+
amount: 0
|
|
4950
|
+
}
|
|
4951
|
+
};
|
|
4952
|
+
}
|
|
4966
4953
|
/** Reconcile from a list of directional adjustments (zero/'none' ones are dropped). */
|
|
4967
4954
|
function reconcileAlbertaNetIncome(federalNetIncomeForTax, adjustments) {
|
|
4968
4955
|
return computeSchedule12({
|
|
@@ -5256,6 +5243,42 @@ function computeClass141AdditionalAllowance(input) {
|
|
|
5256
5243
|
issues
|
|
5257
5244
|
};
|
|
5258
5245
|
}
|
|
5246
|
+
/**
|
|
5247
|
+
* s.13(39): on a disposition of class 14.1 property that was eligible capital
|
|
5248
|
+
* property (ECP) before 1 January 2017, the taxpayer is deemed to have
|
|
5249
|
+
* acquired additional class 14.1 property with a capital cost equal to the
|
|
5250
|
+
* LEAST of three amounts: 1/4 of the proceeds of disposition, 1/4 of the
|
|
5251
|
+
* capital cost of the property disposed of, and (per the explanatory notes to
|
|
5252
|
+
* the enacting bill) a third amount tied to the property's own pre-2017
|
|
5253
|
+
* CEC-sourced history. Old CEC only pulled 75% of an expenditure into the
|
|
5254
|
+
* pool (and correspondingly only 75% of a disposition receipt reduced it,
|
|
5255
|
+
* with the other 25% capital-gain-like) — without this addback, the switch to
|
|
5256
|
+
* class 14.1's 100% inclusion would create MORE recapture on legacy goodwill
|
|
5257
|
+
* than the old regime ever intended.
|
|
5258
|
+
*
|
|
5259
|
+
* The FIRST TWO limbs are corroborated by two independent primary/near-primary
|
|
5260
|
+
* sources (Finance Canada's own explanatory notes to the enacting bill, cross-
|
|
5261
|
+
* checked against a summary of the statute). The THIRD limb's exact wording
|
|
5262
|
+
* could not be confirmed against the Act's own text (the retrieval tooling
|
|
5263
|
+
* available here truncates before s.13(39) — see this repo's
|
|
5264
|
+
* `research/findings/federal/CCA-straight-line-classes.md`), so — same
|
|
5265
|
+
* fail-closed convention as `computeClass141AdditionalAllowance` just above —
|
|
5266
|
+
* this function bounds the addback by a caller-supplied REMAINING transitional
|
|
5267
|
+
* balance instead of guessing at the statute's own third limb. A missing
|
|
5268
|
+
* balance behaves as zero, never as unlimited.
|
|
5269
|
+
*
|
|
5270
|
+
* The RESULT is a deemed capital-cost addition — the caller adds it to the
|
|
5271
|
+
* class 14.1 row's `netAdjustments` (or applies it directly against a
|
|
5272
|
+
* recapture already computed by `computeCcaClass`) for the SAME year as the
|
|
5273
|
+
* disposition; it is not itself a CCA claim.
|
|
5274
|
+
*/
|
|
5275
|
+
const CLASS_14_1_RECAPTURE_REDUCTION_RATE = .25;
|
|
5276
|
+
function computeClass141RecaptureReduction(input) {
|
|
5277
|
+
if (!input.transitionalBalanceRemaining) return 0;
|
|
5278
|
+
const proceeds = Math.max(0, input.proceeds);
|
|
5279
|
+
const capitalCost = Math.max(0, input.capitalCost);
|
|
5280
|
+
return Math.round(Math.min(CLASS_14_1_RECAPTURE_REDUCTION_RATE * proceeds, CLASS_14_1_RECAPTURE_REDUCTION_RATE * capitalCost, Math.max(0, input.transitionalBalanceRemaining)));
|
|
5281
|
+
}
|
|
5259
5282
|
//#endregion
|
|
5260
5283
|
//#region src/t2/schedules/schedule8.ts
|
|
5261
5284
|
/**
|
|
@@ -5651,155 +5674,34 @@ function computeAlbertaSchedule13(input) {
|
|
|
5651
5674
|
};
|
|
5652
5675
|
}
|
|
5653
5676
|
//#endregion
|
|
5654
|
-
//#region src/t2/at1/schedules/schedule14-cec.ts
|
|
5655
|
-
/**
|
|
5656
|
-
* Alberta AT1 Schedule 14 — Cumulative Eligible Capital Deduction.
|
|
5657
|
-
*
|
|
5658
|
-
* **Read this before using it.** Eligible capital property was REPEALED on
|
|
5659
|
-
* 1 January 2017 and replaced by CCA class 14.1. The TRA keeps Schedule 14 only
|
|
5660
|
-
* for tax years that **end on or after 1 January 2017 and include 31 December
|
|
5661
|
-
* 2016** — the straddling year — for which the Schedule 14 Supplemental Worksheet
|
|
5662
|
-
* must also be filed, separately from the Net File payload. For any wholly
|
|
5663
|
-
* post-2016 tax year, class 14.1 on Schedule 8 / AT1 Schedule 13 replaces this
|
|
5664
|
-
* schedule entirely and it must not be filed.
|
|
5665
|
-
*
|
|
5666
|
-
* It is implemented because prior-year returns and amendments are in scope, not
|
|
5667
|
-
* because a current-year filing needs it. `appliesToTaxYear` states the rule.
|
|
5668
|
-
*
|
|
5669
|
-
* Same reconciliation shape as the other Alberta schedules: every figure defaults
|
|
5670
|
-
* to the corresponding federal one (T2 Schedule 10, lines 010nnn), and the form is
|
|
5671
|
-
* forbidden when the return declares no Alberta/federal divergence and required
|
|
5672
|
-
* when the opening balance or the claim (014024 / 014040) differs from federal.
|
|
5673
|
-
*
|
|
5674
|
-
* Line map (TRA spec §3.2.3.15) and the specified arithmetic:
|
|
5675
|
-
*
|
|
5676
|
-
* 014002 CEC balance at the end of the preceding year ← fed 010220
|
|
5677
|
-
* 014004 cost of eligible capital property acquired ← fed 010222
|
|
5678
|
-
* 014006 transferred on amalgamation or wind-up ← fed 010224
|
|
5679
|
-
* 014008 other adjustments (additions side) ← fed 010226
|
|
5680
|
-
* 014011 non-taxable portion of a non-arm's-length
|
|
5681
|
-
* transferor's gain, post-2002-12-20 ← fed 010228 × ½
|
|
5682
|
-
* 014014 proceeds of sale, net of outlays ← fed 010242
|
|
5683
|
-
* 014016 gross s.80(7) forgiven-debt reduction ← fed 010244
|
|
5684
|
-
* 014018 other adjustments (deductions side) ← fed 010246
|
|
5685
|
-
* 014023 CEC for property no longer owned after ceasing
|
|
5686
|
-
* to carry on that business ← fed 010249
|
|
5687
|
-
* 014024 current year deduction
|
|
5688
|
-
* 014026 CEC closing balance
|
|
5689
|
-
*
|
|
5690
|
-
* A = ((014004 + 014008) × ¾) − 014011 floored at 0
|
|
5691
|
-
* B = 014002 + A + 014006
|
|
5692
|
-
* C = (014014 + 014016 + 014018) × ¾
|
|
5693
|
-
* D = B − C floored at 0
|
|
5694
|
-
*
|
|
5695
|
-
* 014024 ≤ (D − 014023) × 7%, never negative
|
|
5696
|
-
* 014026 = D − 014023 − 014024 when D is positive, otherwise nil
|
|
5697
|
-
*
|
|
5698
|
-
* The ¾ inclusion and the 7% declining rate are the old CEC regime's, not the
|
|
5699
|
-
* federal 75%-of-income donation limit and not a CCA rate — they only look
|
|
5700
|
-
* similar.
|
|
5701
|
-
*
|
|
5702
|
-
* When D is NEGATIVE the schedule's "Amount to be Included in Income Arising from
|
|
5703
|
-
* Disposition" section must be completed instead, and the deduction section must
|
|
5704
|
-
* not be; when D is non-negative that section must be left blank. Both directions
|
|
5705
|
-
* are reported so a filer cannot complete the wrong half.
|
|
5706
|
-
*
|
|
5707
|
-
* Whole dollars, pure.
|
|
5708
|
-
*/
|
|
5709
|
-
/** The ¾ inclusion rate of the repealed cumulative eligible capital regime. */
|
|
5710
|
-
const CEC_INCLUSION_RATE = .75;
|
|
5711
|
-
/** The 7% declining-balance rate of the repealed regime. */
|
|
5712
|
-
const CEC_DEDUCTION_RATE = .07;
|
|
5713
|
-
const nn$22 = (v) => Math.max(0, v ?? 0);
|
|
5714
|
-
/**
|
|
5715
|
-
* Schedule 14 applies only to a tax year that ENDS on or after 2017-01-01 and
|
|
5716
|
-
* INCLUDES 2016-12-31 — the year straddling the repeal of eligible capital
|
|
5717
|
-
* property. A wholly pre-2017 year used the federal Schedule 10 regime as it then
|
|
5718
|
-
* stood; a wholly post-2016 year uses class 14.1.
|
|
5719
|
-
*/
|
|
5720
|
-
function cecScheduleAppliesToTaxYear(taxYearStart, taxYearEnd) {
|
|
5721
|
-
if (!taxYearStart || !taxYearEnd) return false;
|
|
5722
|
-
const start = Date.parse(`${taxYearStart.slice(0, 10)}T00:00:00Z`);
|
|
5723
|
-
const end = Date.parse(`${taxYearEnd.slice(0, 10)}T00:00:00Z`);
|
|
5724
|
-
const repeal = Date.parse("2017-01-01T00:00:00Z");
|
|
5725
|
-
const lastEcpDay = Date.parse("2016-12-31T00:00:00Z");
|
|
5726
|
-
if (Number.isNaN(start) || Number.isNaN(end)) return false;
|
|
5727
|
-
return end >= repeal && start <= lastEcpDay && end >= lastEcpDay;
|
|
5728
|
-
}
|
|
5729
|
-
function computeAlbertaSchedule14(input) {
|
|
5730
|
-
const issues = [];
|
|
5731
|
-
const openingBalance = nn$22(input.openingBalance);
|
|
5732
|
-
const acquisitions = nn$22(input.acquisitions);
|
|
5733
|
-
const transferredIn = nn$22(input.transferredIn);
|
|
5734
|
-
const otherAdditions = nn$22(input.otherAdditions);
|
|
5735
|
-
const nonArmsLength = nn$22(input.nonArmsLengthNonTaxablePortion);
|
|
5736
|
-
const proceedsOfSale = nn$22(input.proceedsOfSale);
|
|
5737
|
-
const forgivenDebt = nn$22(input.forgivenDebtReduction);
|
|
5738
|
-
const otherDeductions = nn$22(input.otherDeductions);
|
|
5739
|
-
const noLongerOwned = nn$22(input.cecForPropertyNoLongerOwned);
|
|
5740
|
-
const a = Math.max(0, Math.round(CEC_INCLUSION_RATE * (acquisitions + otherAdditions)) - nonArmsLength);
|
|
5741
|
-
const b = openingBalance + a + transferredIn;
|
|
5742
|
-
const c = Math.round(CEC_INCLUSION_RATE * (proceedsOfSale + forgivenDebt + otherDeductions));
|
|
5743
|
-
const rawD = b - c;
|
|
5744
|
-
const d = Math.max(0, rawD);
|
|
5745
|
-
const incomeInclusionSectionApplies = rawD < 0;
|
|
5746
|
-
const deductionBase = Math.max(0, d - noLongerOwned);
|
|
5747
|
-
const maxDeduction = incomeInclusionSectionApplies ? 0 : Math.round(CEC_DEDUCTION_RATE * deductionBase);
|
|
5748
|
-
const amountClaimed = input.amountClaimed != null ? Math.max(0, Math.min(input.amountClaimed, maxDeduction)) : maxDeduction;
|
|
5749
|
-
const closingBalance = incomeInclusionSectionApplies ? 0 : Math.max(0, deductionBase - amountClaimed);
|
|
5750
|
-
if (incomeInclusionSectionApplies && !input.incomeInclusion) issues.push("Alberta Schedule 14: the pool is negative, so the deduction section must be left blank and the \"Amount to be Included in Income Arising from Disposition\" section (014032-014048) completed. No figures for that section were supplied.");
|
|
5751
|
-
if (!incomeInclusionSectionApplies && input.incomeInclusion) issues.push("Alberta Schedule 14: the pool is not negative, so the \"Amount to be Included in Income Arising from Disposition\" section must NOT be completed. The figures supplied for it were ignored.");
|
|
5752
|
-
const appliesToTaxYear = cecScheduleAppliesToTaxYear(input.taxYearStart, input.taxYearEnd);
|
|
5753
|
-
if (input.taxYearStart && input.taxYearEnd && !appliesToTaxYear) issues.push("Alberta Schedule 14: eligible capital property was repealed on 1 January 2017. This schedule applies only to a tax year ending on or after that date that also includes 31 December 2016. For a wholly post-2016 year, use CCA class 14.1 on Schedule 13 instead.");
|
|
5754
|
-
const formRequired = Boolean(input.differsFromFederal);
|
|
5755
|
-
const formPermitted = (input.reportsDifferentAlbertaIncome ?? false) || (input.electsDifferentDiscretionaryAmounts ?? false);
|
|
5756
|
-
if (formRequired && !formPermitted) issues.push("Alberta Schedule 14: the opening balance or the claim 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.");
|
|
5757
|
-
return {
|
|
5758
|
-
a,
|
|
5759
|
-
b,
|
|
5760
|
-
c,
|
|
5761
|
-
d,
|
|
5762
|
-
rawD,
|
|
5763
|
-
amountClaimed,
|
|
5764
|
-
maxDeduction,
|
|
5765
|
-
closingBalance,
|
|
5766
|
-
incomeInclusionSectionApplies,
|
|
5767
|
-
appliesToTaxYear,
|
|
5768
|
-
supplementalWorksheetRequired: appliesToTaxYear,
|
|
5769
|
-
formRequired,
|
|
5770
|
-
formPermitted,
|
|
5771
|
-
issues
|
|
5772
|
-
};
|
|
5773
|
-
}
|
|
5774
|
-
//#endregion
|
|
5775
5677
|
//#region src/t2/at1/schedules/schedule16-sred.ts
|
|
5776
|
-
const nn$
|
|
5678
|
+
const nn$23 = (v) => Math.max(0, Math.round(v ?? 0));
|
|
5777
5679
|
/**
|
|
5778
5680
|
* Line 016004 for federal T661 versions from 2008 onward: lines 429 + 431 + 432.
|
|
5779
5681
|
* The 2007-and-earlier form used a single line 430, which can be passed to
|
|
5780
5682
|
* `assistance` directly.
|
|
5781
5683
|
*/
|
|
5782
5684
|
function assistanceFrom(line429, line431, line432) {
|
|
5783
|
-
return nn$
|
|
5685
|
+
return nn$23(line429) + nn$23(line431) + nn$23(line432);
|
|
5784
5686
|
}
|
|
5785
5687
|
function computeAlbertaSchedule16(input) {
|
|
5786
5688
|
const issues = [];
|
|
5787
|
-
const currentYearExpenditures = nn$
|
|
5788
|
-
const assistance = nn$
|
|
5789
|
-
const priorYearItcClaimed = nn$
|
|
5790
|
-
const saleOfCapitalAssetsAndOther = nn$
|
|
5791
|
-
const assistanceRepayments = nn$
|
|
5792
|
-
const openingPoolBalance = nn$
|
|
5793
|
-
const poolTransferredIn = nn$
|
|
5794
|
-
const priorYearItcRecaptured = nn$
|
|
5689
|
+
const currentYearExpenditures = nn$23(input.currentYearExpenditures);
|
|
5690
|
+
const assistance = nn$23(input.assistance);
|
|
5691
|
+
const priorYearItcClaimed = nn$23(input.priorYearItcClaimed);
|
|
5692
|
+
const saleOfCapitalAssetsAndOther = nn$23(input.saleOfCapitalAssetsAndOther);
|
|
5693
|
+
const assistanceRepayments = nn$23(input.assistanceRepayments);
|
|
5694
|
+
const openingPoolBalance = nn$23(input.openingPoolBalance);
|
|
5695
|
+
const poolTransferredIn = nn$23(input.poolTransferredIn);
|
|
5696
|
+
const priorYearItcRecaptured = nn$23(input.priorYearItcRecaptured);
|
|
5795
5697
|
const totalDeductions = assistance + priorYearItcClaimed + saleOfCapitalAssetsAndOther;
|
|
5796
5698
|
const totalAdditions = assistanceRepayments + openingPoolBalance + poolTransferredIn + priorYearItcRecaptured;
|
|
5797
5699
|
const subtotal = currentYearExpenditures - totalDeductions + totalAdditions;
|
|
5798
5700
|
const deductionAvailable = Math.max(0, subtotal);
|
|
5799
5701
|
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.`);
|
|
5800
5702
|
const amountClaimed = input.amountClaimed != null ? Math.max(0, Math.min(Math.round(input.amountClaimed), deductionAvailable)) : deductionAvailable;
|
|
5801
|
-
const openingDiffers = input.federalOpeningPoolBalance !== void 0 && nn$
|
|
5802
|
-
const claimDiffers = input.federalAmountClaimed !== void 0 && nn$
|
|
5703
|
+
const openingDiffers = input.federalOpeningPoolBalance !== void 0 && nn$23(input.federalOpeningPoolBalance) !== openingPoolBalance;
|
|
5704
|
+
const claimDiffers = input.federalAmountClaimed !== void 0 && nn$23(input.federalAmountClaimed) !== amountClaimed;
|
|
5803
5705
|
const formRequired = openingDiffers || claimDiffers;
|
|
5804
5706
|
const formPermitted = (input.reportsDifferentAlbertaIncome ?? false) || (input.electsDifferentDiscretionaryAmounts ?? false);
|
|
5805
5707
|
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.");
|
|
@@ -5927,10 +5829,10 @@ const AT1_RESERVE_LINES = Object.freeze({
|
|
|
5927
5829
|
closing: "017077"
|
|
5928
5830
|
}
|
|
5929
5831
|
});
|
|
5930
|
-
const nn$
|
|
5832
|
+
const nn$22 = (v) => Math.max(0, Math.round(v ?? 0));
|
|
5931
5833
|
/** `undefined` falls back to federal; a `0` is a real Alberta override. */
|
|
5932
5834
|
function pick(alberta, federal) {
|
|
5933
|
-
return nn$
|
|
5835
|
+
return nn$22(alberta !== void 0 ? alberta : federal);
|
|
5934
5836
|
}
|
|
5935
5837
|
function computeAlbertaSchedule17(input) {
|
|
5936
5838
|
const issues = [];
|
|
@@ -6033,7 +5935,7 @@ const AT1_DISPOSITION_CATEGORIES = [
|
|
|
6033
5935
|
* Line 018076 then applies the inclusion rate once, to the total.
|
|
6034
5936
|
*/
|
|
6035
5937
|
const SECTION_34_2_GROSS_UP = 2;
|
|
6036
|
-
const nn$
|
|
5938
|
+
const nn$21 = (v) => Math.max(0, v ?? 0);
|
|
6037
5939
|
const num = (v) => v ?? 0;
|
|
6038
5940
|
/** Merge one category: an omitted Alberta field takes federal; a `0` overrides. */
|
|
6039
5941
|
function mergeCategory(federal, alberta) {
|
|
@@ -6044,9 +5946,9 @@ function mergeCategory(federal, alberta) {
|
|
|
6044
5946
|
const o = f.outlays;
|
|
6045
5947
|
return {
|
|
6046
5948
|
totals: {
|
|
6047
|
-
proceeds: nn$
|
|
5949
|
+
proceeds: nn$21(p),
|
|
6048
5950
|
acb: num(c),
|
|
6049
|
-
outlays: nn$
|
|
5951
|
+
outlays: nn$21(o)
|
|
6050
5952
|
},
|
|
6051
5953
|
differs: a.proceeds !== void 0 || a.acb !== void 0
|
|
6052
5954
|
};
|
|
@@ -6068,17 +5970,17 @@ function computeAlbertaSchedule18(input) {
|
|
|
6068
5970
|
const gainOf = (c) => categories.find((x) => x.category === c)?.gain ?? 0;
|
|
6069
5971
|
const personalUseGain = gainOf("personalUse");
|
|
6070
5972
|
const listedPersonalGain = gainOf("listedPersonal");
|
|
6071
|
-
const lppLossesApplied = listedPersonalGain > 0 ? Math.min(nn$
|
|
5973
|
+
const lppLossesApplied = listedPersonalGain > 0 ? Math.min(nn$21(input.unappliedLppLosses), listedPersonalGain) : 0;
|
|
6072
5974
|
const ordinaryGains = gainOf("shares") + gainOf("realEstate") + gainOf("bonds") + gainOf("otherProperties");
|
|
6073
5975
|
const lppComponent = listedPersonalGain >= 0 ? listedPersonalGain - lppLossesApplied : 0;
|
|
6074
|
-
const reserveOpening = nn$
|
|
6075
|
-
const reserveClosing = nn$
|
|
6076
|
-
const netBeforeInclusionRate = ordinaryGains + personalUseGain + lppComponent + nn$
|
|
5976
|
+
const reserveOpening = nn$21(input.albertaReserveOpening ?? input.federalReserveOpening);
|
|
5977
|
+
const reserveClosing = nn$21(input.albertaReserveClosing ?? input.federalReserveClosing);
|
|
5978
|
+
const netBeforeInclusionRate = ordinaryGains + personalUseGain + lppComponent + nn$21(input.capitalGainsDividends) + reserveOpening - reserveClosing - nn$21(input.gainOnDonatedSecurities) - nn$21(input.gainOnDonatedEcologicalLand) + Math.min(nn$21(input.exemptionThreshold), nn$21(input.capitalGainsFromActualProperty)) + 2 * nn$21(input.section342TaxableCapitalGains) - 2 * nn$21(input.section342AllowableCapitalLosses);
|
|
6077
5979
|
const taxableCapitalGain = Math.max(0, Math.round(inclusionRate * netBeforeInclusionRate));
|
|
6078
5980
|
const abil = (input.abilEntries ?? []).map((e) => ({
|
|
6079
5981
|
name: e.name,
|
|
6080
5982
|
kind: e.kind,
|
|
6081
|
-
businessInvestmentLoss: nn$
|
|
5983
|
+
businessInvestmentLoss: nn$21(e.proceeds) - (nn$21(e.acb) + nn$21(e.outlays))
|
|
6082
5984
|
}));
|
|
6083
5985
|
const totalBil = abil.reduce((s, e) => s + Math.min(0, e.businessInvestmentLoss), 0);
|
|
6084
5986
|
const allowableBusinessInvestmentLoss = -Math.round(inclusionRate * -totalBil);
|
|
@@ -6109,7 +6011,7 @@ function computeAlbertaSchedule18(input) {
|
|
|
6109
6011
|
}
|
|
6110
6012
|
//#endregion
|
|
6111
6013
|
//#region src/t2/at1/schedules/schedule20-donations.ts
|
|
6112
|
-
const nn$
|
|
6014
|
+
const nn$20 = (v) => Math.max(0, v ?? 0);
|
|
6113
6015
|
/**
|
|
6114
6016
|
* Alberta figures default to federal, per-field. A `0` entered on the Alberta
|
|
6115
6017
|
* side is a real override and must not be swallowed by the default, so the
|
|
@@ -6134,11 +6036,11 @@ function resolveCarryforward(federal, alberta) {
|
|
|
6134
6036
|
return out;
|
|
6135
6037
|
}
|
|
6136
6038
|
function computeSchedule20(input) {
|
|
6137
|
-
const openingBalance = nn$
|
|
6138
|
-
const expired = nn$
|
|
6139
|
-
const transferredIn = nn$
|
|
6140
|
-
const currentYearGifts = nn$
|
|
6141
|
-
const acquisitionOfControlAdjustment = nn$
|
|
6039
|
+
const openingBalance = nn$20(input.openingBalance);
|
|
6040
|
+
const expired = nn$20(input.expired);
|
|
6041
|
+
const transferredIn = nn$20(input.transferredIn);
|
|
6042
|
+
const currentYearGifts = nn$20(input.currentYearGifts);
|
|
6043
|
+
const acquisitionOfControlAdjustment = nn$20(input.acquisitionOfControlAdjustment);
|
|
6142
6044
|
const availableBeforeClaim = Math.max(0, openingBalance - expired + transferredIn + currentYearGifts - acquisitionOfControlAdjustment);
|
|
6143
6045
|
const issues = [];
|
|
6144
6046
|
let ceiling;
|
|
@@ -6209,12 +6111,12 @@ function computeSchedule20(input) {
|
|
|
6209
6111
|
const AT1_DONATION_INCOME_RATE = .75;
|
|
6210
6112
|
/** Gains and recapture on gifted capital property add back at 25%. */
|
|
6211
6113
|
const AT1_DONATION_GAIN_RATE = .25;
|
|
6212
|
-
const nn$
|
|
6114
|
+
const nn$19 = (v) => Math.max(0, v ?? 0);
|
|
6213
6115
|
function computeDonationMaximum(input) {
|
|
6214
6116
|
const incomeComponent = Math.round(AT1_DONATION_INCOME_RATE * Math.max(0, input.albertaNetIncomeForTax));
|
|
6215
|
-
const lesserOfProceedsAndCost = Math.min(nn$
|
|
6216
|
-
const allowableRecapture = Math.min(nn$
|
|
6217
|
-
const gainsComponent = Math.round(AT1_DONATION_GAIN_RATE * (nn$
|
|
6117
|
+
const lesserOfProceedsAndCost = Math.min(nn$19(input.proceedsNetOfOutlays), nn$19(input.capitalCost));
|
|
6118
|
+
const allowableRecapture = Math.min(nn$19(input.recaptureOnGifts), lesserOfProceedsAndCost);
|
|
6119
|
+
const gainsComponent = Math.round(AT1_DONATION_GAIN_RATE * (nn$19(input.taxableCapitalGainsOnGifts) + nn$19(input.deemedGiftGains) + allowableRecapture));
|
|
6218
6120
|
return {
|
|
6219
6121
|
incomeComponent,
|
|
6220
6122
|
lesserOfProceedsAndCost,
|
|
@@ -6658,6 +6560,35 @@ function computeSBD(input, rates = CORP_TAX_2024) {
|
|
|
6658
6560
|
sbdAmount: Math.round(rates.SBD_RATE * sbdIncome)
|
|
6659
6561
|
};
|
|
6660
6562
|
}
|
|
6563
|
+
const nn$18 = (v) => v ?? 0;
|
|
6564
|
+
function computeAggregateInvestmentIncome(input) {
|
|
6565
|
+
const amountA = nn$18(input.allowableCapitalLosses) + nn$18(input.netCapitalLossesClaimed);
|
|
6566
|
+
const amountB = Math.max(0, nn$18(input.taxableCapitalGains) - amountA);
|
|
6567
|
+
const amountC = nn$18(input.exemptIncome) + nn$18(input.agriInvestFundReceived) + nn$18(input.taxableDividendsDeductible) + nn$18(input.trustPropertyIncome);
|
|
6568
|
+
const amountD = nn$18(input.incomeFromProperty) - amountC;
|
|
6569
|
+
const amountE = amountB + amountD;
|
|
6570
|
+
return {
|
|
6571
|
+
amountA,
|
|
6572
|
+
amountB,
|
|
6573
|
+
amountC,
|
|
6574
|
+
amountD,
|
|
6575
|
+
amountE,
|
|
6576
|
+
aggregateInvestmentIncome: Math.max(0, amountE - nn$18(input.lossesFromProperty))
|
|
6577
|
+
};
|
|
6578
|
+
}
|
|
6579
|
+
function computeAdjustedAggregateInvestmentIncome(input) {
|
|
6580
|
+
const amountF = Math.max(0, nn$18(input.taxableCapitalGains) - nn$18(input.allowableCapitalLosses));
|
|
6581
|
+
const amountG = nn$18(input.exemptIncome) + nn$18(input.agriInvestFundReceived) + nn$18(input.dividendsFromConnectedCorporations) + nn$18(input.trustPropertyIncome);
|
|
6582
|
+
const amountH = nn$18(input.incomeFromProperty) - amountG;
|
|
6583
|
+
const amountI = amountF + amountH;
|
|
6584
|
+
return {
|
|
6585
|
+
amountF,
|
|
6586
|
+
amountG,
|
|
6587
|
+
amountH,
|
|
6588
|
+
amountI,
|
|
6589
|
+
adjustedAggregateInvestmentIncome: Math.max(0, amountI - nn$18(input.lossesFromProperty) + nn$18(input.subsection91_4Deduction))
|
|
6590
|
+
};
|
|
6591
|
+
}
|
|
6661
6592
|
//#endregion
|
|
6662
6593
|
//#region src/t2/jacket/part1-tax.ts
|
|
6663
6594
|
/**
|
|
@@ -6967,6 +6898,60 @@ function assessEifel(input, thresholds) {
|
|
|
6967
6898
|
};
|
|
6968
6899
|
}
|
|
6969
6900
|
//#endregion
|
|
6901
|
+
//#region src/t2/schedules/part-vi-1-deduction.ts
|
|
6902
|
+
const PART_VI_1_DEDUCTION_BANDS = [
|
|
6903
|
+
{
|
|
6904
|
+
from: "0000-01-01",
|
|
6905
|
+
multiple: 3
|
|
6906
|
+
},
|
|
6907
|
+
{
|
|
6908
|
+
from: "2010-01-01",
|
|
6909
|
+
multiple: 3.2
|
|
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`);
|
|
6918
|
+
}
|
|
6919
|
+
/** The multiple in force for a taxation year ending on `taxYearEnd`. */
|
|
6920
|
+
function partVI1DeductionMultiple(taxYearEnd, bands = PART_VI_1_DEDUCTION_BANDS) {
|
|
6921
|
+
const end = utcDay$1(taxYearEnd);
|
|
6922
|
+
if (Number.isNaN(end)) return 0;
|
|
6923
|
+
let multiple = 0;
|
|
6924
|
+
for (const band of [...bands].sort((a, b) => utcDay$1(a.from) - utcDay$1(b.from))) if (end >= utcDay$1(band.from)) multiple = band.multiple;
|
|
6925
|
+
return multiple;
|
|
6926
|
+
}
|
|
6927
|
+
/**
|
|
6928
|
+
* The paragraph 110(1)(k) deduction.
|
|
6929
|
+
*
|
|
6930
|
+
* An unreadable year end yields nil and says so, rather than defaulting to the
|
|
6931
|
+
* current multiple — guessing the year would misstate taxable income, and this
|
|
6932
|
+
* deduction is large relative to the tax it follows.
|
|
6933
|
+
*/
|
|
6934
|
+
function computePartVI1Deduction(partVI1Tax, taxYearEnd, bands = PART_VI_1_DEDUCTION_BANDS) {
|
|
6935
|
+
const issues = [];
|
|
6936
|
+
const tax = Math.max(0, Math.round(partVI1Tax));
|
|
6937
|
+
const multiple = partVI1DeductionMultiple(taxYearEnd, bands);
|
|
6938
|
+
if (multiple === 0) {
|
|
6939
|
+
issues.push(`ITA 110(1)(k): the taxation year end "${taxYearEnd}" could not be read, so no Part VI.1 deduction was computed. The multiple depends on the year end (3 before 2010, 3.2 to 2011, 3.5 after) and cannot be assumed.`);
|
|
6940
|
+
return {
|
|
6941
|
+
partVI1Tax: tax,
|
|
6942
|
+
multiple: 0,
|
|
6943
|
+
deduction: 0,
|
|
6944
|
+
issues
|
|
6945
|
+
};
|
|
6946
|
+
}
|
|
6947
|
+
return {
|
|
6948
|
+
partVI1Tax: tax,
|
|
6949
|
+
multiple,
|
|
6950
|
+
deduction: Math.round(multiple * tax),
|
|
6951
|
+
issues
|
|
6952
|
+
};
|
|
6953
|
+
}
|
|
6954
|
+
//#endregion
|
|
6970
6955
|
//#region src/t2/schedules/schedule1.ts
|
|
6971
6956
|
function computeSchedule1(input) {
|
|
6972
6957
|
const additions = [...input.additions ?? []];
|
|
@@ -7095,10 +7080,10 @@ function assertSchedule1Fileable(result) {
|
|
|
7095
7080
|
}
|
|
7096
7081
|
//#endregion
|
|
7097
7082
|
//#region src/t2/schedules/schedule2-donations.ts
|
|
7098
|
-
const nn$
|
|
7083
|
+
const nn$17 = (v) => Math.max(0, v ?? 0);
|
|
7099
7084
|
function computeSchedule2(input, rates) {
|
|
7100
|
-
const openingDonationPool = nn$
|
|
7101
|
-
const currentYearDonations = nn$
|
|
7085
|
+
const openingDonationPool = nn$17(input.openingDonationPool);
|
|
7086
|
+
const currentYearDonations = nn$17(input.currentYearDonations);
|
|
7102
7087
|
const available = openingDonationPool + currentYearDonations;
|
|
7103
7088
|
const deductionLimit = Math.max(0, Math.round(rates.DONATION_INCOME_LIMIT_RATE * input.netIncomeForTax));
|
|
7104
7089
|
const donationsClaimed = Math.min(available, deductionLimit);
|
|
@@ -7137,25 +7122,25 @@ function computeSchedule2(input, rates) {
|
|
|
7137
7122
|
const PART_IV_RATE = 115 / 300;
|
|
7138
7123
|
/** 30⅔% — the refundable portion of Part I tax on aggregate investment income. */
|
|
7139
7124
|
const REFUNDABLE_PART_I_RATE = 92 / 300;
|
|
7140
|
-
const nn$
|
|
7125
|
+
const nn$16 = (v) => Math.max(0, v ?? 0);
|
|
7141
7126
|
const DEFAULT_PART4_RATES = {
|
|
7142
7127
|
PART_IV_RATE,
|
|
7143
7128
|
REFUNDABLE_PART_I_RATE
|
|
7144
7129
|
};
|
|
7145
7130
|
function computePart4Rdtoh(input, rates = DEFAULT_PART4_RATES) {
|
|
7146
|
-
const portfolio = nn$
|
|
7147
|
-
const eligible = Math.min(portfolio, nn$
|
|
7131
|
+
const portfolio = nn$16(input.portfolioDividendsReceived);
|
|
7132
|
+
const eligible = Math.min(portfolio, nn$16(input.eligiblePortfolioDividends));
|
|
7148
7133
|
const nonEligible = portfolio - eligible;
|
|
7149
|
-
const aaii = nn$
|
|
7134
|
+
const aaii = nn$16(input.aggregateInvestmentIncome);
|
|
7150
7135
|
const partIvOnEligible = Math.round(eligible * rates.PART_IV_RATE);
|
|
7151
7136
|
const partIvOnNonEligible = Math.round(nonEligible * rates.PART_IV_RATE);
|
|
7152
7137
|
const partIvTax = partIvOnEligible + partIvOnNonEligible;
|
|
7153
7138
|
const refundablePartI = Math.round(aaii * rates.REFUNDABLE_PART_I_RATE);
|
|
7154
7139
|
const erdtohAddition = partIvOnEligible;
|
|
7155
7140
|
const nerdtohAddition = partIvOnNonEligible + refundablePartI;
|
|
7156
|
-
const erdtohClosing = nn$
|
|
7157
|
-
const nerdtohClosing = nn$
|
|
7158
|
-
const refundClaim = Math.round(nn$
|
|
7141
|
+
const erdtohClosing = nn$16(input.openingErdtoh) + erdtohAddition;
|
|
7142
|
+
const nerdtohClosing = nn$16(input.openingNerdtoh) + nerdtohAddition;
|
|
7143
|
+
const refundClaim = Math.round(nn$16(input.taxableDividendsPaid) * PART_IV_RATE);
|
|
7159
7144
|
return {
|
|
7160
7145
|
partIvTax,
|
|
7161
7146
|
refundablePartI,
|
|
@@ -7319,7 +7304,7 @@ const PROVINCE_NAMES = {
|
|
|
7319
7304
|
AB: "Alberta",
|
|
7320
7305
|
QC: "Quebec"
|
|
7321
7306
|
};
|
|
7322
|
-
const nn$
|
|
7307
|
+
const nn$15 = (v) => Math.max(0, v ?? 0);
|
|
7323
7308
|
function computeProvincialAllocation(input, rates = PROVINCE_RATES_2024) {
|
|
7324
7309
|
const byProvince = /* @__PURE__ */ new Map();
|
|
7325
7310
|
for (const pe of input.permanentEstablishments) {
|
|
@@ -7328,8 +7313,8 @@ function computeProvincialAllocation(input, rates = PROVINCE_RATES_2024) {
|
|
|
7328
7313
|
grossRevenue: 0,
|
|
7329
7314
|
salariesWages: 0
|
|
7330
7315
|
};
|
|
7331
|
-
cur.grossRevenue += nn$
|
|
7332
|
-
cur.salariesWages += nn$
|
|
7316
|
+
cur.grossRevenue += nn$15(pe.grossRevenue);
|
|
7317
|
+
cur.salariesWages += nn$15(pe.salariesWages);
|
|
7333
7318
|
byProvince.set(key, cur);
|
|
7334
7319
|
}
|
|
7335
7320
|
const totalRevenue = [...byProvince.values()].reduce((s, p) => s + p.grossRevenue, 0);
|
|
@@ -7412,6 +7397,302 @@ function computeSchedule6(dispositions, inclusionRate) {
|
|
|
7412
7397
|
};
|
|
7413
7398
|
}
|
|
7414
7399
|
//#endregion
|
|
7400
|
+
//#region src/t2/schedules/schedule12-resource-deductions.ts
|
|
7401
|
+
/**
|
|
7402
|
+
* T2 Schedule 12 — Resource-Related Deductions (2025 and later tax years).
|
|
7403
|
+
*
|
|
7404
|
+
* Federal T2 had ZERO tracking for any of this before this module — the
|
|
7405
|
+
* Alberta side (AT1 Schedule 15, `t2/at1/schedules/schedule15-resource-related-deductions.ts`)
|
|
7406
|
+
* has been fully built and wired for a while, computing an Alberta figure to
|
|
7407
|
+
* diff against a federal figure that was always silently 0. This module
|
|
7408
|
+
* closes that gap on the federal side.
|
|
7409
|
+
*
|
|
7410
|
+
* Source: `research/sources/cra-forms/pdf/T2SCH12-resource-related-deductions.pdf`
|
|
7411
|
+
* (T2 SCH 12 E (26), downloaded 2026-09-03 — canada.ca was unreachable
|
|
7412
|
+
* earlier in this project; re-verified reachable on this date), rendered
|
|
7413
|
+
* page-by-page and read directly, not run through `pdftotext` (this form is
|
|
7414
|
+
* a grid, the same class of layout `pdftotext -layout` has misaligned
|
|
7415
|
+
* elsewhere in this codebase — rendering avoided that risk from the start).
|
|
7416
|
+
*
|
|
7417
|
+
* ── Five claim totals, one per Schedule 1 line ──────────────────────────────
|
|
7418
|
+
*
|
|
7419
|
+
* Part 1+2+3 Depletion (EDA regular/successor + CMEDB) → line 344
|
|
7420
|
+
* Part 4 Cumulative Canadian exploration expenses → line 341
|
|
7421
|
+
* Part 5 Cumulative Canadian development expenses → line 340
|
|
7422
|
+
* Part 6 Cumulative Canadian oil & gas property exp. → line 342
|
|
7423
|
+
* Part 7+8+9 Foreign exploration/development + resource → line 345
|
|
7424
|
+
*
|
|
7425
|
+
* ── What this module deliberately does NOT model ────────────────────────────
|
|
7426
|
+
*
|
|
7427
|
+
* The real form's full continuity has columns this module has no input for:
|
|
7428
|
+
* amalgamation/wind-up transfers, transfers to/from a successor corporation,
|
|
7429
|
+
* flow-through share renunciations, the look-back rule (s.66(12.66)), and
|
|
7430
|
+
* CEE↔CDE reclassification (ss.66.1(9)/66.7(9)). These are real provisions,
|
|
7431
|
+
* genuinely rare for a typical filer, and each one entered as a bare "other
|
|
7432
|
+
* additions/deductions" figure risks silently misclassifying something the
|
|
7433
|
+
* form treats specially (e.g. a flow-through renunciation has its own
|
|
7434
|
+
* unique interaction with the pool). Each pool below accepts a plain
|
|
7435
|
+
* `otherAdditions`/`otherDeductions` catch-all instead and says so in its
|
|
7436
|
+
* own doc comment — an honest scope limit, not a silent gap. Successor
|
|
7437
|
+
* pools ARE modelled (the form structurally requires the split), but with
|
|
7438
|
+
* the same collapsed catch-all shape as the regular pools.
|
|
7439
|
+
*
|
|
7440
|
+
* ACDE (Accelerated Canadian development expenses, generally incurred
|
|
7441
|
+
* after November 20, 2018 and before 2025) is NOT modelled as a separate
|
|
7442
|
+
* input: this schedule version is titled "2025 and later tax years", so a
|
|
7443
|
+
* CURRENT-year expense entered here is, for the ordinary case, always
|
|
7444
|
+
* RCDE-eligible rather than ACDE-eligible (RCDE covers 2024-2034,
|
|
7445
|
+
* overlapping the day this schedule starts applying). The narrow exception
|
|
7446
|
+
* — a tax year straddling the 2024/2025 boundary with genuine pre-2025
|
|
7447
|
+
* current-year CDE/COGPE additions — is not separately split out; treating
|
|
7448
|
+
* 100% of current-year CDE/COGPE additions as RCDE-eligible is the correct
|
|
7449
|
+
* default for the mainline case this schedule version targets, not a guess.
|
|
7450
|
+
* Same logic for ACOGPE/RCOGPE (Part 6).
|
|
7451
|
+
*
|
|
7452
|
+
* The CCOGPE↔CDE cross-linkage (a negative CCOGPE subtotal routes to EITHER
|
|
7453
|
+
* CDE line 105/133 depending on an s.66.7(4)(a)(iii) designation this
|
|
7454
|
+
* engine has no source for) is the SAME ambiguity the AT1 module already
|
|
7455
|
+
* flags unresolved for its own mirror of this rule — this module raises the
|
|
7456
|
+
* identical class of `issues` entry rather than guessing a designation
|
|
7457
|
+
* status it cannot know.
|
|
7458
|
+
*
|
|
7459
|
+
* Whole dollars, pure functions, no I/O.
|
|
7460
|
+
*/
|
|
7461
|
+
const nn$14 = (v) => Math.max(0, v ?? 0);
|
|
7462
|
+
const round = (v) => Math.round(v);
|
|
7463
|
+
/** CDE/CCOGPE-style short-tax-year proration: full rate at ≥357 days, else rate × days/365. */
|
|
7464
|
+
function stepYearFactor(daysInTaxYear) {
|
|
7465
|
+
const days = daysInTaxYear ?? 365;
|
|
7466
|
+
return days >= 357 ? 1 : Math.max(0, days) / 365;
|
|
7467
|
+
}
|
|
7468
|
+
/** A discretionary claim capped at `cap` (≥ 0); defaults to the maximum when omitted. */
|
|
7469
|
+
function claimUpToCap(requested, cap, issues, label) {
|
|
7470
|
+
const c = Math.max(0, round(cap));
|
|
7471
|
+
if (requested === void 0) return c;
|
|
7472
|
+
if (requested < 0) {
|
|
7473
|
+
issues.push(`${label}: a requested claim of ${requested} is negative; treated as 0.`);
|
|
7474
|
+
return 0;
|
|
7475
|
+
}
|
|
7476
|
+
if (round(requested) > c) {
|
|
7477
|
+
issues.push(`${label}: the requested claim of ${requested} exceeds the maximum allowable ${c}; capped at ${c}.`);
|
|
7478
|
+
return c;
|
|
7479
|
+
}
|
|
7480
|
+
return round(requested);
|
|
7481
|
+
}
|
|
7482
|
+
/**
|
|
7483
|
+
* CEE-style claim: at or below a zero/negative subtotal the claim MUST equal
|
|
7484
|
+
* that (negative) subtotal — an income inclusion, not a deduction. Above
|
|
7485
|
+
* zero, a discretionary claim up to the subtotal (no percentage rate).
|
|
7486
|
+
*/
|
|
7487
|
+
function forcedOrCappedClaim(requested, subtotal, issues, label) {
|
|
7488
|
+
if (subtotal <= 0) {
|
|
7489
|
+
if (requested !== void 0 && round(requested) !== round(subtotal)) issues.push(`${label}: the pool subtotal is ${subtotal} (≤ 0), so the claim must equal the subtotal (an income inclusion) — overriding the requested ${requested}.`);
|
|
7490
|
+
return round(subtotal);
|
|
7491
|
+
}
|
|
7492
|
+
return claimUpToCap(requested, subtotal, issues, label);
|
|
7493
|
+
}
|
|
7494
|
+
function computeDepletion(input = {}) {
|
|
7495
|
+
const issues = [];
|
|
7496
|
+
const edaRegularPool = nn$14(input.edaRegularOpening);
|
|
7497
|
+
const edaRegularClaim = claimUpToCap(input.edaRegularClaim, edaRegularPool, issues, "Schedule 12 EDA regular (115)");
|
|
7498
|
+
const edaRegularClosing = edaRegularPool - edaRegularClaim;
|
|
7499
|
+
const edaSuccessorPool = nn$14(input.edaSuccessorOpening);
|
|
7500
|
+
const edaSuccessorClaim = claimUpToCap(input.edaSuccessorClaim, edaSuccessorPool, issues, "Schedule 12 EDA successor (140)");
|
|
7501
|
+
const edaSuccessorClosing = edaSuccessorPool - edaSuccessorClaim;
|
|
7502
|
+
const cmedbPool = nn$14(input.cmedbOpening);
|
|
7503
|
+
const cmedbClaim = claimUpToCap(input.cmedbClaim, cmedbPool, issues, "Schedule 12 CMEDB (170)");
|
|
7504
|
+
return {
|
|
7505
|
+
edaRegularPool,
|
|
7506
|
+
edaRegularClaim,
|
|
7507
|
+
edaRegularClosing,
|
|
7508
|
+
edaSuccessorPool,
|
|
7509
|
+
edaSuccessorClaim,
|
|
7510
|
+
edaSuccessorClosing,
|
|
7511
|
+
cmedbPool,
|
|
7512
|
+
cmedbClaim,
|
|
7513
|
+
cmedbClosing: cmedbPool - cmedbClaim,
|
|
7514
|
+
totalClaim: edaRegularClaim + edaSuccessorClaim + cmedbClaim,
|
|
7515
|
+
issues
|
|
7516
|
+
};
|
|
7517
|
+
}
|
|
7518
|
+
function computeCee(input = {}) {
|
|
7519
|
+
const issues = [];
|
|
7520
|
+
const regularSubtotal = nn$14(input.regularOpening) + nn$14(input.regularCurrentYearExpenses) + nn$14(input.regularOtherAdditions) - nn$14(input.regularGovernmentAssistance) - nn$14(input.regularOtherDeductions);
|
|
7521
|
+
const regularClaim = forcedOrCappedClaim(input.regularClaim, regularSubtotal, issues, "Schedule 12 CEE regular (245)");
|
|
7522
|
+
const regularClosing = regularSubtotal > 0 ? regularSubtotal - regularClaim : 0;
|
|
7523
|
+
const successorSubtotal = nn$14(input.successorOpening) - nn$14(input.successorOtherDeductions);
|
|
7524
|
+
const successorClaim = forcedOrCappedClaim(input.successorClaim, successorSubtotal, issues, "Schedule 12 CEE successor (295)");
|
|
7525
|
+
return {
|
|
7526
|
+
regularSubtotal,
|
|
7527
|
+
regularClaim,
|
|
7528
|
+
regularClosing,
|
|
7529
|
+
successorSubtotal,
|
|
7530
|
+
successorClaim,
|
|
7531
|
+
successorClosing: successorSubtotal > 0 ? successorSubtotal - successorClaim : 0,
|
|
7532
|
+
totalClaim: regularClaim + successorClaim,
|
|
7533
|
+
issues
|
|
7534
|
+
};
|
|
7535
|
+
}
|
|
7536
|
+
/** ITA s.66.2(2) base CDE rate. */
|
|
7537
|
+
const CDE_BASE_RATE = .3;
|
|
7538
|
+
/** The RCDE bonus rate on top of the base rate (s.66.2, 2024+ enhancement). */
|
|
7539
|
+
const CDE_RCDE_BONUS_RATE = .15;
|
|
7540
|
+
function computeCde(input = {}, daysInTaxYear, cogpe = {
|
|
7541
|
+
regularSubtotal: 0,
|
|
7542
|
+
successorSubtotal: 0
|
|
7543
|
+
}) {
|
|
7544
|
+
const issues = [];
|
|
7545
|
+
const regularCreditBalance = cogpe.regularSubtotal < 0 ? round(cogpe.regularSubtotal) : nn$14(input.regularCreditBalanceInCogpePool);
|
|
7546
|
+
const regularSubtotal = nn$14(input.regularOpening) + nn$14(input.regularCurrentYearExpenses) + nn$14(input.regularOtherAdditions) - nn$14(input.regularGovernmentAssistance) - nn$14(input.regularReceivableOnDisposition) - regularCreditBalance - nn$14(input.regularOtherDeductions);
|
|
7547
|
+
const rcdePortion = Math.min(nn$14(input.regularCurrentYearExpenses), Math.max(0, regularSubtotal));
|
|
7548
|
+
const regularCap = CDE_BASE_RATE * stepYearFactor(daysInTaxYear) * regularSubtotal + CDE_RCDE_BONUS_RATE * stepYearFactor(daysInTaxYear) * rcdePortion;
|
|
7549
|
+
const regularClaim = regularSubtotal > 0 ? claimUpToCap(input.regularClaim, regularCap, issues, "Schedule 12 CDE regular (345)") : 0;
|
|
7550
|
+
const regularClosing = Math.max(0, regularSubtotal - regularClaim);
|
|
7551
|
+
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$14(input.successorCreditBalanceInCogpePool);
|
|
7553
|
+
const successorSubtotal = nn$14(input.successorOpening) - successorCreditBalance - nn$14(input.successorOtherDeductions);
|
|
7554
|
+
const successorCap = CDE_BASE_RATE * stepYearFactor(daysInTaxYear) * successorSubtotal;
|
|
7555
|
+
const successorClaim = successorSubtotal > 0 ? claimUpToCap(input.successorClaim, successorCap, issues, "Schedule 12 CDE successor (395)") : 0;
|
|
7556
|
+
return {
|
|
7557
|
+
regularSubtotal,
|
|
7558
|
+
regularClaim,
|
|
7559
|
+
regularClosing,
|
|
7560
|
+
successorSubtotal,
|
|
7561
|
+
successorClaim,
|
|
7562
|
+
successorClosing: Math.max(0, successorSubtotal - successorClaim),
|
|
7563
|
+
totalClaim: regularClaim + successorClaim,
|
|
7564
|
+
issues
|
|
7565
|
+
};
|
|
7566
|
+
}
|
|
7567
|
+
/** ITA s.66.4(2) base COGPE rate. */
|
|
7568
|
+
const COGPE_BASE_RATE = .1;
|
|
7569
|
+
/** The RCOGPE bonus rate on top of the base rate. */
|
|
7570
|
+
const COGPE_RCOGPE_BONUS_RATE = .05;
|
|
7571
|
+
function computeCogpe(input = {}, daysInTaxYear) {
|
|
7572
|
+
const issues = [];
|
|
7573
|
+
const regularSubtotal = nn$14(input.regularOpening) + nn$14(input.regularCurrentYearExpenses) + nn$14(input.regularOtherAdditions) - nn$14(input.regularReceivableOnDisposition) - nn$14(input.regularGovernmentAssistance) - nn$14(input.regularOtherDeductions);
|
|
7574
|
+
const rcogpePortion = Math.min(nn$14(input.regularCurrentYearExpenses), Math.max(0, regularSubtotal));
|
|
7575
|
+
const regularCap = COGPE_BASE_RATE * stepYearFactor(daysInTaxYear) * regularSubtotal + COGPE_RCOGPE_BONUS_RATE * stepYearFactor(daysInTaxYear) * rcogpePortion;
|
|
7576
|
+
const regularClaim = regularSubtotal > 0 ? claimUpToCap(input.regularClaim, regularCap, issues, "Schedule 12 COGPE regular (445)") : 0;
|
|
7577
|
+
const regularClosing = regularSubtotal > 0 ? regularSubtotal - regularClaim : 0;
|
|
7578
|
+
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$14(input.successorOpening) - nn$14(input.successorReceivableOnDisposition) - nn$14(input.successorOtherDeductions);
|
|
7580
|
+
const successorCap = COGPE_BASE_RATE * stepYearFactor(daysInTaxYear) * successorSubtotal;
|
|
7581
|
+
const successorClaim = successorSubtotal > 0 ? claimUpToCap(input.successorClaim, successorCap, issues, "Schedule 12 COGPE successor (495)") : 0;
|
|
7582
|
+
const successorClosing = Math.max(0, successorSubtotal - successorClaim);
|
|
7583
|
+
if (successorSubtotal < 0) issues.push("Schedule 12 COGPE successor (495): the pool subtotal is negative. Per the form this carries to CDE successor line 380 (with a s.66.7(4)(a)(iii) designation) or back into this SAME pool's own regular-side line 440 (without one) — neither route is auto-applied; supply the appropriate override manually.");
|
|
7584
|
+
return {
|
|
7585
|
+
regularSubtotal,
|
|
7586
|
+
regularClaim,
|
|
7587
|
+
regularClosing,
|
|
7588
|
+
successorSubtotal,
|
|
7589
|
+
successorClaim,
|
|
7590
|
+
successorClosing,
|
|
7591
|
+
totalClaim: regularClaim + successorClaim,
|
|
7592
|
+
issues
|
|
7593
|
+
};
|
|
7594
|
+
}
|
|
7595
|
+
/** Part 7 — Foreign exploration and development expenses (pre-2001 tax years; still a real, if rare, carryforward). */
|
|
7596
|
+
function computeForeignExploration(input = {}, daysInTaxYear) {
|
|
7597
|
+
const issues = [];
|
|
7598
|
+
const regularPool = nn$14(input.regularOpening) - nn$14(input.regularOtherDeductions);
|
|
7599
|
+
let regularClaim = 0;
|
|
7600
|
+
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
|
+
else if (regularPool > 0) {
|
|
7602
|
+
const cap = Math.max(COGPE_BASE_RATE * stepYearFactor(daysInTaxYear) * regularPool, nn$14(input.regularForeignResourceIncome));
|
|
7603
|
+
regularClaim = claimUpToCap(input.regularClaim, Math.min(regularPool, cap), issues, "Schedule 12 FEDE regular (520)");
|
|
7604
|
+
}
|
|
7605
|
+
const regularClosing = regularPool - regularClaim;
|
|
7606
|
+
const successorPool = nn$14(input.successorOpening) - nn$14(input.successorOtherDeductions);
|
|
7607
|
+
let successorClaim = 0;
|
|
7608
|
+
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$14(input.successorForeignResourceIncome)), issues, "Schedule 12 FEDE successor (570)");
|
|
7610
|
+
const successorClosing = successorPool - successorClaim;
|
|
7611
|
+
return {
|
|
7612
|
+
regularPool,
|
|
7613
|
+
regularClaim,
|
|
7614
|
+
regularClosing,
|
|
7615
|
+
successorPool,
|
|
7616
|
+
successorClaim,
|
|
7617
|
+
successorClosing,
|
|
7618
|
+
issues
|
|
7619
|
+
};
|
|
7620
|
+
}
|
|
7621
|
+
/** Part 8 — specified foreign exploration/development, regular OR successor (call once per column; rates are identical). */
|
|
7622
|
+
function computeSpecifiedForeignExploration(input = {}, label) {
|
|
7623
|
+
const issues = [];
|
|
7624
|
+
const pool = nn$14(input.openingBalance) - nn$14(input.otherDeductions);
|
|
7625
|
+
let claim = 0;
|
|
7626
|
+
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$14(input.foreignResourceIncome), pool)), issues, label);
|
|
7628
|
+
return {
|
|
7629
|
+
pool,
|
|
7630
|
+
claim,
|
|
7631
|
+
closing: pool - claim,
|
|
7632
|
+
issues
|
|
7633
|
+
};
|
|
7634
|
+
}
|
|
7635
|
+
/** Part 9 — cumulative foreign resource expenses, regular OR successor. */
|
|
7636
|
+
function computeCumulativeForeignResource(input = {}, daysInTaxYear, label) {
|
|
7637
|
+
const issues = [];
|
|
7638
|
+
const pool = nn$14(input.openingBalance) + nn$14(input.currentYearExpenses) - nn$14(input.otherDeductions);
|
|
7639
|
+
let claim = 0;
|
|
7640
|
+
if (pool < 0) issues.push(`${label}: a country-level pool is negative — include it as income on Schedule 1 manually.`);
|
|
7641
|
+
else if (pool > 0) {
|
|
7642
|
+
const a = Math.max(.1 * stepYearFactor(daysInTaxYear) * pool, Math.min(.3 * stepYearFactor(daysInTaxYear) * pool, nn$14(input.foreignResourceIncome)));
|
|
7643
|
+
const cap = a + Math.min(pool - a, nn$14(input.foreignResourceIncome));
|
|
7644
|
+
claim = claimUpToCap(input.claim, Math.min(pool, cap), issues, label);
|
|
7645
|
+
}
|
|
7646
|
+
return {
|
|
7647
|
+
pool,
|
|
7648
|
+
claim,
|
|
7649
|
+
closing: pool - claim,
|
|
7650
|
+
issues
|
|
7651
|
+
};
|
|
7652
|
+
}
|
|
7653
|
+
function computeSchedule12ResourceDeductions(input) {
|
|
7654
|
+
const cogpe = input.cogpe ? computeCogpe(input.cogpe, input.daysInTaxYear) : void 0;
|
|
7655
|
+
const depletion = input.depletion ? computeDepletion(input.depletion) : void 0;
|
|
7656
|
+
const cee = input.cee ? computeCee(input.cee) : void 0;
|
|
7657
|
+
const cde = input.cde ? computeCde(input.cde, input.daysInTaxYear, {
|
|
7658
|
+
regularSubtotal: cogpe?.regularSubtotal ?? 0,
|
|
7659
|
+
successorSubtotal: cogpe?.successorSubtotal ?? 0
|
|
7660
|
+
}) : void 0;
|
|
7661
|
+
const foreignExploration = input.foreignExploration ? computeForeignExploration(input.foreignExploration, input.daysInTaxYear) : void 0;
|
|
7662
|
+
const specifiedForeignRegular = input.specifiedForeignRegular ? computeSpecifiedForeignExploration(input.specifiedForeignRegular, "Schedule 12 SFEDE regular") : void 0;
|
|
7663
|
+
const specifiedForeignSuccessor = input.specifiedForeignSuccessor ? computeSpecifiedForeignExploration(input.specifiedForeignSuccessor, "Schedule 12 SFEDE successor") : void 0;
|
|
7664
|
+
const cumulativeForeignRegular = input.cumulativeForeignRegular ? computeCumulativeForeignResource(input.cumulativeForeignRegular, input.daysInTaxYear, "Schedule 12 CFRE regular") : void 0;
|
|
7665
|
+
const cumulativeForeignSuccessor = input.cumulativeForeignSuccessor ? computeCumulativeForeignResource(input.cumulativeForeignSuccessor, input.daysInTaxYear, "Schedule 12 CFRE successor") : void 0;
|
|
7666
|
+
const issues = [
|
|
7667
|
+
...depletion?.issues ?? [],
|
|
7668
|
+
...cee?.issues ?? [],
|
|
7669
|
+
...cde?.issues ?? [],
|
|
7670
|
+
...cogpe?.issues ?? [],
|
|
7671
|
+
...foreignExploration?.issues ?? [],
|
|
7672
|
+
...specifiedForeignRegular?.issues ?? [],
|
|
7673
|
+
...specifiedForeignSuccessor?.issues ?? [],
|
|
7674
|
+
...cumulativeForeignRegular?.issues ?? [],
|
|
7675
|
+
...cumulativeForeignSuccessor?.issues ?? []
|
|
7676
|
+
];
|
|
7677
|
+
return {
|
|
7678
|
+
...depletion ? { depletion } : {},
|
|
7679
|
+
...cee ? { cee } : {},
|
|
7680
|
+
...cde ? { cde } : {},
|
|
7681
|
+
...cogpe ? { cogpe } : {},
|
|
7682
|
+
...foreignExploration ? { foreignExploration } : {},
|
|
7683
|
+
...specifiedForeignRegular ? { specifiedForeignRegular } : {},
|
|
7684
|
+
...specifiedForeignSuccessor ? { specifiedForeignSuccessor } : {},
|
|
7685
|
+
...cumulativeForeignRegular ? { cumulativeForeignRegular } : {},
|
|
7686
|
+
...cumulativeForeignSuccessor ? { cumulativeForeignSuccessor } : {},
|
|
7687
|
+
depletionClaim: depletion?.totalClaim ?? 0,
|
|
7688
|
+
ceeClaim: cee?.totalClaim ?? 0,
|
|
7689
|
+
cdeClaim: cde?.totalClaim ?? 0,
|
|
7690
|
+
cogpeClaim: cogpe?.totalClaim ?? 0,
|
|
7691
|
+
foreignClaim: (foreignExploration?.regularClaim ?? 0) + (foreignExploration?.successorClaim ?? 0) + (specifiedForeignRegular?.claim ?? 0) + (specifiedForeignSuccessor?.claim ?? 0) + (cumulativeForeignRegular?.claim ?? 0) + (cumulativeForeignSuccessor?.claim ?? 0),
|
|
7692
|
+
issues
|
|
7693
|
+
};
|
|
7694
|
+
}
|
|
7695
|
+
//#endregion
|
|
7415
7696
|
//#region src/t2/schedules/schedule13-reserves.ts
|
|
7416
7697
|
const nn$13 = (v) => Math.max(0, Math.round(v ?? 0));
|
|
7417
7698
|
function computeSchedule13(rows = []) {
|
|
@@ -7672,11 +7953,11 @@ function computeSchedule31(input, rates) {
|
|
|
7672
7953
|
* Part 2 Investment allowance = lines 401–407 → line 490
|
|
7673
7954
|
* Part 3 Taxable capital = capital − investment allowance → line 500
|
|
7674
7955
|
* Part 4 Taxable capital employed in Canada
|
|
7675
|
-
* = taxable capital × (taxable income earned in Canada ÷ taxable income) → line
|
|
7956
|
+
* = taxable capital × (taxable income earned in Canada ÷ taxable income) → line 790
|
|
7676
7957
|
*
|
|
7677
7958
|
* Part 5 of the paper form (the 0.225% figure at line 415) is the SUPERSEDED
|
|
7678
7959
|
* capital-tax-era grind; the CURRENT business-limit grind (straight-line $10M→$50M)
|
|
7679
|
-
* lives in Schedule 7. This schedule therefore stops at line
|
|
7960
|
+
* lives in Schedule 7. This schedule therefore stops at line 790 and hands that
|
|
7680
7961
|
* figure to the Schedule 7 grind. The federal Part I.3 tax itself was repealed
|
|
7681
7962
|
* (2006) and is not computed. Pure, integer whole dollars.
|
|
7682
7963
|
*/
|
|
@@ -8054,18 +8335,50 @@ function shortYearProrationFactor(periodStart, periodEnd) {
|
|
|
8054
8335
|
if (days >= 365) return 1;
|
|
8055
8336
|
return days / 365;
|
|
8056
8337
|
}
|
|
8338
|
+
/** Same inclusive day count as `shortYearProrationFactor`, but the raw days — Schedule 12's ≥357-day step proration needs the count itself, not a pre-divided factor. */
|
|
8339
|
+
function daysInTaxYear(periodStart, periodEnd) {
|
|
8340
|
+
if (!periodStart || !periodEnd) return void 0;
|
|
8341
|
+
const start = periodStart instanceof Date ? periodStart : new Date(periodStart);
|
|
8342
|
+
const ms = (periodEnd instanceof Date ? periodEnd : new Date(periodEnd)).getTime() - start.getTime();
|
|
8343
|
+
if (!Number.isFinite(ms) || ms < 0) return void 0;
|
|
8344
|
+
return Math.round(ms / 864e5) + 1;
|
|
8345
|
+
}
|
|
8057
8346
|
function computeFederalT2(input) {
|
|
8058
8347
|
const book = input.rateBook ?? CORP_TAX_RATE_BOOK;
|
|
8059
8348
|
const taxYear = input.taxYear ?? latestRateYear(book);
|
|
8060
8349
|
const rates = input.rates ?? resolveCorpTaxRates(taxYear, book);
|
|
8061
8350
|
const prorationFactor = shortYearProrationFactor(input.periodStart, input.periodEnd);
|
|
8062
|
-
const
|
|
8351
|
+
const ccaRaw = input.ccaClasses?.length ? computeCcaSchedule(input.ccaClasses, resolveCcaRates(taxYear), prorationFactor) : void 0;
|
|
8352
|
+
const class141RecaptureReduction = input.class141Disposition ? computeClass141RecaptureReduction(input.class141Disposition) : 0;
|
|
8353
|
+
const cca = ccaRaw && class141RecaptureReduction > 0 ? (() => {
|
|
8354
|
+
const idx = ccaRaw.classes.findIndex((c) => c.ccaClass === "14.1");
|
|
8355
|
+
const row = idx >= 0 ? ccaRaw.classes[idx] : void 0;
|
|
8356
|
+
const reduction = row ? Math.min(class141RecaptureReduction, row.recapture) : 0;
|
|
8357
|
+
if (!row || reduction === 0) return ccaRaw;
|
|
8358
|
+
const classes = ccaRaw.classes.slice();
|
|
8359
|
+
classes[idx] = {
|
|
8360
|
+
...row,
|
|
8361
|
+
recapture: row.recapture - reduction
|
|
8362
|
+
};
|
|
8363
|
+
return {
|
|
8364
|
+
...ccaRaw,
|
|
8365
|
+
classes,
|
|
8366
|
+
totalRecapture: ccaRaw.totalRecapture - reduction
|
|
8367
|
+
};
|
|
8368
|
+
})() : ccaRaw;
|
|
8063
8369
|
const class13 = input.class13 ? computeClass13(input.class13) : void 0;
|
|
8064
8370
|
const class14 = input.class14 ? computeClass14(input.class14) : void 0;
|
|
8371
|
+
const class141Row = cca?.classes.find((c) => c.ccaClass === "14.1");
|
|
8372
|
+
const class141AdditionalAllowance = input.class141Transitional && class141Row ? computeClass141AdditionalAllowance({
|
|
8373
|
+
...input.class141Transitional,
|
|
8374
|
+
ordinaryClaim: class141Row.ccaClaimed,
|
|
8375
|
+
uccBeforeCca: class141Row.uccBeforeCca,
|
|
8376
|
+
taxYearEnd: isoDay(input.periodEnd)
|
|
8377
|
+
}) : void 0;
|
|
8065
8378
|
const capitalGains = input.capitalDispositions?.length ? computeSchedule6(input.capitalDispositions, rates.CAPITAL_GAINS_INCLUSION_RATE) : void 0;
|
|
8066
8379
|
const schedule1Additions = [...input.schedule1Additions ?? []];
|
|
8067
8380
|
const schedule1Deductions = [...input.schedule1Deductions ?? []];
|
|
8068
|
-
const totalCcaDeduction = (cca?.totalCca ?? 0) + (class13?.ccaClaimed ?? 0) + (class14?.ccaClaimed ?? 0);
|
|
8381
|
+
const totalCcaDeduction = (cca?.totalCca ?? 0) + (class13?.ccaClaimed ?? 0) + (class14?.ccaClaimed ?? 0) + (class141AdditionalAllowance?.additionalAllowance ?? 0);
|
|
8069
8382
|
if (totalCcaDeduction > 0) schedule1Deductions.push({
|
|
8070
8383
|
line: "403",
|
|
8071
8384
|
label: "Capital cost allowance from Schedule 8",
|
|
@@ -8106,22 +8419,83 @@ function computeFederalT2(input) {
|
|
|
8106
8419
|
ref: "s.20(1)"
|
|
8107
8420
|
});
|
|
8108
8421
|
}
|
|
8422
|
+
const resolvedResourceDeductionDays = input.resourceDeductions?.daysInTaxYear ?? daysInTaxYear(input.periodStart, input.periodEnd);
|
|
8423
|
+
const resourceDeductions = input.resourceDeductions ? computeSchedule12ResourceDeductions({
|
|
8424
|
+
...input.resourceDeductions,
|
|
8425
|
+
...resolvedResourceDeductionDays !== void 0 ? { daysInTaxYear: resolvedResourceDeductionDays } : {}
|
|
8426
|
+
}) : void 0;
|
|
8427
|
+
if (resourceDeductions) {
|
|
8428
|
+
if (resourceDeductions.cdeClaim > 0) schedule1Deductions.push({
|
|
8429
|
+
line: "340",
|
|
8430
|
+
label: "Canadian development expenses from Schedule 12",
|
|
8431
|
+
amount: resourceDeductions.cdeClaim,
|
|
8432
|
+
ref: "s.66.2(2)"
|
|
8433
|
+
});
|
|
8434
|
+
if (resourceDeductions.ceeClaim !== 0) schedule1Deductions.push({
|
|
8435
|
+
line: "341",
|
|
8436
|
+
label: "Canadian exploration expenses from Schedule 12",
|
|
8437
|
+
amount: resourceDeductions.ceeClaim,
|
|
8438
|
+
ref: "s.66.1(2)"
|
|
8439
|
+
});
|
|
8440
|
+
if (resourceDeductions.cogpeClaim > 0) schedule1Deductions.push({
|
|
8441
|
+
line: "342",
|
|
8442
|
+
label: "Canadian oil and gas property expenses from Schedule 12",
|
|
8443
|
+
amount: resourceDeductions.cogpeClaim,
|
|
8444
|
+
ref: "s.66.4(2)"
|
|
8445
|
+
});
|
|
8446
|
+
if (resourceDeductions.depletionClaim > 0) schedule1Deductions.push({
|
|
8447
|
+
line: "344",
|
|
8448
|
+
label: "Depletion from Schedule 12",
|
|
8449
|
+
amount: resourceDeductions.depletionClaim,
|
|
8450
|
+
ref: "Reg. 1201/1202/1203"
|
|
8451
|
+
});
|
|
8452
|
+
if (resourceDeductions.foreignClaim > 0) schedule1Deductions.push({
|
|
8453
|
+
line: "345",
|
|
8454
|
+
label: "Foreign exploration, development and resource expenses from Schedule 12",
|
|
8455
|
+
amount: resourceDeductions.foreignClaim,
|
|
8456
|
+
ref: "s.66(4)/66.7(2)"
|
|
8457
|
+
});
|
|
8458
|
+
}
|
|
8109
8459
|
const schedule1 = computeSchedule1({
|
|
8110
8460
|
bookNetIncome: input.bookNetIncome,
|
|
8111
8461
|
...schedule1Additions.length ? { additions: schedule1Additions } : {},
|
|
8112
8462
|
...schedule1Deductions.length ? { deductions: schedule1Deductions } : {}
|
|
8113
8463
|
});
|
|
8464
|
+
const partVI1 = input.preferredShareDividends && ((input.preferredShareDividends.shortTermPreferredDividends ?? 0) > 0 || (input.preferredShareDividends.otherPreferredDividends ?? 0) > 0) ? computeSchedule43(input.preferredShareDividends, {
|
|
8465
|
+
SHORT_TERM_RATE: rates.PART_VI_1_SHORT_TERM_RATE,
|
|
8466
|
+
ELECTED_RATE: rates.PART_VI_1_ELECTED_RATE,
|
|
8467
|
+
BASE_RATE: rates.PART_VI_1_BASE_RATE,
|
|
8468
|
+
DIVIDEND_ALLOWANCE: rates.PART_VI_1_DIVIDEND_ALLOWANCE,
|
|
8469
|
+
ALLOWANCE_GRIND_THRESHOLD: rates.PART_VI_1_ALLOWANCE_GRIND_THRESHOLD
|
|
8470
|
+
}) : void 0;
|
|
8471
|
+
const partVI1Deduction = partVI1 ? computePartVI1Deduction(partVI1.partVI1Tax, isoDay(input.periodEnd)) : void 0;
|
|
8114
8472
|
const donations = input.charitableDonations !== void 0 || input.openingDonationPool !== void 0 ? computeSchedule2({
|
|
8115
8473
|
...input.openingDonationPool !== void 0 ? { openingDonationPool: input.openingDonationPool } : {},
|
|
8116
8474
|
...input.charitableDonations !== void 0 ? { currentYearDonations: input.charitableDonations } : {},
|
|
8117
8475
|
netIncomeForTax: schedule1.netIncomeForTax
|
|
8118
8476
|
}, rates) : void 0;
|
|
8119
|
-
const
|
|
8120
|
-
|
|
8121
|
-
|
|
8122
|
-
|
|
8123
|
-
|
|
8124
|
-
|
|
8477
|
+
const culturalEcologicalGiftsClaimed = Math.max(0, input.culturalEcologicalGifts ?? 0);
|
|
8478
|
+
const divisionCDeductions = [
|
|
8479
|
+
...donations && donations.donationsClaimed > 0 ? [{
|
|
8480
|
+
line: "112",
|
|
8481
|
+
label: "Charitable donations and gifts from Schedule 2",
|
|
8482
|
+
amount: donations.donationsClaimed,
|
|
8483
|
+
ref: "s.110.1"
|
|
8484
|
+
}] : [],
|
|
8485
|
+
...culturalEcologicalGiftsClaimed > 0 ? [{
|
|
8486
|
+
line: "112",
|
|
8487
|
+
label: "Gifts of certified cultural property and ecologically sensitive land from Schedule 2",
|
|
8488
|
+
amount: culturalEcologicalGiftsClaimed,
|
|
8489
|
+
ref: "s.110.1(1)(b)/(c) — not subject to the 75% income limit"
|
|
8490
|
+
}] : [],
|
|
8491
|
+
...partVI1Deduction && partVI1Deduction.deduction > 0 ? [{
|
|
8492
|
+
line: "325",
|
|
8493
|
+
label: "Part VI.1 tax deduction",
|
|
8494
|
+
amount: partVI1Deduction.deduction,
|
|
8495
|
+
ref: `s.110(1)(k) — ${partVI1Deduction.multiple}× Part VI.1 tax payable`
|
|
8496
|
+
}] : [],
|
|
8497
|
+
...input.divisionCDeductions ?? []
|
|
8498
|
+
];
|
|
8125
8499
|
const taxableIncomeCalc = computeTaxableIncome({
|
|
8126
8500
|
netIncomeForTax: schedule1.netIncomeForTax,
|
|
8127
8501
|
...divisionCDeductions.length ? { deductions: divisionCDeductions } : {}
|
|
@@ -8152,10 +8526,15 @@ function computeFederalT2(input) {
|
|
|
8152
8526
|
...input.taxableCapitalDetail.taxableIncome === void 0 ? { taxableIncome } : {}
|
|
8153
8527
|
}) : void 0;
|
|
8154
8528
|
const grindTaxableCapital = input.taxableCapital ?? taxableCapitalSchedule?.taxableCapitalEmployedInCanada;
|
|
8529
|
+
const adjustedAggregateInvestmentIncomeSchedule = input.adjustedAggregateInvestmentIncomeDetail ? computeAdjustedAggregateInvestmentIncome(input.adjustedAggregateInvestmentIncomeDetail) : void 0;
|
|
8530
|
+
const resolvedAaii = input.aaii ?? adjustedAggregateInvestmentIncomeSchedule?.adjustedAggregateInvestmentIncome;
|
|
8531
|
+
const aggregateInvestmentIncomeSchedule = input.aggregateInvestmentIncomeDetail ? computeAggregateInvestmentIncome(input.aggregateInvestmentIncomeDetail) : void 0;
|
|
8532
|
+
const resolvedAggregateInvestmentIncome = input.aggregateInvestmentIncome ?? aggregateInvestmentIncomeSchedule?.aggregateInvestmentIncome;
|
|
8533
|
+
const rdtohAggregateInvestmentIncome = resolvedAggregateInvestmentIncome ?? resolvedAaii;
|
|
8155
8534
|
const businessLimit = computeBusinessLimit({
|
|
8156
8535
|
...input.businessLimit !== void 0 ? { businessLimit: input.businessLimit } : {},
|
|
8157
8536
|
...grindTaxableCapital !== void 0 ? { taxableCapital: grindTaxableCapital } : {},
|
|
8158
|
-
...
|
|
8537
|
+
...resolvedAaii !== void 0 ? { aaii: resolvedAaii } : {},
|
|
8159
8538
|
...prorationFactor < 1 ? { prorationFactor } : {}
|
|
8160
8539
|
}, rates);
|
|
8161
8540
|
const sbd = input.isCcpc === true ? computeSBD({
|
|
@@ -8176,7 +8555,7 @@ function computeFederalT2(input) {
|
|
|
8176
8555
|
const part4Rdtoh = computePart4Rdtoh({
|
|
8177
8556
|
portfolioDividendsReceived: input.portfolioDividendsReceived ?? 0,
|
|
8178
8557
|
...input.eligiblePortfolioDividends !== void 0 ? { eligiblePortfolioDividends: input.eligiblePortfolioDividends } : {},
|
|
8179
|
-
...
|
|
8558
|
+
...rdtohAggregateInvestmentIncome !== void 0 ? { aggregateInvestmentIncome: rdtohAggregateInvestmentIncome } : {},
|
|
8180
8559
|
...input.taxableDividendsPaid !== void 0 ? { taxableDividendsPaid: input.taxableDividendsPaid } : {},
|
|
8181
8560
|
...input.openingErdtoh !== void 0 ? { openingErdtoh: input.openingErdtoh } : {},
|
|
8182
8561
|
...input.openingNerdtoh !== void 0 ? { openingNerdtoh: input.openingNerdtoh } : {}
|
|
@@ -8209,7 +8588,7 @@ function computeFederalT2(input) {
|
|
|
8209
8588
|
}, rates) : void 0;
|
|
8210
8589
|
const grip = input.openingGrip !== void 0 || input.eligibleDividendsReceived !== void 0 || input.eligibleDividendsDesignated !== void 0 ? computeGrip({
|
|
8211
8590
|
...input.openingGrip !== void 0 ? { openingGrip: input.openingGrip } : {},
|
|
8212
|
-
generalRateIncome: Math.max(0, taxableIncome - sbd.sbdIncome - (
|
|
8591
|
+
generalRateIncome: Math.max(0, taxableIncome - sbd.sbdIncome - (resolvedAggregateInvestmentIncome ?? resolvedAaii ?? 0)),
|
|
8213
8592
|
...input.eligibleDividendsReceived !== void 0 ? { eligibleDividendsReceived: input.eligibleDividendsReceived } : {},
|
|
8214
8593
|
...input.eligibleDividendsDesignated !== void 0 ? { eligibleDividendsDesignated: input.eligibleDividendsDesignated } : {}
|
|
8215
8594
|
}, rates.GRIP_FACTOR) : void 0;
|
|
@@ -8223,13 +8602,6 @@ function computeFederalT2(input) {
|
|
|
8223
8602
|
...input.electedOrdinaryDividendAmount !== void 0 ? { electedAmount: input.electedOrdinaryDividendAmount } : {},
|
|
8224
8603
|
...input.electOrdinaryDividend !== void 0 ? { electsMaximum: input.electOrdinaryDividend } : {}
|
|
8225
8604
|
}, rates.PART_III_1_RATE, rates.PART_III_1_PARAGRAPH_C_RATE) : void 0;
|
|
8226
|
-
const partVI1 = input.preferredShareDividends && ((input.preferredShareDividends.shortTermPreferredDividends ?? 0) > 0 || (input.preferredShareDividends.otherPreferredDividends ?? 0) > 0) ? computeSchedule43(input.preferredShareDividends, {
|
|
8227
|
-
SHORT_TERM_RATE: rates.PART_VI_1_SHORT_TERM_RATE,
|
|
8228
|
-
ELECTED_RATE: rates.PART_VI_1_ELECTED_RATE,
|
|
8229
|
-
BASE_RATE: rates.PART_VI_1_BASE_RATE,
|
|
8230
|
-
DIVIDEND_ALLOWANCE: rates.PART_VI_1_DIVIDEND_ALLOWANCE,
|
|
8231
|
-
ALLOWANCE_GRIND_THRESHOLD: rates.PART_VI_1_ALLOWANCE_GRIND_THRESHOLD
|
|
8232
|
-
}) : void 0;
|
|
8233
8605
|
const totalFederalTax = partIAfterCredits + (itcRecapture?.totalRecapture ?? 0) + part4Rdtoh.partIvTax - part4Rdtoh.dividendRefund - (sredItc?.totalItcBenefit ?? 0) + (partIII1?.partIII1Tax ?? 0) + (partVI1?.partVI1Tax ?? 0);
|
|
8234
8606
|
const baseProvinceRates = resolveProvinceRates(taxYear);
|
|
8235
8607
|
const provinceRates = input.provincialRateChanges && input.periodStart && input.periodEnd ? blendProvinceRateTable(baseProvinceRates, input.provincialRateChanges, input.periodStart, input.periodEnd) : baseProvinceRates;
|
|
@@ -8264,6 +8636,8 @@ function computeFederalT2(input) {
|
|
|
8264
8636
|
schedule1,
|
|
8265
8637
|
taxableIncomeCalc,
|
|
8266
8638
|
businessLimit,
|
|
8639
|
+
...adjustedAggregateInvestmentIncomeSchedule ? { adjustedAggregateInvestmentIncomeSchedule } : {},
|
|
8640
|
+
...aggregateInvestmentIncomeSchedule ? { aggregateInvestmentIncomeSchedule } : {},
|
|
8267
8641
|
sbd,
|
|
8268
8642
|
partI,
|
|
8269
8643
|
part4Rdtoh,
|
|
@@ -8273,6 +8647,8 @@ function computeFederalT2(input) {
|
|
|
8273
8647
|
...cca ? { cca } : {},
|
|
8274
8648
|
...class13 ? { class13 } : {},
|
|
8275
8649
|
...class14 ? { class14 } : {},
|
|
8650
|
+
...class141AdditionalAllowance ? { class141AdditionalAllowance } : {},
|
|
8651
|
+
...class141RecaptureReduction > 0 ? { class141RecaptureReduction } : {},
|
|
8276
8652
|
...capitalGains ? { capitalGains } : {},
|
|
8277
8653
|
...provincial ? { provincial } : {},
|
|
8278
8654
|
...provincialAllocation ? { provincialAllocation } : {},
|
|
@@ -8280,6 +8656,7 @@ function computeFederalT2(input) {
|
|
|
8280
8656
|
...lrip ? { lrip } : {},
|
|
8281
8657
|
...partIII1 ? { partIII1 } : {},
|
|
8282
8658
|
...partVI1 ? { partVI1 } : {},
|
|
8659
|
+
...partVI1Deduction ? { partVI1Deduction } : {},
|
|
8283
8660
|
eifel,
|
|
8284
8661
|
...internetBusiness ? { internetBusiness } : {},
|
|
8285
8662
|
...firstReturn ? { firstReturn } : {},
|
|
@@ -8290,6 +8667,7 @@ function computeFederalT2(input) {
|
|
|
8290
8667
|
...associatedAllocation ? { associatedAllocation } : {},
|
|
8291
8668
|
...reserves ? { reserves } : {},
|
|
8292
8669
|
...taxableCapitalSchedule ? { taxableCapitalSchedule } : {},
|
|
8670
|
+
...resourceDeductions ? { resourceDeductions } : {},
|
|
8293
8671
|
netIncomeForTax: schedule1.netIncomeForTax,
|
|
8294
8672
|
taxableIncome,
|
|
8295
8673
|
federalTaxPayable: partI.partITaxPayable,
|
|
@@ -8708,6 +9086,7 @@ const OPTIONAL_NUMERIC_FIELDS = [
|
|
|
8708
9086
|
"businessLimit",
|
|
8709
9087
|
"taxableCapital",
|
|
8710
9088
|
"aaii",
|
|
9089
|
+
"aggregateInvestmentIncome",
|
|
8711
9090
|
"portfolioDividendsReceived",
|
|
8712
9091
|
"eligiblePortfolioDividends",
|
|
8713
9092
|
"taxableDividendsPaid",
|
|
@@ -8826,19 +9205,19 @@ function renderT2DraftReturn(data, opts = {}) {
|
|
|
8826
9205
|
if (data.questionnaire) {
|
|
8827
9206
|
const q = data.questionnaire;
|
|
8828
9207
|
out.push(" <Questionnaire>");
|
|
8829
|
-
out.push(el(4, "AddressChanged", yn(q.addressChanged)
|
|
8830
|
-
out.push(el(4, "FirstYearFiling", yn(q.firstYear), "
|
|
8831
|
-
out.push(el(4, "FinalReturn", yn(q.finalReturn)));
|
|
8832
|
-
out.push(el(4, "FirstReturnAfterAmalgamation", yn(q.amalgamation), "
|
|
8833
|
-
out.push(el(4, "WindUpOfSubsidiary", yn(q.windUp), "
|
|
8834
|
-
out.push(el(4, "AcquisitionOfControl", yn(q.acquisitionOfControl)));
|
|
8835
|
-
out.push(el(4, "
|
|
9208
|
+
out.push(el(4, "AddressChanged", yn(q.addressChanged)));
|
|
9209
|
+
out.push(el(4, "FirstYearFiling", yn(q.firstYear), "070"));
|
|
9210
|
+
out.push(el(4, "FinalReturn", yn(q.finalReturn), "078"));
|
|
9211
|
+
out.push(el(4, "FirstReturnAfterAmalgamation", yn(q.amalgamation), "071"));
|
|
9212
|
+
out.push(el(4, "WindUpOfSubsidiary", yn(q.windUp), "072"));
|
|
9213
|
+
out.push(el(4, "AcquisitionOfControl", yn(q.acquisitionOfControl), "063"));
|
|
9214
|
+
out.push(el(4, "DeemedYearEnd", yn(q.deemedYearEnd), "066"));
|
|
8836
9215
|
out.push(el(4, "ResidentOfCanada", yn(q.residentOfCanada), "080"));
|
|
8837
|
-
out.push(el(4, "ProfessionalCorporation", yn(q.professionalCorp)));
|
|
9216
|
+
out.push(el(4, "ProfessionalCorporation", yn(q.professionalCorp), "067"));
|
|
8838
9217
|
out.push(el(4, "Inactive", yn(q.inactive)));
|
|
8839
9218
|
out.push(el(4, "AssociatedCCPC", yn(q.associated), "160"));
|
|
8840
9219
|
out.push(el(4, "AssociatedClaimingExpenditureLimit", yn(q.associatedClaimingExpenditureLimit), "161"));
|
|
8841
|
-
out.push(el(4, "RelatedCorporations", yn(q.relatedCorporations)));
|
|
9220
|
+
out.push(el(4, "RelatedCorporations", yn(q.relatedCorporations), "150"));
|
|
8842
9221
|
out.push(el(4, "CharitableDonations", yn(q.charitableDonations), "201"));
|
|
8843
9222
|
out.push(el(4, "Dividends", yn(q.dividends), "202"));
|
|
8844
9223
|
out.push(el(4, "ClaimingLosses", yn(q.claimingLosses), "204"));
|
|
@@ -9188,7 +9567,7 @@ const EIFEL_FIRST_YEAR_START = "2023-10-01";
|
|
|
9188
9567
|
/** The transitional 40% band ends when years beginning in 2024 start. */
|
|
9189
9568
|
const EIFEL_STANDARD_RATIO_FROM = "2024-01-01";
|
|
9190
9569
|
const nn$1 = (v) => Math.max(0, Math.round(v ?? 0));
|
|
9191
|
-
function utcDay
|
|
9570
|
+
function utcDay(iso) {
|
|
9192
9571
|
return Date.parse(`${iso.slice(0, 10)}T00:00:00Z`);
|
|
9193
9572
|
}
|
|
9194
9573
|
/**
|
|
@@ -9196,9 +9575,9 @@ function utcDay$1(iso) {
|
|
|
9196
9575
|
* Returns 0 for a year beginning before the regime applies at all.
|
|
9197
9576
|
*/
|
|
9198
9577
|
function ratioOfPermissibleExpenses(taxYearStart) {
|
|
9199
|
-
const start = utcDay
|
|
9200
|
-
if (Number.isNaN(start) || start < utcDay
|
|
9201
|
-
return start < utcDay
|
|
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;
|
|
9202
9581
|
}
|
|
9203
9582
|
function computeEifelLimitation(input) {
|
|
9204
9583
|
const issues = [];
|
|
@@ -9238,60 +9617,6 @@ function computeEifelLimitation(input) {
|
|
|
9238
9617
|
};
|
|
9239
9618
|
}
|
|
9240
9619
|
//#endregion
|
|
9241
|
-
//#region src/t2/schedules/part-vi-1-deduction.ts
|
|
9242
|
-
const PART_VI_1_DEDUCTION_BANDS = [
|
|
9243
|
-
{
|
|
9244
|
-
from: "0000-01-01",
|
|
9245
|
-
multiple: 3
|
|
9246
|
-
},
|
|
9247
|
-
{
|
|
9248
|
-
from: "2010-01-01",
|
|
9249
|
-
multiple: 3.2
|
|
9250
|
-
},
|
|
9251
|
-
{
|
|
9252
|
-
from: "2012-01-01",
|
|
9253
|
-
multiple: 3.5
|
|
9254
|
-
}
|
|
9255
|
-
];
|
|
9256
|
-
function utcDay(iso) {
|
|
9257
|
-
return Date.parse(`${iso.slice(0, 10)}T00:00:00Z`);
|
|
9258
|
-
}
|
|
9259
|
-
/** The multiple in force for a taxation year ending on `taxYearEnd`. */
|
|
9260
|
-
function partVI1DeductionMultiple(taxYearEnd, bands = PART_VI_1_DEDUCTION_BANDS) {
|
|
9261
|
-
const end = utcDay(taxYearEnd);
|
|
9262
|
-
if (Number.isNaN(end)) return 0;
|
|
9263
|
-
let multiple = 0;
|
|
9264
|
-
for (const band of [...bands].sort((a, b) => utcDay(a.from) - utcDay(b.from))) if (end >= utcDay(band.from)) multiple = band.multiple;
|
|
9265
|
-
return multiple;
|
|
9266
|
-
}
|
|
9267
|
-
/**
|
|
9268
|
-
* The paragraph 110(1)(k) deduction.
|
|
9269
|
-
*
|
|
9270
|
-
* An unreadable year end yields nil and says so, rather than defaulting to the
|
|
9271
|
-
* current multiple — guessing the year would misstate taxable income, and this
|
|
9272
|
-
* deduction is large relative to the tax it follows.
|
|
9273
|
-
*/
|
|
9274
|
-
function computePartVI1Deduction(partVI1Tax, taxYearEnd, bands = PART_VI_1_DEDUCTION_BANDS) {
|
|
9275
|
-
const issues = [];
|
|
9276
|
-
const tax = Math.max(0, Math.round(partVI1Tax));
|
|
9277
|
-
const multiple = partVI1DeductionMultiple(taxYearEnd, bands);
|
|
9278
|
-
if (multiple === 0) {
|
|
9279
|
-
issues.push(`ITA 110(1)(k): the taxation year end "${taxYearEnd}" could not be read, so no Part VI.1 deduction was computed. The multiple depends on the year end (3 before 2010, 3.2 to 2011, 3.5 after) and cannot be assumed.`);
|
|
9280
|
-
return {
|
|
9281
|
-
partVI1Tax: tax,
|
|
9282
|
-
multiple: 0,
|
|
9283
|
-
deduction: 0,
|
|
9284
|
-
issues
|
|
9285
|
-
};
|
|
9286
|
-
}
|
|
9287
|
-
return {
|
|
9288
|
-
partVI1Tax: tax,
|
|
9289
|
-
multiple,
|
|
9290
|
-
deduction: Math.round(multiple * tax),
|
|
9291
|
-
issues
|
|
9292
|
-
};
|
|
9293
|
-
}
|
|
9294
|
-
//#endregion
|
|
9295
9620
|
//#region src/t2/schedules/schedule27-mp.ts
|
|
9296
9621
|
/**
|
|
9297
9622
|
* T2 Schedule 27 — Canadian Manufacturing and Processing Profits Deduction
|
|
@@ -9362,6 +9687,72 @@ const MP_RATES_2024 = Object.freeze({
|
|
|
9362
9687
|
GENERAL_RATE_REDUCTION: .13
|
|
9363
9688
|
});
|
|
9364
9689
|
const nn = (v) => Math.max(0, Math.round(v ?? 0));
|
|
9690
|
+
/** The $200,000 combined-active-business-income ceiling, s.5201 of the Regulations. */
|
|
9691
|
+
const SMALL_MANUFACTURER_INCOME_THRESHOLD = 2e5;
|
|
9692
|
+
function computeSmallManufacturerTest(input) {
|
|
9693
|
+
const issues = [];
|
|
9694
|
+
const line100 = nn(input.activeBusinessIncome);
|
|
9695
|
+
const combinedActiveBusinessIncome = line100 + nn(input.associatedActiveBusinessIncome);
|
|
9696
|
+
const failures = [];
|
|
9697
|
+
if (!input.primarilyManufacturing) failures.push("activities during the year were not primarily manufacturing or processing");
|
|
9698
|
+
if (combinedActiveBusinessIncome > 2e5) failures.push(`combined active business income (${combinedActiveBusinessIncome}, line 110) exceeds the $${SMALL_MANUFACTURER_INCOME_THRESHOLD.toLocaleString()} ceiling under s.5201 of the Regulations`);
|
|
9699
|
+
if (input.excludedActivity) failures.push(`${input.excludedActivity} is an excluded activity under s.5201(c)-(c.3)`);
|
|
9700
|
+
if (input.activeBusinessOutsideCanada) failures.push("an active business was carried on outside Canada during the year");
|
|
9701
|
+
const qualifies = failures.length === 0;
|
|
9702
|
+
if (!qualifies) issues.push(`Schedule 27 Part 1: does not qualify as a small manufacturing corporation — ${failures.join("; ")}. Complete Part 2 (the labour-and-capital formula) instead.`);
|
|
9703
|
+
return {
|
|
9704
|
+
qualifies,
|
|
9705
|
+
combinedActiveBusinessIncome,
|
|
9706
|
+
canadianMPProfits: qualifies ? line100 : 0,
|
|
9707
|
+
issues
|
|
9708
|
+
};
|
|
9709
|
+
}
|
|
9710
|
+
function computePart2MPProfits(input) {
|
|
9711
|
+
const issues = [];
|
|
9712
|
+
const adjubi = nn(input.adjustedBusinessIncome);
|
|
9713
|
+
const c = nn(input.costOfCapital);
|
|
9714
|
+
const mc = Math.min(nn(input.costOfMPCapital), c);
|
|
9715
|
+
const l = nn(input.costOfLabour);
|
|
9716
|
+
const ml = Math.min(nn(input.costOfMPLabour), l);
|
|
9717
|
+
const denominator = c + l;
|
|
9718
|
+
if (denominator === 0) {
|
|
9719
|
+
issues.push("Schedule 27 Part 2: cost of capital (C) and cost of labour (L) are both nil, so the (MC+ML)/(C+L) ratio cannot be computed. No M&P profits claimed.");
|
|
9720
|
+
return {
|
|
9721
|
+
ratio: 0,
|
|
9722
|
+
canadianMPProfits: 0,
|
|
9723
|
+
issues
|
|
9724
|
+
};
|
|
9725
|
+
}
|
|
9726
|
+
const ratio = (mc + ml) / denominator;
|
|
9727
|
+
return {
|
|
9728
|
+
ratio,
|
|
9729
|
+
canadianMPProfits: Math.max(0, Math.round(adjubi * ratio)),
|
|
9730
|
+
issues
|
|
9731
|
+
};
|
|
9732
|
+
}
|
|
9733
|
+
/**
|
|
9734
|
+
* "Small manufacturing corporations that meet all requirements in Part 1
|
|
9735
|
+
* should begin with Part 1 ... all other corporations should begin with
|
|
9736
|
+
* Part 2" — the form's own routing (page 1), reproduced here.
|
|
9737
|
+
*/
|
|
9738
|
+
function computeCanadianMPProfits(input) {
|
|
9739
|
+
const smallManufacturerTest = input.smallManufacturer ? computeSmallManufacturerTest(input.smallManufacturer) : void 0;
|
|
9740
|
+
if (smallManufacturerTest?.qualifies) return {
|
|
9741
|
+
method: "part1",
|
|
9742
|
+
canadianMPProfits: smallManufacturerTest.canadianMPProfits,
|
|
9743
|
+
smallManufacturerTest,
|
|
9744
|
+
issues: smallManufacturerTest.issues
|
|
9745
|
+
};
|
|
9746
|
+
const part2Result = input.part2 ? computePart2MPProfits(input.part2) : void 0;
|
|
9747
|
+
const issues = [...smallManufacturerTest?.issues ?? [], ...part2Result?.issues ?? []];
|
|
9748
|
+
return {
|
|
9749
|
+
...part2Result ? { method: "part2" } : {},
|
|
9750
|
+
canadianMPProfits: part2Result?.canadianMPProfits ?? 0,
|
|
9751
|
+
...smallManufacturerTest ? { smallManufacturerTest } : {},
|
|
9752
|
+
...part2Result ? { part2Result } : {},
|
|
9753
|
+
issues
|
|
9754
|
+
};
|
|
9755
|
+
}
|
|
9365
9756
|
function computeMpDeduction(input, rates = MP_RATES_2024) {
|
|
9366
9757
|
const issues = [];
|
|
9367
9758
|
const mpProfits = nn(input.manufacturingAndProcessingProfits);
|
|
@@ -9403,4 +9794,4 @@ function computeMpDeduction(input, rates = MP_RATES_2024) {
|
|
|
9403
9794
|
};
|
|
9404
9795
|
}
|
|
9405
9796
|
//#endregion
|
|
9406
|
-
export {
|
|
9797
|
+
export { computeCde as $, toRsiSchedule as $n, ALBERTA_SRED_PROGRAM_START as $r, computeOtherLossByYearOfOrigin as $t, formatConformanceReport as A, schedule1Values as Ai, computeClass141RecaptureReduction as An, computeIeg as Ar, assessEifel as At, computeSchedule54 as B, AB_TAX_2024 as Bi, albertaCurrentYearLoss as Bn, computeCeeRegular as Br, netCapitalLossApplied as Bt, computeQuebecAllocationFactor as C, schedule10Values as Ci, CLASS_14_1_RECAPTURE_REDUCTION_RATE as Cn, at1Engine as Cr, mealsAndEntertainmentAddBack as Ct, resolveQuebecTaxRates as D, schedule16Values as Di, computeClass13 as Dn, computeIegAgreement as Dr, computePartVI1Deduction as Dt, QC_TAX_RATE_BOOK as E, schedule13Values as Ei, MIN_LEASEHOLD_PERIODS as En, allocateIegExpenditureLimit as Er, PART_VI_1_DEDUCTION_BANDS as Et, SCHEDULE_88_MAX_URLS as F, schedule4970Values as Fi, resolveCcaRates as Fn, computeAlbertaSchedule15 as Fr, blendProvinceRateTable as Ft, computeSchedule31 as G, hasExactRateYear as Gi, albertaTerminalLossDifference as Gn, computeEdaRegular as Gr, computeAggregateInvestmentIncome as Gt, computeSchedule43 as H, resolveAlbertaTaxRates as Hi, albertaRecaptureDifference as Hn, computeCfreRegular as Hr, computeCcpcActiveBusinessTax as Ht, normalizeSchedule88 as I, computeAlbertaTax as Ii, albertaAbilDifference as In, computeCcogpeRegular as Ir, dayWeightedRate as It, computeZetm as J, LossCarrybackError as Jn, computeFedeSuccessor as Jr, CORP_TAX_2024 as Jt, ITC_RECAPTURE_PERIOD_YEARS as K, latestRateYear as Ki, computeSchedule12 as Kn, computeEdaSuccessor as Kr, computeBusinessLimit as Kt, computeSchedule55 as L, computeAlbertaSbd as Li, albertaCapitalGainDifference as Ln, computeCcogpeSuccessor as Lr, charitableDonationsDeduction as Lt, runConformanceSuite as M, schedule21Values as Mi, CCA_DECLINING_BALANCE_RATES_2024 as Mn, computeIegReductionFactor as Mr, PROVINCE_RATE_BOOK as Mt, computeFederalT2 as N, schedule29Values as Ni, CCA_RATE_BOOK as Nn, computeIegEligibleExpenditures as Nr, isSchedule5Province as Nt, T2_LINE_META as O, schedule17Values as Oi, computeClass14 as On, computeIegGroupFigures as Or, partVI1DeductionMultiple as Ot, computeSchedule101 as P, schedule2Values as Pi, isDecliningBalanceClass as Pn, iegT661SourceLine as Pr, resolveProvinceRates as Pt, computeSchedule13 as Q, toRsiLineItems as Qn, ALBERTA_SRED_EXPENDITURE_CUTOFF as Qr, computeNonCapitalLossByYearOfOrigin as Qt, LRIP_INVESTMENT_CORPORATION_MULTIPLE as R, AB_GENERAL_RATE_BANDS as Ri, albertaCcaDifference as Rn, computeCdeRegular as Rr, computeTaxableIncome as Rt, computeQuebecReturn as S, at1LineItemId as Si, CLASS_14_1_MINIMUM_DEDUCTION as Sn, xmlEscape as Sr, incomeTaxProvisionAddBack as St, QC_TAX_2024 as T, schedule12Values as Ti, MAX_LEASEHOLD_PERIODS as Tn, allocateIegEvenly as Tr, terminalLossDeduction as Tt, LARGE_CORPORATION_THRESHOLD as U, earliestRateYear as Ui, albertaReserveDifference as Un, computeCfreSuccessor as Ur, computePartITax as Ut, computeGrip as V, AB_TAX_RATE_BOOK as Vi, albertaDispositionAdjustments as Vn, computeCeeSuccessor as Vr, nonCapitalLossApplied as Vt, computeTaxableCapital as W, extendRateBook as Wi, albertaResourceDeductionDifference as Wn, computeCmedb as Wr, computeAdjustedAggregateInvestmentIncome as Wt, computeBusinessLimitAllocation as X, toRsiHeader as Xn, computeSfedeCountrySuccessor as Xr, resolveCorpTaxRates as Xt, allocateEvenly as Y, computeLossCarryback as Yn, computeSfedeCountryRegular as Yr, CORP_TAX_RATE_BOOK as Yt, computeSchedule21 as Z, toRsiJacketSchedules as Zn, schedule15Values as Zr, T2_CERTIFICATION_FIXTURES as Zt, computeT2Settlement as _, SINGLE_JURISDICTION_ALBERTA_FACTOR as _i, computeAlbertaSchedule13 as _n, assertAt1MandatoryComplete as _r, assertSchedule1Fileable as _t, computeCanadianMPProfits as a, computeSchedule8$1 as ai, AT1_DONATION_INCOME_RATE as an, formatRsiAmount as ar, computeSchedule12ResourceDeductions as at, renderCo17DraftReturn as b, AT1_SCHEDULES_WITHOUT_BUILDERS as bi, computeCcaSchedule as bn, at1TaxPayableDeductions as br, deferredIncomeTaxProvisionAddBack as bt, computeSmallManufacturerTest as c, schedule7Values as ci, AT1_DISPOSITION_CATEGORIES as cn, renderAt1Rsi as cr, computeProvincialAllocation as ct, EIFEL_STANDARD_RATIO_FROM as d, computeAlbertaSchedule5 as di, AT1_RESERVE_KINDS as dn, renderAt1NetFile as dr, PART_IV_RATE as dt, ALBERTA_SRED_TAX_CREDIT_RATE as ei, computeLossSchedule as en, RSI_COLUMN_GAP as er, computeCee as et, EIFEL_TRANSITIONAL_RATIO as f, schedule5Values as fi, AT1_RESERVE_LINES as fn, AT1_CRITICAL_MANDATORY_FIELDS as fr, REFUNDABLE_PART_I_RATE as ft, computeAdjustedTaxableIncome as g, schedule3Values as gi, computeAlbertaSchedule16 as gn, albertaBalanceUnpaid as gr, amortizationAddBack as gt, FOREIGN_TAX_CREDIT_GROSS_UP as h, computeSchedule3 as hi, assistanceFrom as hn, At1TaxPayableMismatchError as hr, Schedule1NotFileableError as ht, SMALL_MANUFACTURER_INCOME_THRESHOLD as i, schedule9Values as ii, AT1_DONATION_GAIN_RATE as in, RsiLineItemError as ir, computeForeignExploration as it, runConformance as j, schedule20Values as ji, leaseholdPeriods as jn, computeIegBaseAmount as jr, PROVINCE_RATES_2024 as jt, foldT2Lines as k, schedule18Values as ki, computeClass141AdditionalAllowance as kn, IEG_2024 as kr, EIFEL_EFFECTIVE_FROM as kt, EIFEL_FIRST_YEAR_START as l, computeAlbertaSchedule6 as li, SECTION_34_2_GROSS_UP as ln, renderRsiHeader as lr, computeSchedule5 as lt, ratioOfPermissibleExpenses as m, schedule4Values as mi, computeAlbertaSchedule17 as mn, At1MandatoryFieldMissingError as mr, computeSchedule2 as mt, MP_GROSS_REVENUE_THRESHOLD as n, computeAlbertaSchedule9 as ni, computeLimitedPartnershipLossRow as nn, RSI_NEGATIVE_PREFIX as nr, computeCumulativeForeignResource as nt, computeMpDeduction as o, schedule8Values as oi, computeDonationMaximum as on, formatRsiDate as or, computeSpecifiedForeignExploration as ot, computeEifelLimitation as p, computeSchedule4 as pi, AT1_RESERVE_TOTAL_LINES as pn, At1CriticalFieldMissingError as pr, computePart4Rdtoh as pt, computeItcRecapture as q, resolveRates as qi, reconcileAlbertaNetIncome as qn, computeFedeRegular as qr, computeSBD as qt, MP_RATES_2024 as r, computeSchedule9MaximumExpenditureLimit as ri, computeLimitedPartnershipLosses as rn, RSI_WORD_GAP as rr, computeDepletion as rt, computePart2MPProfits as s, computeAlbertaSchedule7 as si, computeSchedule20 as sn, formatRsiText as sr, computeSchedule6 as st, MP_EXCLUDED_ACTIVITIES as t, allocateSchedule9ExpenditureLimit as ti, computeLossContinuity as tn, RSI_DELIMITER as tr, computeCogpe as tt, EIFEL_STANDARD_RATIO as u, schedule6Values as ui, computeAlbertaSchedule18 as un, renderRsiLineItem as ur, computeSchedule4Losses as ut, renderT2DraftReturn as v, computeAllocationFactor as vi, UnsupportedCcaClassError as vn, assertAt1TaxPayableReconciles as vr, ccaDeduction as vt, computeQuebecTax as w, schedule12LossDeductions as wi, CLASS_14_1_TRANSITIONAL_RATE as wn, computeAlbertaReturn as wr, recaptureAddBack as wt, co17Engine as x, AT1_SCHEDULES_WITH_BUILDERS as xi, computeSchedule8 as xn, at1YesNo as xr, findSchedule1LineDefects as xt, t2Engine as y, computeAt4970 as yi, computeCcaClass as yn, assertCriticalFields as yr, computeSchedule1 as yt, LRIP_INVESTMENT_INCOME_FACTOR as z, computeDayWeightedGeneralTax as zi, albertaCcaScheduleAdjustments as zn, computeCdeSuccessor as zr, dividendsDeductibleS112 as zt };
|