@classytic/ca-tax 0.0.5 → 0.0.12
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 +238 -0
- package/dist/forms.mjs +340 -72
- package/dist/index.mjs +2 -2
- package/dist/index3.d.mts +3007 -21
- package/dist/index4.d.mts +2 -2
- package/dist/t2/index.d.mts +2 -2
- package/dist/t2/index.mjs +2 -2
- package/dist/t2.mjs +2688 -172
- package/package.json +5 -5
package/dist/t2.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { rt as SCHEDULE_1_LINE_BY_NUMBER } from "./forms.mjs";
|
|
1
|
+
import { kt as AT1_SCHEDULE_21_POOLS, rt as SCHEDULE_1_LINE_BY_NUMBER } from "./forms.mjs";
|
|
2
2
|
//#region src/t2/rates/rate-book.ts
|
|
3
3
|
/**
|
|
4
4
|
* Resolve the table in effect for `taxYear` — the entry with the greatest
|
|
@@ -254,9 +254,18 @@ function computeAlbertaTax(input, rates = AB_TAX_2024) {
|
|
|
254
254
|
const AT1_SCHEDULES_WITH_BUILDERS = Object.freeze([
|
|
255
255
|
"001",
|
|
256
256
|
"002",
|
|
257
|
+
"003",
|
|
258
|
+
"004",
|
|
259
|
+
"005",
|
|
260
|
+
"006",
|
|
261
|
+
"007",
|
|
262
|
+
"008",
|
|
263
|
+
"009",
|
|
257
264
|
"010",
|
|
265
|
+
"011",
|
|
258
266
|
"012",
|
|
259
267
|
"013",
|
|
268
|
+
"015",
|
|
260
269
|
"016",
|
|
261
270
|
"017",
|
|
262
271
|
"018",
|
|
@@ -677,38 +686,26 @@ function schedule12Values(input) {
|
|
|
677
686
|
values
|
|
678
687
|
};
|
|
679
688
|
}
|
|
680
|
-
/**
|
|
681
|
-
const
|
|
682
|
-
nonCapital:
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
restrictedFarm: {
|
|
701
|
-
opening: "091",
|
|
702
|
-
current: "097",
|
|
703
|
-
carryBack: "105",
|
|
704
|
-
closing: "107"
|
|
705
|
-
},
|
|
706
|
-
listedPersonalProperty: {
|
|
707
|
-
opening: "111",
|
|
708
|
-
current: "117",
|
|
709
|
-
carryBack: "123",
|
|
710
|
-
closing: "125"
|
|
711
|
-
}
|
|
689
|
+
/** `Schedule21FilingInput` key → `AT1_SCHEDULE_21_POOLS` key. */
|
|
690
|
+
const POOL_KEY = {
|
|
691
|
+
nonCapital: "non-capital",
|
|
692
|
+
capital: "capital",
|
|
693
|
+
farm: "farm",
|
|
694
|
+
restrictedFarm: "restricted-farm",
|
|
695
|
+
listedPersonalProperty: "listed-personal"
|
|
696
|
+
};
|
|
697
|
+
/** `AlbertaLossPool` field → the `LossContinuityResult` field it reports. */
|
|
698
|
+
const POOL_FIELD_TO_RESULT_KEY = {
|
|
699
|
+
carriedForward: "openingBalance",
|
|
700
|
+
expired: "expired",
|
|
701
|
+
opening: "balanceAtBeginningOfYear",
|
|
702
|
+
windUpTransfer: "windUpTransfer",
|
|
703
|
+
currentYearLoss: "currentYearLoss",
|
|
704
|
+
appliedAgainstIncome: "appliedCurrentYear",
|
|
705
|
+
section80Adjustment: "section80Adjustment",
|
|
706
|
+
otherAdjustments: "otherAdjustments",
|
|
707
|
+
carryBack: "carriedBack",
|
|
708
|
+
closing: "closingBalance"
|
|
712
709
|
};
|
|
713
710
|
function schedule21Values(input) {
|
|
714
711
|
const values = [];
|
|
@@ -717,14 +714,97 @@ function schedule21Values(input) {
|
|
|
717
714
|
value
|
|
718
715
|
});
|
|
719
716
|
if (input.currentYearNonCapitalLoss !== void 0) put("021", input.currentYearNonCapitalLoss);
|
|
720
|
-
for (const [
|
|
721
|
-
const c = input[
|
|
717
|
+
for (const [inputKey, poolKey] of Object.entries(POOL_KEY)) {
|
|
718
|
+
const c = input[inputKey];
|
|
722
719
|
if (!c) continue;
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
720
|
+
const pool = AT1_SCHEDULE_21_POOLS.find((p) => p.key === poolKey);
|
|
721
|
+
for (const [field, resultKey] of Object.entries(POOL_FIELD_TO_RESULT_KEY)) {
|
|
722
|
+
const line = pool[field];
|
|
723
|
+
if (!line) continue;
|
|
724
|
+
put(line, c[resultKey]);
|
|
725
|
+
}
|
|
727
726
|
}
|
|
727
|
+
input.limitedPartnershipLosses?.rows.forEach((r, i) => {
|
|
728
|
+
const n = i + 1;
|
|
729
|
+
if (r.identifier !== void 0) values.push({
|
|
730
|
+
lineItemId: at1LineItemId("021", "131", n),
|
|
731
|
+
value: r.identifier
|
|
732
|
+
});
|
|
733
|
+
values.push({
|
|
734
|
+
lineItemId: at1LineItemId("021", "133", n),
|
|
735
|
+
value: r.precedingYearBalance
|
|
736
|
+
});
|
|
737
|
+
values.push({
|
|
738
|
+
lineItemId: at1LineItemId("021", "135", n),
|
|
739
|
+
value: r.transferredOnWindUp
|
|
740
|
+
});
|
|
741
|
+
values.push({
|
|
742
|
+
lineItemId: at1LineItemId("021", "137", n),
|
|
743
|
+
value: r.currentYearLoss
|
|
744
|
+
});
|
|
745
|
+
values.push({
|
|
746
|
+
lineItemId: at1LineItemId("021", "139", n),
|
|
747
|
+
value: r.applied
|
|
748
|
+
});
|
|
749
|
+
values.push({
|
|
750
|
+
lineItemId: at1LineItemId("021", "141", n),
|
|
751
|
+
value: r.closingBalance
|
|
752
|
+
});
|
|
753
|
+
});
|
|
754
|
+
input.nonCapitalByYearOfOrigin?.rows.forEach((r, i) => {
|
|
755
|
+
const n = i + 1;
|
|
756
|
+
values.push({
|
|
757
|
+
lineItemId: at1LineItemId("021", "151", n),
|
|
758
|
+
value: r.yearIndex
|
|
759
|
+
});
|
|
760
|
+
if (r.taxYearEnd !== void 0) values.push({
|
|
761
|
+
lineItemId: at1LineItemId("021", "153", n),
|
|
762
|
+
value: r.taxYearEnd
|
|
763
|
+
});
|
|
764
|
+
values.push({
|
|
765
|
+
lineItemId: at1LineItemId("021", "155", n),
|
|
766
|
+
value: r.balanceAtBeginning
|
|
767
|
+
});
|
|
768
|
+
values.push({
|
|
769
|
+
lineItemId: at1LineItemId("021", "157", n),
|
|
770
|
+
value: r.lossIncurred
|
|
771
|
+
});
|
|
772
|
+
values.push({
|
|
773
|
+
lineItemId: at1LineItemId("021", "159", n),
|
|
774
|
+
value: r.adjustments
|
|
775
|
+
});
|
|
776
|
+
values.push({
|
|
777
|
+
lineItemId: at1LineItemId("021", "165", n),
|
|
778
|
+
value: r.carriedBack
|
|
779
|
+
});
|
|
780
|
+
values.push({
|
|
781
|
+
lineItemId: at1LineItemId("021", "167", n),
|
|
782
|
+
value: r.applied
|
|
783
|
+
});
|
|
784
|
+
values.push({
|
|
785
|
+
lineItemId: at1LineItemId("021", "169", n),
|
|
786
|
+
value: r.balanceAtEnd
|
|
787
|
+
});
|
|
788
|
+
});
|
|
789
|
+
input.otherLossesByYearOfOrigin?.rows.forEach((r, i) => {
|
|
790
|
+
const n = i + 1;
|
|
791
|
+
values.push({
|
|
792
|
+
lineItemId: at1LineItemId("021", "181", n),
|
|
793
|
+
value: r.yearIndex
|
|
794
|
+
});
|
|
795
|
+
values.push({
|
|
796
|
+
lineItemId: at1LineItemId("021", "183", n),
|
|
797
|
+
value: r.farmLosses
|
|
798
|
+
});
|
|
799
|
+
values.push({
|
|
800
|
+
lineItemId: at1LineItemId("021", "185", n),
|
|
801
|
+
value: r.restrictedFarmLosses
|
|
802
|
+
});
|
|
803
|
+
if (r.yearIndex <= 7) values.push({
|
|
804
|
+
lineItemId: at1LineItemId("021", "187", n),
|
|
805
|
+
value: r.listedPersonalPropertyLosses
|
|
806
|
+
});
|
|
807
|
+
});
|
|
728
808
|
return {
|
|
729
809
|
scheduleId: "021",
|
|
730
810
|
values
|
|
@@ -811,150 +891,2384 @@ function schedule10Values(input) {
|
|
|
811
891
|
], input.capital.carrybacks)) put(f, Math.round(rate * c.amount));
|
|
812
892
|
}
|
|
813
893
|
return {
|
|
814
|
-
scheduleId: "010",
|
|
815
|
-
values
|
|
894
|
+
scheduleId: "010",
|
|
895
|
+
values
|
|
896
|
+
};
|
|
897
|
+
}
|
|
898
|
+
const S20_CHARITABLE = {
|
|
899
|
+
opening: "002",
|
|
900
|
+
expired: "004",
|
|
901
|
+
beginning: "006",
|
|
902
|
+
transferred: "008",
|
|
903
|
+
currentYear: "010",
|
|
904
|
+
subtotal: "012",
|
|
905
|
+
acquisitionOfControl: "013",
|
|
906
|
+
available: "014",
|
|
907
|
+
applied: "016",
|
|
908
|
+
closing: "018"
|
|
909
|
+
};
|
|
910
|
+
const S20_GIFTS = {
|
|
911
|
+
opening: "062",
|
|
912
|
+
expired: "064",
|
|
913
|
+
beginning: "066",
|
|
914
|
+
transferred: "068",
|
|
915
|
+
currentYear: "070",
|
|
916
|
+
subtotal: "072",
|
|
917
|
+
acquisitionOfControl: "073",
|
|
918
|
+
available: "074",
|
|
919
|
+
applied: "076",
|
|
920
|
+
closing: "078"
|
|
921
|
+
};
|
|
922
|
+
function donationContinuityValues(result, f) {
|
|
923
|
+
const put = (fieldId, value) => ({
|
|
924
|
+
lineItemId: at1LineItemId("020", fieldId),
|
|
925
|
+
value
|
|
926
|
+
});
|
|
927
|
+
return [
|
|
928
|
+
put(f.opening, result.openingBalance),
|
|
929
|
+
put(f.expired, result.expired),
|
|
930
|
+
put(f.beginning, Math.max(0, result.openingBalance - result.expired)),
|
|
931
|
+
put(f.transferred, result.transferredIn),
|
|
932
|
+
put(f.currentYear, result.currentYearGifts),
|
|
933
|
+
put(f.subtotal, result.transferredIn + result.currentYearGifts),
|
|
934
|
+
put(f.acquisitionOfControl, result.acquisitionOfControlAdjustment),
|
|
935
|
+
put(f.available, result.availableBeforeClaim),
|
|
936
|
+
put(f.applied, result.amountApplied),
|
|
937
|
+
put(f.closing, result.closingBalance)
|
|
938
|
+
];
|
|
939
|
+
}
|
|
940
|
+
function schedule20Values(input) {
|
|
941
|
+
const values = [];
|
|
942
|
+
if (input.charitable) values.push(...donationContinuityValues(input.charitable, S20_CHARITABLE));
|
|
943
|
+
if (input.gifts) values.push(...donationContinuityValues(input.gifts, S20_GIFTS));
|
|
944
|
+
if (input.maximum) {
|
|
945
|
+
const put = (fieldId, value) => values.push({
|
|
946
|
+
lineItemId: at1LineItemId("020", fieldId),
|
|
947
|
+
value
|
|
948
|
+
});
|
|
949
|
+
put("030", input.maximum.incomeComponent);
|
|
950
|
+
put("042", input.maximum.lesserOfProceedsAndCost);
|
|
951
|
+
put("044", input.maximum.allowableRecapture);
|
|
952
|
+
put("046", input.maximum.gainsComponent);
|
|
953
|
+
put("048", input.maximum.maximumDeduction);
|
|
954
|
+
}
|
|
955
|
+
return {
|
|
956
|
+
scheduleId: "020",
|
|
957
|
+
values
|
|
958
|
+
};
|
|
959
|
+
}
|
|
960
|
+
/**
|
|
961
|
+
* The SR&ED expenditure POOL — a deduction against income, not the investment tax
|
|
962
|
+
* credit and not the innovation grant.
|
|
963
|
+
*
|
|
964
|
+
* Line numbers and the subtotal formula verified against the live form, which
|
|
965
|
+
* states it exactly as transcribed:
|
|
966
|
+
*
|
|
967
|
+
* 016 = 002 − (004 + 006 + 008) + 010 + 012 + 014 + 015
|
|
968
|
+
*
|
|
969
|
+
* and closes the year-over-year chain in as many words: line 022 is *"the carry
|
|
970
|
+
* forward amount for next year, line 012"*.
|
|
971
|
+
*/
|
|
972
|
+
function schedule16Values(result) {
|
|
973
|
+
const values = [];
|
|
974
|
+
const put = (fieldId, value) => values.push({
|
|
975
|
+
lineItemId: at1LineItemId("016", fieldId),
|
|
976
|
+
value
|
|
977
|
+
});
|
|
978
|
+
put("002", result.currentYearExpenditures);
|
|
979
|
+
put("016", result.subtotal);
|
|
980
|
+
put("018", result.deductionAvailable);
|
|
981
|
+
put("020", result.amountClaimed);
|
|
982
|
+
put("022", result.unclaimedPoolBalance);
|
|
983
|
+
return {
|
|
984
|
+
scheduleId: "016",
|
|
985
|
+
values
|
|
986
|
+
};
|
|
987
|
+
}
|
|
988
|
+
//#endregion
|
|
989
|
+
//#region src/t2/at1/schedules/at4970-ieg-projects.ts
|
|
990
|
+
const nn$34 = (v) => Math.max(0, Math.round(v ?? 0));
|
|
991
|
+
function computeAt4970(input) {
|
|
992
|
+
const projects = input.projects.map((p) => ({
|
|
993
|
+
title: p.title,
|
|
994
|
+
...p.projectCode !== void 0 ? { projectCode: p.projectCode } : {},
|
|
995
|
+
albertaPortion: nn$34(p.albertaPortion),
|
|
996
|
+
otherPortion: nn$34(p.otherPortion),
|
|
997
|
+
salariesAndWages: nn$34(p.salariesAndWages),
|
|
998
|
+
federalProxyAmount: nn$34(p.federalProxyAmount),
|
|
999
|
+
albertaProxyAmount: nn$34(p.albertaProxyAmount)
|
|
1000
|
+
}));
|
|
1001
|
+
const totals = {
|
|
1002
|
+
albertaPortion: projects.reduce((s, p) => s + p.albertaPortion, 0),
|
|
1003
|
+
otherPortion: projects.reduce((s, p) => s + p.otherPortion, 0),
|
|
1004
|
+
salariesAndWages: projects.reduce((s, p) => s + p.salariesAndWages, 0),
|
|
1005
|
+
federalProxyAmount: projects.reduce((s, p) => s + p.federalProxyAmount, 0),
|
|
1006
|
+
albertaProxyAmount: projects.reduce((s, p) => s + p.albertaProxyAmount, 0)
|
|
1007
|
+
};
|
|
1008
|
+
const jurisdictions = (input.jurisdictions ?? []).map((j) => ({
|
|
1009
|
+
jurisdiction: j.jurisdiction,
|
|
1010
|
+
amountIncurred: nn$34(j.amountIncurred)
|
|
1011
|
+
}));
|
|
1012
|
+
return {
|
|
1013
|
+
projects,
|
|
1014
|
+
totals,
|
|
1015
|
+
jurisdictions,
|
|
1016
|
+
jurisdictionTotal: jurisdictions.reduce((s, j) => s + j.amountIncurred, 0)
|
|
1017
|
+
};
|
|
1018
|
+
}
|
|
1019
|
+
//#endregion
|
|
1020
|
+
//#region src/t2/at1/schedules/schedule2.ts
|
|
1021
|
+
/** Round to six decimal places — the AT1 allocation-factor precision. */
|
|
1022
|
+
function round6(n) {
|
|
1023
|
+
return Math.round(n * 1e6) / 1e6;
|
|
1024
|
+
}
|
|
1025
|
+
/** Single Alberta PE, none elsewhere → all income is Alberta income. */
|
|
1026
|
+
const SINGLE_JURISDICTION_ALBERTA_FACTOR = 1;
|
|
1027
|
+
function computeAllocationFactor(input) {
|
|
1028
|
+
const hasRevenue = input.totalGrossRevenue > 0;
|
|
1029
|
+
const hasSalaries = input.totalSalaries > 0;
|
|
1030
|
+
const revenueRatio = hasRevenue ? input.albertaGrossRevenue / input.totalGrossRevenue : 0;
|
|
1031
|
+
const salariesRatio = hasSalaries ? input.albertaSalaries / input.totalSalaries : 0;
|
|
1032
|
+
let factor;
|
|
1033
|
+
if (hasRevenue && hasSalaries) factor = (revenueRatio + salariesRatio) / 2;
|
|
1034
|
+
else if (hasRevenue) factor = revenueRatio;
|
|
1035
|
+
else if (hasSalaries) factor = salariesRatio;
|
|
1036
|
+
else factor = 0;
|
|
1037
|
+
return round6(factor);
|
|
1038
|
+
}
|
|
1039
|
+
//#endregion
|
|
1040
|
+
//#region src/t2/at1/schedules/schedule3-other-deductions-credits.ts
|
|
1041
|
+
/**
|
|
1042
|
+
* Alberta AT1 Schedule 3 — Alberta Other Tax Deductions and Credits.
|
|
1043
|
+
*
|
|
1044
|
+
* NOT one calculation. The spec (TRA spec §3.2.3.4, "3B3B3.2.3.4 Schedule 3 -
|
|
1045
|
+
* Alberta Other Tax Deductions and Credits", `AT1-Chapter3-2025.2-full.txt`
|
|
1046
|
+
* lines 4127-4898) groups THREE independent non-refundable investment tax
|
|
1047
|
+
* credit continuities under one shared ceiling:
|
|
1048
|
+
*
|
|
1049
|
+
* ITC Investor Tax Credit (lines 100-108, 120-130)
|
|
1050
|
+
* CITC Capital Investment Tax Credit (lines 200-208, 220-230)
|
|
1051
|
+
* APITC Agri-Processing Investment Tax Credit (lines 300-316, 330-340)
|
|
1052
|
+
* MAD Maximum Allowable Deduction — the shared ceiling (lines 600-604)
|
|
1053
|
+
*
|
|
1054
|
+
* No matching form PDF exists under `research/sources/tra-forms/pdf/` (searched
|
|
1055
|
+
* for `AT1SCH03*` — nothing found, unlike every other schedule this package
|
|
1056
|
+
* models). The specification TEXT is therefore the only source for this
|
|
1057
|
+
* schedule's shape; there is no live-form layout to cross-check it against.
|
|
1058
|
+
*
|
|
1059
|
+
* ── The shared ceiling (lines 600-604) ───────────────────────────────────────
|
|
1060
|
+
*
|
|
1061
|
+
* 600 = 003104 + 003204 + 003312 (ITC + CITC + APITC applied)
|
|
1062
|
+
* 602 = 000068 − (000070+000071+000072+000074) (AT1 page 2 room)
|
|
1063
|
+
* 604 = lesser of 600 and 602 ("Total Deduction")
|
|
1064
|
+
*
|
|
1065
|
+
* `000068`/`000070`/`000071`/`000072`/`000074` are AT1 page-2 jacket lines this
|
|
1066
|
+
* engine does not compute here (out of this module's scope per the task's scope
|
|
1067
|
+
* rule) — they are plain numeric inputs (`MaximumAllowableDeductionInput`).
|
|
1068
|
+
*
|
|
1069
|
+
* ── Three pools, one room, in a STATED precedence ────────────────────────────
|
|
1070
|
+
*
|
|
1071
|
+
* ITC is applied first, capped only by 602 itself:
|
|
1072
|
+
* 104 ≤ 000068 − (000070+000071+000072+000074)
|
|
1073
|
+
*
|
|
1074
|
+
* CITC is gated behind ITC: "If 003108 > 0 [ITC still has an unused carryforward
|
|
1075
|
+
* balance after this year's application], then [204] must equal zero." Only once
|
|
1076
|
+
* the ITC pool is fully drawn down may CITC be claimed, capped at what room ITC
|
|
1077
|
+
* left behind:
|
|
1078
|
+
* 204 ≤ 602 − 104 (when 108 = 0; otherwise 204 = 0)
|
|
1079
|
+
*
|
|
1080
|
+
* APITC draws on what both leave behind, but against a DIFFERENT room formula —
|
|
1081
|
+
* the spec's four "cannot exceed" clauses for 304/306/308/310 all subtract only
|
|
1082
|
+
* `(000070+000072)`, NOT `000071`/`000074` the way 104/204/602 do. That asymmetry
|
|
1083
|
+
* is transcribed exactly as written, not corrected, because it repeats
|
|
1084
|
+
* identically across all five APITC business-rule cells (304, 306, 308, 310, 312)
|
|
1085
|
+
* — consistent enough to be deliberate rather than a transcription slip:
|
|
1086
|
+
* 312 ≤ 000068 − (000070+000072) − (104+204)
|
|
1087
|
+
*
|
|
1088
|
+
* ── APITC: per-vintage percentage caps ───────────────────────────────────────
|
|
1089
|
+
*
|
|
1090
|
+
* The four "cannot exceed" clauses for 304/306/308/310, read together, are
|
|
1091
|
+
* algebraically just ONE combined-total constraint stated four times from four
|
|
1092
|
+
* different partial-sum vantage points (each says "this line ≤ R − the lines
|
|
1093
|
+
* listed", and the lines listed are exactly the OTHER three) — they collapse to
|
|
1094
|
+
* `304+306+308+310 ≤ R`, which is exactly what 312's own business rule states
|
|
1095
|
+
* directly. So the four clauses add nothing beyond that one shared-room ceiling;
|
|
1096
|
+
* what makes each vintage different is its OWN percentage cap from AAPITC
|
|
1097
|
+
* (330-340):
|
|
1098
|
+
*
|
|
1099
|
+
* occurrence 0 (current year, 334/336 occ 0) ≤ 20% of that vintage's receipt
|
|
1100
|
+
* occurrence 1 (1st preceding, occ 1) ≤ 30% of that vintage's receipt
|
|
1101
|
+
* occurrence 2 (2nd preceding, occ 2) ≤ 50% of that vintage's receipt
|
|
1102
|
+
* occurrences 3-10 (3rd-10th preceding) no percentage cap, own balance only
|
|
1103
|
+
*
|
|
1104
|
+
* `computeSchedule3` claims each vintage's OWN cap first, then allocates the
|
|
1105
|
+
* shared room OLDEST-VINTAGE-FIRST when the total requested exceeds it — APITC
|
|
1106
|
+
* is a 10-year-preceding, use-it-or-lose-it credit and the spec states no
|
|
1107
|
+
* application order, so this engine flags that choice in `issues` rather than
|
|
1108
|
+
* silently guessing at NetFile's actual tie-break. Supply `amountApplied` on
|
|
1109
|
+
* each vintage directly for exact filing parity.
|
|
1110
|
+
*
|
|
1111
|
+
* ── What is deliberately NOT modelled ────────────────────────────────────────
|
|
1112
|
+
*
|
|
1113
|
+
* The AITC/ACITC year-of-origin analysis tables (120-130, 220-230) are
|
|
1114
|
+
* supplementary detail TRA requires when a corporation carries ITC or CITC.
|
|
1115
|
+
* Unlike AAPITC, the spec gives them no percentage cap or application order of
|
|
1116
|
+
* their own — every business rule on those lines is a reconciliation back to the
|
|
1117
|
+
* aggregate 104/106/204/206 this module already computes (e.g. "126 … Value must
|
|
1118
|
+
* be less than or equal to 124+125", "130 … calculate 124+125-126-128"). Adding a
|
|
1119
|
+
* per-vintage array for ITC/CITC would only re-derive numbers this module
|
|
1120
|
+
* already produces without a spec-given rule to allocate them across years, so
|
|
1121
|
+
* it is left out; a caller filing the AITC/ACITC detail pages supplies that
|
|
1122
|
+
* per-vintage split itself.
|
|
1123
|
+
*
|
|
1124
|
+
* Whole dollars, pure.
|
|
1125
|
+
*/
|
|
1126
|
+
const nn$33 = (v) => Math.max(0, Math.round(v ?? 0));
|
|
1127
|
+
const raw = (v) => Math.round(v ?? 0);
|
|
1128
|
+
function computeItc(input, roomCap, issues) {
|
|
1129
|
+
const certificatesIssued = nn$33(input.certificatesIssued);
|
|
1130
|
+
const carryforwardFromPriorYear = nn$33(input.carryforwardFromPriorYear);
|
|
1131
|
+
const expired = nn$33(input.expired);
|
|
1132
|
+
const availableBeforeClaim = certificatesIssued + carryforwardFromPriorYear;
|
|
1133
|
+
const cap = Math.min(availableBeforeClaim, roomCap);
|
|
1134
|
+
const wanted = input.amountApplied != null ? nn$33(input.amountApplied) : cap;
|
|
1135
|
+
const amountApplied = Math.max(0, Math.min(wanted, cap));
|
|
1136
|
+
const carryforwardToNextYear = availableBeforeClaim - amountApplied - expired;
|
|
1137
|
+
if (carryforwardToNextYear < 0) issues.push(`Alberta Schedule 3 (ITC): expired (${expired}) plus the amount applied (${amountApplied}) exceed the available pool (${availableBeforeClaim}) by ${-carryforwardToNextYear}. Check the 100/102/104/106 inputs.`);
|
|
1138
|
+
return {
|
|
1139
|
+
certificatesIssued,
|
|
1140
|
+
carryforwardFromPriorYear,
|
|
1141
|
+
availableBeforeClaim,
|
|
1142
|
+
amountApplied,
|
|
1143
|
+
expired,
|
|
1144
|
+
carryforwardToNextYear
|
|
1145
|
+
};
|
|
1146
|
+
}
|
|
1147
|
+
function computeCitc(input, roomCap, itcApplied, itcCarryforwardRemaining, issues) {
|
|
1148
|
+
const certificatesIssued = nn$33(input.certificatesIssued);
|
|
1149
|
+
const carryforwardFromPriorYear = nn$33(input.carryforwardFromPriorYear);
|
|
1150
|
+
const expired = nn$33(input.expired);
|
|
1151
|
+
const availableBeforeClaim = certificatesIssued + carryforwardFromPriorYear;
|
|
1152
|
+
let amountApplied;
|
|
1153
|
+
if (itcCarryforwardRemaining > 0) {
|
|
1154
|
+
amountApplied = 0;
|
|
1155
|
+
if (input.amountApplied != null && nn$33(input.amountApplied) > 0) issues.push(`Alberta Schedule 3 (CITC): a claim of ${nn$33(input.amountApplied)} was requested, but the Investor Tax Credit still has an unused carryforward balance (${itcCarryforwardRemaining}) after this year's application, so line 204 must be nil until ITC is fully drawn down.`);
|
|
1156
|
+
} else {
|
|
1157
|
+
const cap = Math.min(availableBeforeClaim, Math.max(0, roomCap - itcApplied));
|
|
1158
|
+
const wanted = input.amountApplied != null ? nn$33(input.amountApplied) : cap;
|
|
1159
|
+
amountApplied = Math.max(0, Math.min(wanted, cap));
|
|
1160
|
+
}
|
|
1161
|
+
const carryforwardToNextYear = availableBeforeClaim - amountApplied - expired;
|
|
1162
|
+
if (carryforwardToNextYear < 0) issues.push(`Alberta Schedule 3 (CITC): expired (${expired}) plus the amount applied (${amountApplied}) exceed the available pool (${availableBeforeClaim}) by ${-carryforwardToNextYear}. Check the 200/202/204/206 inputs.`);
|
|
1163
|
+
return {
|
|
1164
|
+
certificatesIssued,
|
|
1165
|
+
carryforwardFromPriorYear,
|
|
1166
|
+
availableBeforeClaim,
|
|
1167
|
+
amountApplied,
|
|
1168
|
+
expired,
|
|
1169
|
+
carryforwardToNextYear
|
|
1170
|
+
};
|
|
1171
|
+
}
|
|
1172
|
+
function computeApitc(input, roomCap, issues) {
|
|
1173
|
+
const current = input.current ?? {};
|
|
1174
|
+
const first = input.firstPreceding ?? {};
|
|
1175
|
+
const second = input.secondPreceding ?? {};
|
|
1176
|
+
const thirdToTenth = input.thirdToTenthPreceding ?? {};
|
|
1177
|
+
const currentAvailable = nn$33(current.received);
|
|
1178
|
+
const firstAvailable = nn$33(first.availableAtBeginning);
|
|
1179
|
+
const secondAvailable = nn$33(second.availableAtBeginning);
|
|
1180
|
+
const thirdToTenthAvailable = nn$33(thirdToTenth.availableAtBeginning);
|
|
1181
|
+
const currentCap = Math.round(currentAvailable * .2);
|
|
1182
|
+
const firstCap = Math.round(firstAvailable * .3);
|
|
1183
|
+
const secondCap = Math.round(secondAvailable * .5);
|
|
1184
|
+
const thirdToTenthCap = thirdToTenthAvailable;
|
|
1185
|
+
const currentAsk = Math.min(current.amountApplied != null ? nn$33(current.amountApplied) : currentCap, currentCap);
|
|
1186
|
+
const firstAsk = Math.min(first.amountApplied != null ? nn$33(first.amountApplied) : firstCap, firstCap);
|
|
1187
|
+
const secondAsk = Math.min(second.amountApplied != null ? nn$33(second.amountApplied) : secondCap, secondCap);
|
|
1188
|
+
const thirdToTenthAsk = Math.min(thirdToTenth.amountApplied != null ? nn$33(thirdToTenth.amountApplied) : thirdToTenthCap, thirdToTenthCap);
|
|
1189
|
+
const totalRequested = currentAsk + firstAsk + secondAsk + thirdToTenthAsk;
|
|
1190
|
+
let room = Math.max(0, roomCap);
|
|
1191
|
+
const allocate = (ask) => {
|
|
1192
|
+
const got = Math.min(ask, room);
|
|
1193
|
+
room -= got;
|
|
1194
|
+
return got;
|
|
1195
|
+
};
|
|
1196
|
+
const thirdToTenthApplied = allocate(thirdToTenthAsk);
|
|
1197
|
+
const secondApplied = allocate(secondAsk);
|
|
1198
|
+
const firstApplied = allocate(firstAsk);
|
|
1199
|
+
const currentApplied = allocate(currentAsk);
|
|
1200
|
+
const totalApplied = currentApplied + firstApplied + secondApplied + thirdToTenthApplied;
|
|
1201
|
+
if (totalApplied < totalRequested) issues.push(`Alberta Schedule 3 (APITC): the shared Maximum Allowable Deduction room (${roomCap}) was insufficient to cover ${totalRequested} requested across vintages; ${totalRequested - totalApplied} went unapplied. Allocation prioritized the oldest vintage first (closest to the 10-year expiry) — the spec states only the combined ceiling on 312, not an application order across 304/306/308/310. Supply amountApplied on each vintage directly for exact filing parity.`);
|
|
1202
|
+
const totalReceived = currentAvailable;
|
|
1203
|
+
const carryforwardFromPriorYear = firstAvailable + secondAvailable + thirdToTenthAvailable;
|
|
1204
|
+
const expired = nn$33(input.expiredThisYear);
|
|
1205
|
+
const availableForCarryforward = totalReceived + carryforwardFromPriorYear - totalApplied - expired;
|
|
1206
|
+
if (availableForCarryforward < 0) issues.push(`Alberta Schedule 3 (APITC): applied (${totalApplied}) plus expired (${expired}) exceed the available pool (${totalReceived + carryforwardFromPriorYear}) by ${-availableForCarryforward}. Check the 300/302/312/314 inputs.`);
|
|
1207
|
+
return {
|
|
1208
|
+
current: {
|
|
1209
|
+
available: currentAvailable,
|
|
1210
|
+
ownCap: currentCap,
|
|
1211
|
+
amountApplied: currentApplied
|
|
1212
|
+
},
|
|
1213
|
+
firstPreceding: {
|
|
1214
|
+
available: firstAvailable,
|
|
1215
|
+
ownCap: firstCap,
|
|
1216
|
+
amountApplied: firstApplied
|
|
1217
|
+
},
|
|
1218
|
+
secondPreceding: {
|
|
1219
|
+
available: secondAvailable,
|
|
1220
|
+
ownCap: secondCap,
|
|
1221
|
+
amountApplied: secondApplied
|
|
1222
|
+
},
|
|
1223
|
+
thirdToTenthPreceding: {
|
|
1224
|
+
available: thirdToTenthAvailable,
|
|
1225
|
+
amountApplied: thirdToTenthApplied
|
|
1226
|
+
},
|
|
1227
|
+
totalReceived,
|
|
1228
|
+
carryforwardFromPriorYear,
|
|
1229
|
+
totalRequested,
|
|
1230
|
+
totalApplied,
|
|
1231
|
+
expired,
|
|
1232
|
+
availableForCarryforward
|
|
1233
|
+
};
|
|
1234
|
+
}
|
|
1235
|
+
function computeSchedule3(input) {
|
|
1236
|
+
const issues = [];
|
|
1237
|
+
const mad = input.mad ?? {};
|
|
1238
|
+
const line068 = nn$33(mad.taxPayableBeforeDeduction);
|
|
1239
|
+
const line070 = nn$33(mad.line070);
|
|
1240
|
+
const line071 = nn$33(mad.line071);
|
|
1241
|
+
const line072 = nn$33(mad.line072);
|
|
1242
|
+
const line074 = nn$33(mad.line074);
|
|
1243
|
+
const room602 = raw(line068) - (line070 + line071 + line072 + line074);
|
|
1244
|
+
const itcCitcCap = Math.max(0, room602);
|
|
1245
|
+
const itc = computeItc(input.itc ?? {}, itcCitcCap, issues);
|
|
1246
|
+
const citc = computeCitc(input.citc ?? {}, itcCitcCap, itc.amountApplied, itc.carryforwardToNextYear, issues);
|
|
1247
|
+
const apitcRoom = Math.max(0, line068 - (line070 + line072) - (itc.amountApplied + citc.amountApplied));
|
|
1248
|
+
const apitc = computeApitc(input.apitc ?? {}, apitcRoom, issues);
|
|
1249
|
+
const creditsApplied = itc.amountApplied + citc.amountApplied + apitc.totalApplied;
|
|
1250
|
+
return {
|
|
1251
|
+
mad: {
|
|
1252
|
+
creditsApplied,
|
|
1253
|
+
room: room602
|
|
1254
|
+
},
|
|
1255
|
+
itc,
|
|
1256
|
+
citc,
|
|
1257
|
+
apitc,
|
|
1258
|
+
totalDeduction: Math.max(0, Math.min(creditsApplied, Math.max(0, room602))),
|
|
1259
|
+
issues
|
|
1260
|
+
};
|
|
1261
|
+
}
|
|
1262
|
+
function schedule3LineItemId(fieldId, occurrence = 1) {
|
|
1263
|
+
return `003${fieldId}${String(occurrence).padStart(3, "0")}`;
|
|
1264
|
+
}
|
|
1265
|
+
/**
|
|
1266
|
+
* Field ids per the spec transcription above: 100-108 (ITC), 200-208 (CITC),
|
|
1267
|
+
* 300-316 (APITC), 600-604 (MAD). The by-year-of-origin detail pages
|
|
1268
|
+
* (120-130/220-230/330-340) are NOT emitted — this module does not compute a
|
|
1269
|
+
* per-vintage split for ITC/CITC (see the module docstring), and the APITC
|
|
1270
|
+
* per-vintage figures this DOES compute (304/306/308/310) are filed on the
|
|
1271
|
+
* 300-series rollup, not re-emitted as an AAPITC occurrence table.
|
|
1272
|
+
*/
|
|
1273
|
+
function schedule3Values(result) {
|
|
1274
|
+
const values = [];
|
|
1275
|
+
const put = (fieldId, value) => values.push({
|
|
1276
|
+
lineItemId: schedule3LineItemId(fieldId),
|
|
1277
|
+
value
|
|
1278
|
+
});
|
|
1279
|
+
put("100", result.itc.certificatesIssued);
|
|
1280
|
+
put("102", result.itc.carryforwardFromPriorYear);
|
|
1281
|
+
put("104", result.itc.amountApplied);
|
|
1282
|
+
put("106", result.itc.expired);
|
|
1283
|
+
put("108", result.itc.carryforwardToNextYear);
|
|
1284
|
+
put("200", result.citc.certificatesIssued);
|
|
1285
|
+
put("202", result.citc.carryforwardFromPriorYear);
|
|
1286
|
+
put("204", result.citc.amountApplied);
|
|
1287
|
+
put("206", result.citc.expired);
|
|
1288
|
+
put("208", result.citc.carryforwardToNextYear);
|
|
1289
|
+
put("300", result.apitc.totalReceived);
|
|
1290
|
+
put("302", result.apitc.carryforwardFromPriorYear);
|
|
1291
|
+
put("304", result.apitc.current.amountApplied);
|
|
1292
|
+
put("306", result.apitc.firstPreceding.amountApplied);
|
|
1293
|
+
put("308", result.apitc.secondPreceding.amountApplied);
|
|
1294
|
+
put("310", result.apitc.thirdToTenthPreceding.amountApplied);
|
|
1295
|
+
put("312", result.apitc.totalApplied);
|
|
1296
|
+
put("314", result.apitc.expired);
|
|
1297
|
+
put("316", result.apitc.availableForCarryforward);
|
|
1298
|
+
put("600", result.mad.creditsApplied);
|
|
1299
|
+
put("602", result.mad.room);
|
|
1300
|
+
put("604", result.totalDeduction);
|
|
1301
|
+
return {
|
|
1302
|
+
scheduleId: "003",
|
|
1303
|
+
values
|
|
1304
|
+
};
|
|
1305
|
+
}
|
|
1306
|
+
//#endregion
|
|
1307
|
+
//#region src/t2/at1/schedules/schedule4-foreign-investment-tax-credit.ts
|
|
1308
|
+
const nn$32 = (v) => Math.max(0, v ?? 0);
|
|
1309
|
+
/** Round to 3 decimal places, half-up — the precision the spec directs for D and G. */
|
|
1310
|
+
function round3(v) {
|
|
1311
|
+
return Math.round((v + Number.EPSILON) * 1e3) / 1e3;
|
|
1312
|
+
}
|
|
1313
|
+
function computeSchedule4(input) {
|
|
1314
|
+
const issues = [];
|
|
1315
|
+
const albertaTaxableIncome = nn$32(input.albertaTaxableIncome);
|
|
1316
|
+
const royaltyTaxDeduction = nn$32(input.royaltyTaxDeduction);
|
|
1317
|
+
const allocationFactor = input.allocationFactor ?? 0;
|
|
1318
|
+
const basicAlbertaTax = nn$32(input.basicAlbertaTax);
|
|
1319
|
+
const denominator = (albertaTaxableIncome - royaltyTaxDeduction) * allocationFactor;
|
|
1320
|
+
const countries = input.countries.map((c) => {
|
|
1321
|
+
if (!c.country) issues.push("Alberta Schedule 4: a country code is required for each occurrence (004002).");
|
|
1322
|
+
const netForeignInvestmentIncome = nn$32(c.netForeignInvestmentIncome);
|
|
1323
|
+
const fedForeignTaxPaid = nn$32(c.fedForeignTaxPaid);
|
|
1324
|
+
const fedIta2012Deduction = nn$32(c.fedIta2012Deduction);
|
|
1325
|
+
const albertaDeduction = Math.max(c.albertaActa82Deduction ?? fedIta2012Deduction, fedIta2012Deduction);
|
|
1326
|
+
const taxPaidNetOfDeduction = Math.max(0, fedForeignTaxPaid - albertaDeduction);
|
|
1327
|
+
const federalNonBusinessForeignTaxCredit = nn$32(c.fedNonBusinessForeignTaxCredit);
|
|
1328
|
+
let incomeProrationAmount;
|
|
1329
|
+
if (denominator === 0) {
|
|
1330
|
+
incomeProrationAmount = 0;
|
|
1331
|
+
if (netForeignInvestmentIncome > 0) issues.push(`Alberta Schedule 4 (${c.country || "unspecified country"}): (albertaTaxableIncome − royaltyTaxDeduction) × allocationFactor is nil, so the D proration (000068 / that product) cannot be computed. Treated as nil rather than dividing by zero.`);
|
|
1332
|
+
} else incomeProrationAmount = round3(netForeignInvestmentIncome * allocationFactor * (basicAlbertaTax / denominator));
|
|
1333
|
+
const taxPaidLessFederalCredit = round3((taxPaidNetOfDeduction - federalNonBusinessForeignTaxCredit) * allocationFactor);
|
|
1334
|
+
const allowableCredit = Math.max(0, Math.round(Math.min(incomeProrationAmount, taxPaidLessFederalCredit)));
|
|
1335
|
+
return {
|
|
1336
|
+
country: c.country,
|
|
1337
|
+
netForeignInvestmentIncome,
|
|
1338
|
+
taxPaidNetOfDeduction,
|
|
1339
|
+
federalNonBusinessForeignTaxCredit,
|
|
1340
|
+
incomeProrationAmount,
|
|
1341
|
+
taxPaidLessFederalCredit,
|
|
1342
|
+
allowableCredit
|
|
1343
|
+
};
|
|
1344
|
+
});
|
|
1345
|
+
const totalAllowableCredit = countries.reduce((sum, c) => sum + c.allowableCredit, 0);
|
|
1346
|
+
if (input.countries.length > 0 && totalAllowableCredit === 0) issues.push("Alberta Schedule 4: total allowable credit is nil across all occurrences — the spec directs that this form not be printed/filed in that case.");
|
|
1347
|
+
return {
|
|
1348
|
+
countries,
|
|
1349
|
+
totalAllowableCredit,
|
|
1350
|
+
issues
|
|
1351
|
+
};
|
|
1352
|
+
}
|
|
1353
|
+
/**
|
|
1354
|
+
* Net File line items for AT1 Schedule 4 — one FIC occurrence per country.
|
|
1355
|
+
* Field ids from the spec (§3.2.3.5): 002 country, 004 net foreign investment
|
|
1356
|
+
* income, 006 foreign tax paid net of deduction, 008 federal non-business
|
|
1357
|
+
* foreign tax credit, 012 allowable credit.
|
|
1358
|
+
*
|
|
1359
|
+
* Does NOT emit jacket line 000072 (the sum-vs-remaining-tax comparison) —
|
|
1360
|
+
* that is a jacket line, not a Schedule 4 line, and belongs to whichever
|
|
1361
|
+
* module builds the jacket. Use `result.totalAllowableCredit` for that.
|
|
1362
|
+
*/
|
|
1363
|
+
function schedule4Values(result) {
|
|
1364
|
+
const values = [];
|
|
1365
|
+
result.countries.forEach((c, i) => {
|
|
1366
|
+
const n = i + 1;
|
|
1367
|
+
const put = (fieldId, value) => values.push({
|
|
1368
|
+
lineItemId: at1LineItemId("004", fieldId, n),
|
|
1369
|
+
value
|
|
1370
|
+
});
|
|
1371
|
+
put("002", c.country);
|
|
1372
|
+
put("004", c.netForeignInvestmentIncome);
|
|
1373
|
+
put("006", c.taxPaidNetOfDeduction);
|
|
1374
|
+
put("008", c.federalNonBusinessForeignTaxCredit);
|
|
1375
|
+
put("012", c.allowableCredit);
|
|
1376
|
+
});
|
|
1377
|
+
return {
|
|
1378
|
+
scheduleId: "004",
|
|
1379
|
+
values
|
|
1380
|
+
};
|
|
1381
|
+
}
|
|
1382
|
+
//#endregion
|
|
1383
|
+
//#region src/t2/at1/schedules/schedule5-royalty-tax-deduction.ts
|
|
1384
|
+
const nn$31 = (v) => Math.max(0, Math.round(v ?? 0));
|
|
1385
|
+
const num$2 = (v) => Math.round(v ?? 0);
|
|
1386
|
+
function processSuccessoredPool(entries, label, issues) {
|
|
1387
|
+
return (entries ?? []).map((e, i) => {
|
|
1388
|
+
const hasBrought = e.poolBroughtForward !== void 0;
|
|
1389
|
+
const hasAcquired = e.acquisitionAmount !== void 0;
|
|
1390
|
+
if (hasBrought && hasAcquired) issues.push(`Alberta Schedule 5: ${label} occurrence ${i + 1} (${e.vendorName}) has both a pool-brought-forward and an acquisition amount; the spec allows only one per occurrence. Using poolBroughtForward and ignoring acquisitionAmount.`);
|
|
1391
|
+
else if (!hasBrought && !hasAcquired) issues.push(`Alberta Schedule 5: ${label} occurrence ${i + 1} (${e.vendorName}) has neither a pool-brought-forward nor an acquisition amount; treating the pool base as zero.`);
|
|
1392
|
+
const base = nn$31(hasBrought ? e.poolBroughtForward : e.acquisitionAmount);
|
|
1393
|
+
const baseKind = hasBrought ? "broughtForward" : hasAcquired ? "acquired" : "unspecified";
|
|
1394
|
+
const propertyIncome = nn$31(e.propertyIncome);
|
|
1395
|
+
const claim = Math.min(base, propertyIncome);
|
|
1396
|
+
return {
|
|
1397
|
+
vendorName: e.vendorName,
|
|
1398
|
+
dateOfEvent: e.dateOfEvent,
|
|
1399
|
+
base,
|
|
1400
|
+
baseKind,
|
|
1401
|
+
propertyIncome,
|
|
1402
|
+
claim,
|
|
1403
|
+
carryForwardBeforeTransfer: base - claim
|
|
1404
|
+
};
|
|
1405
|
+
});
|
|
1406
|
+
}
|
|
1407
|
+
function computeAlbertaSchedule5(input) {
|
|
1408
|
+
const issues = [];
|
|
1409
|
+
const crownCharges = nn$31(input.crownChargesNetOfReimbursements);
|
|
1410
|
+
const resourceAllowance = nn$31(input.albertaResourceAllowance ?? input.federalResourceAllowance);
|
|
1411
|
+
const reimbursements = nn$31(input.reimbursementsForCrownCharges);
|
|
1412
|
+
const predecessorTransfersTotal = (input.predecessorTransfers ?? []).reduce((s, t) => s + nn$31(t.amountTransferred), 0);
|
|
1413
|
+
const attributedRoyaltyIncomeCarryForwardIn = nn$31(input.openingUnsuccessoredPoolBalance) + predecessorTransfersTotal;
|
|
1414
|
+
const unsuccessoredPoolAvailable = crownCharges - resourceAllowance - reimbursements + attributedRoyaltyIncomeCarryForwardIn;
|
|
1415
|
+
const hasSuccessoredPools = input.hasSuccessoredPools ?? false;
|
|
1416
|
+
if (!hasSuccessoredPools && ((input.secondSuccessoredPools?.length ?? 0) > 0 || (input.firstSuccessoredPools?.length ?? 0) > 0)) issues.push("Alberta Schedule 5: hasSuccessoredPools (005200) is false, but successored pool occurrences were supplied. Per the spec, 005101-005140 must not exist when 005200 = 2 (No); the supplied occurrences were ignored.");
|
|
1417
|
+
const secondSuccessoredPools = hasSuccessoredPools ? processSuccessoredPool(input.secondSuccessoredPools, "second successored (SSPI)", issues) : [];
|
|
1418
|
+
const firstSuccessoredPools = hasSuccessoredPools ? processSuccessoredPool(input.firstSuccessoredPools, "first successored (FSPI)", issues) : [];
|
|
1419
|
+
const secondSuccessoredSubtotal = secondSuccessoredPools.reduce((s, e) => s + e.carryForwardBeforeTransfer, 0);
|
|
1420
|
+
const firstSuccessoredSubtotal = firstSuccessoredPools.reduce((s, e) => s + e.carryForwardBeforeTransfer, 0);
|
|
1421
|
+
const successoredTotal = secondSuccessoredPools.reduce((s, e) => s + e.claim, 0) + firstSuccessoredPools.reduce((s, e) => s + e.claim, 0);
|
|
1422
|
+
const albertaTaxableIncome = num$2(input.albertaTaxableIncomeBeforeDeduction);
|
|
1423
|
+
const crtdMaxClaimable = Math.max(0, Math.min(unsuccessoredPoolAvailable, albertaTaxableIncome - successoredTotal));
|
|
1424
|
+
const crtdClaim = input.crtdAmountClaimed != null ? Math.max(0, Math.min(Math.round(input.crtdAmountClaimed), crtdMaxClaimable)) : crtdMaxClaimable;
|
|
1425
|
+
const poolAvailableCarryForward = unsuccessoredPoolAvailable - crtdClaim;
|
|
1426
|
+
const transferredOnDisposal = nn$31(input.transferredOnDisposal);
|
|
1427
|
+
const uncappedTotal = crtdClaim + successoredTotal;
|
|
1428
|
+
const totalRoyaltyTaxDeduction = Math.max(0, Math.min(uncappedTotal, albertaTaxableIncome));
|
|
1429
|
+
if (totalRoyaltyTaxDeduction < uncappedTotal && uncappedTotal > albertaTaxableIncome) if (albertaTaxableIncome < 0) issues.push(`Alberta Schedule 5: Alberta taxable income before the deduction (AT1 line 062) is ${albertaTaxableIncome}, which is negative. AT1 line 064 is specified as "005016 + 005140, cannot exceed 000062" with no stated floor; this engine floors the combined deduction at zero rather than reporting a negative Royalty Tax Deduction. The successored-pool claims (005140 = ${successoredTotal}) are computed independently of line 062 and are NOT reduced by this cap — review manually if this scenario occurs.`);
|
|
1430
|
+
else issues.push(`Alberta Schedule 5: the combined Royalty Tax Deduction (005016 + 005140 = ${uncappedTotal}) exceeds Alberta taxable income before the deduction (AT1 line 062 = ${albertaTaxableIncome}); AT1 line 064 is capped at ${totalRoyaltyTaxDeduction} per the spec.`);
|
|
1431
|
+
const netOfResourceAllowance = crownCharges - resourceAllowance;
|
|
1432
|
+
const carryForwardRaw = netOfResourceAllowance >= 0 ? netOfResourceAllowance + attributedRoyaltyIncomeCarryForwardIn - totalRoyaltyTaxDeduction - transferredOnDisposal : attributedRoyaltyIncomeCarryForwardIn - totalRoyaltyTaxDeduction - transferredOnDisposal;
|
|
1433
|
+
const attributedRoyaltyIncomeCarryForwardOut = Math.max(0, carryForwardRaw);
|
|
1434
|
+
if (input.poolTransfer) {
|
|
1435
|
+
const { type, acquirerName } = input.poolTransfer;
|
|
1436
|
+
if ((type === 1 || type === 2) && !acquirerName) issues.push("Alberta Schedule 5: pool transfer type (005026) is 1 or 2, but the acquiring corporation's legal name (005027) is missing.");
|
|
1437
|
+
if (type === 3 && acquirerName) issues.push("Alberta Schedule 5: pool transfer type (005026) is 3 (no transfer), but an acquiring corporation name (005027) was supplied. Per the spec, 005027 must be blank when 005026 = 3.");
|
|
1438
|
+
}
|
|
1439
|
+
if (input.changeInControlEndedPrecedingYear !== void 0 && input.at1TaxYearEndChanged !== void 0 && input.at1TaxYearEndChangeReason !== void 0) {
|
|
1440
|
+
const cicChangedYearEnd = input.at1TaxYearEndChanged && input.at1TaxYearEndChangeReason === 2;
|
|
1441
|
+
if (input.changeInControlEndedPrecedingYear !== cicChangedYearEnd) issues.push(`Alberta Schedule 5: 005100 (change in control ended the preceding taxation year) is ${input.changeInControlEndedPrecedingYear}, which is inconsistent with AT1 core 000038/000039 (tax year end changed due to change in control = ${cicChangedYearEnd}). Per the spec, these must agree in both directions.`);
|
|
1442
|
+
}
|
|
1443
|
+
const formRequired = crownCharges > 0 || attributedRoyaltyIncomeCarryForwardIn > 0 || hasSuccessoredPools;
|
|
1444
|
+
return {
|
|
1445
|
+
crownCharges,
|
|
1446
|
+
resourceAllowance,
|
|
1447
|
+
reimbursements,
|
|
1448
|
+
predecessorTransfersTotal,
|
|
1449
|
+
attributedRoyaltyIncomeCarryForwardIn,
|
|
1450
|
+
unsuccessoredPoolAvailable,
|
|
1451
|
+
crtdMaxClaimable,
|
|
1452
|
+
crtdClaim,
|
|
1453
|
+
poolAvailableCarryForward,
|
|
1454
|
+
transferredOnDisposal,
|
|
1455
|
+
secondSuccessoredPools,
|
|
1456
|
+
firstSuccessoredPools,
|
|
1457
|
+
secondSuccessoredSubtotal,
|
|
1458
|
+
firstSuccessoredSubtotal,
|
|
1459
|
+
successoredTotal,
|
|
1460
|
+
totalRoyaltyTaxDeduction,
|
|
1461
|
+
attributedRoyaltyIncomeCarryForwardOut,
|
|
1462
|
+
...input.poolTransfer !== void 0 ? { poolTransfer: input.poolTransfer } : {},
|
|
1463
|
+
...input.changeInControlEndedPrecedingYear !== void 0 ? { changeInControlEndedPrecedingYear: input.changeInControlEndedPrecedingYear } : {},
|
|
1464
|
+
formRequired,
|
|
1465
|
+
issues
|
|
1466
|
+
};
|
|
1467
|
+
}
|
|
1468
|
+
/** `005` + field id + 3-digit occurrence — the nine-digit AT1 line item id. */
|
|
1469
|
+
function schedule5LineItemId(fieldId, occurrence = 1) {
|
|
1470
|
+
return `005${fieldId}${String(occurrence).padStart(3, "0")}`;
|
|
1471
|
+
}
|
|
1472
|
+
function putSuccessoredPool(values, entries, fields) {
|
|
1473
|
+
entries.forEach((e, i) => {
|
|
1474
|
+
const n = i + 1;
|
|
1475
|
+
const put = (fieldId, value) => values.push({
|
|
1476
|
+
lineItemId: schedule5LineItemId(fieldId, n),
|
|
1477
|
+
value
|
|
1478
|
+
});
|
|
1479
|
+
put(fields.vendorName, e.vendorName);
|
|
1480
|
+
put(fields.dateOfEvent, e.dateOfEvent);
|
|
1481
|
+
if (e.baseKind === "broughtForward") put(fields.broughtForward, e.base);
|
|
1482
|
+
else if (e.baseKind === "acquired") put(fields.acquired, e.base);
|
|
1483
|
+
put(fields.propertyIncome, e.propertyIncome);
|
|
1484
|
+
put(fields.claim, e.claim);
|
|
1485
|
+
put(fields.carryForward, e.carryForwardBeforeTransfer);
|
|
1486
|
+
});
|
|
1487
|
+
}
|
|
1488
|
+
function schedule5Values(result) {
|
|
1489
|
+
const values = [];
|
|
1490
|
+
const put = (fieldId, value) => values.push({
|
|
1491
|
+
lineItemId: schedule5LineItemId(fieldId),
|
|
1492
|
+
value
|
|
1493
|
+
});
|
|
1494
|
+
put("001", result.crownCharges);
|
|
1495
|
+
put("005", result.resourceAllowance);
|
|
1496
|
+
put("007", result.reimbursements);
|
|
1497
|
+
put("011", result.attributedRoyaltyIncomeCarryForwardIn);
|
|
1498
|
+
put("016", result.crtdClaim);
|
|
1499
|
+
put("017", result.poolAvailableCarryForward);
|
|
1500
|
+
put("023", result.transferredOnDisposal);
|
|
1501
|
+
put("025", result.attributedRoyaltyIncomeCarryForwardOut);
|
|
1502
|
+
if (result.poolTransfer) {
|
|
1503
|
+
put("026", result.poolTransfer.type);
|
|
1504
|
+
if (result.poolTransfer.acquirerName) put("027", result.poolTransfer.acquirerName);
|
|
1505
|
+
}
|
|
1506
|
+
if (result.changeInControlEndedPrecedingYear !== void 0) put("100", result.changeInControlEndedPrecedingYear ? 1 : 2);
|
|
1507
|
+
putSuccessoredPool(values, result.secondSuccessoredPools, {
|
|
1508
|
+
vendorName: "101",
|
|
1509
|
+
dateOfEvent: "103",
|
|
1510
|
+
broughtForward: "105",
|
|
1511
|
+
acquired: "107",
|
|
1512
|
+
propertyIncome: "109",
|
|
1513
|
+
claim: "111",
|
|
1514
|
+
carryForward: "113"
|
|
1515
|
+
});
|
|
1516
|
+
put("115", result.secondSuccessoredSubtotal);
|
|
1517
|
+
putSuccessoredPool(values, result.firstSuccessoredPools, {
|
|
1518
|
+
vendorName: "121",
|
|
1519
|
+
dateOfEvent: "123",
|
|
1520
|
+
broughtForward: "125",
|
|
1521
|
+
acquired: "127",
|
|
1522
|
+
propertyIncome: "129",
|
|
1523
|
+
claim: "131",
|
|
1524
|
+
carryForward: "133"
|
|
1525
|
+
});
|
|
1526
|
+
put("135", result.firstSuccessoredSubtotal);
|
|
1527
|
+
put("140", result.successoredTotal);
|
|
1528
|
+
return {
|
|
1529
|
+
scheduleId: "005",
|
|
1530
|
+
values
|
|
1531
|
+
};
|
|
1532
|
+
}
|
|
1533
|
+
//#endregion
|
|
1534
|
+
//#region src/t2/at1/schedules/schedule6-royalty-tax-credit.ts
|
|
1535
|
+
const rd$1 = (v) => Math.round(v ?? 0);
|
|
1536
|
+
const nn$30 = (v) => Math.max(0, Math.round(v ?? 0));
|
|
1537
|
+
const round4$1 = (v) => Math.round(v * 1e4) / 1e4;
|
|
1538
|
+
function computeWeightedAverageRate(quarters, issues) {
|
|
1539
|
+
if (quarters.length === 0) {
|
|
1540
|
+
issues.push("Alberta Schedule 6: no quarters were supplied for the weighted average rate (006008 is mandatory). Defaulted to 0 — supply the RTC quarterly rate(s) from Alberta Treasury Board and Finance's published rate table.");
|
|
1541
|
+
return 0;
|
|
1542
|
+
}
|
|
1543
|
+
const totalDays = quarters.reduce((s, q) => s + Math.max(0, q.days), 0);
|
|
1544
|
+
if (totalDays <= 0) {
|
|
1545
|
+
issues.push("Alberta Schedule 6: the quarters supplied for 006008 total zero days.");
|
|
1546
|
+
return 0;
|
|
1547
|
+
}
|
|
1548
|
+
const weighted = quarters.reduce((s, q) => s + Math.max(0, q.days) / totalDays * q.rate, 0);
|
|
1549
|
+
return round4$1(weighted);
|
|
1550
|
+
}
|
|
1551
|
+
function resolveAllocations(allocations, pool, issues) {
|
|
1552
|
+
const totalRequested = allocations.reduce((s, a) => s + nn$30(a.allocatedAmount), 0);
|
|
1553
|
+
if (totalRequested > pool) issues.push(`Alberta Schedule 6: the associated group allocated ${totalRequested} of a Crown Royalty Shelter pool of ${pool} (006034 occurrences exceed the $2,000,000 × (006028/365) limit). Allocations were capped in the order given — the group must agree a valid split.`);
|
|
1554
|
+
let remaining = pool;
|
|
1555
|
+
return allocations.map((a) => {
|
|
1556
|
+
const requestedAmount = nn$30(a.allocatedAmount);
|
|
1557
|
+
const allocatedAmount = Math.min(requestedAmount, remaining);
|
|
1558
|
+
remaining -= allocatedAmount;
|
|
1559
|
+
return {
|
|
1560
|
+
name: a.name,
|
|
1561
|
+
...a.albertaCan !== void 0 ? { albertaCan: a.albertaCan } : {},
|
|
1562
|
+
allocatedAmount,
|
|
1563
|
+
requestedAmount
|
|
1564
|
+
};
|
|
1565
|
+
});
|
|
1566
|
+
}
|
|
1567
|
+
function schedule6LineItemId(fieldId, occurrence = 1) {
|
|
1568
|
+
return `006${fieldId}${String(occurrence).padStart(3, "0")}`;
|
|
1569
|
+
}
|
|
1570
|
+
/**
|
|
1571
|
+
* Emits every field this module's own MAPPINGS transcription actually defines
|
|
1572
|
+
* a number for: 006002/004/006/008, and — only when the corporation is
|
|
1573
|
+
* associated — the ACRS section (006022-028) and the AACRS allocation table
|
|
1574
|
+
* (006030-034, one occurrence per row).
|
|
1575
|
+
*
|
|
1576
|
+
* ── No credit amount is filed here, because none exists on this schedule ────
|
|
1577
|
+
*
|
|
1578
|
+
* See the module docstring's "CONFIRMED: there is no 'credit' dollar amount
|
|
1579
|
+
* to compute here" section — the Alberta Royalty Tax Credit is an instalment
|
|
1580
|
+
* program (AT1 jacket line 000082, the shared "Payments & Instalments"
|
|
1581
|
+
* schedule), not a value Schedule 6 computes and files. This builder emits
|
|
1582
|
+
* exactly the three components the schedule DOES define (006004, 006006,
|
|
1583
|
+
* 006008) plus the ACRS/AACRS detail when associated — matching
|
|
1584
|
+
* `schedule3Values`'s `At1ScheduleDataLike` shape exactly: `{ scheduleId,
|
|
1585
|
+
* values }`.
|
|
1586
|
+
*/
|
|
1587
|
+
function schedule6Values(result) {
|
|
1588
|
+
const values = [];
|
|
1589
|
+
const put = (fieldId, value, occurrence = 1) => values.push({
|
|
1590
|
+
lineItemId: schedule6LineItemId(fieldId, occurrence),
|
|
1591
|
+
value
|
|
1592
|
+
});
|
|
1593
|
+
put("002", result.associatedWithCrownRoyaltyCorporations ? 1 : 2);
|
|
1594
|
+
put("004", result.albertaCrownRoyaltyIncurred);
|
|
1595
|
+
put("006", result.crownRoyaltyShelter);
|
|
1596
|
+
put("008", result.weightedAverageRate);
|
|
1597
|
+
if (result.associatedWithCrownRoyaltyCorporations && result.longestAssociatedYear) {
|
|
1598
|
+
if (result.longestAssociatedYear.albertaCan !== void 0) values.push({
|
|
1599
|
+
lineItemId: schedule6LineItemId("022"),
|
|
1600
|
+
value: result.longestAssociatedYear.albertaCan
|
|
1601
|
+
});
|
|
1602
|
+
if (result.longestAssociatedYear.taxationYearBeginning !== void 0) values.push({
|
|
1603
|
+
lineItemId: schedule6LineItemId("024"),
|
|
1604
|
+
value: result.longestAssociatedYear.taxationYearBeginning
|
|
1605
|
+
});
|
|
1606
|
+
if (result.longestAssociatedYear.taxationYearEnding !== void 0) values.push({
|
|
1607
|
+
lineItemId: schedule6LineItemId("026"),
|
|
1608
|
+
value: result.longestAssociatedYear.taxationYearEnding
|
|
1609
|
+
});
|
|
1610
|
+
put("028", result.longestAssociatedYear.days);
|
|
1611
|
+
result.allocations.forEach((a, i) => {
|
|
1612
|
+
const occurrence = i + 1;
|
|
1613
|
+
values.push({
|
|
1614
|
+
lineItemId: schedule6LineItemId("030", occurrence),
|
|
1615
|
+
value: a.name
|
|
1616
|
+
});
|
|
1617
|
+
if (a.albertaCan !== void 0) values.push({
|
|
1618
|
+
lineItemId: schedule6LineItemId("032", occurrence),
|
|
1619
|
+
value: a.albertaCan
|
|
1620
|
+
});
|
|
1621
|
+
put("034", a.allocatedAmount, occurrence);
|
|
1622
|
+
});
|
|
1623
|
+
}
|
|
1624
|
+
return {
|
|
1625
|
+
scheduleId: "006",
|
|
1626
|
+
values
|
|
1627
|
+
};
|
|
1628
|
+
}
|
|
1629
|
+
function computeAlbertaSchedule6(input) {
|
|
1630
|
+
const issues = [];
|
|
1631
|
+
const associatedWithCrownRoyaltyCorporations = input.associatedWithCrownRoyaltyCorporations ?? false;
|
|
1632
|
+
const albertaCrownRoyaltyIncurred = rd$1(input.albertaCrownRoyaltyIncurred);
|
|
1633
|
+
const weightedAverageRate = computeWeightedAverageRate(input.quarters ?? [], issues);
|
|
1634
|
+
const formRequired = albertaCrownRoyaltyIncurred > 0;
|
|
1635
|
+
if (!associatedWithCrownRoyaltyCorporations) {
|
|
1636
|
+
const days = Math.max(0, Math.min(input.taxationYearDays ?? 365, 365));
|
|
1637
|
+
return {
|
|
1638
|
+
associatedWithCrownRoyaltyCorporations,
|
|
1639
|
+
albertaCrownRoyaltyIncurred,
|
|
1640
|
+
crownRoyaltyShelter: Math.round(2e6 * (days / 365)),
|
|
1641
|
+
weightedAverageRate,
|
|
1642
|
+
aggregateShelterPool: 0,
|
|
1643
|
+
allocations: [],
|
|
1644
|
+
totalAllocated: 0,
|
|
1645
|
+
formRequired,
|
|
1646
|
+
issues
|
|
1647
|
+
};
|
|
1648
|
+
}
|
|
1649
|
+
if (!input.longestAssociatedYear) issues.push("Alberta Schedule 6: the corporation is associated with one or more corporations that incurred Alberta Crown Royalty (006002 = 1), but no ACRS data (006022-006028, the associated corporation with the longest taxation year) was supplied. The Crown Royalty Shelter pool defaulted to zero.");
|
|
1650
|
+
const days = Math.max(0, Math.min(input.longestAssociatedYear?.days ?? 0, 365));
|
|
1651
|
+
const aggregateShelterPool = Math.round(2e6 * (days / 365));
|
|
1652
|
+
const rawAllocations = input.allocations ?? [];
|
|
1653
|
+
if (rawAllocations.length === 0) issues.push("Alberta Schedule 6: the corporation is associated (006002 = 1), but no AACRS allocation rows (006030-006034) were supplied. This filer's own Crown Royalty Shelter (006006) defaulted to zero.");
|
|
1654
|
+
const allocations = resolveAllocations(rawAllocations, aggregateShelterPool, issues);
|
|
1655
|
+
const totalAllocated = allocations.reduce((s, a) => s + a.allocatedAmount, 0);
|
|
1656
|
+
return {
|
|
1657
|
+
associatedWithCrownRoyaltyCorporations,
|
|
1658
|
+
albertaCrownRoyaltyIncurred,
|
|
1659
|
+
crownRoyaltyShelter: allocations[0]?.allocatedAmount ?? 0,
|
|
1660
|
+
weightedAverageRate,
|
|
1661
|
+
longestAssociatedYear: {
|
|
1662
|
+
...input.longestAssociatedYear?.albertaCan !== void 0 ? { albertaCan: input.longestAssociatedYear.albertaCan } : {},
|
|
1663
|
+
...input.longestAssociatedYear?.taxationYearBeginning !== void 0 ? { taxationYearBeginning: input.longestAssociatedYear.taxationYearBeginning } : {},
|
|
1664
|
+
...input.longestAssociatedYear?.taxationYearEnding !== void 0 ? { taxationYearEnding: input.longestAssociatedYear.taxationYearEnding } : {},
|
|
1665
|
+
days
|
|
1666
|
+
},
|
|
1667
|
+
aggregateShelterPool,
|
|
1668
|
+
allocations,
|
|
1669
|
+
totalAllocated,
|
|
1670
|
+
formRequired,
|
|
1671
|
+
issues
|
|
1672
|
+
};
|
|
1673
|
+
}
|
|
1674
|
+
//#endregion
|
|
1675
|
+
//#region src/t2/at1/schedules/schedule7-royalty-supplemental.ts
|
|
1676
|
+
/** Signed whole-dollar rounding — no floor, several of these lines are marked "+/-". */
|
|
1677
|
+
const rd = (v) => Math.round(v ?? 0);
|
|
1678
|
+
/** Non-negative whole-dollar rounding, for the "+"-only lines. */
|
|
1679
|
+
const nn$29 = (v) => Math.max(0, Math.round(v ?? 0));
|
|
1680
|
+
const round4 = (v) => Math.round(v * 1e4) / 1e4;
|
|
1681
|
+
function resolvePartnership(p, index, issues) {
|
|
1682
|
+
if (!p.name) issues.push(`Alberta Schedule 7: partnership row ${index + 1} has no name (007071 is mandatory for every PITI occurrence).`);
|
|
1683
|
+
if (p.interestPercent < 0 || p.interestPercent > 1) issues.push(`Alberta Schedule 7: ${p.name || `partnership row ${index + 1}`} has an interest of ${p.interestPercent}, expected a decimal between 0 and 1 (007073, e.g. .7500 for 75%).`);
|
|
1684
|
+
return {
|
|
1685
|
+
name: p.name,
|
|
1686
|
+
interestPercent: round4(p.interestPercent),
|
|
1687
|
+
...p.fiscalPeriodEnd !== void 0 ? { fiscalPeriodEnd: p.fiscalPeriodEnd } : {},
|
|
1688
|
+
shareEligibleForCredit: nn$29(p.shareEligibleForCredit),
|
|
1689
|
+
shareOtherRoyaltiesNotEligible: nn$29(p.shareOtherRoyaltiesNotEligible),
|
|
1690
|
+
shareOtherCrownChargesEligibleForDeduction: nn$29(p.shareOtherCrownChargesEligibleForDeduction)
|
|
1691
|
+
};
|
|
1692
|
+
}
|
|
1693
|
+
function resolveAdjustment(a, index, issues) {
|
|
1694
|
+
if (!a.priorProductionPeriodEnd) issues.push(`Alberta Schedule 7: prior-year adjustment row ${index + 1} has no prior production period (007083 is mandatory for every ACRA occurrence).`);
|
|
1695
|
+
if (a.sourceOfAdjustment !== 1 && a.sourceOfAdjustment !== 2) issues.push(`Alberta Schedule 7: prior-year adjustment row ${index + 1} has no valid source code (007085 must be 1 = Dept. of Resource Development or 2 = Operator).`);
|
|
1696
|
+
return {
|
|
1697
|
+
...a.priorProductionPeriodEnd !== void 0 ? { priorProductionPeriodEnd: a.priorProductionPeriodEnd } : {},
|
|
1698
|
+
...a.sourceOfAdjustment !== void 0 ? { sourceOfAdjustment: a.sourceOfAdjustment } : {},
|
|
1699
|
+
increase: nn$29(a.increase),
|
|
1700
|
+
decrease: nn$29(a.decrease),
|
|
1701
|
+
adjustmentNotEligibleForCredit: rd(a.adjustmentNotEligibleForCredit)
|
|
1702
|
+
};
|
|
1703
|
+
}
|
|
1704
|
+
function schedule7LineItemId(fieldId, occurrence = 1) {
|
|
1705
|
+
return `007${fieldId}${String(occurrence).padStart(3, "0")}`;
|
|
1706
|
+
}
|
|
1707
|
+
/**
|
|
1708
|
+
* Emits CPI (007003-029), the computed totals 007051 and 007061, and the two
|
|
1709
|
+
* repeating sections — PITI (007071-081, one occurrence per partnership) and
|
|
1710
|
+
* ACRA (007083-091, one occurrence per prior-year adjustment).
|
|
1711
|
+
*
|
|
1712
|
+
* 007061 is filed even though it has no defining row of its own anywhere in
|
|
1713
|
+
* this schedule's MAPPINGS block (spec lines 6654-7251) — see the module
|
|
1714
|
+
* docstring's "Two totals with NO defining row of their own in this MAPPINGS
|
|
1715
|
+
* table" section. It is a real Schedule 7 output line: AT1 Schedule 5's own
|
|
1716
|
+
* field 005001 definition (spec lines 5237-5248) names it explicitly as
|
|
1717
|
+
* "Schedule 7, line 061" and gives its formula in full, so it is filed here
|
|
1718
|
+
* under that citation rather than omitted for lack of a home row.
|
|
1719
|
+
*/
|
|
1720
|
+
function schedule7Values(result) {
|
|
1721
|
+
const values = [];
|
|
1722
|
+
const put = (fieldId, value, occurrence = 1) => values.push({
|
|
1723
|
+
lineItemId: schedule7LineItemId(fieldId, occurrence),
|
|
1724
|
+
value
|
|
1725
|
+
});
|
|
1726
|
+
put("003", result.eligibleCrownRoyalty);
|
|
1727
|
+
put("005", result.otherRoyaltiesNotEligible);
|
|
1728
|
+
put("007", result.royaltyPaidToOtherJurisdictions);
|
|
1729
|
+
put("009", result.nonDeductibleCrownLeaseRentals);
|
|
1730
|
+
put("011", result.mineralTaxes);
|
|
1731
|
+
put("013", result.saskatchewanResourcesSurcharge);
|
|
1732
|
+
result.otherNonDeductibleCrownChargeTypes.forEach((name, i) => {
|
|
1733
|
+
values.push({
|
|
1734
|
+
lineItemId: schedule7LineItemId(String(14 + i).padStart(3, "0")),
|
|
1735
|
+
value: name
|
|
1736
|
+
});
|
|
1737
|
+
});
|
|
1738
|
+
put("017", result.otherNonDeductibleCrownCharges);
|
|
1739
|
+
put("025", result.crownLeaseRentalsCapitalized);
|
|
1740
|
+
if (result.otherBalanceSheetDeductionName !== void 0) values.push({
|
|
1741
|
+
lineItemId: schedule7LineItemId("027"),
|
|
1742
|
+
value: result.otherBalanceSheetDeductionName
|
|
1743
|
+
});
|
|
1744
|
+
put("029", result.otherBalanceSheetDeduction);
|
|
1745
|
+
result.partnerships.forEach((p, i) => {
|
|
1746
|
+
const occurrence = i + 1;
|
|
1747
|
+
values.push({
|
|
1748
|
+
lineItemId: schedule7LineItemId("071", occurrence),
|
|
1749
|
+
value: p.name
|
|
1750
|
+
});
|
|
1751
|
+
put("073", p.interestPercent, occurrence);
|
|
1752
|
+
if (p.fiscalPeriodEnd !== void 0) values.push({
|
|
1753
|
+
lineItemId: schedule7LineItemId("075", occurrence),
|
|
1754
|
+
value: p.fiscalPeriodEnd
|
|
1755
|
+
});
|
|
1756
|
+
put("077", p.shareEligibleForCredit, occurrence);
|
|
1757
|
+
put("079", p.shareOtherRoyaltiesNotEligible, occurrence);
|
|
1758
|
+
put("081", p.shareOtherCrownChargesEligibleForDeduction, occurrence);
|
|
1759
|
+
});
|
|
1760
|
+
result.priorYearAdjustments.forEach((a, i) => {
|
|
1761
|
+
const occurrence = i + 1;
|
|
1762
|
+
if (a.priorProductionPeriodEnd !== void 0) values.push({
|
|
1763
|
+
lineItemId: schedule7LineItemId("083", occurrence),
|
|
1764
|
+
value: a.priorProductionPeriodEnd
|
|
1765
|
+
});
|
|
1766
|
+
if (a.sourceOfAdjustment !== void 0) put("085", a.sourceOfAdjustment, occurrence);
|
|
1767
|
+
put("087", a.increase, occurrence);
|
|
1768
|
+
put("089", a.decrease, occurrence);
|
|
1769
|
+
put("091", a.adjustmentNotEligibleForCredit, occurrence);
|
|
1770
|
+
});
|
|
1771
|
+
put("051", result.totalAdjustments);
|
|
1772
|
+
put("061", result.crownChargesNetOfReimbursements);
|
|
1773
|
+
return {
|
|
1774
|
+
scheduleId: "007",
|
|
1775
|
+
values
|
|
1776
|
+
};
|
|
1777
|
+
}
|
|
1778
|
+
function computeAlbertaSchedule7(input) {
|
|
1779
|
+
const issues = [];
|
|
1780
|
+
const eligibleCrownRoyalty = rd(input.eligibleCrownRoyalty);
|
|
1781
|
+
const otherRoyaltiesNotEligible = rd(input.otherRoyaltiesNotEligible);
|
|
1782
|
+
const royaltyPaidToOtherJurisdictions = rd(input.royaltyPaidToOtherJurisdictions);
|
|
1783
|
+
const nonDeductibleCrownLeaseRentals = rd(input.nonDeductibleCrownLeaseRentals);
|
|
1784
|
+
const mineralTaxes = rd(input.mineralTaxes);
|
|
1785
|
+
const saskatchewanResourcesSurcharge = rd(input.saskatchewanResourcesSurcharge);
|
|
1786
|
+
const otherNonDeductibleCrownChargeTypes = (input.otherNonDeductibleCrownChargeTypes ?? []).slice(0, 3);
|
|
1787
|
+
if ((input.otherNonDeductibleCrownChargeTypes?.length ?? 0) > 3) issues.push("Alberta Schedule 7: more than three other non-deductible crown charge types were supplied (007014/015/016 allow three); only the first three were kept.");
|
|
1788
|
+
let otherNonDeductibleCrownCharges = rd(input.otherNonDeductibleCrownCharges);
|
|
1789
|
+
if (otherNonDeductibleCrownChargeTypes.length === 0 && otherNonDeductibleCrownCharges !== 0) {
|
|
1790
|
+
issues.push("Alberta Schedule 7: an amount was given for other non-deductible crown charges (007017) but no charge type was named (007014/015/016). The spec defaults 007017 to zero when no type is named; the amount was zeroed out.");
|
|
1791
|
+
otherNonDeductibleCrownCharges = 0;
|
|
1792
|
+
}
|
|
1793
|
+
const crownLeaseRentalsCapitalized = rd(input.crownLeaseRentalsCapitalized);
|
|
1794
|
+
let otherBalanceSheetDeduction = nn$29(input.otherBalanceSheetDeduction);
|
|
1795
|
+
if (!input.otherBalanceSheetDeductionName && otherBalanceSheetDeduction !== 0) {
|
|
1796
|
+
issues.push("Alberta Schedule 7: an amount was given for another balance sheet eligible deduction (007029) but no deduction was named (007027). The spec defaults 007029 to zero when no name is given; the amount was zeroed out.");
|
|
1797
|
+
otherBalanceSheetDeduction = 0;
|
|
1798
|
+
}
|
|
1799
|
+
const partnerships = (input.partnerships ?? []).map((p, i) => resolvePartnership(p, i, issues));
|
|
1800
|
+
const totalPartnershipShareEligibleForCredit = partnerships.reduce((s, p) => s + p.shareEligibleForCredit, 0);
|
|
1801
|
+
const totalPartnershipShareOtherRoyaltiesNotEligible = partnerships.reduce((s, p) => s + p.shareOtherRoyaltiesNotEligible, 0);
|
|
1802
|
+
const totalPartnershipShareOtherCrownCharges = partnerships.reduce((s, p) => s + p.shareOtherCrownChargesEligibleForDeduction, 0);
|
|
1803
|
+
const priorYearAdjustments = (input.priorYearAdjustments ?? []).map((a, i) => resolveAdjustment(a, i, issues));
|
|
1804
|
+
const totalIncrease = priorYearAdjustments.reduce((s, a) => s + a.increase, 0);
|
|
1805
|
+
const totalDecrease = priorYearAdjustments.reduce((s, a) => s + a.decrease, 0);
|
|
1806
|
+
const totalAdjustmentNotEligible = priorYearAdjustments.reduce((s, a) => s + a.adjustmentNotEligibleForCredit, 0);
|
|
1807
|
+
const totalAdjustments = priorYearAdjustments.length === 0 ? 0 : totalIncrease - totalDecrease + totalAdjustmentNotEligible;
|
|
1808
|
+
const crownChargesNetOfReimbursements = eligibleCrownRoyalty + otherRoyaltiesNotEligible + royaltyPaidToOtherJurisdictions + nonDeductibleCrownLeaseRentals + mineralTaxes + saskatchewanResourcesSurcharge + otherNonDeductibleCrownCharges + crownLeaseRentalsCapitalized + otherBalanceSheetDeduction + totalPartnershipShareEligibleForCredit + totalPartnershipShareOtherRoyaltiesNotEligible + totalPartnershipShareOtherCrownCharges - totalAdjustments;
|
|
1809
|
+
const albertaCrownRoyaltyForSchedule6 = eligibleCrownRoyalty + totalPartnershipShareEligibleForCredit - totalIncrease + totalDecrease;
|
|
1810
|
+
return {
|
|
1811
|
+
eligibleCrownRoyalty,
|
|
1812
|
+
otherRoyaltiesNotEligible,
|
|
1813
|
+
royaltyPaidToOtherJurisdictions,
|
|
1814
|
+
nonDeductibleCrownLeaseRentals,
|
|
1815
|
+
mineralTaxes,
|
|
1816
|
+
saskatchewanResourcesSurcharge,
|
|
1817
|
+
otherNonDeductibleCrownChargeTypes,
|
|
1818
|
+
otherNonDeductibleCrownCharges,
|
|
1819
|
+
crownLeaseRentalsCapitalized,
|
|
1820
|
+
...input.otherBalanceSheetDeductionName !== void 0 ? { otherBalanceSheetDeductionName: input.otherBalanceSheetDeductionName } : {},
|
|
1821
|
+
otherBalanceSheetDeduction,
|
|
1822
|
+
partnerships,
|
|
1823
|
+
totalPartnershipShareEligibleForCredit,
|
|
1824
|
+
totalPartnershipShareOtherRoyaltiesNotEligible,
|
|
1825
|
+
totalPartnershipShareOtherCrownCharges,
|
|
1826
|
+
priorYearAdjustments,
|
|
1827
|
+
totalAdjustments,
|
|
1828
|
+
crownChargesNetOfReimbursements,
|
|
1829
|
+
albertaCrownRoyaltyForSchedule6,
|
|
1830
|
+
issues
|
|
1831
|
+
};
|
|
1832
|
+
}
|
|
1833
|
+
//#endregion
|
|
1834
|
+
//#region src/t2/at1/schedules/schedule8-political-contributions.ts
|
|
1835
|
+
const nn$28 = (v) => Math.max(0, Math.round(v ?? 0));
|
|
1836
|
+
function yearOf(dateIso) {
|
|
1837
|
+
if (!dateIso || dateIso.length < 4) return void 0;
|
|
1838
|
+
const y = Number(dateIso.slice(0, 4));
|
|
1839
|
+
return Number.isFinite(y) ? y : void 0;
|
|
1840
|
+
}
|
|
1841
|
+
/** Tiered rate for the "all made in 2003 or earlier" branch. */
|
|
1842
|
+
function tierTo2003(a) {
|
|
1843
|
+
if (a <= 150) return a * .75;
|
|
1844
|
+
if (a <= 825) return 112.5 + (a - 150) * .5;
|
|
1845
|
+
return 450 + (a - 825) * .333;
|
|
1846
|
+
}
|
|
1847
|
+
/** Tiered rate for the "all made in 2004 or later" branch. */
|
|
1848
|
+
function tierFrom2004(a) {
|
|
1849
|
+
if (a <= 200) return a * .75;
|
|
1850
|
+
if (a <= 900) return 150 + (a - 200) * .5;
|
|
1851
|
+
return 600 + (a - 900) * .333;
|
|
1852
|
+
}
|
|
1853
|
+
function computeSchedule8$1(input) {
|
|
1854
|
+
const issues = [];
|
|
1855
|
+
const contributions = input.contributions ?? [];
|
|
1856
|
+
contributions.forEach((c, i) => {
|
|
1857
|
+
if (!c.dateOfDonation) issues.push(`Alberta Schedule 8: contribution #${i + 1} (${c.name || "unnamed"}) has no date of donation (008006) — the spec requires one for every receipted contribution.`);
|
|
1858
|
+
if (!c.receiptNumber) issues.push(`Alberta Schedule 8: contribution #${i + 1} (${c.name || "unnamed"}) has no official receipt number (008004).`);
|
|
1859
|
+
});
|
|
1860
|
+
const partnershipContributionsTo2003 = nn$28(input.partnershipContributionsTo2003);
|
|
1861
|
+
const partnershipContributionsFrom2004 = nn$28(input.partnershipContributionsFrom2004);
|
|
1862
|
+
const totalDirect = contributions.reduce((sum, c) => sum + nn$28(c.amount), 0);
|
|
1863
|
+
const directTo2003 = contributions.filter((c) => (yearOf(c.dateOfDonation) ?? 0) <= 2003).reduce((sum, c) => sum + nn$28(c.amount), 0);
|
|
1864
|
+
const directFrom2004 = contributions.filter((c) => (yearOf(c.dateOfDonation) ?? 9999) >= 2004).reduce((sum, c) => sum + nn$28(c.amount), 0);
|
|
1865
|
+
const directIn2004Only = contributions.filter((c) => yearOf(c.dateOfDonation) === 2004).reduce((sum, c) => sum + nn$28(c.amount), 0);
|
|
1866
|
+
const hasTo2003 = directTo2003 > 0 || partnershipContributionsTo2003 > 0;
|
|
1867
|
+
const hasFrom2004 = directFrom2004 > 0 || partnershipContributionsFrom2004 > 0;
|
|
1868
|
+
if (!hasTo2003 && !hasFrom2004) return {
|
|
1869
|
+
contributions,
|
|
1870
|
+
partnershipContributionsTo2003,
|
|
1871
|
+
partnershipContributionsFrom2004,
|
|
1872
|
+
period: "none",
|
|
1873
|
+
creditBeforeCeiling: 0,
|
|
1874
|
+
credit: 0,
|
|
1875
|
+
issues
|
|
1876
|
+
};
|
|
1877
|
+
const taxYearBeginYear = yearOf(input.taxYearBegin);
|
|
1878
|
+
const taxYearEndYear = yearOf(input.taxYearEnd);
|
|
1879
|
+
const taxYearStraddles2003to2004 = taxYearBeginYear === 2003 && taxYearEndYear === 2004;
|
|
1880
|
+
const ceiling = input.remainingBasicTax;
|
|
1881
|
+
let period;
|
|
1882
|
+
let rawCredit;
|
|
1883
|
+
let credit;
|
|
1884
|
+
if (hasTo2003 && !hasFrom2004) {
|
|
1885
|
+
period = "to-2003";
|
|
1886
|
+
rawCredit = tierTo2003(totalDirect + partnershipContributionsTo2003);
|
|
1887
|
+
if (ceiling == null) {
|
|
1888
|
+
issues.push("Alberta Schedule 8: remainingBasicTax (000068 − (000070+000071+000072)) was not supplied, so no political contributions credit can be claimed for the 2003-or-earlier rate period.");
|
|
1889
|
+
credit = 0;
|
|
1890
|
+
} else credit = Math.max(0, Math.round(Math.min(rawCredit, 750, ceiling)));
|
|
1891
|
+
} else if (hasFrom2004 && !hasTo2003) {
|
|
1892
|
+
period = "from-2004";
|
|
1893
|
+
rawCredit = tierFrom2004(totalDirect + partnershipContributionsFrom2004);
|
|
1894
|
+
if (ceiling == null) {
|
|
1895
|
+
issues.push("Alberta Schedule 8: remainingBasicTax (000068 − (000070+000071+000072)) was not supplied, so no political contributions credit can be claimed for the 2004-or-later rate period.");
|
|
1896
|
+
credit = 0;
|
|
1897
|
+
} else credit = Math.max(0, Math.round(Math.min(rawCredit, 1e3, ceiling)));
|
|
1898
|
+
} else if (taxYearStraddles2003to2004) {
|
|
1899
|
+
period = "straddle-2003-2004";
|
|
1900
|
+
const x = directIn2004Only + partnershipContributionsFrom2004;
|
|
1901
|
+
const y = totalDirect + partnershipContributionsTo2003 + partnershipContributionsFrom2004;
|
|
1902
|
+
const a = Math.min(y, 150);
|
|
1903
|
+
const b = Math.min(Math.max(0, x - a), 50);
|
|
1904
|
+
const c = Math.min(Math.max(0, y - (a + b)), 675);
|
|
1905
|
+
const d = Math.min(Math.max(0, x - (a + b + c)), 225);
|
|
1906
|
+
const e = Math.min(Math.max(0, y - (a + b + c + d)), 900);
|
|
1907
|
+
const f = Math.min(Math.max(0, x - (a + b + c + d + e)), 300);
|
|
1908
|
+
rawCredit = .75 * a + .75 * b + .5 * c + .5 * d + e / 3 + f / 3;
|
|
1909
|
+
credit = Math.max(0, Math.round(rawCredit));
|
|
1910
|
+
} else {
|
|
1911
|
+
period = "none";
|
|
1912
|
+
rawCredit = 0;
|
|
1913
|
+
credit = 0;
|
|
1914
|
+
issues.push("Alberta Schedule 8: contributions span both the 2003-or-earlier and 2004-or-later rate periods, but the tax year does not begin in 2003 and end in 2004 — the spec only defines a mixed-period formula for that straddling tax year. No credit computed.");
|
|
1915
|
+
}
|
|
1916
|
+
return {
|
|
1917
|
+
contributions,
|
|
1918
|
+
partnershipContributionsTo2003,
|
|
1919
|
+
partnershipContributionsFrom2004,
|
|
1920
|
+
period,
|
|
1921
|
+
creditBeforeCeiling: Math.round(rawCredit),
|
|
1922
|
+
credit,
|
|
1923
|
+
issues
|
|
1924
|
+
};
|
|
1925
|
+
}
|
|
1926
|
+
/**
|
|
1927
|
+
* Net File line items for AT1 Schedule 8: one PCD occurrence per contribution
|
|
1928
|
+
* (002 name, 004 receipt number, 006 date, 008 amount), plus the two APC
|
|
1929
|
+
* partnership totals (012, 013).
|
|
1930
|
+
*
|
|
1931
|
+
* Does NOT emit jacket line 000074 (the actual tax credit) — that is a
|
|
1932
|
+
* jacket line, not a Schedule 8 line. Use `result.credit` for that.
|
|
1933
|
+
*/
|
|
1934
|
+
function schedule8Values(result) {
|
|
1935
|
+
const values = [];
|
|
1936
|
+
result.contributions.forEach((c, i) => {
|
|
1937
|
+
const n = i + 1;
|
|
1938
|
+
const put = (fieldId, value) => values.push({
|
|
1939
|
+
lineItemId: at1LineItemId("008", fieldId, n),
|
|
1940
|
+
value
|
|
1941
|
+
});
|
|
1942
|
+
put("002", c.name);
|
|
1943
|
+
put("004", c.receiptNumber);
|
|
1944
|
+
put("006", c.dateOfDonation);
|
|
1945
|
+
put("008", Math.max(0, Math.round(c.amount)));
|
|
1946
|
+
});
|
|
1947
|
+
values.push({
|
|
1948
|
+
lineItemId: at1LineItemId("008", "012"),
|
|
1949
|
+
value: result.partnershipContributionsTo2003
|
|
1950
|
+
});
|
|
1951
|
+
values.push({
|
|
1952
|
+
lineItemId: at1LineItemId("008", "013"),
|
|
1953
|
+
value: result.partnershipContributionsFrom2004
|
|
1954
|
+
});
|
|
1955
|
+
return {
|
|
1956
|
+
scheduleId: "008",
|
|
1957
|
+
values
|
|
1958
|
+
};
|
|
1959
|
+
}
|
|
1960
|
+
//#endregion
|
|
1961
|
+
//#region src/t2/at1/schedules/schedule9-sred-tax-credit.ts
|
|
1962
|
+
const nn$27 = (v) => Math.max(0, Math.round(v ?? 0));
|
|
1963
|
+
/** Signed whole-dollar rounding, for fields the spec marks "+/-". */
|
|
1964
|
+
const signed = (v) => Math.round(v);
|
|
1965
|
+
/** 009120's flat rate — "lesser of line 009031 and 009108 X 10%". */
|
|
1966
|
+
const ALBERTA_SRED_TAX_CREDIT_RATE = .1;
|
|
1967
|
+
/** Alberta's SR&ED program did not exist before this date (line 009104's note). */
|
|
1968
|
+
const ALBERTA_SRED_PROGRAM_START = "2009-01-01";
|
|
1969
|
+
/** Alberta SR&ED expenditures carried out after this date are not eligible (module docstring). */
|
|
1970
|
+
const ALBERTA_SRED_EXPENDITURE_CUTOFF = "2019-12-31";
|
|
1971
|
+
/**
|
|
1972
|
+
* 009104 / 009206's day-prorated $4,000,000 expenditure limit. Days are clamped
|
|
1973
|
+
* to [0, 366] — 366 only for a year genuinely spanning a February 29, per the
|
|
1974
|
+
* spec's own note.
|
|
1975
|
+
*/
|
|
1976
|
+
function computeSchedule9MaximumExpenditureLimit(daysInTaxYear = 365) {
|
|
1977
|
+
return Math.round(4e6 * (Math.max(0, Math.min(daysInTaxYear, 366)) / 365));
|
|
1978
|
+
}
|
|
1979
|
+
function computeAlbertaSchedule9(input) {
|
|
1980
|
+
const issues = [];
|
|
1981
|
+
const federalQualifiedExpenditures = nn$27(input.federalQualifiedExpenditures);
|
|
1982
|
+
const albertaPortionOfExpenditures = nn$27(input.albertaPortionOfExpenditures);
|
|
1983
|
+
const federalProxyAmountInAlbertaPortion = nn$27(input.federalProxyAmountInAlbertaPortion);
|
|
1984
|
+
const albertaProxyAmount = nn$27(input.albertaProxyAmount);
|
|
1985
|
+
const albertaCreditReducingFederalExpense = nn$27(input.albertaCreditReducingFederalExpense);
|
|
1986
|
+
const priorYearFederalItcReceived = nn$27(input.priorYearFederalItcReceived);
|
|
1987
|
+
const totalAlbertaExpendituresAllYears = nn$27(input.totalAlbertaExpendituresAllYears);
|
|
1988
|
+
const totalFederalExpendituresAllYears = nn$27(input.totalFederalExpendituresAllYears);
|
|
1989
|
+
const albertaPortionOfRepayments = nn$27(input.albertaPortionOfRepayments);
|
|
1990
|
+
const disposalRecapture = nn$27(input.disposalRecapture);
|
|
1991
|
+
const priorYearFederalItcAdjustment = nn$27(input.priorYearFederalItcAdjustment);
|
|
1992
|
+
if (albertaPortionOfExpenditures > federalQualifiedExpenditures) issues.push(`Alberta Schedule 9: the Alberta portion of expenditures (009005 = ${albertaPortionOfExpenditures}) exceeds the federal total (009003 = ${federalQualifiedExpenditures}). 009005 must not exceed 009003.`);
|
|
1993
|
+
const priorYearItcAlbertaPortion = totalFederalExpendituresAllYears > 0 ? Math.round(priorYearFederalItcReceived * totalAlbertaExpendituresAllYears / totalFederalExpendituresAllYears) : 0;
|
|
1994
|
+
if (totalFederalExpendituresAllYears === 0 && priorYearFederalItcReceived > 0) issues.push("Alberta Schedule 9: a prior-year federal ITC (009015) was supplied but total federal expenditures for those years (009019) is nil, so no Alberta portion (009023) could be allocated. Supply 009019 if a prior-year ITC allocation is expected.");
|
|
1995
|
+
const derivedEligibleExpenditures = albertaPortionOfExpenditures - federalProxyAmountInAlbertaPortion + albertaProxyAmount + albertaCreditReducingFederalExpense - priorYearItcAlbertaPortion + albertaPortionOfRepayments;
|
|
1996
|
+
const eligibleExpenditures = input.eligibleExpenditures !== void 0 ? signed(input.eligibleExpenditures) : derivedEligibleExpenditures;
|
|
1997
|
+
if (input.eligibleExpenditures === void 0) issues.push(`Alberta Schedule 9: line 009031 ("Total eligible expenditures for Alberta purposes") has no formula in the TRA spec's mapping tables (the text jumps from 009025 to 009040). Derived here as 005 − 007 + 009 + 011 − 023 + 025 = ${derivedEligibleExpenditures}, from the lines the spec captions unambiguously "Deduct"/"Add". Supply eligibleExpenditures directly to override with the authoritative figure — see the Guide to Claiming the Alberta SR&ED Tax Credit.`);
|
|
1998
|
+
if (input.fieldOfScience === void 0) issues.push("Alberta Schedule 9: line 009040 (primary field of science or technology) is mandatory on the live form and was not supplied.");
|
|
1999
|
+
const isAssociated = input.isAssociated ?? false;
|
|
2000
|
+
const nonAssociatedMaximumExpenditureLimit = computeSchedule9MaximumExpenditureLimit(input.daysInTaxYear ?? 365);
|
|
2001
|
+
let maximumExpenditureLimit;
|
|
2002
|
+
if (isAssociated) if (input.allocatedExpenditureLimit === void 0) {
|
|
2003
|
+
issues.push("Alberta Schedule 9: the corporation is associated (009100 = 1) but no allocated expenditure limit (009102) was supplied. Complete the Allocation of the Maximum Expenditure Limit (page 3) and pass its result as allocatedExpenditureLimit — see allocateSchedule9ExpenditureLimit.");
|
|
2004
|
+
maximumExpenditureLimit = 0;
|
|
2005
|
+
} else maximumExpenditureLimit = nn$27(input.allocatedExpenditureLimit);
|
|
2006
|
+
else maximumExpenditureLimit = nonAssociatedMaximumExpenditureLimit;
|
|
2007
|
+
if (input.taxationYearEnd !== void 0 && input.taxationYearEnd > "2019-12-31") issues.push(`Alberta Schedule 9: the taxation year end (${input.taxationYearEnd}) falls after ${ALBERTA_SRED_EXPENDITURE_CUTOFF}. The Alberta SR&ED Tax Credit may not be claimed for expenditures carried out in Alberta after that date — confirm albertaPortionOfExpenditures (009005) excludes any post-cutoff spending.`);
|
|
2008
|
+
const netCredit = Math.round(Math.min(eligibleExpenditures, maximumExpenditureLimit) * ALBERTA_SRED_TAX_CREDIT_RATE) - disposalRecapture - priorYearFederalItcAdjustment;
|
|
2009
|
+
return {
|
|
2010
|
+
federalQualifiedExpenditures,
|
|
2011
|
+
albertaPortionOfExpenditures,
|
|
2012
|
+
federalProxyAmountInAlbertaPortion,
|
|
2013
|
+
albertaProxyAmount,
|
|
2014
|
+
albertaCreditReducingFederalExpense,
|
|
2015
|
+
priorYearFederalItcReceived,
|
|
2016
|
+
totalAlbertaExpendituresAllYears,
|
|
2017
|
+
totalFederalExpendituresAllYears,
|
|
2018
|
+
priorYearItcAlbertaPortion,
|
|
2019
|
+
albertaPortionOfRepayments,
|
|
2020
|
+
eligibleExpenditures,
|
|
2021
|
+
derivedEligibleExpenditures,
|
|
2022
|
+
fieldOfScience: input.fieldOfScience,
|
|
2023
|
+
isAssociated,
|
|
2024
|
+
nonAssociatedMaximumExpenditureLimit,
|
|
2025
|
+
maximumExpenditureLimit,
|
|
2026
|
+
disposalRecapture,
|
|
2027
|
+
priorYearFederalItcAdjustment,
|
|
2028
|
+
netCredit,
|
|
2029
|
+
issues
|
|
2030
|
+
};
|
|
2031
|
+
}
|
|
2032
|
+
/**
|
|
2033
|
+
* Allocate the day-prorated $4,000,000 maximum expenditure limit among an
|
|
2034
|
+
* associated group (page 3). Per the spec, EACH occurrence of 009240 and the
|
|
2035
|
+
* SUM of all occurrences are independently capped at the limit — unlike a
|
|
2036
|
+
* running-remainder split, one member requesting more than the limit does not
|
|
2037
|
+
* consume another member's room; it is simply capped and flagged.
|
|
2038
|
+
*/
|
|
2039
|
+
function allocateSchedule9ExpenditureLimit(daysInLongestYear, requested) {
|
|
2040
|
+
const issues = [];
|
|
2041
|
+
const days = Math.max(0, Math.min(daysInLongestYear, 366));
|
|
2042
|
+
const maximumExpenditureLimit = computeSchedule9MaximumExpenditureLimit(days);
|
|
2043
|
+
const members = requested.map((m) => {
|
|
2044
|
+
const requestedAmount = nn$27(m.allocated);
|
|
2045
|
+
if (requestedAmount > maximumExpenditureLimit) issues.push(`Alberta Schedule 9: ${m.name} was allocated ${requestedAmount}, exceeding the maximum expenditure limit of ${maximumExpenditureLimit} (009240 cannot exceed $4,000,000 x 009206/365). Capped at ${maximumExpenditureLimit}.`);
|
|
2046
|
+
return {
|
|
2047
|
+
name: m.name,
|
|
2048
|
+
...m.albertaCan !== void 0 ? { albertaCan: m.albertaCan } : {},
|
|
2049
|
+
allocated: Math.min(requestedAmount, maximumExpenditureLimit)
|
|
2050
|
+
};
|
|
2051
|
+
});
|
|
2052
|
+
const totalAllocated = members.reduce((s, m) => s + m.allocated, 0);
|
|
2053
|
+
if (totalAllocated > maximumExpenditureLimit) issues.push(`Alberta Schedule 9: the associated group allocated a total of ${totalAllocated}, exceeding the maximum expenditure limit of ${maximumExpenditureLimit} (the sum of all 009240 occurrences cannot exceed $4,000,000 x 009206/365). The group must agree a valid split.`);
|
|
2054
|
+
return {
|
|
2055
|
+
daysInLongestYear: days,
|
|
2056
|
+
maximumExpenditureLimit,
|
|
2057
|
+
members,
|
|
2058
|
+
totalAllocated,
|
|
2059
|
+
claimantAllocatedAmount: members[0]?.allocated ?? 0,
|
|
2060
|
+
unallocated: Math.max(0, maximumExpenditureLimit - totalAllocated),
|
|
2061
|
+
issues
|
|
2062
|
+
};
|
|
2063
|
+
}
|
|
2064
|
+
function schedule9LineItemId(fieldId, occurrence = 1) {
|
|
2065
|
+
return `009${fieldId}${String(occurrence).padStart(3, "0")}`;
|
|
2066
|
+
}
|
|
2067
|
+
/**
|
|
2068
|
+
* Field ids per the spec transcription in the module docstring: 003-025 (the
|
|
2069
|
+
* expenditure buildup), 040 (field of science), 100-120 (the credit
|
|
2070
|
+
* calculation), and — when `group` is supplied — 200-240 (page 3's
|
|
2071
|
+
* allocation). Line 031 has no confirmed transmitted status of its own (see
|
|
2072
|
+
* the module docstring's "line 009031 has no formula in the spec text"), but
|
|
2073
|
+
* is filed anyway alongside 106 since both carry the identical "Total
|
|
2074
|
+
* eligible expenditures for Alberta purposes" figure per the spec's own
|
|
2075
|
+
* cross-reference ("106 ... Value must equal 009031").
|
|
2076
|
+
*/
|
|
2077
|
+
function schedule9Values(result, group) {
|
|
2078
|
+
const values = [];
|
|
2079
|
+
const put = (fieldId, value) => values.push({
|
|
2080
|
+
lineItemId: schedule9LineItemId(fieldId),
|
|
2081
|
+
value
|
|
2082
|
+
});
|
|
2083
|
+
put("003", result.federalQualifiedExpenditures);
|
|
2084
|
+
put("005", result.albertaPortionOfExpenditures);
|
|
2085
|
+
put("007", result.federalProxyAmountInAlbertaPortion);
|
|
2086
|
+
put("009", result.albertaProxyAmount);
|
|
2087
|
+
put("011", result.albertaCreditReducingFederalExpense);
|
|
2088
|
+
put("015", result.priorYearFederalItcReceived);
|
|
2089
|
+
put("017", result.totalAlbertaExpendituresAllYears);
|
|
2090
|
+
put("019", result.totalFederalExpendituresAllYears);
|
|
2091
|
+
put("023", result.priorYearItcAlbertaPortion);
|
|
2092
|
+
put("025", result.albertaPortionOfRepayments);
|
|
2093
|
+
put("031", result.eligibleExpenditures);
|
|
2094
|
+
if (result.fieldOfScience !== void 0) put("040", result.fieldOfScience);
|
|
2095
|
+
put("100", result.isAssociated ? 1 : 2);
|
|
2096
|
+
if (result.isAssociated) put("102", result.maximumExpenditureLimit);
|
|
2097
|
+
else put("104", result.nonAssociatedMaximumExpenditureLimit);
|
|
2098
|
+
put("106", result.eligibleExpenditures);
|
|
2099
|
+
put("108", result.maximumExpenditureLimit);
|
|
2100
|
+
put("112", result.disposalRecapture);
|
|
2101
|
+
put("116", result.priorYearFederalItcAdjustment);
|
|
2102
|
+
put("120", result.netCredit);
|
|
2103
|
+
if (group) {
|
|
2104
|
+
if (group.longestYearCan !== void 0) values.push({
|
|
2105
|
+
lineItemId: schedule9LineItemId("200"),
|
|
2106
|
+
value: group.longestYearCan
|
|
2107
|
+
});
|
|
2108
|
+
if (group.longestYearBegin !== void 0) values.push({
|
|
2109
|
+
lineItemId: schedule9LineItemId("202"),
|
|
2110
|
+
value: group.longestYearBegin
|
|
2111
|
+
});
|
|
2112
|
+
if (group.longestYearEnd !== void 0) values.push({
|
|
2113
|
+
lineItemId: schedule9LineItemId("204"),
|
|
2114
|
+
value: group.longestYearEnd
|
|
2115
|
+
});
|
|
2116
|
+
values.push({
|
|
2117
|
+
lineItemId: schedule9LineItemId("206"),
|
|
2118
|
+
value: group.allocation.daysInLongestYear
|
|
2119
|
+
});
|
|
2120
|
+
group.allocation.members.forEach((m, i) => {
|
|
2121
|
+
const occurrence = i + 1;
|
|
2122
|
+
values.push({
|
|
2123
|
+
lineItemId: schedule9LineItemId("220", occurrence),
|
|
2124
|
+
value: m.name
|
|
2125
|
+
});
|
|
2126
|
+
if (m.albertaCan !== void 0) values.push({
|
|
2127
|
+
lineItemId: schedule9LineItemId("230", occurrence),
|
|
2128
|
+
value: m.albertaCan
|
|
2129
|
+
});
|
|
2130
|
+
values.push({
|
|
2131
|
+
lineItemId: schedule9LineItemId("240", occurrence),
|
|
2132
|
+
value: m.allocated
|
|
2133
|
+
});
|
|
2134
|
+
});
|
|
2135
|
+
}
|
|
2136
|
+
return {
|
|
2137
|
+
scheduleId: "009",
|
|
2138
|
+
values
|
|
2139
|
+
};
|
|
2140
|
+
}
|
|
2141
|
+
//#endregion
|
|
2142
|
+
//#region src/t2/at1/schedules/schedule11-manufacturing-processing.ts
|
|
2143
|
+
const nn$26 = (v) => Math.max(0, Math.round(v ?? 0));
|
|
2144
|
+
function computeSchedule11(input) {
|
|
2145
|
+
const issues = [];
|
|
2146
|
+
const dateEligible = input.taxYearStart < "2001-04-01";
|
|
2147
|
+
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.`);
|
|
2148
|
+
let grossRevenueRatio;
|
|
2149
|
+
let revenueEligible = true;
|
|
2150
|
+
if (dateEligible) if (input.manufacturingGrossRevenue == null || input.totalGrossRevenue == null) {
|
|
2151
|
+
revenueEligible = false;
|
|
2152
|
+
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.");
|
|
2153
|
+
} else {
|
|
2154
|
+
const total = nn$26(input.totalGrossRevenue);
|
|
2155
|
+
grossRevenueRatio = total > 0 ? nn$26(input.manufacturingGrossRevenue) / total : 0;
|
|
2156
|
+
if (grossRevenueRatio < .1) {
|
|
2157
|
+
revenueEligible = false;
|
|
2158
|
+
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.`);
|
|
2159
|
+
}
|
|
2160
|
+
}
|
|
2161
|
+
const eligible = dateEligible && revenueEligible;
|
|
2162
|
+
let albertaAdjubi;
|
|
2163
|
+
if (input.albertaAdjubiFromSchedule12) albertaAdjubi = Math.max(0, Math.round(input.albertaAdjubiFromSchedule12.line112 + input.albertaAdjubiFromSchedule12.line114));
|
|
2164
|
+
else {
|
|
2165
|
+
albertaAdjubi = nn$26(input.federalAdjubi);
|
|
2166
|
+
if (input.federalAdjubi == null && eligible) issues.push("Schedule 11: neither `federalAdjubi` (fed 027130) nor `albertaAdjubiFromSchedule12` was supplied; line 011001 defaults to nil.");
|
|
2167
|
+
}
|
|
2168
|
+
let aggregateInvestmentIncome;
|
|
2169
|
+
if (input.isCcpc) if (input.schedule12Exists) aggregateInvestmentIncome = nn$26(input.albertaAggregateInvestmentIncome);
|
|
2170
|
+
else {
|
|
2171
|
+
aggregateInvestmentIncome = nn$26(input.federalAggregateInvestmentIncome);
|
|
2172
|
+
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.");
|
|
2173
|
+
}
|
|
2174
|
+
const isSmallManufacturingCorp = input.isSmallManufacturingCorp ?? false;
|
|
2175
|
+
let costOfCapital = 0;
|
|
2176
|
+
let albertaCostOfCapital = 0;
|
|
2177
|
+
let costOfLabour = 0;
|
|
2178
|
+
let albertaCostOfLabour = 0;
|
|
2179
|
+
let albertaManufacturingProcessingProfits = 0;
|
|
2180
|
+
if (isSmallManufacturingCorp) {
|
|
2181
|
+
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.");
|
|
2182
|
+
if (input.smallManufacturerAmpp != null) albertaManufacturingProcessingProfits = nn$26(input.smallManufacturerAmpp);
|
|
2183
|
+
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.");
|
|
2184
|
+
} else {
|
|
2185
|
+
costOfCapital = nn$26(input.costOfCapital);
|
|
2186
|
+
albertaCostOfCapital = nn$26(input.albertaCostOfCapital);
|
|
2187
|
+
costOfLabour = nn$26(input.costOfLabour);
|
|
2188
|
+
albertaCostOfLabour = nn$26(input.albertaCostOfLabour);
|
|
2189
|
+
if (albertaCostOfCapital > costOfCapital) {
|
|
2190
|
+
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}.`);
|
|
2191
|
+
albertaCostOfCapital = costOfCapital;
|
|
2192
|
+
}
|
|
2193
|
+
if (albertaCostOfLabour > costOfLabour) {
|
|
2194
|
+
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}.`);
|
|
2195
|
+
albertaCostOfLabour = costOfLabour;
|
|
2196
|
+
}
|
|
2197
|
+
const denominator = costOfCapital + costOfLabour;
|
|
2198
|
+
if (denominator === 0) {
|
|
2199
|
+
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.");
|
|
2200
|
+
} else {
|
|
2201
|
+
const factor = (Math.min(albertaCostOfCapital * 100 / 85, costOfCapital) + Math.min(albertaCostOfLabour * 100 / 75, costOfLabour)) / denominator;
|
|
2202
|
+
albertaManufacturingProcessingProfits = Math.round(albertaAdjubi * factor);
|
|
2203
|
+
}
|
|
2204
|
+
}
|
|
2205
|
+
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.`);
|
|
2206
|
+
if (!eligible) albertaManufacturingProcessingProfits = 0;
|
|
2207
|
+
return {
|
|
2208
|
+
eligible,
|
|
2209
|
+
isSmallManufacturingCorp,
|
|
2210
|
+
albertaAdjubi,
|
|
2211
|
+
...aggregateInvestmentIncome !== void 0 ? { aggregateInvestmentIncome } : {},
|
|
2212
|
+
costOfCapital,
|
|
2213
|
+
albertaCostOfCapital,
|
|
2214
|
+
costOfLabour,
|
|
2215
|
+
albertaCostOfLabour,
|
|
2216
|
+
albertaManufacturingProcessingProfits,
|
|
2217
|
+
...grossRevenueRatio !== void 0 ? { grossRevenueRatio } : {},
|
|
2218
|
+
issues
|
|
2219
|
+
};
|
|
2220
|
+
}
|
|
2221
|
+
function schedule11LineItemId(fieldId, occurrence = 1) {
|
|
2222
|
+
return `011${fieldId}${String(occurrence).padStart(3, "0")}`;
|
|
2223
|
+
}
|
|
2224
|
+
/**
|
|
2225
|
+
* Field ids per the spec transcription above: 001 (AMPPD/ADJUBI), 013 (CCPC
|
|
2226
|
+
* aggregate investment income), 031/033/037/039 (cost of capital/labour, both
|
|
2227
|
+
* jurisdictions) and 042 (Alberta M&P Profits).
|
|
2228
|
+
*
|
|
2229
|
+
* Line 042 is ALWAYS emitted, including when the historical-eligibility gate
|
|
2230
|
+
* (pre-2001-04-01 tax year AND the 10% gross-revenue test) has forced it to
|
|
2231
|
+
* nil — an ineligible year still has a line 011042 on the form, and it reads
|
|
2232
|
+
* nil, so this files nil rather than omitting the line entirely. The REASON
|
|
2233
|
+
* it is nil (a `Schedule 11: … applies only where the tax year begins before
|
|
2234
|
+
* 2001-04-01 …` / `… below the 10% threshold …` entry) lives on
|
|
2235
|
+
* `result.issues`, which this builder does not carry onto the wire itself —
|
|
2236
|
+
* the caller already has `result` (this function's own input) and so already
|
|
2237
|
+
* has `result.issues` sitting beside whatever this returns; duplicating it
|
|
2238
|
+
* onto `At1ScheduleDataLike`, which has no field for prose, would only be
|
|
2239
|
+
* losing information conversion by not adding any.
|
|
2240
|
+
*
|
|
2241
|
+
* Line 013 (CCPC aggregate investment income) is the one line legitimately
|
|
2242
|
+
* OMITTED rather than filed as nil: it is undefined, not zero, for a non-CCPC
|
|
2243
|
+
* corporation — the spec's own business rule gates it on `000029 = 1 or 2`,
|
|
2244
|
+
* so a non-CCPC has no box to fill here at all, unlike line 042's "nil is a
|
|
2245
|
+
* real answer" case above.
|
|
2246
|
+
*/
|
|
2247
|
+
function schedule11Values(result) {
|
|
2248
|
+
const values = [];
|
|
2249
|
+
const put = (fieldId, value) => values.push({
|
|
2250
|
+
lineItemId: schedule11LineItemId(fieldId),
|
|
2251
|
+
value
|
|
2252
|
+
});
|
|
2253
|
+
put("001", result.albertaAdjubi);
|
|
2254
|
+
if (result.aggregateInvestmentIncome !== void 0) put("013", result.aggregateInvestmentIncome);
|
|
2255
|
+
put("031", result.costOfCapital);
|
|
2256
|
+
put("033", result.albertaCostOfCapital);
|
|
2257
|
+
put("037", result.costOfLabour);
|
|
2258
|
+
put("039", result.albertaCostOfLabour);
|
|
2259
|
+
put("042", result.albertaManufacturingProcessingProfits);
|
|
2260
|
+
return {
|
|
2261
|
+
scheduleId: "011",
|
|
2262
|
+
values
|
|
2263
|
+
};
|
|
2264
|
+
}
|
|
2265
|
+
//#endregion
|
|
2266
|
+
//#region src/t2/at1/schedules/schedule15-resource-related-deductions.ts
|
|
2267
|
+
/**
|
|
2268
|
+
* Alberta AT1 Schedule 15 — Alberta Resource Related Deductions.
|
|
2269
|
+
*
|
|
2270
|
+
* Source: `research/sources/tra-spec/AT1-Chapter3-2025.2-full.txt`, lines
|
|
2271
|
+
* 12394-15937 (§3.2.3.16 "Schedule 15 - Alberta Resource Related Deductions").
|
|
2272
|
+
* There is NO standalone AT1SCH15 PDF under `research/sources/tra-forms/pdf/`
|
|
2273
|
+
* (unlike schedules 1, 2, 10, 12, 13, 16, 17, 18, 20, 21, 29, which all have
|
|
2274
|
+
* one) — the NetFile mapping spec above is the ONLY source available for this
|
|
2275
|
+
* schedule, so every field below is cited to that text file alone and cannot
|
|
2276
|
+
* be cross-checked against a rendered form layout.
|
|
2277
|
+
*
|
|
2278
|
+
* Like AT1 Schedule 18 (dispositions) and Schedule 13 (CCA), this is a
|
|
2279
|
+
* RECONCILIATION overlay, not a second engine: for most lines, the Alberta
|
|
2280
|
+
* figure defaults to the corresponding FEDERAL pool figure, and only the
|
|
2281
|
+
* lines where Alberta actually diverges are entered. The form is forbidden
|
|
2282
|
+
* when the return declares no Alberta/federal divergence (000060 AND 000061
|
|
2283
|
+
* both 2) and required when the opening balance or the claim for Alberta
|
|
2284
|
+
* purposes differs from federal (line 015 gating text, source lines
|
|
2285
|
+
* 12444-12456).
|
|
2286
|
+
*
|
|
2287
|
+
* Despite the task brief's expectation of a "resource allowance" pool, THERE
|
|
2288
|
+
* IS NO resource-allowance computation on this schedule — the federal
|
|
2289
|
+
* resource allowance deduction was repealed for taxation years after 1989
|
|
2290
|
+
* (phased out through the mid-1990s) and this schedule is entirely about the
|
|
2291
|
+
* EIGHT resource-expense CONTINUITY pools that survive it:
|
|
2292
|
+
*
|
|
2293
|
+
* EDA — Continuity of Earned Depletion Base (grandfathered; regular +
|
|
2294
|
+
* successor expenses), lines 001-021.
|
|
2295
|
+
* CMEDB — Continuity of Mining Exploration Depletion Base, lines 023-033.
|
|
2296
|
+
* CEE — Cumulative Canadian Exploration Expenses (regular + successor),
|
|
2297
|
+
* lines 041-083.
|
|
2298
|
+
* CDE — Cumulative Canadian Development Expenses (regular + successor),
|
|
2299
|
+
* lines 091-143.
|
|
2300
|
+
* CCOGPE — Cumulative Canadian Oil and Gas Property Expenses (regular +
|
|
2301
|
+
* successor), lines 151-191.
|
|
2302
|
+
* FEDE — Foreign Exploration and Development Expenses (regular +
|
|
2303
|
+
* successor), lines 201-233.
|
|
2304
|
+
* SFEDE — Specified Foreign Exploration and Development Expenses, PER
|
|
2305
|
+
* COUNTRY (regular + successor), lines 241-277.
|
|
2306
|
+
* CFRE — Cumulative Foreign Resource Expenses, PER COUNTRY (regular +
|
|
2307
|
+
* successor), lines 281-317.
|
|
2308
|
+
*
|
|
2309
|
+
* Each pool is modelled as its own `Input`/`Result` pair and its own pure
|
|
2310
|
+
* `computeXxx` function, per this directory's convention (see
|
|
2311
|
+
* `schedule18-dispositions.ts`, `schedule21-year-of-origin.ts`). A single
|
|
2312
|
+
* `computeAlbertaSchedule15` at the bottom composes all eight (accepting the
|
|
2313
|
+
* already-computed CCOGPE results where CDE needs them — see "CCOGPE ↔ CDE
|
|
2314
|
+
* cross-linkage" below) and applies the schedule-level 000060/000061 gate.
|
|
2315
|
+
*
|
|
2316
|
+
* ── Two proration conventions, NOT interchangeable ──────────────────────────
|
|
2317
|
+
*
|
|
2318
|
+
* The current-year-claim caps use TWO different short-tax-year formulas, and
|
|
2319
|
+
* the spec is explicit that they differ:
|
|
2320
|
+
*
|
|
2321
|
+
* - CDE (lines 115, 141) and CCOGPE (lines 169, 189) use a STEP function:
|
|
2322
|
+
* "if days in tax year ≥ 357, cap = rate × pool; if < 357, cap = rate ×
|
|
2323
|
+
* (days/365) × pool" — i.e. the proration is skipped entirely for a
|
|
2324
|
+
* near-full year.
|
|
2325
|
+
* - FEDE (line 209), SFEDE (line 253) and CFRE (lines 293, 313) use a
|
|
2326
|
+
* PLAIN `days/365` multiplier with no 357-day step.
|
|
2327
|
+
*
|
|
2328
|
+
* `stepYearFactor` implements the first; `linearYearFactor` the second. CEE
|
|
2329
|
+
* (lines 061, 081) and EDA/CMEDB have no day-proration at all — CEE is fully
|
|
2330
|
+
* claimable up to the pool balance in one year, no percentage rate applies.
|
|
2331
|
+
*
|
|
2332
|
+
* ── CCOGPE ↔ CDE cross-linkage (FLAGGED, not fully auto-wired) ──────────────
|
|
2333
|
+
*
|
|
2334
|
+
* When a CCOGPE pool's pre-claim subtotal is NEGATIVE, three things in the
|
|
2335
|
+
* spec text interact in a way this module resolves only PARTIALLY:
|
|
2336
|
+
*
|
|
2337
|
+
* 1. CDE line 105 ("Deduct: credit balance in the cumulative Canadian oil
|
|
2338
|
+
* and gas property expense pool", source lines 13604-13622) has its OWN
|
|
2339
|
+
* self-contained formula: `A = 015151+015153+015155+015157-015159-
|
|
2340
|
+
* 015161-015165-015167; if A < 0, value = A; otherwise enter fed
|
|
2341
|
+
* 012330`. This is unconditional — it does not mention the designation
|
|
2342
|
+
* election. This module implements 105 EXACTLY this way, computed from
|
|
2343
|
+
* the already-computed CCOGPE-regular pool subtotal (see
|
|
2344
|
+
* `computeCdeRegular`'s `ccogpeRegular` parameter).
|
|
2345
|
+
* 2. CCOGPE line 169 ("Deduct: current year claim...", source lines
|
|
2346
|
+
* 14281-14370) separately says that when that SAME subtotal A is
|
|
2347
|
+
* negative, it "must be carried forward to 015105" ONLY if the
|
|
2348
|
+
* corporation "has made a designation pursuant to subparagraph
|
|
2349
|
+
* 66.7(4)(a)(iii)" — and to 015133 (CDE SUCCESSOR, not 105) if it has
|
|
2350
|
+
* NOT. This CONTRADICTS (1)'s unconditional reading. Line 189 (source
|
|
2351
|
+
* lines 14646-14661) makes the analogous claim for the CCOGPE-successor
|
|
2352
|
+
* pool: negative → 015133 if designated, or "included in 015167"
|
|
2353
|
+
* (CCOGPE's OWN regular-pool deduction line, not a CDE line) if not.
|
|
2354
|
+
*
|
|
2355
|
+
* This module resolves (1) literally (105 is auto-computed, unconditionally,
|
|
2356
|
+
* from the CCOGPE-regular subtotal) because that is the more specific,
|
|
2357
|
+
* self-contained rule attached directly to line 105 itself. It does NOT
|
|
2358
|
+
* auto-route a negative CCOGPE-successor subtotal into CDE line 133 or back
|
|
2359
|
+
* into CCOGPE-regular line 167, because (a) line 133 has no unconditional
|
|
2360
|
+
* formula of its own — only the ambiguous "value may not exceed amount A"
|
|
2361
|
+
* (source lines 13945-13962), and (b) whether it should land on 133 or 167
|
|
2362
|
+
* hinges on the 66.7(4)(a)(iii) designation, which this schedule has no
|
|
2363
|
+
* source for and no sibling schedule to pull it from. Whenever the CCOGPE-
|
|
2364
|
+
* successor subtotal goes negative, `computeCcogpeSuccessor` raises an issue
|
|
2365
|
+
* naming lines 133/167/189 so a preparer resolves the routing by hand; the
|
|
2366
|
+
* pool's own claim and closing balance are zeroed per the schedule's
|
|
2367
|
+
* unconditional instruction ("enter zero at 015189 and 015191").
|
|
2368
|
+
*
|
|
2369
|
+
* A second, independent anomaly: CCOGPE-successor's own closing balance
|
|
2370
|
+
* formula (line 191, source lines 14731-14740) reads literally as "value =
|
|
2371
|
+
* 015173+015175+015177-015181-015185-015187-015189 **-015167-015169**" when
|
|
2372
|
+
* the pre-subtraction total is positive — i.e. it appears to subtract the
|
|
2373
|
+
* CCOGPE-REGULAR pool's OWN deduction (167) and claim (169) from the
|
|
2374
|
+
* SUCCESSOR pool's closing balance. No other continuity balance on this
|
|
2375
|
+
* schedule mixes fields across the regular/successor split this way, and
|
|
2376
|
+
* nothing else in the 000-series explains why a successor balance would
|
|
2377
|
+
* absorb the regular pool's claim. This module computes 191 with the clean,
|
|
2378
|
+
* schedule-consistent formula (additions − deductions − claim, floored at
|
|
2379
|
+
* zero) and raises an issue quoting the literal spec text whenever 167 or
|
|
2380
|
+
* 169 is non-zero (the only case where the two readings diverge), so a
|
|
2381
|
+
* reviewer can check it against the real form — which, again, has no PDF in
|
|
2382
|
+
* this engine's sources to check against.
|
|
2383
|
+
*
|
|
2384
|
+
* ── Other flagged items ─────────────────────────────────────────────────────
|
|
2385
|
+
*
|
|
2386
|
+
* - CDE line 107 ("Deduct: other deductions or transfers", source lines
|
|
2387
|
+
* 13681-13691) carries a parenthetical "(Note: If 015139 is negative,
|
|
2388
|
+
* include the amount at 015107 as a positive value.)" — there is NO line
|
|
2389
|
+
* 139 anywhere else in this schedule's field list (CDE regular runs
|
|
2390
|
+
* 091-117 with no 108/109/113/114/116/139 gaps that resolve to it, and
|
|
2391
|
+
* no other pool numbers into the 130s except CDE-successor's own 133-137,
|
|
2392
|
+
* which are a different pool entirely). This looks like either an OCR
|
|
2393
|
+
* artifact or a reference to a paper-form-only field outside the NetFile
|
|
2394
|
+
* schema (the same category as Schedule 21's RIFE section). Not modelled;
|
|
2395
|
+
* flagged verbatim whenever the schedule is computed.
|
|
2396
|
+
* - Negative-pool amounts on FEDE, SFEDE and CFRE (claim lines 209, 221,
|
|
2397
|
+
* 253, 273, 293, 313) are, per the spec, "include[d] in 012040" — a
|
|
2398
|
+
* FEDERAL T2 line, entirely outside this schedule and this engine's
|
|
2399
|
+
* stated scope for Schedule 15. This module zeroes the claim/closing per
|
|
2400
|
+
* the schedule's own instruction and raises an issue noting the federal
|
|
2401
|
+
* inclusion is the caller's responsibility elsewhere.
|
|
2402
|
+
* - CFRE line 293's "B" component is capped at "the global foreign
|
|
2403
|
+
* resource limit for the year designated for that country" (source lines
|
|
2404
|
+
* 15703-15711) — a quantity with no definition or source anywhere in
|
|
2405
|
+
* this spec excerpt. Modelled as an optional plain-number INPUT per
|
|
2406
|
+
* country (`globalForeignResourceLimit`); omitting it makes B = 0 (the
|
|
2407
|
+
* conservative, under-claim direction) and raises an issue rather than
|
|
2408
|
+
* inventing a limit.
|
|
2409
|
+
*
|
|
2410
|
+
* Whole dollars, pure functions, no I/O.
|
|
2411
|
+
*/
|
|
2412
|
+
const nn$25 = (v) => Math.max(0, v ?? 0);
|
|
2413
|
+
const num$1 = (v) => v ?? 0;
|
|
2414
|
+
const round = (v) => Math.round(v);
|
|
2415
|
+
/** `override ?? federal`, tracking whether an Alberta-specific figure was actually entered. */
|
|
2416
|
+
function reconcile(federal, override) {
|
|
2417
|
+
return override !== void 0 ? {
|
|
2418
|
+
value: override,
|
|
2419
|
+
differs: true
|
|
2420
|
+
} : {
|
|
2421
|
+
value: num$1(federal),
|
|
2422
|
+
differs: false
|
|
2423
|
+
};
|
|
2424
|
+
}
|
|
2425
|
+
/**
|
|
2426
|
+
* CDE / CCOGPE style short-tax-year proration: the full rate applies with NO
|
|
2427
|
+
* proration once the tax year reaches 357 days; below that, rate × days/365.
|
|
2428
|
+
*/
|
|
2429
|
+
function stepYearFactor(daysInTaxYear) {
|
|
2430
|
+
const days = daysInTaxYear ?? 365;
|
|
2431
|
+
return days >= 357 ? 1 : Math.max(0, days) / 365;
|
|
2432
|
+
}
|
|
2433
|
+
/** FEDE / SFEDE / CFRE style proration: plain days/365, no 357-day step. */
|
|
2434
|
+
function linearYearFactor(daysInTaxYear) {
|
|
2435
|
+
return Math.max(0, daysInTaxYear ?? 365) / 365;
|
|
2436
|
+
}
|
|
2437
|
+
/** A discretionary claim capped at `cap` (≥ 0), defaulting to the maximum (`cap`) when omitted. */
|
|
2438
|
+
function claimUpToCap(requested, cap, issues, label) {
|
|
2439
|
+
const c = Math.max(0, round(cap));
|
|
2440
|
+
if (requested === void 0) return c;
|
|
2441
|
+
if (requested < 0) {
|
|
2442
|
+
issues.push(`${label}: a requested claim of ${requested} is negative; treated as 0.`);
|
|
2443
|
+
return 0;
|
|
2444
|
+
}
|
|
2445
|
+
if (round(requested) > c) {
|
|
2446
|
+
issues.push(`${label}: the requested claim of ${requested} exceeds the maximum allowable ${c} for the year; capped at ${c}.`);
|
|
2447
|
+
return c;
|
|
2448
|
+
}
|
|
2449
|
+
return round(requested);
|
|
2450
|
+
}
|
|
2451
|
+
/**
|
|
2452
|
+
* CEE-style claim: when the pool subtotal is ≤ 0 the claim MUST equal that
|
|
2453
|
+
* (negative or zero) subtotal — an income inclusion, not a deduction — and
|
|
2454
|
+
* any requested figure is overridden. When positive, it is a discretionary
|
|
2455
|
+
* claim up to the subtotal (100% claimable, no percentage rate), defaulting
|
|
2456
|
+
* to the maximum.
|
|
2457
|
+
*/
|
|
2458
|
+
function forcedOrCappedClaim(requested, subtotal, issues, label) {
|
|
2459
|
+
if (subtotal <= 0) {
|
|
2460
|
+
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}.`);
|
|
2461
|
+
return round(subtotal);
|
|
2462
|
+
}
|
|
2463
|
+
return claimUpToCap(requested, subtotal, issues, label);
|
|
2464
|
+
}
|
|
2465
|
+
function computeEdaRegular(input) {
|
|
2466
|
+
const issues = [];
|
|
2467
|
+
const f = input.federal;
|
|
2468
|
+
const o = input.albertaOverride ?? {};
|
|
2469
|
+
const opening = reconcile(f.openingBalance, o.openingBalance);
|
|
2470
|
+
const amalg = reconcile(f.amalgamationTransfer, o.amalgamationTransfer);
|
|
2471
|
+
const sale = reconcile(f.saleTransfer, o.saleTransfer);
|
|
2472
|
+
const poolBeforeClaim = opening.value + amalg.value - sale.value;
|
|
2473
|
+
const claim = pool_cappedClaim(reconcile(f.regulation1201Claim, o.regulation1201Claim), poolBeforeClaim, issues, "Schedule 15 EDA regular (015007)");
|
|
2474
|
+
const closingBalance = poolBeforeClaim - claim.value;
|
|
2475
|
+
return {
|
|
2476
|
+
openingBalance: opening.value,
|
|
2477
|
+
amalgamationTransfer: amalg.value,
|
|
2478
|
+
saleTransfer: sale.value,
|
|
2479
|
+
poolBeforeClaim,
|
|
2480
|
+
claim: claim.value,
|
|
2481
|
+
closingBalance,
|
|
2482
|
+
differsFromFederal: opening.differs || amalg.differs || sale.differs || claim.differs,
|
|
2483
|
+
issues
|
|
2484
|
+
};
|
|
2485
|
+
}
|
|
2486
|
+
/** A reconciled figure that is ALSO capped by a pool — the EDA/CMEDB claim shape (015007, 015019). */
|
|
2487
|
+
function pool_cappedClaim(reconciled, pool, issues, label) {
|
|
2488
|
+
const cap = Math.max(0, round(pool));
|
|
2489
|
+
if (pool <= 0) return {
|
|
2490
|
+
value: 0,
|
|
2491
|
+
differs: reconciled.differs
|
|
2492
|
+
};
|
|
2493
|
+
if (round(reconciled.value) > cap) {
|
|
2494
|
+
issues.push(`${label}: the entered claim ${reconciled.value} exceeds the pool ${cap}; capped.`);
|
|
2495
|
+
return {
|
|
2496
|
+
value: cap,
|
|
2497
|
+
differs: reconciled.differs
|
|
2498
|
+
};
|
|
2499
|
+
}
|
|
2500
|
+
return {
|
|
2501
|
+
value: Math.max(0, round(reconciled.value)),
|
|
2502
|
+
differs: reconciled.differs
|
|
2503
|
+
};
|
|
2504
|
+
}
|
|
2505
|
+
function computeEdaSuccessor(input) {
|
|
2506
|
+
const issues = [];
|
|
2507
|
+
const f = input.federal;
|
|
2508
|
+
const o = input.albertaOverride ?? {};
|
|
2509
|
+
const opening = reconcile(f.openingBalance, o.openingBalance);
|
|
2510
|
+
const amalg = reconcile(f.amalgamationTransfer, o.amalgamationTransfer);
|
|
2511
|
+
const other = reconcile(f.otherTransfer, o.otherTransfer);
|
|
2512
|
+
const sale = reconcile(f.saleTransfer, o.saleTransfer);
|
|
2513
|
+
const poolBeforeClaim = opening.value + amalg.value + other.value - sale.value;
|
|
2514
|
+
const claim = pool_cappedClaim(reconcile(f.regulation1202Claim, o.regulation1202Claim), poolBeforeClaim, issues, "Schedule 15 EDA successor (015019)");
|
|
2515
|
+
const closingBalance = poolBeforeClaim - claim.value;
|
|
2516
|
+
return {
|
|
2517
|
+
openingBalance: opening.value,
|
|
2518
|
+
amalgamationTransfer: amalg.value,
|
|
2519
|
+
otherTransfer: other.value,
|
|
2520
|
+
saleTransfer: sale.value,
|
|
2521
|
+
poolBeforeClaim,
|
|
2522
|
+
claim: claim.value,
|
|
2523
|
+
closingBalance,
|
|
2524
|
+
differsFromFederal: opening.differs || amalg.differs || other.differs || sale.differs || claim.differs,
|
|
2525
|
+
issues
|
|
2526
|
+
};
|
|
2527
|
+
}
|
|
2528
|
+
function computeCmedb(input) {
|
|
2529
|
+
const issues = [];
|
|
2530
|
+
const f = input.federal;
|
|
2531
|
+
const o = input.albertaOverride ?? {};
|
|
2532
|
+
const opening = reconcile(f.openingBalance, o.openingBalance);
|
|
2533
|
+
const amalg = reconcile(f.amalgamationTransfer, o.amalgamationTransfer);
|
|
2534
|
+
const other = reconcile(f.otherTransfer, o.otherTransfer);
|
|
2535
|
+
const disposal = reconcile(f.disposalTransfer, o.disposalTransfer);
|
|
2536
|
+
const poolBeforeClaim = opening.value + amalg.value + other.value - disposal.value;
|
|
2537
|
+
const claim = poolBeforeClaim <= 0 ? 0 : claimUpToCap(input.claimed, poolBeforeClaim, issues, "Schedule 15 CMEDB (015031)");
|
|
2538
|
+
const closingBalance = poolBeforeClaim - claim;
|
|
2539
|
+
return {
|
|
2540
|
+
openingBalance: opening.value,
|
|
2541
|
+
amalgamationTransfer: amalg.value,
|
|
2542
|
+
otherTransfer: other.value,
|
|
2543
|
+
disposalTransfer: disposal.value,
|
|
2544
|
+
poolBeforeClaim,
|
|
2545
|
+
claim,
|
|
2546
|
+
closingBalance,
|
|
2547
|
+
differsFromFederal: opening.differs || amalg.differs || other.differs || disposal.differs,
|
|
2548
|
+
issues
|
|
2549
|
+
};
|
|
2550
|
+
}
|
|
2551
|
+
function computeCeeRegular(input) {
|
|
2552
|
+
const issues = [];
|
|
2553
|
+
const f = input.federal;
|
|
2554
|
+
const o = input.albertaOverride ?? {};
|
|
2555
|
+
const opening = reconcile(f.openingBalance, o.openingBalance);
|
|
2556
|
+
const amalg = reconcile(f.amalgamationTransfer, o.amalgamationTransfer);
|
|
2557
|
+
const otherAdd = reconcile(f.otherAdditions, o.otherAdditions);
|
|
2558
|
+
const otherDed = reconcile(f.otherDeductions, o.otherDeductions);
|
|
2559
|
+
const toSuccessor = reconcile(f.transferredToSuccessor, o.transferredToSuccessor);
|
|
2560
|
+
const currentYearExpenses = num$1(f.currentYearExpenses);
|
|
2561
|
+
const lookBackExpenses = num$1(f.lookBackExpenses);
|
|
2562
|
+
const reclassifiedFromCde = num$1(f.reclassifiedFromCde);
|
|
2563
|
+
const renewableConservationExpenses = num$1(f.renewableConservationExpenses);
|
|
2564
|
+
const governmentAssistance = num$1(f.governmentAssistance);
|
|
2565
|
+
const renouncedFlowThrough = num$1(f.renouncedFlowThrough);
|
|
2566
|
+
const renouncedLookBack = num$1(f.renouncedLookBack);
|
|
2567
|
+
const subtotal = opening.value + currentYearExpenses + lookBackExpenses + reclassifiedFromCde + amalg.value + renewableConservationExpenses + otherAdd.value - governmentAssistance - otherDed.value - renouncedFlowThrough - toSuccessor.value - renouncedLookBack;
|
|
2568
|
+
const claim = forcedOrCappedClaim(input.claimed, subtotal, issues, "Schedule 15 CEE regular (015061)");
|
|
2569
|
+
const closingBalance = subtotal > 0 ? subtotal - claim : 0;
|
|
2570
|
+
return {
|
|
2571
|
+
openingBalance: opening.value,
|
|
2572
|
+
currentYearExpenses,
|
|
2573
|
+
lookBackExpenses,
|
|
2574
|
+
reclassifiedFromCde,
|
|
2575
|
+
amalgamationTransfer: amalg.value,
|
|
2576
|
+
renewableConservationExpenses,
|
|
2577
|
+
otherAdditions: otherAdd.value,
|
|
2578
|
+
governmentAssistance,
|
|
2579
|
+
otherDeductions: otherDed.value,
|
|
2580
|
+
renouncedFlowThrough,
|
|
2581
|
+
transferredToSuccessor: toSuccessor.value,
|
|
2582
|
+
renouncedLookBack,
|
|
2583
|
+
subtotal,
|
|
2584
|
+
claim,
|
|
2585
|
+
closingBalance,
|
|
2586
|
+
differsFromFederal: opening.differs || amalg.differs || otherAdd.differs || otherDed.differs || toSuccessor.differs,
|
|
2587
|
+
issues
|
|
2588
|
+
};
|
|
2589
|
+
}
|
|
2590
|
+
function computeCeeSuccessor(input) {
|
|
2591
|
+
const issues = [];
|
|
2592
|
+
const f = input.federal;
|
|
2593
|
+
const o = input.albertaOverride ?? {};
|
|
2594
|
+
const opening = reconcile(f.openingBalance, o.openingBalance);
|
|
2595
|
+
const reclassified = num$1(f.reclassifiedFromCde);
|
|
2596
|
+
const amalg = reconcile(f.amalgamationTransfer, o.amalgamationTransfer);
|
|
2597
|
+
const other = reconcile(f.otherTransfer, o.otherTransfer);
|
|
2598
|
+
const otherDed = reconcile(f.otherDeductions, o.otherDeductions);
|
|
2599
|
+
const toSuccessor = reconcile(f.transferredToSuccessor, o.transferredToSuccessor);
|
|
2600
|
+
const subtotal = opening.value + reclassified + amalg.value + other.value - otherDed.value - toSuccessor.value;
|
|
2601
|
+
const claim = forcedOrCappedClaim(input.claimed, subtotal, issues, "Schedule 15 CEE successor (015081)");
|
|
2602
|
+
const closingBalance = subtotal - claim;
|
|
2603
|
+
return {
|
|
2604
|
+
openingBalance: opening.value,
|
|
2605
|
+
reclassifiedFromCde: reclassified,
|
|
2606
|
+
amalgamationTransfer: amalg.value,
|
|
2607
|
+
otherTransfer: other.value,
|
|
2608
|
+
otherDeductions: otherDed.value,
|
|
2609
|
+
transferredToSuccessor: toSuccessor.value,
|
|
2610
|
+
subtotal,
|
|
2611
|
+
claim,
|
|
2612
|
+
closingBalance,
|
|
2613
|
+
differsFromFederal: opening.differs || amalg.differs || other.differs || otherDed.differs || toSuccessor.differs,
|
|
2614
|
+
issues
|
|
2615
|
+
};
|
|
2616
|
+
}
|
|
2617
|
+
/** CDE / CCOGPE claim rate — 30% for CDE (ITA s.66.2(2)), applied via `stepYearFactor`. */
|
|
2618
|
+
const CDE_CLAIM_RATE = .3;
|
|
2619
|
+
/** CCOGPE claim rate — 10% (ITA s.66.4(2)/66.7(5)), applied via `stepYearFactor`. */
|
|
2620
|
+
const CCOGPE_CLAIM_RATE = .1;
|
|
2621
|
+
function computeCdeRegular(input, ccogpeRegular) {
|
|
2622
|
+
const issues = [];
|
|
2623
|
+
const f = input.federal;
|
|
2624
|
+
const o = input.albertaOverride ?? {};
|
|
2625
|
+
const opening = reconcile(f.openingBalance, o.openingBalance);
|
|
2626
|
+
const currentYearExpenses = num$1(f.currentYearExpenses);
|
|
2627
|
+
const lookBackExpenses = num$1(f.lookBackExpenses);
|
|
2628
|
+
const amalg = reconcile(f.amalgamationTransfer, o.amalgamationTransfer);
|
|
2629
|
+
const otherAdd = reconcile(f.otherAdditions, o.otherAdditions);
|
|
2630
|
+
const reclassified = num$1(f.reclassifiedFromCee);
|
|
2631
|
+
const governmentAssistance = num$1(f.governmentAssistance);
|
|
2632
|
+
const receivable = reconcile(f.receivableOnDisposition, o.receivableOnDisposition);
|
|
2633
|
+
const creditBalanceReconciled = reconcile(f.creditBalanceInCogpePool, o.creditBalanceInCogpePool);
|
|
2634
|
+
const creditBalance = ccogpeRegular.subtotal < 0 ? {
|
|
2635
|
+
value: round(ccogpeRegular.subtotal),
|
|
2636
|
+
differs: true
|
|
2637
|
+
} : creditBalanceReconciled;
|
|
2638
|
+
const otherDed = reconcile(f.otherDeductions, o.otherDeductions);
|
|
2639
|
+
const renouncedFlowThrough = num$1(f.renouncedFlowThrough);
|
|
2640
|
+
const toSuccessor = reconcile(f.transferredToSuccessor, o.transferredToSuccessor);
|
|
2641
|
+
const renouncedLookBack = num$1(f.renouncedLookBack);
|
|
2642
|
+
const subtotal = opening.value + currentYearExpenses + lookBackExpenses + amalg.value + otherAdd.value - reclassified - governmentAssistance - receivable.value - creditBalance.value - otherDed.value - toSuccessor.value - renouncedFlowThrough - renouncedLookBack;
|
|
2643
|
+
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.");
|
|
2644
|
+
const claim = subtotal > 0 ? claimUpToCap(input.claimed, CDE_CLAIM_RATE * stepYearFactor(input.daysInTaxYear) * subtotal, issues, "Schedule 15 CDE regular (015115)") : 0;
|
|
2645
|
+
const closingBalance = Math.max(0, subtotal - claim);
|
|
2646
|
+
return {
|
|
2647
|
+
openingBalance: opening.value,
|
|
2648
|
+
currentYearExpenses,
|
|
2649
|
+
lookBackExpenses,
|
|
2650
|
+
amalgamationTransfer: amalg.value,
|
|
2651
|
+
otherAdditions: otherAdd.value,
|
|
2652
|
+
reclassifiedFromCee: reclassified,
|
|
2653
|
+
governmentAssistance,
|
|
2654
|
+
receivableOnDisposition: receivable.value,
|
|
2655
|
+
creditBalanceInCogpePool: creditBalance.value,
|
|
2656
|
+
otherDeductions: otherDed.value,
|
|
2657
|
+
renouncedFlowThrough,
|
|
2658
|
+
transferredToSuccessor: toSuccessor.value,
|
|
2659
|
+
renouncedLookBack,
|
|
2660
|
+
subtotal,
|
|
2661
|
+
claim,
|
|
2662
|
+
closingBalance,
|
|
2663
|
+
differsFromFederal: opening.differs || amalg.differs || otherAdd.differs || receivable.differs || creditBalance.differs || otherDed.differs || toSuccessor.differs,
|
|
2664
|
+
issues
|
|
2665
|
+
};
|
|
2666
|
+
}
|
|
2667
|
+
function computeCdeSuccessor(input, ccogpeSuccessor) {
|
|
2668
|
+
const issues = [];
|
|
2669
|
+
const f = input.federal;
|
|
2670
|
+
const o = input.albertaOverride ?? {};
|
|
2671
|
+
const opening = reconcile(f.openingBalance, o.openingBalance);
|
|
2672
|
+
const amalg = reconcile(f.amalgamationTransfer, o.amalgamationTransfer);
|
|
2673
|
+
const other = reconcile(f.otherTransfer, o.otherTransfer);
|
|
2674
|
+
const reclassified = num$1(f.reclassifiedFromCee);
|
|
2675
|
+
const creditBalanceReconciled = reconcile(f.creditBalanceInCogpePool, o.creditBalanceInCogpePool);
|
|
2676
|
+
const creditBalance = ccogpeSuccessor.subtotal < 0 ? {
|
|
2677
|
+
value: round(ccogpeSuccessor.subtotal),
|
|
2678
|
+
differs: true
|
|
2679
|
+
} : creditBalanceReconciled;
|
|
2680
|
+
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.");
|
|
2681
|
+
const otherDed = reconcile(f.otherDeductions, o.otherDeductions);
|
|
2682
|
+
const toSuccessor = reconcile(f.transferredToSuccessor, o.transferredToSuccessor);
|
|
2683
|
+
const subtotal = opening.value + amalg.value + other.value - reclassified - creditBalance.value - otherDed.value - toSuccessor.value;
|
|
2684
|
+
const claim = subtotal > 0 ? claimUpToCap(input.claimed, CDE_CLAIM_RATE * stepYearFactor(input.daysInTaxYear) * subtotal, issues, "Schedule 15 CDE successor (015141)") : 0;
|
|
2685
|
+
const closingBalance = Math.max(0, subtotal - claim);
|
|
2686
|
+
return {
|
|
2687
|
+
openingBalance: opening.value,
|
|
2688
|
+
amalgamationTransfer: amalg.value,
|
|
2689
|
+
otherTransfer: other.value,
|
|
2690
|
+
reclassifiedFromCee: reclassified,
|
|
2691
|
+
creditBalanceInCogpePool: creditBalance.value,
|
|
2692
|
+
otherDeductions: otherDed.value,
|
|
2693
|
+
transferredToSuccessor: toSuccessor.value,
|
|
2694
|
+
subtotal,
|
|
2695
|
+
claim,
|
|
2696
|
+
closingBalance,
|
|
2697
|
+
differsFromFederal: opening.differs || amalg.differs || other.differs || creditBalance.differs || otherDed.differs || toSuccessor.differs,
|
|
2698
|
+
issues
|
|
2699
|
+
};
|
|
2700
|
+
}
|
|
2701
|
+
function computeCcogpeRegular(input) {
|
|
2702
|
+
const issues = [];
|
|
2703
|
+
const f = input.federal;
|
|
2704
|
+
const o = input.albertaOverride ?? {};
|
|
2705
|
+
const opening = reconcile(f.openingBalance, o.openingBalance);
|
|
2706
|
+
const currentYearExpenses = num$1(f.currentYearExpenses);
|
|
2707
|
+
const amalg = reconcile(f.amalgamationTransfer, o.amalgamationTransfer);
|
|
2708
|
+
const otherAdd = reconcile(f.otherAdditions, o.otherAdditions);
|
|
2709
|
+
const receivable = reconcile(f.receivableOnDisposition, o.receivableOnDisposition);
|
|
2710
|
+
const governmentAssistance = num$1(f.governmentAssistance);
|
|
2711
|
+
const toSuccessor = reconcile(f.transferredToSuccessor, o.transferredToSuccessor);
|
|
2712
|
+
const otherDed = reconcile(f.otherDeductions, o.otherDeductions);
|
|
2713
|
+
const subtotal = opening.value + currentYearExpenses + amalg.value + otherAdd.value - receivable.value - governmentAssistance - toSuccessor.value - otherDed.value;
|
|
2714
|
+
let claim = 0;
|
|
2715
|
+
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.");
|
|
2716
|
+
else if (subtotal > 0) claim = claimUpToCap(input.claimed, CCOGPE_CLAIM_RATE * stepYearFactor(input.daysInTaxYear) * subtotal, issues, "Schedule 15 CCOGPE regular (015169)");
|
|
2717
|
+
const closingBalance = subtotal > 0 ? subtotal - claim : 0;
|
|
2718
|
+
return {
|
|
2719
|
+
openingBalance: opening.value,
|
|
2720
|
+
currentYearExpenses,
|
|
2721
|
+
amalgamationTransfer: amalg.value,
|
|
2722
|
+
otherAdditions: otherAdd.value,
|
|
2723
|
+
receivableOnDisposition: receivable.value,
|
|
2724
|
+
governmentAssistance,
|
|
2725
|
+
transferredToSuccessor: toSuccessor.value,
|
|
2726
|
+
otherDeductions: otherDed.value,
|
|
2727
|
+
subtotal,
|
|
2728
|
+
claim,
|
|
2729
|
+
closingBalance,
|
|
2730
|
+
differsFromFederal: opening.differs || amalg.differs || otherAdd.differs || receivable.differs || toSuccessor.differs || otherDed.differs,
|
|
2731
|
+
issues
|
|
2732
|
+
};
|
|
2733
|
+
}
|
|
2734
|
+
function computeCcogpeSuccessor(input) {
|
|
2735
|
+
const issues = [];
|
|
2736
|
+
const f = input.federal;
|
|
2737
|
+
const o = input.albertaOverride ?? {};
|
|
2738
|
+
const opening = reconcile(f.openingBalance, o.openingBalance);
|
|
2739
|
+
const amalg = reconcile(f.amalgamationTransfer, o.amalgamationTransfer);
|
|
2740
|
+
const other = reconcile(f.otherTransfer, o.otherTransfer);
|
|
2741
|
+
const receivable = reconcile(f.receivableOnDisposition, o.receivableOnDisposition);
|
|
2742
|
+
const toSuccessor = reconcile(f.transferredToSuccessor, o.transferredToSuccessor);
|
|
2743
|
+
const otherDed = reconcile(f.otherDeductions, o.otherDeductions);
|
|
2744
|
+
const subtotal = opening.value + amalg.value + other.value - receivable.value - toSuccessor.value - otherDed.value;
|
|
2745
|
+
let claim = 0;
|
|
2746
|
+
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.");
|
|
2747
|
+
else if (subtotal > 0) claim = claimUpToCap(input.claimed, CCOGPE_CLAIM_RATE * stepYearFactor(input.daysInTaxYear) * subtotal, issues, "Schedule 15 CCOGPE successor (015189)");
|
|
2748
|
+
const closingBalance = Math.max(0, subtotal - claim);
|
|
2749
|
+
return {
|
|
2750
|
+
openingBalance: opening.value,
|
|
2751
|
+
amalgamationTransfer: amalg.value,
|
|
2752
|
+
otherTransfer: other.value,
|
|
2753
|
+
receivableOnDisposition: receivable.value,
|
|
2754
|
+
transferredToSuccessor: toSuccessor.value,
|
|
2755
|
+
otherDeductions: otherDed.value,
|
|
2756
|
+
subtotal,
|
|
2757
|
+
claim,
|
|
2758
|
+
closingBalance,
|
|
2759
|
+
differsFromFederal: opening.differs || amalg.differs || other.differs || receivable.differs || toSuccessor.differs || otherDed.differs,
|
|
2760
|
+
issues
|
|
2761
|
+
};
|
|
2762
|
+
}
|
|
2763
|
+
function computeFedeRegular(input) {
|
|
2764
|
+
const issues = [];
|
|
2765
|
+
const f = input.federal;
|
|
2766
|
+
const o = input.albertaOverride ?? {};
|
|
2767
|
+
const opening = reconcile(f.openingBalance, o.openingBalance);
|
|
2768
|
+
const amalg = reconcile(f.amalgamationTransfer, o.amalgamationTransfer);
|
|
2769
|
+
const otherDed = reconcile(f.otherDeductions, o.otherDeductions);
|
|
2770
|
+
const foreignResourceIncome = num$1(f.foreignResourceIncome);
|
|
2771
|
+
const pool = opening.value + amalg.value - otherDed.value;
|
|
2772
|
+
let claim = 0;
|
|
2773
|
+
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.");
|
|
2774
|
+
else if (pool > 0) {
|
|
2775
|
+
const cap = Math.max(CCOGPE_CLAIM_RATE * linearYearFactor(input.daysInTaxYear) * pool, foreignResourceIncome);
|
|
2776
|
+
claim = claimUpToCap(input.claimed, Math.min(pool, cap), issues, "Schedule 15 FEDE regular (015209)");
|
|
2777
|
+
}
|
|
2778
|
+
const closingBalance = pool - claim;
|
|
2779
|
+
return {
|
|
2780
|
+
openingBalance: opening.value,
|
|
2781
|
+
amalgamationTransfer: amalg.value,
|
|
2782
|
+
otherDeductions: otherDed.value,
|
|
2783
|
+
foreignResourceIncome,
|
|
2784
|
+
pool,
|
|
2785
|
+
claim,
|
|
2786
|
+
closingBalance,
|
|
2787
|
+
differsFromFederal: opening.differs || amalg.differs || otherDed.differs,
|
|
2788
|
+
issues
|
|
816
2789
|
};
|
|
817
2790
|
}
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
lineItemId: at1LineItemId("020", fieldId),
|
|
845
|
-
value
|
|
846
|
-
});
|
|
847
|
-
return [
|
|
848
|
-
put(f.opening, result.openingBalance),
|
|
849
|
-
put(f.expired, result.expired),
|
|
850
|
-
put(f.beginning, Math.max(0, result.openingBalance - result.expired)),
|
|
851
|
-
put(f.transferred, result.transferredIn),
|
|
852
|
-
put(f.currentYear, result.currentYearGifts),
|
|
853
|
-
put(f.subtotal, result.transferredIn + result.currentYearGifts),
|
|
854
|
-
put(f.acquisitionOfControl, result.acquisitionOfControlAdjustment),
|
|
855
|
-
put(f.available, result.availableBeforeClaim),
|
|
856
|
-
put(f.applied, result.amountApplied),
|
|
857
|
-
put(f.closing, result.closingBalance)
|
|
858
|
-
];
|
|
2791
|
+
function computeFedeSuccessor(input) {
|
|
2792
|
+
const issues = [];
|
|
2793
|
+
const f = input.federal;
|
|
2794
|
+
const o = input.albertaOverride ?? {};
|
|
2795
|
+
const opening = reconcile(f.openingBalance, o.openingBalance);
|
|
2796
|
+
const amalg = reconcile(f.amalgamationTransfer, o.amalgamationTransfer);
|
|
2797
|
+
const other = reconcile(f.otherTransfer, o.otherTransfer);
|
|
2798
|
+
const otherDed = reconcile(f.otherDeductions, o.otherDeductions);
|
|
2799
|
+
const foreignResourceIncome = num$1(f.foreignResourceIncome);
|
|
2800
|
+
const pool = opening.value + amalg.value + other.value - otherDed.value;
|
|
2801
|
+
let claim = 0;
|
|
2802
|
+
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.");
|
|
2803
|
+
else if (pool > 0) claim = claimUpToCap(input.claimed, Math.min(pool, foreignResourceIncome), issues, "Schedule 15 FEDE successor (015221)");
|
|
2804
|
+
const closingBalance = pool - claim;
|
|
2805
|
+
return {
|
|
2806
|
+
openingBalance: opening.value,
|
|
2807
|
+
amalgamationTransfer: amalg.value,
|
|
2808
|
+
otherTransfer: other.value,
|
|
2809
|
+
otherDeductions: otherDed.value,
|
|
2810
|
+
foreignResourceIncome,
|
|
2811
|
+
pool,
|
|
2812
|
+
claim,
|
|
2813
|
+
closingBalance,
|
|
2814
|
+
differsFromFederal: opening.differs || amalg.differs || other.differs || otherDed.differs,
|
|
2815
|
+
issues
|
|
2816
|
+
};
|
|
859
2817
|
}
|
|
860
|
-
function
|
|
861
|
-
const
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
2818
|
+
function computeSfedeCountryRegular(input) {
|
|
2819
|
+
const issues = [];
|
|
2820
|
+
const f = input.federal;
|
|
2821
|
+
const o = input.albertaOverride ?? {};
|
|
2822
|
+
const opening = reconcile(f.openingBalance, o.openingBalance);
|
|
2823
|
+
const amalg = reconcile(f.amalgamationTransfer, o.amalgamationTransfer);
|
|
2824
|
+
const otherAdd = reconcile(f.otherAdditions, o.otherAdditions);
|
|
2825
|
+
const otherDed = reconcile(f.otherDeductions, o.otherDeductions);
|
|
2826
|
+
const foreignResourceIncome = num$1(f.foreignResourceIncome);
|
|
2827
|
+
const pool = opening.value + amalg.value + otherAdd.value - otherDed.value;
|
|
2828
|
+
let claim = 0;
|
|
2829
|
+
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.`);
|
|
2830
|
+
else if (pool > 0) {
|
|
2831
|
+
const cap = Math.max(CCOGPE_CLAIM_RATE * linearYearFactor(input.daysInTaxYear) * pool, foreignResourceIncome);
|
|
2832
|
+
claim = claimUpToCap(input.claimed, Math.min(pool, cap), issues, `Schedule 15 SFEDE regular, country ${f.countryCode} (015253)`);
|
|
874
2833
|
}
|
|
2834
|
+
const closingBalance = pool - claim;
|
|
875
2835
|
return {
|
|
876
|
-
|
|
877
|
-
|
|
2836
|
+
countryCode: f.countryCode,
|
|
2837
|
+
openingBalance: opening.value,
|
|
2838
|
+
amalgamationTransfer: amalg.value,
|
|
2839
|
+
otherAdditions: otherAdd.value,
|
|
2840
|
+
otherDeductions: otherDed.value,
|
|
2841
|
+
foreignResourceIncome,
|
|
2842
|
+
pool,
|
|
2843
|
+
claim,
|
|
2844
|
+
closingBalance,
|
|
2845
|
+
differsFromFederal: opening.differs || amalg.differs || otherAdd.differs || otherDed.differs,
|
|
2846
|
+
issues
|
|
2847
|
+
};
|
|
2848
|
+
}
|
|
2849
|
+
function computeSfedeCountrySuccessor(input) {
|
|
2850
|
+
const issues = [];
|
|
2851
|
+
const f = input.federal;
|
|
2852
|
+
const o = input.albertaOverride ?? {};
|
|
2853
|
+
const opening = reconcile(f.openingBalance, o.openingBalance);
|
|
2854
|
+
const amalg = reconcile(f.amalgamationTransfer, o.amalgamationTransfer);
|
|
2855
|
+
const other = reconcile(f.otherTransfer, o.otherTransfer);
|
|
2856
|
+
const otherDed = reconcile(f.otherDeductions, o.otherDeductions);
|
|
2857
|
+
const foreignResourceIncome = num$1(f.foreignResourceIncome);
|
|
2858
|
+
const pool = opening.value + amalg.value + other.value - otherDed.value;
|
|
2859
|
+
let claim = 0;
|
|
2860
|
+
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.`);
|
|
2861
|
+
else if (pool > 0) claim = claimUpToCap(input.claimed, Math.min(pool, foreignResourceIncome), issues, `Schedule 15 SFEDE successor, country ${f.countryCode} (015273)`);
|
|
2862
|
+
const closingBalance = pool - claim;
|
|
2863
|
+
return {
|
|
2864
|
+
countryCode: f.countryCode,
|
|
2865
|
+
openingBalance: opening.value,
|
|
2866
|
+
amalgamationTransfer: amalg.value,
|
|
2867
|
+
otherTransfer: other.value,
|
|
2868
|
+
otherDeductions: otherDed.value,
|
|
2869
|
+
foreignResourceIncome,
|
|
2870
|
+
pool,
|
|
2871
|
+
claim,
|
|
2872
|
+
closingBalance,
|
|
2873
|
+
differsFromFederal: opening.differs || amalg.differs || other.differs || otherDed.differs,
|
|
2874
|
+
issues
|
|
878
2875
|
};
|
|
879
2876
|
}
|
|
880
2877
|
/**
|
|
881
|
-
*
|
|
882
|
-
*
|
|
883
|
-
*
|
|
884
|
-
*
|
|
885
|
-
*
|
|
886
|
-
*
|
|
887
|
-
* 016 = 002 − (004 + 006 + 008) + 010 + 012 + 014 + 015
|
|
888
|
-
*
|
|
889
|
-
* and closes the year-over-year chain in as many words: line 022 is *"the carry
|
|
890
|
-
* forward amount for next year, line 012"*.
|
|
2878
|
+
* CFRE regular claims need a second pass across all countries (line 015293's
|
|
2879
|
+
* "A" component caps at "total of all occurrences of 015297"), so this takes
|
|
2880
|
+
* the whole array and the pre-summed `sumForeignResourceIncome` across every
|
|
2881
|
+
* country's own 015297 rather than being called per-entry like the other
|
|
2882
|
+
* per-country pools.
|
|
891
2883
|
*/
|
|
892
|
-
function
|
|
893
|
-
const
|
|
894
|
-
const
|
|
895
|
-
|
|
896
|
-
|
|
2884
|
+
function computeCfreRegular(entries) {
|
|
2885
|
+
const issues = [];
|
|
2886
|
+
const pools = entries.map((e) => {
|
|
2887
|
+
const f = e.federal;
|
|
2888
|
+
const o = e.albertaOverride ?? {};
|
|
2889
|
+
const opening = reconcile(f.openingBalance, o.openingBalance);
|
|
2890
|
+
const currentYearExpenses = num$1(f.currentYearExpenses);
|
|
2891
|
+
const amalg = reconcile(f.amalgamationTransfer, o.amalgamationTransfer);
|
|
2892
|
+
const otherAdd = reconcile(f.otherAdditions, o.otherAdditions);
|
|
2893
|
+
const otherDed = reconcile(f.otherDeductions, o.otherDeductions);
|
|
2894
|
+
return {
|
|
2895
|
+
e,
|
|
2896
|
+
opening,
|
|
2897
|
+
currentYearExpenses,
|
|
2898
|
+
amalg,
|
|
2899
|
+
otherAdd,
|
|
2900
|
+
otherDed,
|
|
2901
|
+
foreignResourceIncome: num$1(f.foreignResourceIncome),
|
|
2902
|
+
pool: opening.value + currentYearExpenses + amalg.value + otherAdd.value - otherDed.value
|
|
2903
|
+
};
|
|
897
2904
|
});
|
|
898
|
-
|
|
899
|
-
put("016", result.subtotal);
|
|
900
|
-
put("018", result.deductionAvailable);
|
|
901
|
-
put("020", result.amountClaimed);
|
|
902
|
-
put("022", result.unclaimedPoolBalance);
|
|
2905
|
+
const sumForeignResourceIncome = pools.reduce((s, p) => s + p.foreignResourceIncome, 0);
|
|
903
2906
|
return {
|
|
904
|
-
|
|
905
|
-
|
|
2907
|
+
entries: pools.map((p) => {
|
|
2908
|
+
const { e, opening, currentYearExpenses, amalg, otherAdd, otherDed, foreignResourceIncome, pool } = p;
|
|
2909
|
+
let claim = 0;
|
|
2910
|
+
if (pool < 0) issues.push(`Schedule 15 CFRE regular, country ${e.federal.countryCode} (015293): 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.`);
|
|
2911
|
+
else if (pool > 0) {
|
|
2912
|
+
const linear = linearYearFactor(e.daysInTaxYear);
|
|
2913
|
+
const partA = Math.max(CCOGPE_CLAIM_RATE * linear * pool, Math.min(CDE_CLAIM_RATE * linear * pool, foreignResourceIncome, sumForeignResourceIncome));
|
|
2914
|
+
const remainder = Math.max(0, pool - partA);
|
|
2915
|
+
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).`);
|
|
2916
|
+
const partB = Math.min(remainder, nn$25(e.globalForeignResourceLimit));
|
|
2917
|
+
claim = claimUpToCap(e.claimed, partA + partB, issues, `Schedule 15 CFRE regular, country ${e.federal.countryCode} (015293)`);
|
|
2918
|
+
}
|
|
2919
|
+
const closingBalance = pool - claim;
|
|
2920
|
+
return {
|
|
2921
|
+
countryCode: e.federal.countryCode,
|
|
2922
|
+
openingBalance: opening.value,
|
|
2923
|
+
currentYearExpenses,
|
|
2924
|
+
amalgamationTransfer: amalg.value,
|
|
2925
|
+
otherAdditions: otherAdd.value,
|
|
2926
|
+
otherDeductions: otherDed.value,
|
|
2927
|
+
foreignResourceIncome,
|
|
2928
|
+
pool,
|
|
2929
|
+
claim,
|
|
2930
|
+
closingBalance,
|
|
2931
|
+
differsFromFederal: opening.differs || amalg.differs || otherAdd.differs || otherDed.differs,
|
|
2932
|
+
issues
|
|
2933
|
+
};
|
|
2934
|
+
}),
|
|
2935
|
+
issues
|
|
906
2936
|
};
|
|
907
2937
|
}
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
const
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
2938
|
+
function computeAlbertaSchedule15(input) {
|
|
2939
|
+
const issues = [];
|
|
2940
|
+
const differsFlags = [];
|
|
2941
|
+
const eda = input.eda ? {
|
|
2942
|
+
regular: computeEdaRegular(input.eda.regular),
|
|
2943
|
+
successor: computeEdaSuccessor(input.eda.successor)
|
|
2944
|
+
} : void 0;
|
|
2945
|
+
if (eda) {
|
|
2946
|
+
issues.push(...eda.regular.issues, ...eda.successor.issues);
|
|
2947
|
+
differsFlags.push(eda.regular.differsFromFederal, eda.successor.differsFromFederal);
|
|
2948
|
+
}
|
|
2949
|
+
const cmedb = input.cmedb ? computeCmedb(input.cmedb) : void 0;
|
|
2950
|
+
if (cmedb) {
|
|
2951
|
+
issues.push(...cmedb.issues);
|
|
2952
|
+
differsFlags.push(cmedb.differsFromFederal);
|
|
2953
|
+
}
|
|
2954
|
+
const cee = input.cee ? {
|
|
2955
|
+
regular: computeCeeRegular(input.cee.regular),
|
|
2956
|
+
successor: computeCeeSuccessor(input.cee.successor)
|
|
2957
|
+
} : void 0;
|
|
2958
|
+
if (cee) {
|
|
2959
|
+
issues.push(...cee.regular.issues, ...cee.successor.issues);
|
|
2960
|
+
differsFlags.push(cee.regular.differsFromFederal, cee.successor.differsFromFederal);
|
|
2961
|
+
}
|
|
2962
|
+
const ccogpe = input.ccogpe ? {
|
|
2963
|
+
regular: computeCcogpeRegular(input.ccogpe.regular),
|
|
2964
|
+
successor: computeCcogpeSuccessor(input.ccogpe.successor)
|
|
2965
|
+
} : void 0;
|
|
2966
|
+
if (ccogpe) {
|
|
2967
|
+
issues.push(...ccogpe.regular.issues, ...ccogpe.successor.issues);
|
|
2968
|
+
differsFlags.push(ccogpe.regular.differsFromFederal, ccogpe.successor.differsFromFederal);
|
|
2969
|
+
}
|
|
2970
|
+
const cde = input.cde ? {
|
|
2971
|
+
regular: computeCdeRegular(input.cde.regular, { subtotal: ccogpe?.regular.subtotal ?? 0 }),
|
|
2972
|
+
successor: computeCdeSuccessor(input.cde.successor, { subtotal: ccogpe?.successor.subtotal ?? 0 })
|
|
2973
|
+
} : void 0;
|
|
2974
|
+
if (cde) {
|
|
2975
|
+
issues.push(...cde.regular.issues, ...cde.successor.issues);
|
|
2976
|
+
differsFlags.push(cde.regular.differsFromFederal, cde.successor.differsFromFederal);
|
|
2977
|
+
if (ccogpe && (ccogpe.regular.otherDeductions !== 0 || ccogpe.regular.claim !== 0)) issues.push("Schedule 15 CCOGPE successor (015191): source lines 14731-14740 read literally as subtracting the CCOGPE-REGULAR pool's own 015167 and 015169 from the SUCCESSOR pool's closing balance, and 015167/015169 are non-zero this year. This module used the clean additions−deductions−claim formula instead (see module doc comment) — confirm against the live TRA form before relying on 015191.");
|
|
2978
|
+
}
|
|
2979
|
+
const fede = input.fede ? {
|
|
2980
|
+
regular: computeFedeRegular(input.fede.regular),
|
|
2981
|
+
successor: computeFedeSuccessor(input.fede.successor)
|
|
2982
|
+
} : void 0;
|
|
2983
|
+
if (fede) {
|
|
2984
|
+
issues.push(...fede.regular.issues, ...fede.successor.issues);
|
|
2985
|
+
differsFlags.push(fede.regular.differsFromFederal, fede.successor.differsFromFederal);
|
|
2986
|
+
}
|
|
2987
|
+
const sfede = input.sfede ? {
|
|
2988
|
+
regular: input.sfede.regular.map(computeSfedeCountryRegular),
|
|
2989
|
+
successor: input.sfede.successor.map(computeSfedeCountrySuccessor)
|
|
2990
|
+
} : void 0;
|
|
2991
|
+
if (sfede) {
|
|
2992
|
+
for (const r of sfede.regular) {
|
|
2993
|
+
issues.push(...r.issues);
|
|
2994
|
+
differsFlags.push(r.differsFromFederal);
|
|
2995
|
+
}
|
|
2996
|
+
for (const s of sfede.successor) {
|
|
2997
|
+
issues.push(...s.issues);
|
|
2998
|
+
differsFlags.push(s.differsFromFederal);
|
|
2999
|
+
}
|
|
3000
|
+
}
|
|
3001
|
+
const cfre = input.cfre ? {
|
|
3002
|
+
regular: computeCfreRegular(input.cfre.regular),
|
|
3003
|
+
successor: computeCfreSuccessor(input.cfre.successor)
|
|
3004
|
+
} : void 0;
|
|
3005
|
+
if (cfre) {
|
|
3006
|
+
issues.push(...cfre.regular.issues, ...cfre.successor.issues);
|
|
3007
|
+
for (const r of cfre.regular.entries) differsFlags.push(r.differsFromFederal);
|
|
3008
|
+
for (const s of cfre.successor.entries) differsFlags.push(s.differsFromFederal);
|
|
3009
|
+
}
|
|
3010
|
+
if (input.cde) issues.push("Schedule 15 CDE regular (015107): the field's own business rule references line 015139, which does not exist elsewhere in this schedule. See module doc comment.");
|
|
3011
|
+
const formRequired = differsFlags.some(Boolean);
|
|
3012
|
+
const formPermitted = (input.reportsDifferentAlbertaIncome ?? false) || (input.electsDifferentDiscretionaryAmounts ?? false);
|
|
3013
|
+
if (formRequired && !formPermitted) issues.push("Alberta Schedule 15: an opening balance or 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.");
|
|
3014
|
+
return {
|
|
3015
|
+
...eda ? { eda } : {},
|
|
3016
|
+
...cmedb ? { cmedb } : {},
|
|
3017
|
+
...cee ? { cee } : {},
|
|
3018
|
+
...cde ? { cde } : {},
|
|
3019
|
+
...ccogpe ? { ccogpe } : {},
|
|
3020
|
+
...fede ? { fede } : {},
|
|
3021
|
+
...sfede ? { sfede: {
|
|
3022
|
+
regular: sfede.regular,
|
|
3023
|
+
successor: sfede.successor
|
|
3024
|
+
} } : {},
|
|
3025
|
+
...cfre ? { cfre: {
|
|
3026
|
+
regular: cfre.regular.entries,
|
|
3027
|
+
successor: cfre.successor.entries
|
|
3028
|
+
} } : {},
|
|
3029
|
+
formRequired,
|
|
3030
|
+
formPermitted,
|
|
3031
|
+
issues
|
|
927
3032
|
};
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
3033
|
+
}
|
|
3034
|
+
/** Line 015313 caps at "total of all occurrence of 015317", so this also processes the whole array. */
|
|
3035
|
+
function computeCfreSuccessor(entries) {
|
|
3036
|
+
const issues = [];
|
|
3037
|
+
const pools = entries.map((e) => {
|
|
3038
|
+
const f = e.federal;
|
|
3039
|
+
const o = e.albertaOverride ?? {};
|
|
3040
|
+
const opening = reconcile(f.openingBalance, o.openingBalance);
|
|
3041
|
+
const amalg = reconcile(f.amalgamationTransfer, o.amalgamationTransfer);
|
|
3042
|
+
const other = reconcile(f.otherTransfer, o.otherTransfer);
|
|
3043
|
+
const otherDed = reconcile(f.otherDeductions, o.otherDeductions);
|
|
3044
|
+
return {
|
|
3045
|
+
e,
|
|
3046
|
+
opening,
|
|
3047
|
+
amalg,
|
|
3048
|
+
other,
|
|
3049
|
+
otherDed,
|
|
3050
|
+
foreignResourceIncome: num$1(f.foreignResourceIncome),
|
|
3051
|
+
pool: opening.value + amalg.value + other.value - otherDed.value
|
|
3052
|
+
};
|
|
3053
|
+
});
|
|
3054
|
+
const sumForeignResourceIncome = pools.reduce((s, p) => s + p.foreignResourceIncome, 0);
|
|
932
3055
|
return {
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
3056
|
+
entries: pools.map((p) => {
|
|
3057
|
+
const { e, opening, amalg, other, otherDed, foreignResourceIncome, pool } = p;
|
|
3058
|
+
let claim = 0;
|
|
3059
|
+
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.`);
|
|
3060
|
+
else if (pool > 0) {
|
|
3061
|
+
const cap = Math.min(CDE_CLAIM_RATE * linearYearFactor(e.daysInTaxYear) * pool, sumForeignResourceIncome);
|
|
3062
|
+
claim = claimUpToCap(e.claimed, cap, issues, `Schedule 15 CFRE successor, country ${e.federal.countryCode} (015313)`);
|
|
3063
|
+
}
|
|
3064
|
+
const closingBalance = pool - claim;
|
|
3065
|
+
return {
|
|
3066
|
+
countryCode: e.federal.countryCode,
|
|
3067
|
+
openingBalance: opening.value,
|
|
3068
|
+
amalgamationTransfer: amalg.value,
|
|
3069
|
+
otherTransfer: other.value,
|
|
3070
|
+
otherDeductions: otherDed.value,
|
|
3071
|
+
foreignResourceIncome,
|
|
3072
|
+
pool,
|
|
3073
|
+
claim,
|
|
3074
|
+
closingBalance,
|
|
3075
|
+
differsFromFederal: opening.differs || amalg.differs || other.differs || otherDed.differs,
|
|
3076
|
+
issues
|
|
3077
|
+
};
|
|
3078
|
+
}),
|
|
3079
|
+
issues
|
|
937
3080
|
};
|
|
938
3081
|
}
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
/** Round to six decimal places — the AT1 allocation-factor precision. */
|
|
942
|
-
function round6(n) {
|
|
943
|
-
return Math.round(n * 1e6) / 1e6;
|
|
3082
|
+
function schedule15LineItemId(fieldId, occurrence = 1) {
|
|
3083
|
+
return `015${fieldId}${String(occurrence).padStart(3, "0")}`;
|
|
944
3084
|
}
|
|
945
|
-
/**
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
3085
|
+
/**
|
|
3086
|
+
* Field ids per the spec transcription in the module doc comment:
|
|
3087
|
+
* EDA 001-021 CMEDB 023-033 CEE 041-083 CDE 091-143
|
|
3088
|
+
* CCOGPE 151-191 FEDE 201-233 SFEDE 241-277 (per country)
|
|
3089
|
+
* CFRE 281-317 (per country)
|
|
3090
|
+
* A pool absent from `result` (never supplied to `computeAlbertaSchedule15`)
|
|
3091
|
+
* emits NOTHING — there is no zero-filled line for a pool the corporation
|
|
3092
|
+
* does not carry, matching every other reconciliation-style AT1 schedule
|
|
3093
|
+
* builder in this package (e.g. `schedule18Values` only emits categories that
|
|
3094
|
+
* were actually computed).
|
|
3095
|
+
*/
|
|
3096
|
+
function schedule15Values(result) {
|
|
3097
|
+
const values = [];
|
|
3098
|
+
const put = (fieldId, value, occurrence = 1) => values.push({
|
|
3099
|
+
lineItemId: schedule15LineItemId(fieldId, occurrence),
|
|
3100
|
+
value
|
|
3101
|
+
});
|
|
3102
|
+
const putStr = (fieldId, value, occurrence = 1) => values.push({
|
|
3103
|
+
lineItemId: schedule15LineItemId(fieldId, occurrence),
|
|
3104
|
+
value
|
|
3105
|
+
});
|
|
3106
|
+
if (result.eda) {
|
|
3107
|
+
const { regular, successor } = result.eda;
|
|
3108
|
+
put("001", regular.openingBalance);
|
|
3109
|
+
put("003", regular.amalgamationTransfer);
|
|
3110
|
+
put("005", regular.saleTransfer);
|
|
3111
|
+
put("007", regular.claim);
|
|
3112
|
+
put("009", regular.closingBalance);
|
|
3113
|
+
put("011", successor.openingBalance);
|
|
3114
|
+
put("013", successor.amalgamationTransfer);
|
|
3115
|
+
put("015", successor.otherTransfer);
|
|
3116
|
+
put("017", successor.saleTransfer);
|
|
3117
|
+
put("019", successor.claim);
|
|
3118
|
+
put("021", successor.closingBalance);
|
|
3119
|
+
}
|
|
3120
|
+
if (result.cmedb) {
|
|
3121
|
+
const c = result.cmedb;
|
|
3122
|
+
put("023", c.openingBalance);
|
|
3123
|
+
put("025", c.amalgamationTransfer);
|
|
3124
|
+
put("027", c.otherTransfer);
|
|
3125
|
+
put("029", c.disposalTransfer);
|
|
3126
|
+
put("031", c.claim);
|
|
3127
|
+
put("033", c.closingBalance);
|
|
3128
|
+
}
|
|
3129
|
+
if (result.cee) {
|
|
3130
|
+
const { regular, successor } = result.cee;
|
|
3131
|
+
put("041", regular.openingBalance);
|
|
3132
|
+
put("043", regular.currentYearExpenses);
|
|
3133
|
+
put("044", regular.lookBackExpenses);
|
|
3134
|
+
put("045", regular.reclassifiedFromCde);
|
|
3135
|
+
put("047", regular.amalgamationTransfer);
|
|
3136
|
+
put("049", regular.renewableConservationExpenses);
|
|
3137
|
+
put("051", regular.otherAdditions);
|
|
3138
|
+
put("053", regular.governmentAssistance);
|
|
3139
|
+
put("055", regular.otherDeductions);
|
|
3140
|
+
put("058", regular.renouncedFlowThrough);
|
|
3141
|
+
put("059", regular.transferredToSuccessor);
|
|
3142
|
+
put("060", regular.renouncedLookBack);
|
|
3143
|
+
put("061", regular.claim);
|
|
3144
|
+
put("063", regular.closingBalance);
|
|
3145
|
+
put("064", successor.openingBalance);
|
|
3146
|
+
put("065", successor.reclassifiedFromCde);
|
|
3147
|
+
put("067", successor.amalgamationTransfer);
|
|
3148
|
+
put("069", successor.otherTransfer);
|
|
3149
|
+
put("077", successor.otherDeductions);
|
|
3150
|
+
put("079", successor.transferredToSuccessor);
|
|
3151
|
+
put("081", successor.claim);
|
|
3152
|
+
put("083", successor.closingBalance);
|
|
3153
|
+
}
|
|
3154
|
+
if (result.cde) {
|
|
3155
|
+
const { regular, successor } = result.cde;
|
|
3156
|
+
put("091", regular.openingBalance);
|
|
3157
|
+
put("093", regular.currentYearExpenses);
|
|
3158
|
+
put("094", regular.lookBackExpenses);
|
|
3159
|
+
put("095", regular.amalgamationTransfer);
|
|
3160
|
+
put("097", regular.otherAdditions);
|
|
3161
|
+
put("099", regular.reclassifiedFromCee);
|
|
3162
|
+
put("101", regular.governmentAssistance);
|
|
3163
|
+
put("103", regular.receivableOnDisposition);
|
|
3164
|
+
put("105", regular.creditBalanceInCogpePool);
|
|
3165
|
+
put("107", regular.otherDeductions);
|
|
3166
|
+
put("110", regular.renouncedFlowThrough);
|
|
3167
|
+
put("111", regular.transferredToSuccessor);
|
|
3168
|
+
put("112", regular.renouncedLookBack);
|
|
3169
|
+
put("115", regular.claim);
|
|
3170
|
+
put("117", regular.closingBalance);
|
|
3171
|
+
put("119", successor.openingBalance);
|
|
3172
|
+
put("121", successor.amalgamationTransfer);
|
|
3173
|
+
put("123", successor.otherTransfer);
|
|
3174
|
+
put("127", successor.reclassifiedFromCee);
|
|
3175
|
+
put("133", successor.creditBalanceInCogpePool);
|
|
3176
|
+
put("135", successor.otherDeductions);
|
|
3177
|
+
put("137", successor.transferredToSuccessor);
|
|
3178
|
+
put("141", successor.claim);
|
|
3179
|
+
put("143", successor.closingBalance);
|
|
3180
|
+
}
|
|
3181
|
+
if (result.ccogpe) {
|
|
3182
|
+
const { regular, successor } = result.ccogpe;
|
|
3183
|
+
put("151", regular.openingBalance);
|
|
3184
|
+
put("153", regular.currentYearExpenses);
|
|
3185
|
+
put("155", regular.amalgamationTransfer);
|
|
3186
|
+
put("157", regular.otherAdditions);
|
|
3187
|
+
put("159", regular.receivableOnDisposition);
|
|
3188
|
+
put("161", regular.governmentAssistance);
|
|
3189
|
+
put("165", regular.transferredToSuccessor);
|
|
3190
|
+
put("167", regular.otherDeductions);
|
|
3191
|
+
put("169", regular.claim);
|
|
3192
|
+
put("171", regular.closingBalance);
|
|
3193
|
+
put("173", successor.openingBalance);
|
|
3194
|
+
put("175", successor.amalgamationTransfer);
|
|
3195
|
+
put("177", successor.otherTransfer);
|
|
3196
|
+
put("181", successor.receivableOnDisposition);
|
|
3197
|
+
put("185", successor.transferredToSuccessor);
|
|
3198
|
+
put("187", successor.otherDeductions);
|
|
3199
|
+
put("189", successor.claim);
|
|
3200
|
+
put("191", successor.closingBalance);
|
|
3201
|
+
}
|
|
3202
|
+
if (result.fede) {
|
|
3203
|
+
const { regular, successor } = result.fede;
|
|
3204
|
+
put("201", regular.openingBalance);
|
|
3205
|
+
put("205", regular.amalgamationTransfer);
|
|
3206
|
+
put("207", regular.otherDeductions);
|
|
3207
|
+
put("209", regular.claim);
|
|
3208
|
+
put("211", regular.closingBalance);
|
|
3209
|
+
put("231", regular.foreignResourceIncome);
|
|
3210
|
+
put("213", successor.openingBalance);
|
|
3211
|
+
put("215", successor.amalgamationTransfer);
|
|
3212
|
+
put("217", successor.otherTransfer);
|
|
3213
|
+
put("219", successor.otherDeductions);
|
|
3214
|
+
put("221", successor.claim);
|
|
3215
|
+
put("223", successor.closingBalance);
|
|
3216
|
+
put("233", successor.foreignResourceIncome);
|
|
3217
|
+
}
|
|
3218
|
+
if (result.sfede) {
|
|
3219
|
+
result.sfede.regular.forEach((r, i) => {
|
|
3220
|
+
const occ = i + 1;
|
|
3221
|
+
putStr("241", r.countryCode, occ);
|
|
3222
|
+
put("243", r.openingBalance, occ);
|
|
3223
|
+
put("247", r.amalgamationTransfer, occ);
|
|
3224
|
+
put("249", r.otherAdditions, occ);
|
|
3225
|
+
put("251", r.otherDeductions, occ);
|
|
3226
|
+
put("253", r.claim, occ);
|
|
3227
|
+
put("255", r.closingBalance, occ);
|
|
3228
|
+
put("257", r.foreignResourceIncome, occ);
|
|
3229
|
+
});
|
|
3230
|
+
result.sfede.successor.forEach((s, i) => {
|
|
3231
|
+
const occ = i + 1;
|
|
3232
|
+
putStr("261", s.countryCode, occ);
|
|
3233
|
+
put("263", s.openingBalance, occ);
|
|
3234
|
+
put("265", s.amalgamationTransfer, occ);
|
|
3235
|
+
put("267", s.otherTransfer, occ);
|
|
3236
|
+
put("269", s.otherDeductions, occ);
|
|
3237
|
+
put("273", s.claim, occ);
|
|
3238
|
+
put("275", s.closingBalance, occ);
|
|
3239
|
+
put("277", s.foreignResourceIncome, occ);
|
|
3240
|
+
});
|
|
3241
|
+
}
|
|
3242
|
+
if (result.cfre) {
|
|
3243
|
+
result.cfre.regular.forEach((r, i) => {
|
|
3244
|
+
const occ = i + 1;
|
|
3245
|
+
putStr("281", r.countryCode, occ);
|
|
3246
|
+
put("283", r.openingBalance, occ);
|
|
3247
|
+
put("285", r.currentYearExpenses, occ);
|
|
3248
|
+
put("287", r.amalgamationTransfer, occ);
|
|
3249
|
+
put("289", r.otherAdditions, occ);
|
|
3250
|
+
put("291", r.otherDeductions, occ);
|
|
3251
|
+
put("293", r.claim, occ);
|
|
3252
|
+
put("295", r.closingBalance, occ);
|
|
3253
|
+
put("297", r.foreignResourceIncome, occ);
|
|
3254
|
+
});
|
|
3255
|
+
result.cfre.successor.forEach((s, i) => {
|
|
3256
|
+
const occ = i + 1;
|
|
3257
|
+
putStr("301", s.countryCode, occ);
|
|
3258
|
+
put("303", s.openingBalance, occ);
|
|
3259
|
+
put("305", s.amalgamationTransfer, occ);
|
|
3260
|
+
put("307", s.otherTransfer, occ);
|
|
3261
|
+
put("309", s.otherDeductions, occ);
|
|
3262
|
+
put("313", s.claim, occ);
|
|
3263
|
+
put("315", s.closingBalance, occ);
|
|
3264
|
+
put("317", s.foreignResourceIncome, occ);
|
|
3265
|
+
});
|
|
3266
|
+
}
|
|
3267
|
+
return {
|
|
3268
|
+
scheduleId: "015",
|
|
3269
|
+
values,
|
|
3270
|
+
issues: result.issues
|
|
3271
|
+
};
|
|
958
3272
|
}
|
|
959
3273
|
//#endregion
|
|
960
3274
|
//#region src/t2/at1/schedules/schedule29-eligible-expenditures.ts
|
|
@@ -1481,9 +3795,18 @@ function computeAlbertaReturn(input) {
|
|
|
1481
3795
|
const sched = input.schedules;
|
|
1482
3796
|
if (sched?.smallBusinessDeduction) schedulePayloads.push(schedule1Values(sched.smallBusinessDeduction));
|
|
1483
3797
|
if (sched?.allocation) schedulePayloads.push(schedule2Values(sched.allocation));
|
|
3798
|
+
if (sched?.otherDeductionsCredits) schedulePayloads.push(schedule3Values(sched.otherDeductionsCredits));
|
|
3799
|
+
if (sched?.foreignInvestmentTaxCredit) schedulePayloads.push(schedule4Values(sched.foreignInvestmentTaxCredit));
|
|
3800
|
+
if (sched?.royaltyTaxDeduction) schedulePayloads.push(schedule5Values(sched.royaltyTaxDeduction));
|
|
3801
|
+
if (sched?.royaltyTaxCredit) schedulePayloads.push(schedule6Values(sched.royaltyTaxCredit));
|
|
3802
|
+
if (sched?.royaltySupplemental) schedulePayloads.push(schedule7Values(sched.royaltySupplemental));
|
|
3803
|
+
if (sched?.politicalContributions) schedulePayloads.push(schedule8Values(sched.politicalContributions));
|
|
3804
|
+
if (sched?.sredTaxCredit) schedulePayloads.push(schedule9Values(sched.sredTaxCredit.result, sched.sredTaxCredit.group));
|
|
1484
3805
|
if (sched?.lossCarryback) schedulePayloads.push(schedule10Values(sched.lossCarryback));
|
|
3806
|
+
if (sched?.manufacturingProcessing) schedulePayloads.push(schedule11Values(sched.manufacturingProcessing));
|
|
1485
3807
|
if (sched?.reconciliation) schedulePayloads.push(schedule12Values(sched.reconciliation));
|
|
1486
3808
|
if (sched?.cca) schedulePayloads.push(schedule13Values(sched.cca));
|
|
3809
|
+
if (sched?.resourceDeductions) schedulePayloads.push(schedule15Values(sched.resourceDeductions));
|
|
1487
3810
|
if (sched?.scientificResearch) schedulePayloads.push(schedule16Values(sched.scientificResearch));
|
|
1488
3811
|
if (sched?.reserves) schedulePayloads.push(schedule17Values(sched.reserves));
|
|
1489
3812
|
if (sched?.dispositions) schedulePayloads.push(schedule18Values(sched.dispositions));
|
|
@@ -3048,6 +5371,83 @@ function applyOverride(federal, o) {
|
|
|
3048
5371
|
opt("applyHalfYearRule", federal.applyHalfYearRule);
|
|
3049
5372
|
return merged;
|
|
3050
5373
|
}
|
|
5374
|
+
/**
|
|
5375
|
+
* Adapts a straight-line {@link Class13Result}/{@link Class14Result} into the
|
|
5376
|
+
* SAME shape every declining-balance class uses, so `classes` stays one
|
|
5377
|
+
* homogeneous array and the filing layer (`schedule13Values`, which reads
|
|
5378
|
+
* only the shared `CcaClassResult` fields) needs no changes at all. Rate/
|
|
5379
|
+
* half-year/AIIP/immediate-expensing are inapplicable to a straight-line
|
|
5380
|
+
* class and reported as 0; neither mechanic produces recapture here.
|
|
5381
|
+
*/
|
|
5382
|
+
function straightLineAsCcaClassResult(ccaClass, r) {
|
|
5383
|
+
return {
|
|
5384
|
+
ccaClass,
|
|
5385
|
+
rate: 0,
|
|
5386
|
+
uccBeforeCca: r.uccBeforeCca,
|
|
5387
|
+
immediateExpensingClaim: 0,
|
|
5388
|
+
halfYearAdjustment: 0,
|
|
5389
|
+
aiipEnhancement: 0,
|
|
5390
|
+
ccaBase: 0,
|
|
5391
|
+
maxCca: r.maxCca,
|
|
5392
|
+
ccaClaimed: r.ccaClaimed,
|
|
5393
|
+
closingUCC: r.closingUCC,
|
|
5394
|
+
recapture: 0,
|
|
5395
|
+
terminalLoss: 0
|
|
5396
|
+
};
|
|
5397
|
+
}
|
|
5398
|
+
/** Federal claims `federalClaim` (max if omitted); Alberta defaults to federal's ACTUAL claim, not federal's max. */
|
|
5399
|
+
function computeClass13Pair(input, issues) {
|
|
5400
|
+
const shared = {
|
|
5401
|
+
layers: input.layers,
|
|
5402
|
+
openingUCC: input.openingUCC
|
|
5403
|
+
};
|
|
5404
|
+
const applyHalfYearRule = input.applyHalfYearRule !== void 0 ? { applyHalfYearRule: input.applyHalfYearRule } : {};
|
|
5405
|
+
const federal = computeClass13({
|
|
5406
|
+
...shared,
|
|
5407
|
+
...applyHalfYearRule,
|
|
5408
|
+
...input.federalClaim !== void 0 ? { claim: input.federalClaim } : {}
|
|
5409
|
+
});
|
|
5410
|
+
const albertaClaim = input.albertaClaim !== void 0 ? input.albertaClaim : federal.ccaClaimed;
|
|
5411
|
+
const alberta = computeClass13({
|
|
5412
|
+
...shared,
|
|
5413
|
+
...applyHalfYearRule,
|
|
5414
|
+
claim: albertaClaim
|
|
5415
|
+
});
|
|
5416
|
+
issues.push(...federal.issues, ...alberta.issues);
|
|
5417
|
+
return {
|
|
5418
|
+
ccaClass: "13",
|
|
5419
|
+
alberta: straightLineAsCcaClassResult("13", alberta),
|
|
5420
|
+
federal: straightLineAsCcaClassResult("13", federal),
|
|
5421
|
+
openingUccDiffers: false,
|
|
5422
|
+
claimDiffers: alberta.ccaClaimed !== federal.ccaClaimed,
|
|
5423
|
+
ccaDifference: alberta.ccaClaimed - federal.ccaClaimed
|
|
5424
|
+
};
|
|
5425
|
+
}
|
|
5426
|
+
function computeClass14Pair(input, issues) {
|
|
5427
|
+
const shared = {
|
|
5428
|
+
properties: input.properties,
|
|
5429
|
+
openingUCC: input.openingUCC,
|
|
5430
|
+
...input.daysInTaxYear !== void 0 ? { daysInTaxYear: input.daysInTaxYear } : {}
|
|
5431
|
+
};
|
|
5432
|
+
const federal = computeClass14({
|
|
5433
|
+
...shared,
|
|
5434
|
+
...input.federalClaim !== void 0 ? { claim: input.federalClaim } : {}
|
|
5435
|
+
});
|
|
5436
|
+
const albertaClaim = input.albertaClaim !== void 0 ? input.albertaClaim : federal.ccaClaimed;
|
|
5437
|
+
const alberta = computeClass14({
|
|
5438
|
+
...shared,
|
|
5439
|
+
claim: albertaClaim
|
|
5440
|
+
});
|
|
5441
|
+
issues.push(...federal.issues, ...alberta.issues);
|
|
5442
|
+
return {
|
|
5443
|
+
ccaClass: "14",
|
|
5444
|
+
alberta: straightLineAsCcaClassResult("14", alberta),
|
|
5445
|
+
federal: straightLineAsCcaClassResult("14", federal),
|
|
5446
|
+
openingUccDiffers: false,
|
|
5447
|
+
claimDiffers: alberta.ccaClaimed !== federal.ccaClaimed,
|
|
5448
|
+
ccaDifference: alberta.ccaClaimed - federal.ccaClaimed
|
|
5449
|
+
};
|
|
5450
|
+
}
|
|
3051
5451
|
function computeAlbertaSchedule13(input) {
|
|
3052
5452
|
const rates = input.rates ?? CCA_DECLINING_BALANCE_RATES_2024;
|
|
3053
5453
|
const issues = [];
|
|
@@ -3068,6 +5468,8 @@ function computeAlbertaSchedule13(input) {
|
|
|
3068
5468
|
ccaDifference: alberta.ccaClaimed - federal.ccaClaimed
|
|
3069
5469
|
};
|
|
3070
5470
|
});
|
|
5471
|
+
if (input.class13) classes.push(computeClass13Pair(input.class13, issues));
|
|
5472
|
+
if (input.class14) classes.push(computeClass14Pair(input.class14, issues));
|
|
3071
5473
|
const sum = (pickFn) => classes.reduce((s, c) => s + pickFn(c), 0);
|
|
3072
5474
|
const albertaTotalCca = sum((c) => c.alberta.ccaClaimed);
|
|
3073
5475
|
const federalTotalCca = sum((c) => c.federal.ccaClaimed);
|
|
@@ -3662,19 +6064,58 @@ function computeDonationMaximum(input) {
|
|
|
3662
6064
|
};
|
|
3663
6065
|
}
|
|
3664
6066
|
//#endregion
|
|
6067
|
+
//#region src/t2/at1/schedules/schedule21-limited-partnership.ts
|
|
6068
|
+
function computeLimitedPartnershipLossRow(row) {
|
|
6069
|
+
const issues = [];
|
|
6070
|
+
const precedingYearBalance = Math.max(0, row.precedingYearBalance);
|
|
6071
|
+
const transferredOnWindUp = Math.max(0, row.transferredOnWindUp ?? 0);
|
|
6072
|
+
const currentYearLoss = Math.max(0, row.currentYearLoss ?? 0);
|
|
6073
|
+
const maxApplied = precedingYearBalance + transferredOnWindUp;
|
|
6074
|
+
const requestedApplied = Math.max(0, row.applied ?? 0);
|
|
6075
|
+
if (requestedApplied > maxApplied) issues.push(`Limited partnership loss${row.identifier ? ` (${row.identifier})` : ""}: the amount applied (${requestedApplied}) cannot exceed the preceding-year balance plus any wind-up transfer (${maxApplied}). Capped at ${maxApplied}.`);
|
|
6076
|
+
const applied = Math.min(requestedApplied, maxApplied);
|
|
6077
|
+
const closingBalance = precedingYearBalance + transferredOnWindUp + currentYearLoss - applied;
|
|
6078
|
+
return {
|
|
6079
|
+
...row.identifier !== void 0 ? { identifier: row.identifier } : {},
|
|
6080
|
+
precedingYearBalance,
|
|
6081
|
+
transferredOnWindUp,
|
|
6082
|
+
currentYearLoss,
|
|
6083
|
+
applied,
|
|
6084
|
+
closingBalance,
|
|
6085
|
+
issues
|
|
6086
|
+
};
|
|
6087
|
+
}
|
|
6088
|
+
function computeLimitedPartnershipLosses(rows) {
|
|
6089
|
+
const computedRows = rows.map(computeLimitedPartnershipLossRow);
|
|
6090
|
+
return {
|
|
6091
|
+
rows: computedRows,
|
|
6092
|
+
totalApplied: computedRows.reduce((s, r) => s + r.applied, 0),
|
|
6093
|
+
totalClosingBalance: computedRows.reduce((s, r) => s + r.closingBalance, 0),
|
|
6094
|
+
issues: computedRows.flatMap((r) => r.issues)
|
|
6095
|
+
};
|
|
6096
|
+
}
|
|
6097
|
+
//#endregion
|
|
3665
6098
|
//#region src/t2/schedules/loss-continuity.ts
|
|
3666
6099
|
function computeLossContinuity(input) {
|
|
3667
6100
|
const currentYearLoss = input.currentYearLoss ?? 0;
|
|
3668
6101
|
const carriedBack = input.carriedBack ?? 0;
|
|
3669
6102
|
const appliedCurrentYear = input.appliedCurrentYear ?? 0;
|
|
3670
6103
|
const expired = input.expired ?? 0;
|
|
3671
|
-
const
|
|
6104
|
+
const windUpTransfer = input.windUpTransfer ?? 0;
|
|
6105
|
+
const section80Adjustment = input.section80Adjustment ?? 0;
|
|
6106
|
+
const otherAdjustments = input.otherAdjustments ?? 0;
|
|
6107
|
+
const balanceAtBeginningOfYear = input.openingBalance - expired;
|
|
6108
|
+
const closingBalance = Math.max(0, balanceAtBeginningOfYear + windUpTransfer + currentYearLoss - appliedCurrentYear - section80Adjustment - otherAdjustments - carriedBack);
|
|
3672
6109
|
return {
|
|
3673
6110
|
openingBalance: input.openingBalance,
|
|
3674
6111
|
currentYearLoss,
|
|
3675
6112
|
carriedBack,
|
|
3676
6113
|
appliedCurrentYear,
|
|
3677
6114
|
expired,
|
|
6115
|
+
windUpTransfer,
|
|
6116
|
+
section80Adjustment,
|
|
6117
|
+
otherAdjustments,
|
|
6118
|
+
balanceAtBeginningOfYear,
|
|
3678
6119
|
closingBalance
|
|
3679
6120
|
};
|
|
3680
6121
|
}
|
|
@@ -3706,6 +6147,76 @@ function computeLossSchedule(input) {
|
|
|
3706
6147
|
};
|
|
3707
6148
|
}
|
|
3708
6149
|
//#endregion
|
|
6150
|
+
//#region src/t2/at1/schedules/schedule21-year-of-origin.ts
|
|
6151
|
+
function sumRows(rows) {
|
|
6152
|
+
const sum = (f) => rows.reduce((s, r) => s + f(r), 0);
|
|
6153
|
+
return {
|
|
6154
|
+
balanceAtBeginning: sum((r) => r.balanceAtBeginning),
|
|
6155
|
+
lossIncurred: sum((r) => r.lossIncurred),
|
|
6156
|
+
adjustments: sum((r) => r.adjustments),
|
|
6157
|
+
carriedBack: sum((r) => r.carriedBack),
|
|
6158
|
+
applied: sum((r) => r.applied),
|
|
6159
|
+
balanceAtEnd: sum((r) => r.balanceAtEnd)
|
|
6160
|
+
};
|
|
6161
|
+
}
|
|
6162
|
+
function computeNonCapitalLossByYearOfOrigin(input) {
|
|
6163
|
+
const issues = [];
|
|
6164
|
+
const lossIncurred = Math.max(0, input.currentYearLoss);
|
|
6165
|
+
const carriedBack = Math.max(0, input.currentYearCarriedBack);
|
|
6166
|
+
const rows = [{
|
|
6167
|
+
yearIndex: 0,
|
|
6168
|
+
balanceAtBeginning: 0,
|
|
6169
|
+
lossIncurred,
|
|
6170
|
+
adjustments: 0,
|
|
6171
|
+
carriedBack,
|
|
6172
|
+
applied: 0,
|
|
6173
|
+
balanceAtEnd: Math.max(0, lossIncurred - carriedBack)
|
|
6174
|
+
}, ...(input.priorVintages ?? []).map((v) => {
|
|
6175
|
+
if (v.yearsAgo < 1 || v.yearsAgo > 20) issues.push(`Non-capital loss year of origin: yearsAgo (${v.yearsAgo}) must be 1-20 — a non-capital loss expires after 20 years.`);
|
|
6176
|
+
const balanceAtBeginning = Math.max(0, v.balanceAtBeginning ?? 0);
|
|
6177
|
+
const adjustments = v.adjustments ?? 0;
|
|
6178
|
+
const applied = Math.max(0, v.applied ?? 0);
|
|
6179
|
+
return {
|
|
6180
|
+
yearIndex: v.yearsAgo,
|
|
6181
|
+
...v.taxYearEnd !== void 0 ? { taxYearEnd: v.taxYearEnd } : {},
|
|
6182
|
+
balanceAtBeginning,
|
|
6183
|
+
lossIncurred: 0,
|
|
6184
|
+
adjustments,
|
|
6185
|
+
carriedBack: 0,
|
|
6186
|
+
applied,
|
|
6187
|
+
balanceAtEnd: Math.max(0, balanceAtBeginning + adjustments - applied)
|
|
6188
|
+
};
|
|
6189
|
+
})];
|
|
6190
|
+
return {
|
|
6191
|
+
rows,
|
|
6192
|
+
totals: sumRows(rows),
|
|
6193
|
+
issues
|
|
6194
|
+
};
|
|
6195
|
+
}
|
|
6196
|
+
function computeOtherLossByYearOfOrigin(rows) {
|
|
6197
|
+
const issues = [];
|
|
6198
|
+
const computed = rows.map((r) => {
|
|
6199
|
+
if (r.yearIndex < 0 || r.yearIndex > 20) issues.push(`Other-loss year of origin: yearIndex (${r.yearIndex}) must be 0-20 — a farm/restricted-farm loss expires after 20 years.`);
|
|
6200
|
+
const listedPersonalPropertyLosses = Math.max(0, r.listedPersonalPropertyLosses ?? 0);
|
|
6201
|
+
if (r.yearIndex > 7 && listedPersonalPropertyLosses > 0) issues.push(`Other-loss year of origin: listed personal property losses cannot exist for occurrence ${r.yearIndex} — that loss type expires after 7 taxation years, not 20.`);
|
|
6202
|
+
return {
|
|
6203
|
+
yearIndex: r.yearIndex,
|
|
6204
|
+
farmLosses: Math.max(0, r.farmLosses ?? 0),
|
|
6205
|
+
restrictedFarmLosses: Math.max(0, r.restrictedFarmLosses ?? 0),
|
|
6206
|
+
listedPersonalPropertyLosses: r.yearIndex > 7 ? 0 : listedPersonalPropertyLosses
|
|
6207
|
+
};
|
|
6208
|
+
});
|
|
6209
|
+
return {
|
|
6210
|
+
rows: computed,
|
|
6211
|
+
totals: {
|
|
6212
|
+
farmLosses: computed.reduce((s, r) => s + r.farmLosses, 0),
|
|
6213
|
+
restrictedFarmLosses: computed.reduce((s, r) => s + r.restrictedFarmLosses, 0),
|
|
6214
|
+
listedPersonalPropertyLosses: computed.reduce((s, r) => s + r.listedPersonalPropertyLosses, 0)
|
|
6215
|
+
},
|
|
6216
|
+
issues
|
|
6217
|
+
};
|
|
6218
|
+
}
|
|
6219
|
+
//#endregion
|
|
3709
6220
|
//#region src/t2/certification/fixtures.ts
|
|
3710
6221
|
const T2_CERTIFICATION_FIXTURES = [
|
|
3711
6222
|
{
|
|
@@ -5389,15 +7900,18 @@ function computeFederalT2(input) {
|
|
|
5389
7900
|
const rates = input.rates ?? resolveCorpTaxRates(taxYear, book);
|
|
5390
7901
|
const prorationFactor = shortYearProrationFactor(input.periodStart, input.periodEnd);
|
|
5391
7902
|
const cca = input.ccaClasses?.length ? computeCcaSchedule(input.ccaClasses, resolveCcaRates(taxYear), prorationFactor) : void 0;
|
|
7903
|
+
const class13 = input.class13 ? computeClass13(input.class13) : void 0;
|
|
7904
|
+
const class14 = input.class14 ? computeClass14(input.class14) : void 0;
|
|
5392
7905
|
const capitalGains = input.capitalDispositions?.length ? computeSchedule6(input.capitalDispositions, rates.CAPITAL_GAINS_INCLUSION_RATE) : void 0;
|
|
5393
7906
|
const schedule1Additions = [...input.schedule1Additions ?? []];
|
|
5394
7907
|
const schedule1Deductions = [...input.schedule1Deductions ?? []];
|
|
7908
|
+
const totalCcaDeduction = (cca?.totalCca ?? 0) + (class13?.ccaClaimed ?? 0) + (class14?.ccaClaimed ?? 0);
|
|
7909
|
+
if (totalCcaDeduction > 0) schedule1Deductions.push({
|
|
7910
|
+
line: "403",
|
|
7911
|
+
label: "Capital cost allowance from Schedule 8",
|
|
7912
|
+
amount: totalCcaDeduction
|
|
7913
|
+
});
|
|
5395
7914
|
if (cca) {
|
|
5396
|
-
if (cca.totalCca > 0) schedule1Deductions.push({
|
|
5397
|
-
line: "403",
|
|
5398
|
-
label: "Capital cost allowance from Schedule 8",
|
|
5399
|
-
amount: cca.totalCca
|
|
5400
|
-
});
|
|
5401
7915
|
if (cca.totalTerminalLoss > 0) schedule1Deductions.push({
|
|
5402
7916
|
line: "404",
|
|
5403
7917
|
label: "Terminal loss from Schedule 8",
|
|
@@ -5597,6 +8111,8 @@ function computeFederalT2(input) {
|
|
|
5597
8111
|
...donations ? { donations } : {},
|
|
5598
8112
|
...lossCarryback ? { lossCarryback } : {},
|
|
5599
8113
|
...cca ? { cca } : {},
|
|
8114
|
+
...class13 ? { class13 } : {},
|
|
8115
|
+
...class14 ? { class14 } : {},
|
|
5600
8116
|
...capitalGains ? { capitalGains } : {},
|
|
5601
8117
|
...provincial ? { provincial } : {},
|
|
5602
8118
|
...provincialAllocation ? { provincialAllocation } : {},
|
|
@@ -6727,4 +9243,4 @@ function computeMpDeduction(input, rates = MP_RATES_2024) {
|
|
|
6727
9243
|
};
|
|
6728
9244
|
}
|
|
6729
9245
|
//#endregion
|
|
6730
|
-
export { computeProvincialAllocation as $,
|
|
9246
|
+
export { computeProvincialAllocation as $, albertaBalanceUnpaid as $n, schedule4Values as $r, AT1_RESERVE_TOTAL_LINES as $t, runConformance as A, hasExactRateYear as Ai, albertaRecaptureDifference as An, computeFedeRegular as Ar, computeCcpcActiveBusinessTax as At, computeGrip as B, RSI_WORD_GAP as Bn, allocateSchedule9ExpenditureLimit as Br, computeLossSchedule as Bt, computeQuebecTax as C, AB_GENERAL_RATE_BANDS as Ci, resolveCcaRates as Cn, computeCeeRegular as Cr, blendProvinceRateTable as Ct, T2_LINE_META as D, resolveAlbertaTaxRates as Di, albertaCcaScheduleAdjustments as Dn, computeCmedb as Dr, dividendsDeductibleS112 as Dt, resolveQuebecTaxRates as E, AB_TAX_RATE_BOOK as Ei, albertaCcaDifference as En, computeCfreSuccessor as Er, computeTaxableIncome as Et, normalizeSchedule88 as F, LossCarrybackError as Fn, computeSchedule11 as Fr, CORP_TAX_RATE_BOOK as Ft, ITC_RECAPTURE_PERIOD_YEARS as G, renderAt1Rsi as Gn, schedule8Values as Gr, AT1_DONATION_INCOME_RATE as Gt, LARGE_CORPORATION_THRESHOLD as H, formatRsiAmount as Hn, computeSchedule9MaximumExpenditureLimit as Hr, computeLimitedPartnershipLossRow as Ht, computeSchedule55 as I, computeLossCarryback as In, schedule11Values as Ir, resolveCorpTaxRates as It, allocateEvenly as J, renderAt1NetFile as Jn, computeAlbertaSchedule6 as Jr, AT1_DISPOSITION_CATEGORIES as Jt, computeItcRecapture as K, renderRsiHeader as Kn, computeAlbertaSchedule7 as Kr, computeDonationMaximum as Kt, LRIP_INVESTMENT_CORPORATION_MULTIPLE as L, RSI_COLUMN_GAP as Ln, ALBERTA_SRED_EXPENDITURE_CUTOFF as Lr, T2_CERTIFICATION_FIXTURES as Lt, computeFederalT2 as M, resolveRates as Mi, albertaTerminalLossDifference as Mn, computeSfedeCountryRegular as Mr, computeBusinessLimit as Mt, computeSchedule101 as N, computeSchedule12 as Nn, computeSfedeCountrySuccessor as Nr, computeSBD as Nt, foldT2Lines as O, earliestRateYear as Oi, albertaCurrentYearLoss as On, computeEdaRegular as Or, netCapitalLossApplied as Ot, SCHEDULE_88_MAX_URLS as P, reconcileAlbertaNetIncome as Pn, schedule15Values as Pr, CORP_TAX_2024 as Pt, computeSchedule6 as Q, At1TaxPayableMismatchError as Qn, computeSchedule4 as Qr, AT1_RESERVE_LINES as Qt, LRIP_INVESTMENT_INCOME_FACTOR as R, RSI_DELIMITER as Rn, ALBERTA_SRED_PROGRAM_START as Rr, computeNonCapitalLossByYearOfOrigin as Rt, computeQuebecAllocationFactor as S, computeAlbertaSbd as Si, isDecliningBalanceClass as Sn, computeCdeSuccessor as Sr, resolveProvinceRates as St, QC_TAX_RATE_BOOK as T, AB_TAX_2024 as Ti, albertaCapitalGainDifference as Tn, computeCfreRegular as Tr, charitableDonationsDeduction as Tt, computeTaxableCapital as U, formatRsiDate as Un, schedule9Values as Ur, computeLimitedPartnershipLosses as Ut, computeSchedule43 as V, RsiLineItemError as Vn, computeAlbertaSchedule9 as Vr, computeLossContinuity as Vt, computeSchedule31 as W, formatRsiText as Wn, computeSchedule8$1 as Wr, AT1_DONATION_GAIN_RATE as Wt, computeSchedule21 as X, At1CriticalFieldMissingError as Xn, computeAlbertaSchedule5 as Xr, computeAlbertaSchedule18 as Xt, computeBusinessLimitAllocation as Y, AT1_CRITICAL_MANDATORY_FIELDS as Yn, schedule6Values as Yr, SECTION_34_2_GROSS_UP as Yt, computeSchedule13 as Z, At1MandatoryFieldMissingError as Zn, schedule5Values as Zr, AT1_RESERVE_KINDS as Zt, renderT2DraftReturn as _, schedule21Values as _i, computeClass14 as _n, iegT661SourceLine as _r, EIFEL_EFFECTIVE_FROM as _t, PART_VI_1_DEDUCTION_BANDS as a, AT1_SCHEDULES_WITHOUT_BUILDERS as ai, cecScheduleAppliesToTaxYear as an, xmlEscape as ar, computeSchedule2 as at, co17Engine as b, schedule4970Values as bi, CCA_DECLINING_BALANCE_RATES_2024 as bn, computeCcogpeSuccessor as br, PROVINCE_RATE_BOOK as bt, EIFEL_FIRST_YEAR_START as c, schedule10Values as ci, UnsupportedCcaClassError as cn, allocateIegEvenly as cr, assertSchedule1Fileable as ct, EIFEL_TRANSITIONAL_RATIO as d, schedule13Values as di, computeSchedule8 as dn, computeIegGroupFigures as dr, deferredIncomeTaxProvisionAddBack as dt, computeSchedule3 as ei, computeAlbertaSchedule17 as en, assertAt1MandatoryComplete as er, computeSchedule5 as et, computeEifelLimitation as f, schedule16Values as fi, CLASS_14_1_MINIMUM_DEDUCTION as fn, IEG_2024 as fr, findSchedule1LineDefects as ft, computeT2Settlement as g, schedule20Values as gi, computeClass13 as gn, computeIegEligibleExpenditures as gr, terminalLossDeduction as gt, computeAdjustedTaxableIncome as h, schedule1Values as hi, MIN_LEASEHOLD_PERIODS as hn, computeIegReductionFactor as hr, recaptureAddBack as ht, computeMpDeduction as i, computeAt4970 as ii, CEC_INCLUSION_RATE as in, at1YesNo as ir, computePart4Rdtoh as it, runConformanceSuite as j, latestRateYear as ji, albertaReserveDifference as jn, computeFedeSuccessor as jr, computePartITax as jt, formatConformanceReport as k, extendRateBook as ki, albertaDispositionAdjustments as kn, computeEdaSuccessor as kr, nonCapitalLossApplied as kt, EIFEL_STANDARD_RATIO as l, schedule12LossDeductions as li, computeCcaClass as ln, allocateIegExpenditureLimit as lr, ccaDeduction as lt, FOREIGN_TAX_CREDIT_GROSS_UP as m, schedule18Values as mi, MAX_LEASEHOLD_PERIODS as mn, computeIegBaseAmount as mr, mealsAndEntertainmentAddBack as mt, MP_GROSS_REVENUE_THRESHOLD as n, SINGLE_JURISDICTION_ALBERTA_FACTOR as ni, computeAlbertaSchedule16 as nn, assertCriticalFields as nr, PART_IV_RATE as nt, computePartVI1Deduction as o, AT1_SCHEDULES_WITH_BUILDERS as oi, computeAlbertaSchedule14 as on, at1Engine as or, Schedule1NotFileableError as ot, ratioOfPermissibleExpenses as p, schedule17Values as pi, CLASS_14_1_TRANSITIONAL_RATE as pn, computeIeg as pr, incomeTaxProvisionAddBack as pt, computeZetm as q, renderRsiLineItem as qn, schedule7Values as qr, computeSchedule20 as qt, MP_RATES_2024 as r, computeAllocationFactor as ri, CEC_DEDUCTION_RATE as rn, at1TaxPayableDeductions as rr, REFUNDABLE_PART_I_RATE as rt, partVI1DeductionMultiple as s, at1LineItemId as si, computeAlbertaSchedule13 as sn, computeAlbertaReturn as sr, amortizationAddBack as st, MP_EXCLUDED_ACTIVITIES as t, schedule3Values as ti, assistanceFrom as tn, assertAt1TaxPayableReconciles as tr, computeSchedule4Losses as tt, EIFEL_STANDARD_RATIO_FROM as u, schedule12Values as ui, computeCcaSchedule as un, computeIegAgreement as ur, computeSchedule1 as ut, t2Engine as v, schedule29Values as vi, computeClass141AdditionalAllowance as vn, computeAlbertaSchedule15 as vr, assessEifel as vt, QC_TAX_2024 as w, computeDayWeightedGeneralTax as wi, albertaAbilDifference as wn, computeCeeSuccessor as wr, dayWeightedRate as wt, computeQuebecReturn as x, computeAlbertaTax as xi, CCA_RATE_BOOK as xn, computeCdeRegular as xr, isSchedule5Province as xt, renderCo17DraftReturn as y, schedule2Values as yi, leaseholdPeriods as yn, computeCcogpeRegular as yr, PROVINCE_RATES_2024 as yt, computeSchedule54 as z, RSI_NEGATIVE_PREFIX as zn, ALBERTA_SRED_TAX_CREDIT_RATE as zr, computeOtherLossByYearOfOrigin as zt };
|