@classytic/ca-tax 0.0.5 → 0.0.13

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/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
- /** Per-pool line numbers, from the live form. */
681
- const S21_POOL_LINES = {
682
- nonCapital: {
683
- opening: "031",
684
- current: "037",
685
- carryBack: "047",
686
- closing: "049"
687
- },
688
- capital: {
689
- opening: "051",
690
- current: "057",
691
- carryBack: "067",
692
- closing: "069"
693
- },
694
- farm: {
695
- opening: "071",
696
- current: "077",
697
- carryBack: "085",
698
- closing: "087"
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 [pool, lines] of Object.entries(S21_POOL_LINES)) {
721
- const c = input[pool];
717
+ for (const [inputKey, poolKey] of Object.entries(POOL_KEY)) {
718
+ const c = input[inputKey];
722
719
  if (!c) continue;
723
- put(lines.opening, c.openingBalance);
724
- put(lines.current, c.currentYearLoss);
725
- put(lines.carryBack, c.carriedBack);
726
- put(lines.closing, c.closingBalance);
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
@@ -732,8 +812,8 @@ function schedule21Values(input) {
732
812
  }
733
813
  function schedule1Values(input) {
734
814
  const values = [];
735
- const put = (fieldId, value) => values.push({
736
- lineItemId: at1LineItemId("001", fieldId),
815
+ const put = (fieldId, value, occurrence = 1) => values.push({
816
+ lineItemId: at1LineItemId("001", fieldId, occurrence),
737
817
  value
738
818
  });
739
819
  if (input.isAssociated !== void 0) put("001", input.isAssociated ? 1 : 2);
@@ -746,6 +826,12 @@ function schedule1Values(input) {
746
826
  put("009", taxable);
747
827
  if (input.royaltyTaxDeduction !== void 0) put("011", royalty);
748
828
  put("013", Math.max(0, taxable - royalty));
829
+ input.agreementMembers?.forEach((m, i) => {
830
+ const n = i + 1;
831
+ if (m.name !== void 0) put("041", m.name, n);
832
+ if (m.albertaCan !== void 0) put("043", m.albertaCan, n);
833
+ if (m.allocatedAmount !== void 0) put("045", m.allocatedAmount, n);
834
+ });
749
835
  return {
750
836
  scheduleId: "001",
751
837
  values
@@ -787,6 +873,10 @@ function schedule10Values(input) {
787
873
  value
788
874
  });
789
875
  };
876
+ if (!!!(input.nonCapital || input.farm || input.otherLoss || input.capital)) return {
877
+ scheduleId: "010",
878
+ values
879
+ };
790
880
  for (const [f, d] of zip([
791
881
  "003",
792
882
  "005",
@@ -801,6 +891,26 @@ function schedule10Values(input) {
801
891
  ], input.nonCapital.carrybacks)) put(f, c.amount);
802
892
  put("010", input.nonCapital.remainingLoss);
803
893
  }
894
+ if (input.farm) {
895
+ put("012", input.farm.currentYearLoss);
896
+ for (const [f, c] of zip([
897
+ "014",
898
+ "016",
899
+ "018"
900
+ ], input.farm.carrybacks)) put(f, c.amount);
901
+ put("020", input.farm.remainingLoss);
902
+ }
903
+ put("023", input.otherLoss?.includesRestrictedFarm ? 1 : 2);
904
+ put("025", input.otherLoss?.includesListedPersonal ? 1 : 2);
905
+ if (input.otherLoss) {
906
+ put("032", input.otherLoss.result.currentYearLoss);
907
+ for (const [f, c] of zip([
908
+ "034",
909
+ "036",
910
+ "038"
911
+ ], input.otherLoss.result.carrybacks)) put(f, c.amount);
912
+ put("040", input.otherLoss.result.remainingLoss);
913
+ }
804
914
  if (input.capital) {
805
915
  const rate = input.inclusionRate ?? .5;
806
916
  put("042", input.capital.currentYearLoss);
@@ -857,104 +967,2365 @@ function donationContinuityValues(result, f) {
857
967
  put(f.closing, result.closingBalance)
858
968
  ];
859
969
  }
860
- function schedule20Values(input) {
861
- const values = [];
862
- if (input.charitable) values.push(...donationContinuityValues(input.charitable, S20_CHARITABLE));
863
- if (input.gifts) values.push(...donationContinuityValues(input.gifts, S20_GIFTS));
864
- if (input.maximum) {
865
- const put = (fieldId, value) => values.push({
866
- lineItemId: at1LineItemId("020", fieldId),
867
- value
868
- });
869
- put("030", input.maximum.incomeComponent);
870
- put("042", input.maximum.lesserOfProceedsAndCost);
871
- put("044", input.maximum.allowableRecapture);
872
- put("046", input.maximum.gainsComponent);
873
- put("048", input.maximum.maximumDeduction);
970
+ function schedule20Values(input) {
971
+ const values = [];
972
+ if (input.charitable) values.push(...donationContinuityValues(input.charitable, S20_CHARITABLE));
973
+ if (input.gifts) values.push(...donationContinuityValues(input.gifts, S20_GIFTS));
974
+ if (input.maximum) {
975
+ const put = (fieldId, value) => values.push({
976
+ lineItemId: at1LineItemId("020", fieldId),
977
+ value
978
+ });
979
+ put("030", input.maximum.incomeComponent);
980
+ put("042", input.maximum.lesserOfProceedsAndCost);
981
+ put("044", input.maximum.allowableRecapture);
982
+ put("046", input.maximum.gainsComponent);
983
+ put("048", input.maximum.maximumDeduction);
984
+ }
985
+ const cf = input.gifts?.carryforward;
986
+ if (cf?.yearOfOrigin !== void 0) {
987
+ values.push({
988
+ lineItemId: at1LineItemId("020", "090"),
989
+ value: cf.yearOfOrigin
990
+ });
991
+ if (cf.charitable !== void 0) values.push({
992
+ lineItemId: at1LineItemId("020", "092"),
993
+ value: cf.charitable
994
+ });
995
+ if (cf.toCanadaOrProvince !== void 0) values.push({
996
+ lineItemId: at1LineItemId("020", "094"),
997
+ value: cf.toCanadaOrProvince
998
+ });
999
+ if (cf.culturalProperty !== void 0) values.push({
1000
+ lineItemId: at1LineItemId("020", "096"),
1001
+ value: cf.culturalProperty
1002
+ });
1003
+ if (cf.ecologicalLand !== void 0) values.push({
1004
+ lineItemId: at1LineItemId("020", "098"),
1005
+ value: cf.ecologicalLand
1006
+ });
1007
+ if (cf.medicine !== void 0) values.push({
1008
+ lineItemId: at1LineItemId("020", "100"),
1009
+ value: cf.medicine
1010
+ });
1011
+ }
1012
+ return {
1013
+ scheduleId: "020",
1014
+ values
1015
+ };
1016
+ }
1017
+ /**
1018
+ * The SR&ED expenditure POOL — a deduction against income, not the investment tax
1019
+ * credit and not the innovation grant.
1020
+ *
1021
+ * Line numbers and the subtotal formula verified against the live form, which
1022
+ * states it exactly as transcribed:
1023
+ *
1024
+ * 016 = 002 − (004 + 006 + 008) + 010 + 012 + 014 + 015
1025
+ *
1026
+ * and closes the year-over-year chain in as many words: line 022 is *"the carry
1027
+ * forward amount for next year, line 012"*.
1028
+ */
1029
+ function schedule16Values(result) {
1030
+ const values = [];
1031
+ const put = (fieldId, value) => values.push({
1032
+ lineItemId: at1LineItemId("016", fieldId),
1033
+ value
1034
+ });
1035
+ put("002", result.currentYearExpenditures);
1036
+ put("016", result.subtotal);
1037
+ put("018", result.deductionAvailable);
1038
+ put("020", result.amountClaimed);
1039
+ put("022", result.unclaimedPoolBalance);
1040
+ return {
1041
+ scheduleId: "016",
1042
+ values
1043
+ };
1044
+ }
1045
+ //#endregion
1046
+ //#region src/t2/at1/schedules/at4970-ieg-projects.ts
1047
+ const nn$34 = (v) => Math.max(0, Math.round(v ?? 0));
1048
+ function computeAt4970(input) {
1049
+ const projects = input.projects.map((p) => ({
1050
+ title: p.title,
1051
+ ...p.projectCode !== void 0 ? { projectCode: p.projectCode } : {},
1052
+ albertaPortion: nn$34(p.albertaPortion),
1053
+ otherPortion: nn$34(p.otherPortion),
1054
+ salariesAndWages: nn$34(p.salariesAndWages),
1055
+ federalProxyAmount: nn$34(p.federalProxyAmount),
1056
+ albertaProxyAmount: nn$34(p.albertaProxyAmount)
1057
+ }));
1058
+ const totals = {
1059
+ albertaPortion: projects.reduce((s, p) => s + p.albertaPortion, 0),
1060
+ otherPortion: projects.reduce((s, p) => s + p.otherPortion, 0),
1061
+ salariesAndWages: projects.reduce((s, p) => s + p.salariesAndWages, 0),
1062
+ federalProxyAmount: projects.reduce((s, p) => s + p.federalProxyAmount, 0),
1063
+ albertaProxyAmount: projects.reduce((s, p) => s + p.albertaProxyAmount, 0)
1064
+ };
1065
+ const jurisdictions = (input.jurisdictions ?? []).map((j) => ({
1066
+ jurisdiction: j.jurisdiction,
1067
+ amountIncurred: nn$34(j.amountIncurred)
1068
+ }));
1069
+ return {
1070
+ projects,
1071
+ totals,
1072
+ jurisdictions,
1073
+ jurisdictionTotal: jurisdictions.reduce((s, j) => s + j.amountIncurred, 0)
1074
+ };
1075
+ }
1076
+ //#endregion
1077
+ //#region src/t2/at1/schedules/schedule2.ts
1078
+ /** Round to six decimal places — the AT1 allocation-factor precision. */
1079
+ function round6(n) {
1080
+ return Math.round(n * 1e6) / 1e6;
1081
+ }
1082
+ /** Single Alberta PE, none elsewhere → all income is Alberta income. */
1083
+ const SINGLE_JURISDICTION_ALBERTA_FACTOR = 1;
1084
+ function computeAllocationFactor(input) {
1085
+ const hasRevenue = input.totalGrossRevenue > 0;
1086
+ const hasSalaries = input.totalSalaries > 0;
1087
+ const revenueRatio = hasRevenue ? input.albertaGrossRevenue / input.totalGrossRevenue : 0;
1088
+ const salariesRatio = hasSalaries ? input.albertaSalaries / input.totalSalaries : 0;
1089
+ let factor;
1090
+ if (hasRevenue && hasSalaries) factor = (revenueRatio + salariesRatio) / 2;
1091
+ else if (hasRevenue) factor = revenueRatio;
1092
+ else if (hasSalaries) factor = salariesRatio;
1093
+ else factor = 0;
1094
+ return round6(factor);
1095
+ }
1096
+ //#endregion
1097
+ //#region src/t2/at1/schedules/schedule3-other-deductions-credits.ts
1098
+ /**
1099
+ * Alberta AT1 Schedule 3 — Alberta Other Tax Deductions and Credits.
1100
+ *
1101
+ * NOT one calculation. The spec (TRA spec §3.2.3.4, "3B3B3.2.3.4 Schedule 3 -
1102
+ * Alberta Other Tax Deductions and Credits", `AT1-Chapter3-2025.2-full.txt`
1103
+ * lines 4127-4898) groups THREE independent non-refundable investment tax
1104
+ * credit continuities under one shared ceiling:
1105
+ *
1106
+ * ITC Investor Tax Credit (lines 100-108, 120-130)
1107
+ * CITC Capital Investment Tax Credit (lines 200-208, 220-230)
1108
+ * APITC Agri-Processing Investment Tax Credit (lines 300-316, 330-340)
1109
+ * MAD Maximum Allowable Deduction — the shared ceiling (lines 600-604)
1110
+ *
1111
+ * No matching form PDF exists under `research/sources/tra-forms/pdf/` (searched
1112
+ * for `AT1SCH03*` — nothing found, unlike every other schedule this package
1113
+ * models). The specification TEXT is therefore the only source for this
1114
+ * schedule's shape; there is no live-form layout to cross-check it against.
1115
+ *
1116
+ * ── The shared ceiling (lines 600-604) ───────────────────────────────────────
1117
+ *
1118
+ * 600 = 003104 + 003204 + 003312 (ITC + CITC + APITC applied)
1119
+ * 602 = 000068 − (000070+000071+000072+000074) (AT1 page 2 room)
1120
+ * 604 = lesser of 600 and 602 ("Total Deduction")
1121
+ *
1122
+ * `000068`/`000070`/`000071`/`000072`/`000074` are AT1 page-2 jacket lines this
1123
+ * engine does not compute here (out of this module's scope per the task's scope
1124
+ * rule) — they are plain numeric inputs (`MaximumAllowableDeductionInput`).
1125
+ *
1126
+ * ── Three pools, one room, in a STATED precedence ────────────────────────────
1127
+ *
1128
+ * ITC is applied first, capped only by 602 itself:
1129
+ * 104 ≤ 000068 − (000070+000071+000072+000074)
1130
+ *
1131
+ * CITC is gated behind ITC: "If 003108 > 0 [ITC still has an unused carryforward
1132
+ * balance after this year's application], then [204] must equal zero." Only once
1133
+ * the ITC pool is fully drawn down may CITC be claimed, capped at what room ITC
1134
+ * left behind:
1135
+ * 204 ≤ 602 − 104 (when 108 = 0; otherwise 204 = 0)
1136
+ *
1137
+ * APITC draws on what both leave behind, but against a DIFFERENT room formula —
1138
+ * the spec's four "cannot exceed" clauses for 304/306/308/310 all subtract only
1139
+ * `(000070+000072)`, NOT `000071`/`000074` the way 104/204/602 do. That asymmetry
1140
+ * is transcribed exactly as written, not corrected, because it repeats
1141
+ * identically across all five APITC business-rule cells (304, 306, 308, 310, 312)
1142
+ * — consistent enough to be deliberate rather than a transcription slip:
1143
+ * 312 ≤ 000068 − (000070+000072) − (104+204)
1144
+ *
1145
+ * ── APITC: per-vintage percentage caps ───────────────────────────────────────
1146
+ *
1147
+ * The four "cannot exceed" clauses for 304/306/308/310, read together, are
1148
+ * algebraically just ONE combined-total constraint stated four times from four
1149
+ * different partial-sum vantage points (each says "this line ≤ R − the lines
1150
+ * listed", and the lines listed are exactly the OTHER three) — they collapse to
1151
+ * `304+306+308+310 ≤ R`, which is exactly what 312's own business rule states
1152
+ * directly. So the four clauses add nothing beyond that one shared-room ceiling;
1153
+ * what makes each vintage different is its OWN percentage cap from AAPITC
1154
+ * (330-340):
1155
+ *
1156
+ * occurrence 0 (current year, 334/336 occ 0) ≤ 20% of that vintage's receipt
1157
+ * occurrence 1 (1st preceding, occ 1) ≤ 30% of that vintage's receipt
1158
+ * occurrence 2 (2nd preceding, occ 2) ≤ 50% of that vintage's receipt
1159
+ * occurrences 3-10 (3rd-10th preceding) no percentage cap, own balance only
1160
+ *
1161
+ * `computeSchedule3` claims each vintage's OWN cap first, then allocates the
1162
+ * shared room OLDEST-VINTAGE-FIRST when the total requested exceeds it — APITC
1163
+ * is a 10-year-preceding, use-it-or-lose-it credit and the spec states no
1164
+ * application order, so this engine flags that choice in `issues` rather than
1165
+ * silently guessing at NetFile's actual tie-break. Supply `amountApplied` on
1166
+ * each vintage directly for exact filing parity.
1167
+ *
1168
+ * ── What is deliberately NOT modelled ────────────────────────────────────────
1169
+ *
1170
+ * The AITC/ACITC year-of-origin analysis tables (120-130, 220-230) are
1171
+ * supplementary detail TRA requires when a corporation carries ITC or CITC.
1172
+ * Unlike AAPITC, the spec gives them no percentage cap or application order of
1173
+ * their own — every business rule on those lines is a reconciliation back to the
1174
+ * aggregate 104/106/204/206 this module already computes (e.g. "126 … Value must
1175
+ * be less than or equal to 124+125", "130 … calculate 124+125-126-128"). Adding a
1176
+ * per-vintage array for ITC/CITC would only re-derive numbers this module
1177
+ * already produces without a spec-given rule to allocate them across years, so
1178
+ * it is left out; a caller filing the AITC/ACITC detail pages supplies that
1179
+ * per-vintage split itself.
1180
+ *
1181
+ * Whole dollars, pure.
1182
+ */
1183
+ const nn$33 = (v) => Math.max(0, Math.round(v ?? 0));
1184
+ const raw = (v) => Math.round(v ?? 0);
1185
+ function computeItc(input, roomCap, issues) {
1186
+ const certificatesIssued = nn$33(input.certificatesIssued);
1187
+ const carryforwardFromPriorYear = nn$33(input.carryforwardFromPriorYear);
1188
+ const expired = nn$33(input.expired);
1189
+ const availableBeforeClaim = certificatesIssued + carryforwardFromPriorYear;
1190
+ const cap = Math.min(availableBeforeClaim, roomCap);
1191
+ const wanted = input.amountApplied != null ? nn$33(input.amountApplied) : cap;
1192
+ const amountApplied = Math.max(0, Math.min(wanted, cap));
1193
+ const carryforwardToNextYear = availableBeforeClaim - amountApplied - expired;
1194
+ 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.`);
1195
+ return {
1196
+ certificatesIssued,
1197
+ carryforwardFromPriorYear,
1198
+ availableBeforeClaim,
1199
+ amountApplied,
1200
+ expired,
1201
+ carryforwardToNextYear
1202
+ };
1203
+ }
1204
+ function computeCitc(input, roomCap, itcApplied, itcCarryforwardRemaining, issues) {
1205
+ const certificatesIssued = nn$33(input.certificatesIssued);
1206
+ const carryforwardFromPriorYear = nn$33(input.carryforwardFromPriorYear);
1207
+ const expired = nn$33(input.expired);
1208
+ const availableBeforeClaim = certificatesIssued + carryforwardFromPriorYear;
1209
+ let amountApplied;
1210
+ if (itcCarryforwardRemaining > 0) {
1211
+ amountApplied = 0;
1212
+ 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.`);
1213
+ } else {
1214
+ const cap = Math.min(availableBeforeClaim, Math.max(0, roomCap - itcApplied));
1215
+ const wanted = input.amountApplied != null ? nn$33(input.amountApplied) : cap;
1216
+ amountApplied = Math.max(0, Math.min(wanted, cap));
1217
+ }
1218
+ const carryforwardToNextYear = availableBeforeClaim - amountApplied - expired;
1219
+ 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.`);
1220
+ return {
1221
+ certificatesIssued,
1222
+ carryforwardFromPriorYear,
1223
+ availableBeforeClaim,
1224
+ amountApplied,
1225
+ expired,
1226
+ carryforwardToNextYear
1227
+ };
1228
+ }
1229
+ function computeApitc(input, roomCap, issues) {
1230
+ const current = input.current ?? {};
1231
+ const first = input.firstPreceding ?? {};
1232
+ const second = input.secondPreceding ?? {};
1233
+ const thirdToTenth = input.thirdToTenthPreceding ?? {};
1234
+ const currentAvailable = nn$33(current.received);
1235
+ const firstAvailable = nn$33(first.availableAtBeginning);
1236
+ const secondAvailable = nn$33(second.availableAtBeginning);
1237
+ const thirdToTenthAvailable = nn$33(thirdToTenth.availableAtBeginning);
1238
+ const currentCap = Math.round(currentAvailable * .2);
1239
+ const firstCap = Math.round(firstAvailable * .3);
1240
+ const secondCap = Math.round(secondAvailable * .5);
1241
+ const thirdToTenthCap = thirdToTenthAvailable;
1242
+ const currentAsk = Math.min(current.amountApplied != null ? nn$33(current.amountApplied) : currentCap, currentCap);
1243
+ const firstAsk = Math.min(first.amountApplied != null ? nn$33(first.amountApplied) : firstCap, firstCap);
1244
+ const secondAsk = Math.min(second.amountApplied != null ? nn$33(second.amountApplied) : secondCap, secondCap);
1245
+ const thirdToTenthAsk = Math.min(thirdToTenth.amountApplied != null ? nn$33(thirdToTenth.amountApplied) : thirdToTenthCap, thirdToTenthCap);
1246
+ const totalRequested = currentAsk + firstAsk + secondAsk + thirdToTenthAsk;
1247
+ let room = Math.max(0, roomCap);
1248
+ const allocate = (ask) => {
1249
+ const got = Math.min(ask, room);
1250
+ room -= got;
1251
+ return got;
1252
+ };
1253
+ const thirdToTenthApplied = allocate(thirdToTenthAsk);
1254
+ const secondApplied = allocate(secondAsk);
1255
+ const firstApplied = allocate(firstAsk);
1256
+ const currentApplied = allocate(currentAsk);
1257
+ const totalApplied = currentApplied + firstApplied + secondApplied + thirdToTenthApplied;
1258
+ 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.`);
1259
+ const totalReceived = currentAvailable;
1260
+ const carryforwardFromPriorYear = firstAvailable + secondAvailable + thirdToTenthAvailable;
1261
+ const expired = nn$33(input.expiredThisYear);
1262
+ const availableForCarryforward = totalReceived + carryforwardFromPriorYear - totalApplied - expired;
1263
+ 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.`);
1264
+ return {
1265
+ current: {
1266
+ available: currentAvailable,
1267
+ ownCap: currentCap,
1268
+ amountApplied: currentApplied
1269
+ },
1270
+ firstPreceding: {
1271
+ available: firstAvailable,
1272
+ ownCap: firstCap,
1273
+ amountApplied: firstApplied
1274
+ },
1275
+ secondPreceding: {
1276
+ available: secondAvailable,
1277
+ ownCap: secondCap,
1278
+ amountApplied: secondApplied
1279
+ },
1280
+ thirdToTenthPreceding: {
1281
+ available: thirdToTenthAvailable,
1282
+ amountApplied: thirdToTenthApplied
1283
+ },
1284
+ totalReceived,
1285
+ carryforwardFromPriorYear,
1286
+ totalRequested,
1287
+ totalApplied,
1288
+ expired,
1289
+ availableForCarryforward
1290
+ };
1291
+ }
1292
+ function computeSchedule3(input) {
1293
+ const issues = [];
1294
+ const mad = input.mad ?? {};
1295
+ const line068 = nn$33(mad.taxPayableBeforeDeduction);
1296
+ const line070 = nn$33(mad.line070);
1297
+ const line071 = nn$33(mad.line071);
1298
+ const line072 = nn$33(mad.line072);
1299
+ const line074 = nn$33(mad.line074);
1300
+ const room602 = raw(line068) - (line070 + line071 + line072 + line074);
1301
+ const itcCitcCap = Math.max(0, room602);
1302
+ const itc = computeItc(input.itc ?? {}, itcCitcCap, issues);
1303
+ const citc = computeCitc(input.citc ?? {}, itcCitcCap, itc.amountApplied, itc.carryforwardToNextYear, issues);
1304
+ const apitcRoom = Math.max(0, line068 - (line070 + line072) - (itc.amountApplied + citc.amountApplied));
1305
+ const apitc = computeApitc(input.apitc ?? {}, apitcRoom, issues);
1306
+ const creditsApplied = itc.amountApplied + citc.amountApplied + apitc.totalApplied;
1307
+ return {
1308
+ mad: {
1309
+ creditsApplied,
1310
+ room: room602
1311
+ },
1312
+ itc,
1313
+ citc,
1314
+ apitc,
1315
+ totalDeduction: Math.max(0, Math.min(creditsApplied, Math.max(0, room602))),
1316
+ issues
1317
+ };
1318
+ }
1319
+ function schedule3LineItemId(fieldId, occurrence = 1) {
1320
+ return `003${fieldId}${String(occurrence).padStart(3, "0")}`;
1321
+ }
1322
+ /**
1323
+ * Field ids per the spec transcription above: 100-108 (ITC), 200-208 (CITC),
1324
+ * 300-316 (APITC), 600-604 (MAD). The by-year-of-origin detail pages
1325
+ * (120-130/220-230/330-340) are NOT emitted — this module does not compute a
1326
+ * per-vintage split for ITC/CITC (see the module docstring), and the APITC
1327
+ * per-vintage figures this DOES compute (304/306/308/310) are filed on the
1328
+ * 300-series rollup, not re-emitted as an AAPITC occurrence table.
1329
+ */
1330
+ function schedule3Values(result) {
1331
+ const values = [];
1332
+ const put = (fieldId, value) => values.push({
1333
+ lineItemId: schedule3LineItemId(fieldId),
1334
+ value
1335
+ });
1336
+ put("100", result.itc.certificatesIssued);
1337
+ put("102", result.itc.carryforwardFromPriorYear);
1338
+ put("104", result.itc.amountApplied);
1339
+ put("106", result.itc.expired);
1340
+ put("108", result.itc.carryforwardToNextYear);
1341
+ put("200", result.citc.certificatesIssued);
1342
+ put("202", result.citc.carryforwardFromPriorYear);
1343
+ put("204", result.citc.amountApplied);
1344
+ put("206", result.citc.expired);
1345
+ put("208", result.citc.carryforwardToNextYear);
1346
+ put("300", result.apitc.totalReceived);
1347
+ put("302", result.apitc.carryforwardFromPriorYear);
1348
+ put("304", result.apitc.current.amountApplied);
1349
+ put("306", result.apitc.firstPreceding.amountApplied);
1350
+ put("308", result.apitc.secondPreceding.amountApplied);
1351
+ put("310", result.apitc.thirdToTenthPreceding.amountApplied);
1352
+ put("312", result.apitc.totalApplied);
1353
+ put("314", result.apitc.expired);
1354
+ put("316", result.apitc.availableForCarryforward);
1355
+ put("600", result.mad.creditsApplied);
1356
+ put("602", result.mad.room);
1357
+ put("604", result.totalDeduction);
1358
+ return {
1359
+ scheduleId: "003",
1360
+ values
1361
+ };
1362
+ }
1363
+ //#endregion
1364
+ //#region src/t2/at1/schedules/schedule4-foreign-investment-tax-credit.ts
1365
+ const nn$32 = (v) => Math.max(0, v ?? 0);
1366
+ /** Round to 3 decimal places, half-up — the precision the spec directs for D and G. */
1367
+ function round3(v) {
1368
+ return Math.round((v + Number.EPSILON) * 1e3) / 1e3;
1369
+ }
1370
+ function computeSchedule4(input) {
1371
+ const issues = [];
1372
+ const albertaTaxableIncome = nn$32(input.albertaTaxableIncome);
1373
+ const royaltyTaxDeduction = nn$32(input.royaltyTaxDeduction);
1374
+ const allocationFactor = input.allocationFactor ?? 0;
1375
+ const basicAlbertaTax = nn$32(input.basicAlbertaTax);
1376
+ const denominator = (albertaTaxableIncome - royaltyTaxDeduction) * allocationFactor;
1377
+ const countries = input.countries.map((c) => {
1378
+ if (!c.country) issues.push("Alberta Schedule 4: a country code is required for each occurrence (004002).");
1379
+ const netForeignInvestmentIncome = nn$32(c.netForeignInvestmentIncome);
1380
+ const fedForeignTaxPaid = nn$32(c.fedForeignTaxPaid);
1381
+ const fedIta2012Deduction = nn$32(c.fedIta2012Deduction);
1382
+ const albertaDeduction = Math.max(c.albertaActa82Deduction ?? fedIta2012Deduction, fedIta2012Deduction);
1383
+ const taxPaidNetOfDeduction = Math.max(0, fedForeignTaxPaid - albertaDeduction);
1384
+ const federalNonBusinessForeignTaxCredit = nn$32(c.fedNonBusinessForeignTaxCredit);
1385
+ let incomeProrationAmount;
1386
+ if (denominator === 0) {
1387
+ incomeProrationAmount = 0;
1388
+ 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.`);
1389
+ } else incomeProrationAmount = round3(netForeignInvestmentIncome * allocationFactor * (basicAlbertaTax / denominator));
1390
+ const taxPaidLessFederalCredit = round3((taxPaidNetOfDeduction - federalNonBusinessForeignTaxCredit) * allocationFactor);
1391
+ const allowableCredit = Math.max(0, Math.round(Math.min(incomeProrationAmount, taxPaidLessFederalCredit)));
1392
+ return {
1393
+ country: c.country,
1394
+ netForeignInvestmentIncome,
1395
+ taxPaidNetOfDeduction,
1396
+ federalNonBusinessForeignTaxCredit,
1397
+ incomeProrationAmount,
1398
+ taxPaidLessFederalCredit,
1399
+ allowableCredit
1400
+ };
1401
+ });
1402
+ const totalAllowableCredit = countries.reduce((sum, c) => sum + c.allowableCredit, 0);
1403
+ 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.");
1404
+ return {
1405
+ countries,
1406
+ totalAllowableCredit,
1407
+ issues
1408
+ };
1409
+ }
1410
+ /**
1411
+ * Net File line items for AT1 Schedule 4 — one FIC occurrence per country.
1412
+ * Field ids from the spec (§3.2.3.5): 002 country, 004 net foreign investment
1413
+ * income, 006 foreign tax paid net of deduction, 008 federal non-business
1414
+ * foreign tax credit, 012 allowable credit.
1415
+ *
1416
+ * Does NOT emit jacket line 000072 (the sum-vs-remaining-tax comparison) —
1417
+ * that is a jacket line, not a Schedule 4 line, and belongs to whichever
1418
+ * module builds the jacket. Use `result.totalAllowableCredit` for that.
1419
+ */
1420
+ function schedule4Values(result) {
1421
+ const values = [];
1422
+ result.countries.forEach((c, i) => {
1423
+ const n = i + 1;
1424
+ const put = (fieldId, value) => values.push({
1425
+ lineItemId: at1LineItemId("004", fieldId, n),
1426
+ value
1427
+ });
1428
+ put("002", c.country);
1429
+ put("004", c.netForeignInvestmentIncome);
1430
+ put("006", c.taxPaidNetOfDeduction);
1431
+ put("008", c.federalNonBusinessForeignTaxCredit);
1432
+ put("012", c.allowableCredit);
1433
+ });
1434
+ return {
1435
+ scheduleId: "004",
1436
+ values
1437
+ };
1438
+ }
1439
+ //#endregion
1440
+ //#region src/t2/at1/schedules/schedule5-royalty-tax-deduction.ts
1441
+ const nn$31 = (v) => Math.max(0, Math.round(v ?? 0));
1442
+ const num$2 = (v) => Math.round(v ?? 0);
1443
+ function processSuccessoredPool(entries, label, issues) {
1444
+ return (entries ?? []).map((e, i) => {
1445
+ const hasBrought = e.poolBroughtForward !== void 0;
1446
+ const hasAcquired = e.acquisitionAmount !== void 0;
1447
+ 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.`);
1448
+ 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.`);
1449
+ const base = nn$31(hasBrought ? e.poolBroughtForward : e.acquisitionAmount);
1450
+ const baseKind = hasBrought ? "broughtForward" : hasAcquired ? "acquired" : "unspecified";
1451
+ const propertyIncome = nn$31(e.propertyIncome);
1452
+ const claim = Math.min(base, propertyIncome);
1453
+ return {
1454
+ vendorName: e.vendorName,
1455
+ dateOfEvent: e.dateOfEvent,
1456
+ base,
1457
+ baseKind,
1458
+ propertyIncome,
1459
+ claim,
1460
+ carryForwardBeforeTransfer: base - claim
1461
+ };
1462
+ });
1463
+ }
1464
+ function computeAlbertaSchedule5(input) {
1465
+ const issues = [];
1466
+ const crownCharges = nn$31(input.crownChargesNetOfReimbursements);
1467
+ const resourceAllowance = nn$31(input.albertaResourceAllowance ?? input.federalResourceAllowance);
1468
+ const reimbursements = nn$31(input.reimbursementsForCrownCharges);
1469
+ const predecessorTransfersTotal = (input.predecessorTransfers ?? []).reduce((s, t) => s + nn$31(t.amountTransferred), 0);
1470
+ const attributedRoyaltyIncomeCarryForwardIn = nn$31(input.openingUnsuccessoredPoolBalance) + predecessorTransfersTotal;
1471
+ const unsuccessoredPoolAvailable = crownCharges - resourceAllowance - reimbursements + attributedRoyaltyIncomeCarryForwardIn;
1472
+ const hasSuccessoredPools = input.hasSuccessoredPools ?? false;
1473
+ 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.");
1474
+ const secondSuccessoredPools = hasSuccessoredPools ? processSuccessoredPool(input.secondSuccessoredPools, "second successored (SSPI)", issues) : [];
1475
+ const firstSuccessoredPools = hasSuccessoredPools ? processSuccessoredPool(input.firstSuccessoredPools, "first successored (FSPI)", issues) : [];
1476
+ const secondSuccessoredSubtotal = secondSuccessoredPools.reduce((s, e) => s + e.carryForwardBeforeTransfer, 0);
1477
+ const firstSuccessoredSubtotal = firstSuccessoredPools.reduce((s, e) => s + e.carryForwardBeforeTransfer, 0);
1478
+ const successoredTotal = secondSuccessoredPools.reduce((s, e) => s + e.claim, 0) + firstSuccessoredPools.reduce((s, e) => s + e.claim, 0);
1479
+ const albertaTaxableIncome = num$2(input.albertaTaxableIncomeBeforeDeduction);
1480
+ const crtdMaxClaimable = Math.max(0, Math.min(unsuccessoredPoolAvailable, albertaTaxableIncome - successoredTotal));
1481
+ const crtdClaim = input.crtdAmountClaimed != null ? Math.max(0, Math.min(Math.round(input.crtdAmountClaimed), crtdMaxClaimable)) : crtdMaxClaimable;
1482
+ const poolAvailableCarryForward = unsuccessoredPoolAvailable - crtdClaim;
1483
+ const transferredOnDisposal = nn$31(input.transferredOnDisposal);
1484
+ const uncappedTotal = crtdClaim + successoredTotal;
1485
+ const totalRoyaltyTaxDeduction = Math.max(0, Math.min(uncappedTotal, albertaTaxableIncome));
1486
+ 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.`);
1487
+ 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.`);
1488
+ const netOfResourceAllowance = crownCharges - resourceAllowance;
1489
+ const carryForwardRaw = netOfResourceAllowance >= 0 ? netOfResourceAllowance + attributedRoyaltyIncomeCarryForwardIn - totalRoyaltyTaxDeduction - transferredOnDisposal : attributedRoyaltyIncomeCarryForwardIn - totalRoyaltyTaxDeduction - transferredOnDisposal;
1490
+ const attributedRoyaltyIncomeCarryForwardOut = Math.max(0, carryForwardRaw);
1491
+ if (input.poolTransfer) {
1492
+ const { type, acquirerName } = input.poolTransfer;
1493
+ 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.");
1494
+ 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.");
1495
+ }
1496
+ if (input.changeInControlEndedPrecedingYear !== void 0 && input.at1TaxYearEndChanged !== void 0 && input.at1TaxYearEndChangeReason !== void 0) {
1497
+ const cicChangedYearEnd = input.at1TaxYearEndChanged && input.at1TaxYearEndChangeReason === 2;
1498
+ 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.`);
1499
+ }
1500
+ const formRequired = crownCharges > 0 || attributedRoyaltyIncomeCarryForwardIn > 0 || hasSuccessoredPools;
1501
+ return {
1502
+ crownCharges,
1503
+ resourceAllowance,
1504
+ reimbursements,
1505
+ predecessorTransfersTotal,
1506
+ attributedRoyaltyIncomeCarryForwardIn,
1507
+ unsuccessoredPoolAvailable,
1508
+ crtdMaxClaimable,
1509
+ crtdClaim,
1510
+ poolAvailableCarryForward,
1511
+ transferredOnDisposal,
1512
+ secondSuccessoredPools,
1513
+ firstSuccessoredPools,
1514
+ secondSuccessoredSubtotal,
1515
+ firstSuccessoredSubtotal,
1516
+ successoredTotal,
1517
+ totalRoyaltyTaxDeduction,
1518
+ attributedRoyaltyIncomeCarryForwardOut,
1519
+ ...input.poolTransfer !== void 0 ? { poolTransfer: input.poolTransfer } : {},
1520
+ ...input.changeInControlEndedPrecedingYear !== void 0 ? { changeInControlEndedPrecedingYear: input.changeInControlEndedPrecedingYear } : {},
1521
+ formRequired,
1522
+ issues
1523
+ };
1524
+ }
1525
+ /** `005` + field id + 3-digit occurrence — the nine-digit AT1 line item id. */
1526
+ function schedule5LineItemId(fieldId, occurrence = 1) {
1527
+ return `005${fieldId}${String(occurrence).padStart(3, "0")}`;
1528
+ }
1529
+ function putSuccessoredPool(values, entries, fields) {
1530
+ entries.forEach((e, i) => {
1531
+ const n = i + 1;
1532
+ const put = (fieldId, value) => values.push({
1533
+ lineItemId: schedule5LineItemId(fieldId, n),
1534
+ value
1535
+ });
1536
+ put(fields.vendorName, e.vendorName);
1537
+ put(fields.dateOfEvent, e.dateOfEvent);
1538
+ if (e.baseKind === "broughtForward") put(fields.broughtForward, e.base);
1539
+ else if (e.baseKind === "acquired") put(fields.acquired, e.base);
1540
+ put(fields.propertyIncome, e.propertyIncome);
1541
+ put(fields.claim, e.claim);
1542
+ put(fields.carryForward, e.carryForwardBeforeTransfer);
1543
+ });
1544
+ }
1545
+ function schedule5Values(result) {
1546
+ const values = [];
1547
+ const put = (fieldId, value) => values.push({
1548
+ lineItemId: schedule5LineItemId(fieldId),
1549
+ value
1550
+ });
1551
+ put("001", result.crownCharges);
1552
+ put("005", result.resourceAllowance);
1553
+ put("007", result.reimbursements);
1554
+ put("011", result.attributedRoyaltyIncomeCarryForwardIn);
1555
+ put("016", result.crtdClaim);
1556
+ put("017", result.poolAvailableCarryForward);
1557
+ put("023", result.transferredOnDisposal);
1558
+ put("025", result.attributedRoyaltyIncomeCarryForwardOut);
1559
+ if (result.poolTransfer) {
1560
+ put("026", result.poolTransfer.type);
1561
+ if (result.poolTransfer.acquirerName) put("027", result.poolTransfer.acquirerName);
1562
+ }
1563
+ if (result.changeInControlEndedPrecedingYear !== void 0) put("100", result.changeInControlEndedPrecedingYear ? 1 : 2);
1564
+ putSuccessoredPool(values, result.secondSuccessoredPools, {
1565
+ vendorName: "101",
1566
+ dateOfEvent: "103",
1567
+ broughtForward: "105",
1568
+ acquired: "107",
1569
+ propertyIncome: "109",
1570
+ claim: "111",
1571
+ carryForward: "113"
1572
+ });
1573
+ put("115", result.secondSuccessoredSubtotal);
1574
+ putSuccessoredPool(values, result.firstSuccessoredPools, {
1575
+ vendorName: "121",
1576
+ dateOfEvent: "123",
1577
+ broughtForward: "125",
1578
+ acquired: "127",
1579
+ propertyIncome: "129",
1580
+ claim: "131",
1581
+ carryForward: "133"
1582
+ });
1583
+ put("135", result.firstSuccessoredSubtotal);
1584
+ put("140", result.successoredTotal);
1585
+ return {
1586
+ scheduleId: "005",
1587
+ values
1588
+ };
1589
+ }
1590
+ //#endregion
1591
+ //#region src/t2/at1/schedules/schedule6-royalty-tax-credit.ts
1592
+ const rd$1 = (v) => Math.round(v ?? 0);
1593
+ const nn$30 = (v) => Math.max(0, Math.round(v ?? 0));
1594
+ const round4$1 = (v) => Math.round(v * 1e4) / 1e4;
1595
+ function computeWeightedAverageRate(quarters, issues) {
1596
+ if (quarters.length === 0) {
1597
+ 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.");
1598
+ return 0;
1599
+ }
1600
+ const totalDays = quarters.reduce((s, q) => s + Math.max(0, q.days), 0);
1601
+ if (totalDays <= 0) {
1602
+ issues.push("Alberta Schedule 6: the quarters supplied for 006008 total zero days.");
1603
+ return 0;
1604
+ }
1605
+ const weighted = quarters.reduce((s, q) => s + Math.max(0, q.days) / totalDays * q.rate, 0);
1606
+ return round4$1(weighted);
1607
+ }
1608
+ function resolveAllocations(allocations, pool, issues) {
1609
+ const totalRequested = allocations.reduce((s, a) => s + nn$30(a.allocatedAmount), 0);
1610
+ 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.`);
1611
+ let remaining = pool;
1612
+ return allocations.map((a) => {
1613
+ const requestedAmount = nn$30(a.allocatedAmount);
1614
+ const allocatedAmount = Math.min(requestedAmount, remaining);
1615
+ remaining -= allocatedAmount;
1616
+ return {
1617
+ name: a.name,
1618
+ ...a.albertaCan !== void 0 ? { albertaCan: a.albertaCan } : {},
1619
+ allocatedAmount,
1620
+ requestedAmount
1621
+ };
1622
+ });
1623
+ }
1624
+ function schedule6LineItemId(fieldId, occurrence = 1) {
1625
+ return `006${fieldId}${String(occurrence).padStart(3, "0")}`;
1626
+ }
1627
+ /**
1628
+ * Emits every field this module's own MAPPINGS transcription actually defines
1629
+ * a number for: 006002/004/006/008, and — only when the corporation is
1630
+ * associated — the ACRS section (006022-028) and the AACRS allocation table
1631
+ * (006030-034, one occurrence per row).
1632
+ *
1633
+ * ── No credit amount is filed here, because none exists on this schedule ────
1634
+ *
1635
+ * See the module docstring's "CONFIRMED: there is no 'credit' dollar amount
1636
+ * to compute here" section — the Alberta Royalty Tax Credit is an instalment
1637
+ * program (AT1 jacket line 000082, the shared "Payments & Instalments"
1638
+ * schedule), not a value Schedule 6 computes and files. This builder emits
1639
+ * exactly the three components the schedule DOES define (006004, 006006,
1640
+ * 006008) plus the ACRS/AACRS detail when associated — matching
1641
+ * `schedule3Values`'s `At1ScheduleDataLike` shape exactly: `{ scheduleId,
1642
+ * values }`.
1643
+ */
1644
+ function schedule6Values(result) {
1645
+ const values = [];
1646
+ const put = (fieldId, value, occurrence = 1) => values.push({
1647
+ lineItemId: schedule6LineItemId(fieldId, occurrence),
1648
+ value
1649
+ });
1650
+ put("002", result.associatedWithCrownRoyaltyCorporations ? 1 : 2);
1651
+ put("004", result.albertaCrownRoyaltyIncurred);
1652
+ put("006", result.crownRoyaltyShelter);
1653
+ put("008", result.weightedAverageRate);
1654
+ if (result.associatedWithCrownRoyaltyCorporations && result.longestAssociatedYear) {
1655
+ if (result.longestAssociatedYear.albertaCan !== void 0) values.push({
1656
+ lineItemId: schedule6LineItemId("022"),
1657
+ value: result.longestAssociatedYear.albertaCan
1658
+ });
1659
+ if (result.longestAssociatedYear.taxationYearBeginning !== void 0) values.push({
1660
+ lineItemId: schedule6LineItemId("024"),
1661
+ value: result.longestAssociatedYear.taxationYearBeginning
1662
+ });
1663
+ if (result.longestAssociatedYear.taxationYearEnding !== void 0) values.push({
1664
+ lineItemId: schedule6LineItemId("026"),
1665
+ value: result.longestAssociatedYear.taxationYearEnding
1666
+ });
1667
+ put("028", result.longestAssociatedYear.days);
1668
+ result.allocations.forEach((a, i) => {
1669
+ const occurrence = i + 1;
1670
+ values.push({
1671
+ lineItemId: schedule6LineItemId("030", occurrence),
1672
+ value: a.name
1673
+ });
1674
+ if (a.albertaCan !== void 0) values.push({
1675
+ lineItemId: schedule6LineItemId("032", occurrence),
1676
+ value: a.albertaCan
1677
+ });
1678
+ put("034", a.allocatedAmount, occurrence);
1679
+ });
1680
+ }
1681
+ return {
1682
+ scheduleId: "006",
1683
+ values
1684
+ };
1685
+ }
1686
+ function computeAlbertaSchedule6(input) {
1687
+ const issues = [];
1688
+ const associatedWithCrownRoyaltyCorporations = input.associatedWithCrownRoyaltyCorporations ?? false;
1689
+ const albertaCrownRoyaltyIncurred = rd$1(input.albertaCrownRoyaltyIncurred);
1690
+ const weightedAverageRate = computeWeightedAverageRate(input.quarters ?? [], issues);
1691
+ const formRequired = albertaCrownRoyaltyIncurred > 0;
1692
+ if (!associatedWithCrownRoyaltyCorporations) {
1693
+ const days = Math.max(0, Math.min(input.taxationYearDays ?? 365, 365));
1694
+ return {
1695
+ associatedWithCrownRoyaltyCorporations,
1696
+ albertaCrownRoyaltyIncurred,
1697
+ crownRoyaltyShelter: Math.round(2e6 * (days / 365)),
1698
+ weightedAverageRate,
1699
+ aggregateShelterPool: 0,
1700
+ allocations: [],
1701
+ totalAllocated: 0,
1702
+ formRequired,
1703
+ issues
1704
+ };
1705
+ }
1706
+ 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.");
1707
+ const days = Math.max(0, Math.min(input.longestAssociatedYear?.days ?? 0, 365));
1708
+ const aggregateShelterPool = Math.round(2e6 * (days / 365));
1709
+ const rawAllocations = input.allocations ?? [];
1710
+ 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.");
1711
+ const allocations = resolveAllocations(rawAllocations, aggregateShelterPool, issues);
1712
+ const totalAllocated = allocations.reduce((s, a) => s + a.allocatedAmount, 0);
1713
+ return {
1714
+ associatedWithCrownRoyaltyCorporations,
1715
+ albertaCrownRoyaltyIncurred,
1716
+ crownRoyaltyShelter: allocations[0]?.allocatedAmount ?? 0,
1717
+ weightedAverageRate,
1718
+ longestAssociatedYear: {
1719
+ ...input.longestAssociatedYear?.albertaCan !== void 0 ? { albertaCan: input.longestAssociatedYear.albertaCan } : {},
1720
+ ...input.longestAssociatedYear?.taxationYearBeginning !== void 0 ? { taxationYearBeginning: input.longestAssociatedYear.taxationYearBeginning } : {},
1721
+ ...input.longestAssociatedYear?.taxationYearEnding !== void 0 ? { taxationYearEnding: input.longestAssociatedYear.taxationYearEnding } : {},
1722
+ days
1723
+ },
1724
+ aggregateShelterPool,
1725
+ allocations,
1726
+ totalAllocated,
1727
+ formRequired,
1728
+ issues
1729
+ };
1730
+ }
1731
+ //#endregion
1732
+ //#region src/t2/at1/schedules/schedule7-royalty-supplemental.ts
1733
+ /** Signed whole-dollar rounding — no floor, several of these lines are marked "+/-". */
1734
+ const rd = (v) => Math.round(v ?? 0);
1735
+ /** Non-negative whole-dollar rounding, for the "+"-only lines. */
1736
+ const nn$29 = (v) => Math.max(0, Math.round(v ?? 0));
1737
+ const round4 = (v) => Math.round(v * 1e4) / 1e4;
1738
+ function resolvePartnership(p, index, issues) {
1739
+ if (!p.name) issues.push(`Alberta Schedule 7: partnership row ${index + 1} has no name (007071 is mandatory for every PITI occurrence).`);
1740
+ 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%).`);
1741
+ return {
1742
+ name: p.name,
1743
+ interestPercent: round4(p.interestPercent),
1744
+ ...p.fiscalPeriodEnd !== void 0 ? { fiscalPeriodEnd: p.fiscalPeriodEnd } : {},
1745
+ shareEligibleForCredit: nn$29(p.shareEligibleForCredit),
1746
+ shareOtherRoyaltiesNotEligible: nn$29(p.shareOtherRoyaltiesNotEligible),
1747
+ shareOtherCrownChargesEligibleForDeduction: nn$29(p.shareOtherCrownChargesEligibleForDeduction)
1748
+ };
1749
+ }
1750
+ function resolveAdjustment(a, index, issues) {
1751
+ 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).`);
1752
+ 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).`);
1753
+ return {
1754
+ ...a.priorProductionPeriodEnd !== void 0 ? { priorProductionPeriodEnd: a.priorProductionPeriodEnd } : {},
1755
+ ...a.sourceOfAdjustment !== void 0 ? { sourceOfAdjustment: a.sourceOfAdjustment } : {},
1756
+ increase: nn$29(a.increase),
1757
+ decrease: nn$29(a.decrease),
1758
+ adjustmentNotEligibleForCredit: rd(a.adjustmentNotEligibleForCredit)
1759
+ };
1760
+ }
1761
+ function schedule7LineItemId(fieldId, occurrence = 1) {
1762
+ return `007${fieldId}${String(occurrence).padStart(3, "0")}`;
1763
+ }
1764
+ /**
1765
+ * Emits CPI (007003-029), the computed totals 007051 and 007061, and the two
1766
+ * repeating sections — PITI (007071-081, one occurrence per partnership) and
1767
+ * ACRA (007083-091, one occurrence per prior-year adjustment).
1768
+ *
1769
+ * 007061 is filed even though it has no defining row of its own anywhere in
1770
+ * this schedule's MAPPINGS block (spec lines 6654-7251) — see the module
1771
+ * docstring's "Two totals with NO defining row of their own in this MAPPINGS
1772
+ * table" section. It is a real Schedule 7 output line: AT1 Schedule 5's own
1773
+ * field 005001 definition (spec lines 5237-5248) names it explicitly as
1774
+ * "Schedule 7, line 061" and gives its formula in full, so it is filed here
1775
+ * under that citation rather than omitted for lack of a home row.
1776
+ */
1777
+ function schedule7Values(result) {
1778
+ const values = [];
1779
+ const put = (fieldId, value, occurrence = 1) => values.push({
1780
+ lineItemId: schedule7LineItemId(fieldId, occurrence),
1781
+ value
1782
+ });
1783
+ put("003", result.eligibleCrownRoyalty);
1784
+ put("005", result.otherRoyaltiesNotEligible);
1785
+ put("007", result.royaltyPaidToOtherJurisdictions);
1786
+ put("009", result.nonDeductibleCrownLeaseRentals);
1787
+ put("011", result.mineralTaxes);
1788
+ put("013", result.saskatchewanResourcesSurcharge);
1789
+ result.otherNonDeductibleCrownChargeTypes.forEach((name, i) => {
1790
+ values.push({
1791
+ lineItemId: schedule7LineItemId(String(14 + i).padStart(3, "0")),
1792
+ value: name
1793
+ });
1794
+ });
1795
+ put("017", result.otherNonDeductibleCrownCharges);
1796
+ put("025", result.crownLeaseRentalsCapitalized);
1797
+ if (result.otherBalanceSheetDeductionName !== void 0) values.push({
1798
+ lineItemId: schedule7LineItemId("027"),
1799
+ value: result.otherBalanceSheetDeductionName
1800
+ });
1801
+ put("029", result.otherBalanceSheetDeduction);
1802
+ result.partnerships.forEach((p, i) => {
1803
+ const occurrence = i + 1;
1804
+ values.push({
1805
+ lineItemId: schedule7LineItemId("071", occurrence),
1806
+ value: p.name
1807
+ });
1808
+ put("073", p.interestPercent, occurrence);
1809
+ if (p.fiscalPeriodEnd !== void 0) values.push({
1810
+ lineItemId: schedule7LineItemId("075", occurrence),
1811
+ value: p.fiscalPeriodEnd
1812
+ });
1813
+ put("077", p.shareEligibleForCredit, occurrence);
1814
+ put("079", p.shareOtherRoyaltiesNotEligible, occurrence);
1815
+ put("081", p.shareOtherCrownChargesEligibleForDeduction, occurrence);
1816
+ });
1817
+ result.priorYearAdjustments.forEach((a, i) => {
1818
+ const occurrence = i + 1;
1819
+ if (a.priorProductionPeriodEnd !== void 0) values.push({
1820
+ lineItemId: schedule7LineItemId("083", occurrence),
1821
+ value: a.priorProductionPeriodEnd
1822
+ });
1823
+ if (a.sourceOfAdjustment !== void 0) put("085", a.sourceOfAdjustment, occurrence);
1824
+ put("087", a.increase, occurrence);
1825
+ put("089", a.decrease, occurrence);
1826
+ put("091", a.adjustmentNotEligibleForCredit, occurrence);
1827
+ });
1828
+ put("051", result.totalAdjustments);
1829
+ put("061", result.crownChargesNetOfReimbursements);
1830
+ return {
1831
+ scheduleId: "007",
1832
+ values
1833
+ };
1834
+ }
1835
+ function computeAlbertaSchedule7(input) {
1836
+ const issues = [];
1837
+ const eligibleCrownRoyalty = rd(input.eligibleCrownRoyalty);
1838
+ const otherRoyaltiesNotEligible = rd(input.otherRoyaltiesNotEligible);
1839
+ const royaltyPaidToOtherJurisdictions = rd(input.royaltyPaidToOtherJurisdictions);
1840
+ const nonDeductibleCrownLeaseRentals = rd(input.nonDeductibleCrownLeaseRentals);
1841
+ const mineralTaxes = rd(input.mineralTaxes);
1842
+ const saskatchewanResourcesSurcharge = rd(input.saskatchewanResourcesSurcharge);
1843
+ const otherNonDeductibleCrownChargeTypes = (input.otherNonDeductibleCrownChargeTypes ?? []).slice(0, 3);
1844
+ 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.");
1845
+ let otherNonDeductibleCrownCharges = rd(input.otherNonDeductibleCrownCharges);
1846
+ if (otherNonDeductibleCrownChargeTypes.length === 0 && otherNonDeductibleCrownCharges !== 0) {
1847
+ 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.");
1848
+ otherNonDeductibleCrownCharges = 0;
1849
+ }
1850
+ const crownLeaseRentalsCapitalized = rd(input.crownLeaseRentalsCapitalized);
1851
+ let otherBalanceSheetDeduction = nn$29(input.otherBalanceSheetDeduction);
1852
+ if (!input.otherBalanceSheetDeductionName && otherBalanceSheetDeduction !== 0) {
1853
+ 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.");
1854
+ otherBalanceSheetDeduction = 0;
1855
+ }
1856
+ const partnerships = (input.partnerships ?? []).map((p, i) => resolvePartnership(p, i, issues));
1857
+ const totalPartnershipShareEligibleForCredit = partnerships.reduce((s, p) => s + p.shareEligibleForCredit, 0);
1858
+ const totalPartnershipShareOtherRoyaltiesNotEligible = partnerships.reduce((s, p) => s + p.shareOtherRoyaltiesNotEligible, 0);
1859
+ const totalPartnershipShareOtherCrownCharges = partnerships.reduce((s, p) => s + p.shareOtherCrownChargesEligibleForDeduction, 0);
1860
+ const priorYearAdjustments = (input.priorYearAdjustments ?? []).map((a, i) => resolveAdjustment(a, i, issues));
1861
+ const totalIncrease = priorYearAdjustments.reduce((s, a) => s + a.increase, 0);
1862
+ const totalDecrease = priorYearAdjustments.reduce((s, a) => s + a.decrease, 0);
1863
+ const totalAdjustmentNotEligible = priorYearAdjustments.reduce((s, a) => s + a.adjustmentNotEligibleForCredit, 0);
1864
+ const totalAdjustments = priorYearAdjustments.length === 0 ? 0 : totalIncrease - totalDecrease + totalAdjustmentNotEligible;
1865
+ const crownChargesNetOfReimbursements = eligibleCrownRoyalty + otherRoyaltiesNotEligible + royaltyPaidToOtherJurisdictions + nonDeductibleCrownLeaseRentals + mineralTaxes + saskatchewanResourcesSurcharge + otherNonDeductibleCrownCharges + crownLeaseRentalsCapitalized + otherBalanceSheetDeduction + totalPartnershipShareEligibleForCredit + totalPartnershipShareOtherRoyaltiesNotEligible + totalPartnershipShareOtherCrownCharges - totalAdjustments;
1866
+ const albertaCrownRoyaltyForSchedule6 = eligibleCrownRoyalty + totalPartnershipShareEligibleForCredit - totalIncrease + totalDecrease;
1867
+ return {
1868
+ eligibleCrownRoyalty,
1869
+ otherRoyaltiesNotEligible,
1870
+ royaltyPaidToOtherJurisdictions,
1871
+ nonDeductibleCrownLeaseRentals,
1872
+ mineralTaxes,
1873
+ saskatchewanResourcesSurcharge,
1874
+ otherNonDeductibleCrownChargeTypes,
1875
+ otherNonDeductibleCrownCharges,
1876
+ crownLeaseRentalsCapitalized,
1877
+ ...input.otherBalanceSheetDeductionName !== void 0 ? { otherBalanceSheetDeductionName: input.otherBalanceSheetDeductionName } : {},
1878
+ otherBalanceSheetDeduction,
1879
+ partnerships,
1880
+ totalPartnershipShareEligibleForCredit,
1881
+ totalPartnershipShareOtherRoyaltiesNotEligible,
1882
+ totalPartnershipShareOtherCrownCharges,
1883
+ priorYearAdjustments,
1884
+ totalAdjustments,
1885
+ crownChargesNetOfReimbursements,
1886
+ albertaCrownRoyaltyForSchedule6,
1887
+ issues
1888
+ };
1889
+ }
1890
+ //#endregion
1891
+ //#region src/t2/at1/schedules/schedule8-political-contributions.ts
1892
+ const nn$28 = (v) => Math.max(0, Math.round(v ?? 0));
1893
+ function yearOf(dateIso) {
1894
+ if (!dateIso || dateIso.length < 4) return void 0;
1895
+ const y = Number(dateIso.slice(0, 4));
1896
+ return Number.isFinite(y) ? y : void 0;
1897
+ }
1898
+ /** Tiered rate for the "all made in 2003 or earlier" branch. */
1899
+ function tierTo2003(a) {
1900
+ if (a <= 150) return a * .75;
1901
+ if (a <= 825) return 112.5 + (a - 150) * .5;
1902
+ return 450 + (a - 825) * .333;
1903
+ }
1904
+ /** Tiered rate for the "all made in 2004 or later" branch. */
1905
+ function tierFrom2004(a) {
1906
+ if (a <= 200) return a * .75;
1907
+ if (a <= 900) return 150 + (a - 200) * .5;
1908
+ return 600 + (a - 900) * .333;
1909
+ }
1910
+ function computeSchedule8$1(input) {
1911
+ const issues = [];
1912
+ const contributions = input.contributions ?? [];
1913
+ contributions.forEach((c, i) => {
1914
+ 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.`);
1915
+ if (!c.receiptNumber) issues.push(`Alberta Schedule 8: contribution #${i + 1} (${c.name || "unnamed"}) has no official receipt number (008004).`);
1916
+ });
1917
+ const partnershipContributionsTo2003 = nn$28(input.partnershipContributionsTo2003);
1918
+ const partnershipContributionsFrom2004 = nn$28(input.partnershipContributionsFrom2004);
1919
+ const totalDirect = contributions.reduce((sum, c) => sum + nn$28(c.amount), 0);
1920
+ const directTo2003 = contributions.filter((c) => (yearOf(c.dateOfDonation) ?? 0) <= 2003).reduce((sum, c) => sum + nn$28(c.amount), 0);
1921
+ const directFrom2004 = contributions.filter((c) => (yearOf(c.dateOfDonation) ?? 9999) >= 2004).reduce((sum, c) => sum + nn$28(c.amount), 0);
1922
+ const directIn2004Only = contributions.filter((c) => yearOf(c.dateOfDonation) === 2004).reduce((sum, c) => sum + nn$28(c.amount), 0);
1923
+ const hasTo2003 = directTo2003 > 0 || partnershipContributionsTo2003 > 0;
1924
+ const hasFrom2004 = directFrom2004 > 0 || partnershipContributionsFrom2004 > 0;
1925
+ if (!hasTo2003 && !hasFrom2004) return {
1926
+ contributions,
1927
+ partnershipContributionsTo2003,
1928
+ partnershipContributionsFrom2004,
1929
+ period: "none",
1930
+ creditBeforeCeiling: 0,
1931
+ credit: 0,
1932
+ issues
1933
+ };
1934
+ const taxYearBeginYear = yearOf(input.taxYearBegin);
1935
+ const taxYearEndYear = yearOf(input.taxYearEnd);
1936
+ const taxYearStraddles2003to2004 = taxYearBeginYear === 2003 && taxYearEndYear === 2004;
1937
+ const ceiling = input.remainingBasicTax;
1938
+ let period;
1939
+ let rawCredit;
1940
+ let credit;
1941
+ if (hasTo2003 && !hasFrom2004) {
1942
+ period = "to-2003";
1943
+ rawCredit = tierTo2003(totalDirect + partnershipContributionsTo2003);
1944
+ if (ceiling == null) {
1945
+ 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.");
1946
+ credit = 0;
1947
+ } else credit = Math.max(0, Math.round(Math.min(rawCredit, 750, ceiling)));
1948
+ } else if (hasFrom2004 && !hasTo2003) {
1949
+ period = "from-2004";
1950
+ rawCredit = tierFrom2004(totalDirect + partnershipContributionsFrom2004);
1951
+ if (ceiling == null) {
1952
+ 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.");
1953
+ credit = 0;
1954
+ } else credit = Math.max(0, Math.round(Math.min(rawCredit, 1e3, ceiling)));
1955
+ } else if (taxYearStraddles2003to2004) {
1956
+ period = "straddle-2003-2004";
1957
+ const x = directIn2004Only + partnershipContributionsFrom2004;
1958
+ const y = totalDirect + partnershipContributionsTo2003 + partnershipContributionsFrom2004;
1959
+ const a = Math.min(y, 150);
1960
+ const b = Math.min(Math.max(0, x - a), 50);
1961
+ const c = Math.min(Math.max(0, y - (a + b)), 675);
1962
+ const d = Math.min(Math.max(0, x - (a + b + c)), 225);
1963
+ const e = Math.min(Math.max(0, y - (a + b + c + d)), 900);
1964
+ const f = Math.min(Math.max(0, x - (a + b + c + d + e)), 300);
1965
+ rawCredit = .75 * a + .75 * b + .5 * c + .5 * d + e / 3 + f / 3;
1966
+ credit = Math.max(0, Math.round(rawCredit));
1967
+ } else {
1968
+ period = "none";
1969
+ rawCredit = 0;
1970
+ credit = 0;
1971
+ 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.");
1972
+ }
1973
+ return {
1974
+ contributions,
1975
+ partnershipContributionsTo2003,
1976
+ partnershipContributionsFrom2004,
1977
+ period,
1978
+ creditBeforeCeiling: Math.round(rawCredit),
1979
+ credit,
1980
+ issues
1981
+ };
1982
+ }
1983
+ /**
1984
+ * Net File line items for AT1 Schedule 8: one PCD occurrence per contribution
1985
+ * (002 name, 004 receipt number, 006 date, 008 amount), plus the two APC
1986
+ * partnership totals (012, 013).
1987
+ *
1988
+ * Does NOT emit jacket line 000074 (the actual tax credit) — that is a
1989
+ * jacket line, not a Schedule 8 line. Use `result.credit` for that.
1990
+ */
1991
+ function schedule8Values(result) {
1992
+ const values = [];
1993
+ result.contributions.forEach((c, i) => {
1994
+ const n = i + 1;
1995
+ const put = (fieldId, value) => values.push({
1996
+ lineItemId: at1LineItemId("008", fieldId, n),
1997
+ value
1998
+ });
1999
+ put("002", c.name);
2000
+ put("004", c.receiptNumber);
2001
+ put("006", c.dateOfDonation);
2002
+ put("008", Math.max(0, Math.round(c.amount)));
2003
+ });
2004
+ values.push({
2005
+ lineItemId: at1LineItemId("008", "012"),
2006
+ value: result.partnershipContributionsTo2003
2007
+ });
2008
+ values.push({
2009
+ lineItemId: at1LineItemId("008", "013"),
2010
+ value: result.partnershipContributionsFrom2004
2011
+ });
2012
+ return {
2013
+ scheduleId: "008",
2014
+ values
2015
+ };
2016
+ }
2017
+ //#endregion
2018
+ //#region src/t2/at1/schedules/schedule9-sred-tax-credit.ts
2019
+ const nn$27 = (v) => Math.max(0, Math.round(v ?? 0));
2020
+ /** Signed whole-dollar rounding, for fields the spec marks "+/-". */
2021
+ const signed = (v) => Math.round(v);
2022
+ /** 009120's flat rate — "lesser of line 009031 and 009108 X 10%". */
2023
+ const ALBERTA_SRED_TAX_CREDIT_RATE = .1;
2024
+ /** Alberta's SR&ED program did not exist before this date (line 009104's note). */
2025
+ const ALBERTA_SRED_PROGRAM_START = "2009-01-01";
2026
+ /** Alberta SR&ED expenditures carried out after this date are not eligible (module docstring). */
2027
+ const ALBERTA_SRED_EXPENDITURE_CUTOFF = "2019-12-31";
2028
+ /**
2029
+ * 009104 / 009206's day-prorated $4,000,000 expenditure limit. Days are clamped
2030
+ * to [0, 366] — 366 only for a year genuinely spanning a February 29, per the
2031
+ * spec's own note.
2032
+ */
2033
+ function computeSchedule9MaximumExpenditureLimit(daysInTaxYear = 365) {
2034
+ return Math.round(4e6 * (Math.max(0, Math.min(daysInTaxYear, 366)) / 365));
2035
+ }
2036
+ function computeAlbertaSchedule9(input) {
2037
+ const issues = [];
2038
+ const federalQualifiedExpenditures = nn$27(input.federalQualifiedExpenditures);
2039
+ const albertaPortionOfExpenditures = nn$27(input.albertaPortionOfExpenditures);
2040
+ const federalProxyAmountInAlbertaPortion = nn$27(input.federalProxyAmountInAlbertaPortion);
2041
+ const albertaProxyAmount = nn$27(input.albertaProxyAmount);
2042
+ const albertaCreditReducingFederalExpense = nn$27(input.albertaCreditReducingFederalExpense);
2043
+ const priorYearFederalItcReceived = nn$27(input.priorYearFederalItcReceived);
2044
+ const totalAlbertaExpendituresAllYears = nn$27(input.totalAlbertaExpendituresAllYears);
2045
+ const totalFederalExpendituresAllYears = nn$27(input.totalFederalExpendituresAllYears);
2046
+ const albertaPortionOfRepayments = nn$27(input.albertaPortionOfRepayments);
2047
+ const disposalRecapture = nn$27(input.disposalRecapture);
2048
+ const priorYearFederalItcAdjustment = nn$27(input.priorYearFederalItcAdjustment);
2049
+ 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.`);
2050
+ const priorYearItcAlbertaPortion = totalFederalExpendituresAllYears > 0 ? Math.round(priorYearFederalItcReceived * totalAlbertaExpendituresAllYears / totalFederalExpendituresAllYears) : 0;
2051
+ 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.");
2052
+ const derivedEligibleExpenditures = albertaPortionOfExpenditures - federalProxyAmountInAlbertaPortion + albertaProxyAmount + albertaCreditReducingFederalExpense - priorYearItcAlbertaPortion + albertaPortionOfRepayments;
2053
+ const eligibleExpenditures = input.eligibleExpenditures !== void 0 ? signed(input.eligibleExpenditures) : derivedEligibleExpenditures;
2054
+ 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.`);
2055
+ 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.");
2056
+ const isAssociated = input.isAssociated ?? false;
2057
+ const nonAssociatedMaximumExpenditureLimit = computeSchedule9MaximumExpenditureLimit(input.daysInTaxYear ?? 365);
2058
+ let maximumExpenditureLimit;
2059
+ if (isAssociated) if (input.allocatedExpenditureLimit === void 0) {
2060
+ 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.");
2061
+ maximumExpenditureLimit = 0;
2062
+ } else maximumExpenditureLimit = nn$27(input.allocatedExpenditureLimit);
2063
+ else maximumExpenditureLimit = nonAssociatedMaximumExpenditureLimit;
2064
+ 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.`);
2065
+ const netCredit = Math.round(Math.min(eligibleExpenditures, maximumExpenditureLimit) * ALBERTA_SRED_TAX_CREDIT_RATE) - disposalRecapture - priorYearFederalItcAdjustment;
2066
+ return {
2067
+ federalQualifiedExpenditures,
2068
+ albertaPortionOfExpenditures,
2069
+ federalProxyAmountInAlbertaPortion,
2070
+ albertaProxyAmount,
2071
+ albertaCreditReducingFederalExpense,
2072
+ priorYearFederalItcReceived,
2073
+ totalAlbertaExpendituresAllYears,
2074
+ totalFederalExpendituresAllYears,
2075
+ priorYearItcAlbertaPortion,
2076
+ albertaPortionOfRepayments,
2077
+ eligibleExpenditures,
2078
+ derivedEligibleExpenditures,
2079
+ fieldOfScience: input.fieldOfScience,
2080
+ isAssociated,
2081
+ nonAssociatedMaximumExpenditureLimit,
2082
+ maximumExpenditureLimit,
2083
+ disposalRecapture,
2084
+ priorYearFederalItcAdjustment,
2085
+ netCredit,
2086
+ issues
2087
+ };
2088
+ }
2089
+ /**
2090
+ * Allocate the day-prorated $4,000,000 maximum expenditure limit among an
2091
+ * associated group (page 3). Per the spec, EACH occurrence of 009240 and the
2092
+ * SUM of all occurrences are independently capped at the limit — unlike a
2093
+ * running-remainder split, one member requesting more than the limit does not
2094
+ * consume another member's room; it is simply capped and flagged.
2095
+ */
2096
+ function allocateSchedule9ExpenditureLimit(daysInLongestYear, requested) {
2097
+ const issues = [];
2098
+ const days = Math.max(0, Math.min(daysInLongestYear, 366));
2099
+ const maximumExpenditureLimit = computeSchedule9MaximumExpenditureLimit(days);
2100
+ const members = requested.map((m) => {
2101
+ const requestedAmount = nn$27(m.allocated);
2102
+ 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}.`);
2103
+ return {
2104
+ name: m.name,
2105
+ ...m.albertaCan !== void 0 ? { albertaCan: m.albertaCan } : {},
2106
+ allocated: Math.min(requestedAmount, maximumExpenditureLimit)
2107
+ };
2108
+ });
2109
+ const totalAllocated = members.reduce((s, m) => s + m.allocated, 0);
2110
+ 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.`);
2111
+ return {
2112
+ daysInLongestYear: days,
2113
+ maximumExpenditureLimit,
2114
+ members,
2115
+ totalAllocated,
2116
+ claimantAllocatedAmount: members[0]?.allocated ?? 0,
2117
+ unallocated: Math.max(0, maximumExpenditureLimit - totalAllocated),
2118
+ issues
2119
+ };
2120
+ }
2121
+ function schedule9LineItemId(fieldId, occurrence = 1) {
2122
+ return `009${fieldId}${String(occurrence).padStart(3, "0")}`;
2123
+ }
2124
+ /**
2125
+ * Field ids per the spec transcription in the module docstring: 003-025 (the
2126
+ * expenditure buildup), 040 (field of science), 100-120 (the credit
2127
+ * calculation), and — when `group` is supplied — 200-240 (page 3's
2128
+ * allocation). Line 031 has no confirmed transmitted status of its own (see
2129
+ * the module docstring's "line 009031 has no formula in the spec text"), but
2130
+ * is filed anyway alongside 106 since both carry the identical "Total
2131
+ * eligible expenditures for Alberta purposes" figure per the spec's own
2132
+ * cross-reference ("106 ... Value must equal 009031").
2133
+ */
2134
+ function schedule9Values(result, group) {
2135
+ const values = [];
2136
+ const put = (fieldId, value) => values.push({
2137
+ lineItemId: schedule9LineItemId(fieldId),
2138
+ value
2139
+ });
2140
+ put("003", result.federalQualifiedExpenditures);
2141
+ put("005", result.albertaPortionOfExpenditures);
2142
+ put("007", result.federalProxyAmountInAlbertaPortion);
2143
+ put("009", result.albertaProxyAmount);
2144
+ put("011", result.albertaCreditReducingFederalExpense);
2145
+ put("015", result.priorYearFederalItcReceived);
2146
+ put("017", result.totalAlbertaExpendituresAllYears);
2147
+ put("019", result.totalFederalExpendituresAllYears);
2148
+ put("023", result.priorYearItcAlbertaPortion);
2149
+ put("025", result.albertaPortionOfRepayments);
2150
+ put("031", result.eligibleExpenditures);
2151
+ if (result.fieldOfScience !== void 0) put("040", result.fieldOfScience);
2152
+ put("100", result.isAssociated ? 1 : 2);
2153
+ if (result.isAssociated) put("102", result.maximumExpenditureLimit);
2154
+ else put("104", result.nonAssociatedMaximumExpenditureLimit);
2155
+ put("106", result.eligibleExpenditures);
2156
+ put("108", result.maximumExpenditureLimit);
2157
+ put("112", result.disposalRecapture);
2158
+ put("116", result.priorYearFederalItcAdjustment);
2159
+ put("120", result.netCredit);
2160
+ if (group) {
2161
+ if (group.longestYearCan !== void 0) values.push({
2162
+ lineItemId: schedule9LineItemId("200"),
2163
+ value: group.longestYearCan
2164
+ });
2165
+ if (group.longestYearBegin !== void 0) values.push({
2166
+ lineItemId: schedule9LineItemId("202"),
2167
+ value: group.longestYearBegin
2168
+ });
2169
+ if (group.longestYearEnd !== void 0) values.push({
2170
+ lineItemId: schedule9LineItemId("204"),
2171
+ value: group.longestYearEnd
2172
+ });
2173
+ values.push({
2174
+ lineItemId: schedule9LineItemId("206"),
2175
+ value: group.allocation.daysInLongestYear
2176
+ });
2177
+ group.allocation.members.forEach((m, i) => {
2178
+ const occurrence = i + 1;
2179
+ values.push({
2180
+ lineItemId: schedule9LineItemId("220", occurrence),
2181
+ value: m.name
2182
+ });
2183
+ if (m.albertaCan !== void 0) values.push({
2184
+ lineItemId: schedule9LineItemId("230", occurrence),
2185
+ value: m.albertaCan
2186
+ });
2187
+ values.push({
2188
+ lineItemId: schedule9LineItemId("240", occurrence),
2189
+ value: m.allocated
2190
+ });
2191
+ });
2192
+ }
2193
+ return {
2194
+ scheduleId: "009",
2195
+ values
2196
+ };
2197
+ }
2198
+ //#endregion
2199
+ //#region src/t2/at1/schedules/schedule11-manufacturing-processing.ts
2200
+ const nn$26 = (v) => Math.max(0, Math.round(v ?? 0));
2201
+ function computeSchedule11(input) {
2202
+ const issues = [];
2203
+ const dateEligible = input.taxYearStart < "2001-04-01";
2204
+ if (!dateEligible) issues.push(`Schedule 11: the Alberta Manufacturing and Processing Profits Deduction applies only where the tax year begins before 2001-04-01 (TRA-spec lines 9135-9146). This tax year begins ${input.taxYearStart}, so no deduction applies; line 011042 is reported as nil regardless of the workings below.`);
2205
+ let grossRevenueRatio;
2206
+ let revenueEligible = true;
2207
+ if (dateEligible) if (input.manufacturingGrossRevenue == null || input.totalGrossRevenue == null) {
2208
+ revenueEligible = false;
2209
+ issues.push("Schedule 11: the 10% manufacturing gross-revenue test (TRA-spec lines 9138-9142) could not be run because gross revenue figures were not supplied, so form 011 is treated as not applicable.");
2210
+ } else {
2211
+ const total = nn$26(input.totalGrossRevenue);
2212
+ grossRevenueRatio = total > 0 ? nn$26(input.manufacturingGrossRevenue) / total : 0;
2213
+ if (grossRevenueRatio < .1) {
2214
+ revenueEligible = false;
2215
+ issues.push(`Schedule 11: manufacturing gross revenue is ${(grossRevenueRatio * 100).toFixed(1)}% of total gross revenue, below the 10% threshold in the AT1 spec, so form 011 is not applicable.`);
2216
+ }
2217
+ }
2218
+ const eligible = dateEligible && revenueEligible;
2219
+ let albertaAdjubi;
2220
+ if (input.albertaAdjubiFromSchedule12) albertaAdjubi = Math.max(0, Math.round(input.albertaAdjubiFromSchedule12.line112 + input.albertaAdjubiFromSchedule12.line114));
2221
+ else {
2222
+ albertaAdjubi = nn$26(input.federalAdjubi);
2223
+ if (input.federalAdjubi == null && eligible) issues.push("Schedule 11: neither `federalAdjubi` (fed 027130) nor `albertaAdjubiFromSchedule12` was supplied; line 011001 defaults to nil.");
2224
+ }
2225
+ let aggregateInvestmentIncome;
2226
+ if (input.isCcpc) if (input.schedule12Exists) aggregateInvestmentIncome = nn$26(input.albertaAggregateInvestmentIncome);
2227
+ else {
2228
+ aggregateInvestmentIncome = nn$26(input.federalAggregateInvestmentIncome);
2229
+ if (input.federalAggregateInvestmentIncome == null) issues.push("Schedule 11: the corp is a CCPC and no Alberta Schedule 12 exists, so line 011013 must equal fed 200440, but `federalAggregateInvestmentIncome` was not supplied; line 011013 defaults to nil.");
2230
+ }
2231
+ const isSmallManufacturingCorp = input.isSmallManufacturingCorp ?? false;
2232
+ let costOfCapital = 0;
2233
+ let albertaCostOfCapital = 0;
2234
+ let costOfLabour = 0;
2235
+ let albertaCostOfLabour = 0;
2236
+ let albertaManufacturingProcessingProfits = 0;
2237
+ if (isSmallManufacturingCorp) {
2238
+ if (input.costOfCapital != null || input.albertaCostOfCapital != null || input.costOfLabour != null || input.albertaCostOfLabour != null) issues.push("Schedule 11: lines 011031-011039 must not exist for a small manufacturing corp, but capital/labour figures were supplied; they are ignored for line 011042.");
2239
+ if (input.smallManufacturerAmpp != null) albertaManufacturingProcessingProfits = nn$26(input.smallManufacturerAmpp);
2240
+ else if (eligible) issues.push("Schedule 11: the small-manufacturing-corp formula for line 011042 is not stated in the transcribed spec range (TRA-spec lines 9082-9397); supply `smallManufacturerAmpp` directly per the AT1 Guide criteria. Line 011042 defaults to nil.");
2241
+ } else {
2242
+ costOfCapital = nn$26(input.costOfCapital);
2243
+ albertaCostOfCapital = nn$26(input.albertaCostOfCapital);
2244
+ costOfLabour = nn$26(input.costOfLabour);
2245
+ albertaCostOfLabour = nn$26(input.albertaCostOfLabour);
2246
+ if (albertaCostOfCapital > costOfCapital) {
2247
+ issues.push(`Schedule 11: line 011033 (Alberta Cost of Manufacturing and Processing Capital, ${albertaCostOfCapital}) exceeds line 011031 (Cost of Capital, ${costOfCapital}); the AT1 spec requires 011033 ≤ 011031. Clamped to ${costOfCapital}.`);
2248
+ albertaCostOfCapital = costOfCapital;
2249
+ }
2250
+ if (albertaCostOfLabour > costOfLabour) {
2251
+ issues.push(`Schedule 11: line 011039 (Alberta Cost of Manufacturing and Processing Labour, ${albertaCostOfLabour}) exceeds line 011037 (Cost of Labour, ${costOfLabour}); the AT1 spec requires 011039 ≤ 011037. Clamped to ${costOfLabour}.`);
2252
+ albertaCostOfLabour = costOfLabour;
2253
+ }
2254
+ const denominator = costOfCapital + costOfLabour;
2255
+ if (denominator === 0) {
2256
+ if (albertaAdjubi > 0 && eligible) issues.push("Schedule 11: Cost of Capital (011031) and Cost of Labour (011037) are both nil, so the line 011042 proration cannot be computed; supply them. Line 011042 defaults to nil.");
2257
+ } else {
2258
+ const factor = (Math.min(albertaCostOfCapital * 100 / 85, costOfCapital) + Math.min(albertaCostOfLabour * 100 / 75, costOfLabour)) / denominator;
2259
+ albertaManufacturingProcessingProfits = Math.round(albertaAdjubi * factor);
2260
+ }
2261
+ }
2262
+ if (!eligible && albertaManufacturingProcessingProfits > 0) issues.push(`Schedule 11: the workings above yield ${albertaManufacturingProcessingProfits}, but the deduction is not applicable this year (see the eligibility issue above); line 011042 is reported as nil.`);
2263
+ if (!eligible) albertaManufacturingProcessingProfits = 0;
2264
+ return {
2265
+ eligible,
2266
+ isSmallManufacturingCorp,
2267
+ albertaAdjubi,
2268
+ ...aggregateInvestmentIncome !== void 0 ? { aggregateInvestmentIncome } : {},
2269
+ costOfCapital,
2270
+ albertaCostOfCapital,
2271
+ costOfLabour,
2272
+ albertaCostOfLabour,
2273
+ albertaManufacturingProcessingProfits,
2274
+ ...grossRevenueRatio !== void 0 ? { grossRevenueRatio } : {},
2275
+ issues
2276
+ };
2277
+ }
2278
+ function schedule11LineItemId(fieldId, occurrence = 1) {
2279
+ return `011${fieldId}${String(occurrence).padStart(3, "0")}`;
2280
+ }
2281
+ /**
2282
+ * Field ids per the spec transcription above: 001 (AMPPD/ADJUBI), 013 (CCPC
2283
+ * aggregate investment income), 031/033/037/039 (cost of capital/labour, both
2284
+ * jurisdictions) and 042 (Alberta M&P Profits).
2285
+ *
2286
+ * Line 042 is ALWAYS emitted, including when the historical-eligibility gate
2287
+ * (pre-2001-04-01 tax year AND the 10% gross-revenue test) has forced it to
2288
+ * nil — an ineligible year still has a line 011042 on the form, and it reads
2289
+ * nil, so this files nil rather than omitting the line entirely. The REASON
2290
+ * it is nil (a `Schedule 11: … applies only where the tax year begins before
2291
+ * 2001-04-01 …` / `… below the 10% threshold …` entry) lives on
2292
+ * `result.issues`, which this builder does not carry onto the wire itself —
2293
+ * the caller already has `result` (this function's own input) and so already
2294
+ * has `result.issues` sitting beside whatever this returns; duplicating it
2295
+ * onto `At1ScheduleDataLike`, which has no field for prose, would only be
2296
+ * losing information conversion by not adding any.
2297
+ *
2298
+ * Line 013 (CCPC aggregate investment income) is the one line legitimately
2299
+ * OMITTED rather than filed as nil: it is undefined, not zero, for a non-CCPC
2300
+ * corporation — the spec's own business rule gates it on `000029 = 1 or 2`,
2301
+ * so a non-CCPC has no box to fill here at all, unlike line 042's "nil is a
2302
+ * real answer" case above.
2303
+ */
2304
+ function schedule11Values(result) {
2305
+ const values = [];
2306
+ const put = (fieldId, value) => values.push({
2307
+ lineItemId: schedule11LineItemId(fieldId),
2308
+ value
2309
+ });
2310
+ put("001", result.albertaAdjubi);
2311
+ if (result.aggregateInvestmentIncome !== void 0) put("013", result.aggregateInvestmentIncome);
2312
+ put("031", result.costOfCapital);
2313
+ put("033", result.albertaCostOfCapital);
2314
+ put("037", result.costOfLabour);
2315
+ put("039", result.albertaCostOfLabour);
2316
+ put("042", result.albertaManufacturingProcessingProfits);
2317
+ return {
2318
+ scheduleId: "011",
2319
+ values
2320
+ };
2321
+ }
2322
+ //#endregion
2323
+ //#region src/t2/at1/schedules/schedule15-resource-related-deductions.ts
2324
+ /**
2325
+ * Alberta AT1 Schedule 15 — Alberta Resource Related Deductions.
2326
+ *
2327
+ * Source: `research/sources/tra-spec/AT1-Chapter3-2025.2-full.txt`, lines
2328
+ * 12394-15937 (§3.2.3.16 "Schedule 15 - Alberta Resource Related Deductions").
2329
+ * There is NO standalone AT1SCH15 PDF under `research/sources/tra-forms/pdf/`
2330
+ * (unlike schedules 1, 2, 10, 12, 13, 16, 17, 18, 20, 21, 29, which all have
2331
+ * one) — the NetFile mapping spec above is the ONLY source available for this
2332
+ * schedule, so every field below is cited to that text file alone and cannot
2333
+ * be cross-checked against a rendered form layout.
2334
+ *
2335
+ * Like AT1 Schedule 18 (dispositions) and Schedule 13 (CCA), this is a
2336
+ * RECONCILIATION overlay, not a second engine: for most lines, the Alberta
2337
+ * figure defaults to the corresponding FEDERAL pool figure, and only the
2338
+ * lines where Alberta actually diverges are entered. The form is forbidden
2339
+ * when the return declares no Alberta/federal divergence (000060 AND 000061
2340
+ * both 2) and required when the opening balance or the claim for Alberta
2341
+ * purposes differs from federal (line 015 gating text, source lines
2342
+ * 12444-12456).
2343
+ *
2344
+ * Despite the task brief's expectation of a "resource allowance" pool, THERE
2345
+ * IS NO resource-allowance computation on this schedule — the federal
2346
+ * resource allowance deduction was repealed for taxation years after 1989
2347
+ * (phased out through the mid-1990s) and this schedule is entirely about the
2348
+ * EIGHT resource-expense CONTINUITY pools that survive it:
2349
+ *
2350
+ * EDA — Continuity of Earned Depletion Base (grandfathered; regular +
2351
+ * successor expenses), lines 001-021.
2352
+ * CMEDB — Continuity of Mining Exploration Depletion Base, lines 023-033.
2353
+ * CEE — Cumulative Canadian Exploration Expenses (regular + successor),
2354
+ * lines 041-083.
2355
+ * CDE — Cumulative Canadian Development Expenses (regular + successor),
2356
+ * lines 091-143.
2357
+ * CCOGPE — Cumulative Canadian Oil and Gas Property Expenses (regular +
2358
+ * successor), lines 151-191.
2359
+ * FEDE — Foreign Exploration and Development Expenses (regular +
2360
+ * successor), lines 201-233.
2361
+ * SFEDE — Specified Foreign Exploration and Development Expenses, PER
2362
+ * COUNTRY (regular + successor), lines 241-277.
2363
+ * CFRE — Cumulative Foreign Resource Expenses, PER COUNTRY (regular +
2364
+ * successor), lines 281-317.
2365
+ *
2366
+ * Each pool is modelled as its own `Input`/`Result` pair and its own pure
2367
+ * `computeXxx` function, per this directory's convention (see
2368
+ * `schedule18-dispositions.ts`, `schedule21-year-of-origin.ts`). A single
2369
+ * `computeAlbertaSchedule15` at the bottom composes all eight (accepting the
2370
+ * already-computed CCOGPE results where CDE needs them — see "CCOGPE ↔ CDE
2371
+ * cross-linkage" below) and applies the schedule-level 000060/000061 gate.
2372
+ *
2373
+ * ── Two proration conventions, NOT interchangeable ──────────────────────────
2374
+ *
2375
+ * The current-year-claim caps use TWO different short-tax-year formulas, and
2376
+ * the spec is explicit that they differ:
2377
+ *
2378
+ * - CDE (lines 115, 141) and CCOGPE (lines 169, 189) use a STEP function:
2379
+ * "if days in tax year ≥ 357, cap = rate × pool; if < 357, cap = rate ×
2380
+ * (days/365) × pool" — i.e. the proration is skipped entirely for a
2381
+ * near-full year.
2382
+ * - FEDE (line 209), SFEDE (line 253) and CFRE (lines 293, 313) use a
2383
+ * PLAIN `days/365` multiplier with no 357-day step.
2384
+ *
2385
+ * `stepYearFactor` implements the first; `linearYearFactor` the second. CEE
2386
+ * (lines 061, 081) and EDA/CMEDB have no day-proration at all — CEE is fully
2387
+ * claimable up to the pool balance in one year, no percentage rate applies.
2388
+ *
2389
+ * ── CCOGPE ↔ CDE cross-linkage (FLAGGED, not fully auto-wired) ──────────────
2390
+ *
2391
+ * When a CCOGPE pool's pre-claim subtotal is NEGATIVE, three things in the
2392
+ * spec text interact in a way this module resolves only PARTIALLY:
2393
+ *
2394
+ * 1. CDE line 105 ("Deduct: credit balance in the cumulative Canadian oil
2395
+ * and gas property expense pool", source lines 13604-13622) has its OWN
2396
+ * self-contained formula: `A = 015151+015153+015155+015157-015159-
2397
+ * 015161-015165-015167; if A < 0, value = A; otherwise enter fed
2398
+ * 012330`. This is unconditional — it does not mention the designation
2399
+ * election. This module implements 105 EXACTLY this way, computed from
2400
+ * the already-computed CCOGPE-regular pool subtotal (see
2401
+ * `computeCdeRegular`'s `ccogpeRegular` parameter).
2402
+ * 2. CCOGPE line 169 ("Deduct: current year claim...", source lines
2403
+ * 14281-14370) separately says that when that SAME subtotal A is
2404
+ * negative, it "must be carried forward to 015105" ONLY if the
2405
+ * corporation "has made a designation pursuant to subparagraph
2406
+ * 66.7(4)(a)(iii)" — and to 015133 (CDE SUCCESSOR, not 105) if it has
2407
+ * NOT. This CONTRADICTS (1)'s unconditional reading. Line 189 (source
2408
+ * lines 14646-14661) makes the analogous claim for the CCOGPE-successor
2409
+ * pool: negative → 015133 if designated, or "included in 015167"
2410
+ * (CCOGPE's OWN regular-pool deduction line, not a CDE line) if not.
2411
+ *
2412
+ * This module resolves (1) literally (105 is auto-computed, unconditionally,
2413
+ * from the CCOGPE-regular subtotal) because that is the more specific,
2414
+ * self-contained rule attached directly to line 105 itself. It does NOT
2415
+ * auto-route a negative CCOGPE-successor subtotal into CDE line 133 or back
2416
+ * into CCOGPE-regular line 167, because (a) line 133 has no unconditional
2417
+ * formula of its own — only the ambiguous "value may not exceed amount A"
2418
+ * (source lines 13945-13962), and (b) whether it should land on 133 or 167
2419
+ * hinges on the 66.7(4)(a)(iii) designation, which this schedule has no
2420
+ * source for and no sibling schedule to pull it from. Whenever the CCOGPE-
2421
+ * successor subtotal goes negative, `computeCcogpeSuccessor` raises an issue
2422
+ * naming lines 133/167/189 so a preparer resolves the routing by hand; the
2423
+ * pool's own claim and closing balance are zeroed per the schedule's
2424
+ * unconditional instruction ("enter zero at 015189 and 015191").
2425
+ *
2426
+ * A second, independent anomaly: CCOGPE-successor's own closing balance
2427
+ * formula (line 191, source lines 14731-14740) reads literally as "value =
2428
+ * 015173+015175+015177-015181-015185-015187-015189 **-015167-015169**" when
2429
+ * the pre-subtraction total is positive — i.e. it appears to subtract the
2430
+ * CCOGPE-REGULAR pool's OWN deduction (167) and claim (169) from the
2431
+ * SUCCESSOR pool's closing balance. No other continuity balance on this
2432
+ * schedule mixes fields across the regular/successor split this way, and
2433
+ * nothing else in the 000-series explains why a successor balance would
2434
+ * absorb the regular pool's claim. This module computes 191 with the clean,
2435
+ * schedule-consistent formula (additions − deductions − claim, floored at
2436
+ * zero) and raises an issue quoting the literal spec text whenever 167 or
2437
+ * 169 is non-zero (the only case where the two readings diverge), so a
2438
+ * reviewer can check it against the real form — which, again, has no PDF in
2439
+ * this engine's sources to check against.
2440
+ *
2441
+ * ── Other flagged items ─────────────────────────────────────────────────────
2442
+ *
2443
+ * - CDE line 107 ("Deduct: other deductions or transfers", source lines
2444
+ * 13681-13691) carries a parenthetical "(Note: If 015139 is negative,
2445
+ * include the amount at 015107 as a positive value.)" — there is NO line
2446
+ * 139 anywhere else in this schedule's field list (CDE regular runs
2447
+ * 091-117 with no 108/109/113/114/116/139 gaps that resolve to it, and
2448
+ * no other pool numbers into the 130s except CDE-successor's own 133-137,
2449
+ * which are a different pool entirely). This looks like either an OCR
2450
+ * artifact or a reference to a paper-form-only field outside the NetFile
2451
+ * schema (the same category as Schedule 21's RIFE section). Not modelled;
2452
+ * flagged verbatim whenever the schedule is computed.
2453
+ * - Negative-pool amounts on FEDE, SFEDE and CFRE (claim lines 209, 221,
2454
+ * 253, 273, 293, 313) are, per the spec, "include[d] in 012040" — a
2455
+ * FEDERAL T2 line, entirely outside this schedule and this engine's
2456
+ * stated scope for Schedule 15. This module zeroes the claim/closing per
2457
+ * the schedule's own instruction and raises an issue noting the federal
2458
+ * inclusion is the caller's responsibility elsewhere.
2459
+ * - CFRE line 293's "B" component is capped at "the global foreign
2460
+ * resource limit for the year designated for that country" (source lines
2461
+ * 15703-15711) — a quantity with no definition or source anywhere in
2462
+ * this spec excerpt. Modelled as an optional plain-number INPUT per
2463
+ * country (`globalForeignResourceLimit`); omitting it makes B = 0 (the
2464
+ * conservative, under-claim direction) and raises an issue rather than
2465
+ * inventing a limit.
2466
+ *
2467
+ * Whole dollars, pure functions, no I/O.
2468
+ */
2469
+ const nn$25 = (v) => Math.max(0, v ?? 0);
2470
+ const num$1 = (v) => v ?? 0;
2471
+ const round = (v) => Math.round(v);
2472
+ /** `override ?? federal`, tracking whether an Alberta-specific figure was actually entered. */
2473
+ function reconcile(federal, override) {
2474
+ return override !== void 0 ? {
2475
+ value: override,
2476
+ differs: true
2477
+ } : {
2478
+ value: num$1(federal),
2479
+ differs: false
2480
+ };
2481
+ }
2482
+ /**
2483
+ * CDE / CCOGPE style short-tax-year proration: the full rate applies with NO
2484
+ * proration once the tax year reaches 357 days; below that, rate × days/365.
2485
+ */
2486
+ function stepYearFactor(daysInTaxYear) {
2487
+ const days = daysInTaxYear ?? 365;
2488
+ return days >= 357 ? 1 : Math.max(0, days) / 365;
2489
+ }
2490
+ /** FEDE / SFEDE / CFRE style proration: plain days/365, no 357-day step. */
2491
+ function linearYearFactor(daysInTaxYear) {
2492
+ return Math.max(0, daysInTaxYear ?? 365) / 365;
2493
+ }
2494
+ /** A discretionary claim capped at `cap` (≥ 0), defaulting to the maximum (`cap`) when omitted. */
2495
+ function claimUpToCap(requested, cap, issues, label) {
2496
+ const c = Math.max(0, round(cap));
2497
+ if (requested === void 0) return c;
2498
+ if (requested < 0) {
2499
+ issues.push(`${label}: a requested claim of ${requested} is negative; treated as 0.`);
2500
+ return 0;
2501
+ }
2502
+ if (round(requested) > c) {
2503
+ issues.push(`${label}: the requested claim of ${requested} exceeds the maximum allowable ${c} for the year; capped at ${c}.`);
2504
+ return c;
2505
+ }
2506
+ return round(requested);
2507
+ }
2508
+ /**
2509
+ * CEE-style claim: when the pool subtotal is ≤ 0 the claim MUST equal that
2510
+ * (negative or zero) subtotal — an income inclusion, not a deduction — and
2511
+ * any requested figure is overridden. When positive, it is a discretionary
2512
+ * claim up to the subtotal (100% claimable, no percentage rate), defaulting
2513
+ * to the maximum.
2514
+ */
2515
+ function forcedOrCappedClaim(requested, subtotal, issues, label) {
2516
+ if (subtotal <= 0) {
2517
+ if (requested !== void 0 && round(requested) !== round(subtotal)) issues.push(`${label}: the pool subtotal is ${subtotal} (≤ 0), so the claim must equal the subtotal (an income inclusion) — overriding the requested ${requested}.`);
2518
+ return round(subtotal);
2519
+ }
2520
+ return claimUpToCap(requested, subtotal, issues, label);
2521
+ }
2522
+ function computeEdaRegular(input) {
2523
+ const issues = [];
2524
+ const f = input.federal;
2525
+ const o = input.albertaOverride ?? {};
2526
+ const opening = reconcile(f.openingBalance, o.openingBalance);
2527
+ const amalg = reconcile(f.amalgamationTransfer, o.amalgamationTransfer);
2528
+ const sale = reconcile(f.saleTransfer, o.saleTransfer);
2529
+ const poolBeforeClaim = opening.value + amalg.value - sale.value;
2530
+ const claim = pool_cappedClaim(reconcile(f.regulation1201Claim, o.regulation1201Claim), poolBeforeClaim, issues, "Schedule 15 EDA regular (015007)");
2531
+ const closingBalance = poolBeforeClaim - claim.value;
2532
+ return {
2533
+ openingBalance: opening.value,
2534
+ amalgamationTransfer: amalg.value,
2535
+ saleTransfer: sale.value,
2536
+ poolBeforeClaim,
2537
+ claim: claim.value,
2538
+ closingBalance,
2539
+ differsFromFederal: opening.differs || amalg.differs || sale.differs || claim.differs,
2540
+ issues
2541
+ };
2542
+ }
2543
+ /** A reconciled figure that is ALSO capped by a pool — the EDA/CMEDB claim shape (015007, 015019). */
2544
+ function pool_cappedClaim(reconciled, pool, issues, label) {
2545
+ const cap = Math.max(0, round(pool));
2546
+ if (pool <= 0) return {
2547
+ value: 0,
2548
+ differs: reconciled.differs
2549
+ };
2550
+ if (round(reconciled.value) > cap) {
2551
+ issues.push(`${label}: the entered claim ${reconciled.value} exceeds the pool ${cap}; capped.`);
2552
+ return {
2553
+ value: cap,
2554
+ differs: reconciled.differs
2555
+ };
2556
+ }
2557
+ return {
2558
+ value: Math.max(0, round(reconciled.value)),
2559
+ differs: reconciled.differs
2560
+ };
2561
+ }
2562
+ function computeEdaSuccessor(input) {
2563
+ const issues = [];
2564
+ const f = input.federal;
2565
+ const o = input.albertaOverride ?? {};
2566
+ const opening = reconcile(f.openingBalance, o.openingBalance);
2567
+ const amalg = reconcile(f.amalgamationTransfer, o.amalgamationTransfer);
2568
+ const other = reconcile(f.otherTransfer, o.otherTransfer);
2569
+ const sale = reconcile(f.saleTransfer, o.saleTransfer);
2570
+ const poolBeforeClaim = opening.value + amalg.value + other.value - sale.value;
2571
+ const claim = pool_cappedClaim(reconcile(f.regulation1202Claim, o.regulation1202Claim), poolBeforeClaim, issues, "Schedule 15 EDA successor (015019)");
2572
+ const closingBalance = poolBeforeClaim - claim.value;
2573
+ return {
2574
+ openingBalance: opening.value,
2575
+ amalgamationTransfer: amalg.value,
2576
+ otherTransfer: other.value,
2577
+ saleTransfer: sale.value,
2578
+ poolBeforeClaim,
2579
+ claim: claim.value,
2580
+ closingBalance,
2581
+ differsFromFederal: opening.differs || amalg.differs || other.differs || sale.differs || claim.differs,
2582
+ issues
2583
+ };
2584
+ }
2585
+ function computeCmedb(input) {
2586
+ const issues = [];
2587
+ const f = input.federal;
2588
+ const o = input.albertaOverride ?? {};
2589
+ const opening = reconcile(f.openingBalance, o.openingBalance);
2590
+ const amalg = reconcile(f.amalgamationTransfer, o.amalgamationTransfer);
2591
+ const other = reconcile(f.otherTransfer, o.otherTransfer);
2592
+ const disposal = reconcile(f.disposalTransfer, o.disposalTransfer);
2593
+ const poolBeforeClaim = opening.value + amalg.value + other.value - disposal.value;
2594
+ const claim = poolBeforeClaim <= 0 ? 0 : claimUpToCap(input.claimed, poolBeforeClaim, issues, "Schedule 15 CMEDB (015031)");
2595
+ const closingBalance = poolBeforeClaim - claim;
2596
+ return {
2597
+ openingBalance: opening.value,
2598
+ amalgamationTransfer: amalg.value,
2599
+ otherTransfer: other.value,
2600
+ disposalTransfer: disposal.value,
2601
+ poolBeforeClaim,
2602
+ claim,
2603
+ closingBalance,
2604
+ differsFromFederal: opening.differs || amalg.differs || other.differs || disposal.differs,
2605
+ issues
2606
+ };
2607
+ }
2608
+ function computeCeeRegular(input) {
2609
+ const issues = [];
2610
+ const f = input.federal;
2611
+ const o = input.albertaOverride ?? {};
2612
+ const opening = reconcile(f.openingBalance, o.openingBalance);
2613
+ const amalg = reconcile(f.amalgamationTransfer, o.amalgamationTransfer);
2614
+ const otherAdd = reconcile(f.otherAdditions, o.otherAdditions);
2615
+ const otherDed = reconcile(f.otherDeductions, o.otherDeductions);
2616
+ const toSuccessor = reconcile(f.transferredToSuccessor, o.transferredToSuccessor);
2617
+ const currentYearExpenses = num$1(f.currentYearExpenses);
2618
+ const lookBackExpenses = num$1(f.lookBackExpenses);
2619
+ const reclassifiedFromCde = num$1(f.reclassifiedFromCde);
2620
+ const renewableConservationExpenses = num$1(f.renewableConservationExpenses);
2621
+ const governmentAssistance = num$1(f.governmentAssistance);
2622
+ const renouncedFlowThrough = num$1(f.renouncedFlowThrough);
2623
+ const renouncedLookBack = num$1(f.renouncedLookBack);
2624
+ const subtotal = opening.value + currentYearExpenses + lookBackExpenses + reclassifiedFromCde + amalg.value + renewableConservationExpenses + otherAdd.value - governmentAssistance - otherDed.value - renouncedFlowThrough - toSuccessor.value - renouncedLookBack;
2625
+ const claim = forcedOrCappedClaim(input.claimed, subtotal, issues, "Schedule 15 CEE regular (015061)");
2626
+ const closingBalance = subtotal > 0 ? subtotal - claim : 0;
2627
+ return {
2628
+ openingBalance: opening.value,
2629
+ currentYearExpenses,
2630
+ lookBackExpenses,
2631
+ reclassifiedFromCde,
2632
+ amalgamationTransfer: amalg.value,
2633
+ renewableConservationExpenses,
2634
+ otherAdditions: otherAdd.value,
2635
+ governmentAssistance,
2636
+ otherDeductions: otherDed.value,
2637
+ renouncedFlowThrough,
2638
+ transferredToSuccessor: toSuccessor.value,
2639
+ renouncedLookBack,
2640
+ subtotal,
2641
+ claim,
2642
+ closingBalance,
2643
+ differsFromFederal: opening.differs || amalg.differs || otherAdd.differs || otherDed.differs || toSuccessor.differs,
2644
+ issues
2645
+ };
2646
+ }
2647
+ function computeCeeSuccessor(input) {
2648
+ const issues = [];
2649
+ const f = input.federal;
2650
+ const o = input.albertaOverride ?? {};
2651
+ const opening = reconcile(f.openingBalance, o.openingBalance);
2652
+ const reclassified = num$1(f.reclassifiedFromCde);
2653
+ const amalg = reconcile(f.amalgamationTransfer, o.amalgamationTransfer);
2654
+ const other = reconcile(f.otherTransfer, o.otherTransfer);
2655
+ const otherDed = reconcile(f.otherDeductions, o.otherDeductions);
2656
+ const toSuccessor = reconcile(f.transferredToSuccessor, o.transferredToSuccessor);
2657
+ const subtotal = opening.value + reclassified + amalg.value + other.value - otherDed.value - toSuccessor.value;
2658
+ const claim = forcedOrCappedClaim(input.claimed, subtotal, issues, "Schedule 15 CEE successor (015081)");
2659
+ const closingBalance = subtotal - claim;
2660
+ return {
2661
+ openingBalance: opening.value,
2662
+ reclassifiedFromCde: reclassified,
2663
+ amalgamationTransfer: amalg.value,
2664
+ otherTransfer: other.value,
2665
+ otherDeductions: otherDed.value,
2666
+ transferredToSuccessor: toSuccessor.value,
2667
+ subtotal,
2668
+ claim,
2669
+ closingBalance,
2670
+ differsFromFederal: opening.differs || amalg.differs || other.differs || otherDed.differs || toSuccessor.differs,
2671
+ issues
2672
+ };
2673
+ }
2674
+ /** CDE / CCOGPE claim rate — 30% for CDE (ITA s.66.2(2)), applied via `stepYearFactor`. */
2675
+ const CDE_CLAIM_RATE = .3;
2676
+ /** CCOGPE claim rate — 10% (ITA s.66.4(2)/66.7(5)), applied via `stepYearFactor`. */
2677
+ const CCOGPE_CLAIM_RATE = .1;
2678
+ function computeCdeRegular(input, ccogpeRegular) {
2679
+ const issues = [];
2680
+ const f = input.federal;
2681
+ const o = input.albertaOverride ?? {};
2682
+ const opening = reconcile(f.openingBalance, o.openingBalance);
2683
+ const currentYearExpenses = num$1(f.currentYearExpenses);
2684
+ const lookBackExpenses = num$1(f.lookBackExpenses);
2685
+ const amalg = reconcile(f.amalgamationTransfer, o.amalgamationTransfer);
2686
+ const otherAdd = reconcile(f.otherAdditions, o.otherAdditions);
2687
+ const reclassified = num$1(f.reclassifiedFromCee);
2688
+ const governmentAssistance = num$1(f.governmentAssistance);
2689
+ const receivable = reconcile(f.receivableOnDisposition, o.receivableOnDisposition);
2690
+ const creditBalanceReconciled = reconcile(f.creditBalanceInCogpePool, o.creditBalanceInCogpePool);
2691
+ const creditBalance = ccogpeRegular.subtotal < 0 ? {
2692
+ value: round(ccogpeRegular.subtotal),
2693
+ differs: true
2694
+ } : creditBalanceReconciled;
2695
+ const otherDed = reconcile(f.otherDeductions, o.otherDeductions);
2696
+ const renouncedFlowThrough = num$1(f.renouncedFlowThrough);
2697
+ const toSuccessor = reconcile(f.transferredToSuccessor, o.transferredToSuccessor);
2698
+ const renouncedLookBack = num$1(f.renouncedLookBack);
2699
+ const subtotal = opening.value + currentYearExpenses + lookBackExpenses + amalg.value + otherAdd.value - reclassified - governmentAssistance - receivable.value - creditBalance.value - otherDed.value - toSuccessor.value - renouncedFlowThrough - renouncedLookBack;
2700
+ if (f.otherDeductions !== void 0 || o.otherDeductions !== void 0) issues.push("Schedule 15 CDE regular (015107): the spec's own business rule for this line adds \"If 015139 is negative, include the amount at 015107 as a positive value\" — line 015139 does not exist anywhere else in Schedule 15 as extracted from the source text (source lines 13681-13691). Not modelled; verify against the live TRA form, which has no PDF in this engine's sources for Schedule 15.");
2701
+ const claim = subtotal > 0 ? claimUpToCap(input.claimed, CDE_CLAIM_RATE * stepYearFactor(input.daysInTaxYear) * subtotal, issues, "Schedule 15 CDE regular (015115)") : 0;
2702
+ const closingBalance = Math.max(0, subtotal - claim);
2703
+ return {
2704
+ openingBalance: opening.value,
2705
+ currentYearExpenses,
2706
+ lookBackExpenses,
2707
+ amalgamationTransfer: amalg.value,
2708
+ otherAdditions: otherAdd.value,
2709
+ reclassifiedFromCee: reclassified,
2710
+ governmentAssistance,
2711
+ receivableOnDisposition: receivable.value,
2712
+ creditBalanceInCogpePool: creditBalance.value,
2713
+ otherDeductions: otherDed.value,
2714
+ renouncedFlowThrough,
2715
+ transferredToSuccessor: toSuccessor.value,
2716
+ renouncedLookBack,
2717
+ subtotal,
2718
+ claim,
2719
+ closingBalance,
2720
+ differsFromFederal: opening.differs || amalg.differs || otherAdd.differs || receivable.differs || creditBalance.differs || otherDed.differs || toSuccessor.differs,
2721
+ issues
2722
+ };
2723
+ }
2724
+ function computeCdeSuccessor(input, ccogpeSuccessor) {
2725
+ const issues = [];
2726
+ const f = input.federal;
2727
+ const o = input.albertaOverride ?? {};
2728
+ const opening = reconcile(f.openingBalance, o.openingBalance);
2729
+ const amalg = reconcile(f.amalgamationTransfer, o.amalgamationTransfer);
2730
+ const other = reconcile(f.otherTransfer, o.otherTransfer);
2731
+ const reclassified = num$1(f.reclassifiedFromCee);
2732
+ const creditBalanceReconciled = reconcile(f.creditBalanceInCogpePool, o.creditBalanceInCogpePool);
2733
+ const creditBalance = ccogpeSuccessor.subtotal < 0 ? {
2734
+ value: round(ccogpeSuccessor.subtotal),
2735
+ differs: true
2736
+ } : creditBalanceReconciled;
2737
+ if (creditBalance.value !== 0) issues.push("Schedule 15 CDE successor (015133): the \"value may not exceed amount A\" wording (source lines 13945-13962) is ambiguous — this module treats it as \"value = A\" (matching line 015105's unconditional wording) whenever the CCOGPE-successor subtotal is negative. Verify against the live TRA form.");
2738
+ const otherDed = reconcile(f.otherDeductions, o.otherDeductions);
2739
+ const toSuccessor = reconcile(f.transferredToSuccessor, o.transferredToSuccessor);
2740
+ const subtotal = opening.value + amalg.value + other.value - reclassified - creditBalance.value - otherDed.value - toSuccessor.value;
2741
+ const claim = subtotal > 0 ? claimUpToCap(input.claimed, CDE_CLAIM_RATE * stepYearFactor(input.daysInTaxYear) * subtotal, issues, "Schedule 15 CDE successor (015141)") : 0;
2742
+ const closingBalance = Math.max(0, subtotal - claim);
2743
+ return {
2744
+ openingBalance: opening.value,
2745
+ amalgamationTransfer: amalg.value,
2746
+ otherTransfer: other.value,
2747
+ reclassifiedFromCee: reclassified,
2748
+ creditBalanceInCogpePool: creditBalance.value,
2749
+ otherDeductions: otherDed.value,
2750
+ transferredToSuccessor: toSuccessor.value,
2751
+ subtotal,
2752
+ claim,
2753
+ closingBalance,
2754
+ differsFromFederal: opening.differs || amalg.differs || other.differs || creditBalance.differs || otherDed.differs || toSuccessor.differs,
2755
+ issues
2756
+ };
2757
+ }
2758
+ function computeCcogpeRegular(input) {
2759
+ const issues = [];
2760
+ const f = input.federal;
2761
+ const o = input.albertaOverride ?? {};
2762
+ const opening = reconcile(f.openingBalance, o.openingBalance);
2763
+ const currentYearExpenses = num$1(f.currentYearExpenses);
2764
+ const amalg = reconcile(f.amalgamationTransfer, o.amalgamationTransfer);
2765
+ const otherAdd = reconcile(f.otherAdditions, o.otherAdditions);
2766
+ const receivable = reconcile(f.receivableOnDisposition, o.receivableOnDisposition);
2767
+ const governmentAssistance = num$1(f.governmentAssistance);
2768
+ const toSuccessor = reconcile(f.transferredToSuccessor, o.transferredToSuccessor);
2769
+ const otherDed = reconcile(f.otherDeductions, o.otherDeductions);
2770
+ const subtotal = opening.value + currentYearExpenses + amalg.value + otherAdd.value - receivable.value - governmentAssistance - toSuccessor.value - otherDed.value;
2771
+ let claim = 0;
2772
+ if (subtotal < 0) issues.push("Schedule 15 CCOGPE regular (015169): the pool subtotal is negative. Per source lines 14346-14359, this must be carried forward to line 015105 (CDE regular) if the corporation has made a designation under subparagraph 66.7(4)(a)(iii), or to line 015133 (CDE successor) if it has not. computeCdeRegular auto-applies the 015105 route unconditionally (see that function's doc comment) — confirm the designation status before relying on that routing when it should instead land on 015133.");
2773
+ else if (subtotal > 0) claim = claimUpToCap(input.claimed, CCOGPE_CLAIM_RATE * stepYearFactor(input.daysInTaxYear) * subtotal, issues, "Schedule 15 CCOGPE regular (015169)");
2774
+ const closingBalance = subtotal > 0 ? subtotal - claim : 0;
2775
+ return {
2776
+ openingBalance: opening.value,
2777
+ currentYearExpenses,
2778
+ amalgamationTransfer: amalg.value,
2779
+ otherAdditions: otherAdd.value,
2780
+ receivableOnDisposition: receivable.value,
2781
+ governmentAssistance,
2782
+ transferredToSuccessor: toSuccessor.value,
2783
+ otherDeductions: otherDed.value,
2784
+ subtotal,
2785
+ claim,
2786
+ closingBalance,
2787
+ differsFromFederal: opening.differs || amalg.differs || otherAdd.differs || receivable.differs || toSuccessor.differs || otherDed.differs,
2788
+ issues
2789
+ };
2790
+ }
2791
+ function computeCcogpeSuccessor(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 receivable = reconcile(f.receivableOnDisposition, o.receivableOnDisposition);
2799
+ const toSuccessor = reconcile(f.transferredToSuccessor, o.transferredToSuccessor);
2800
+ const otherDed = reconcile(f.otherDeductions, o.otherDeductions);
2801
+ const subtotal = opening.value + amalg.value + other.value - receivable.value - toSuccessor.value - otherDed.value;
2802
+ let claim = 0;
2803
+ if (subtotal < 0) issues.push("Schedule 15 CCOGPE successor (015189): the pool subtotal is negative. Per source lines 14646-14660, this must be carried forward to line 015133 (CDE successor) if the corporation has made a designation under subparagraph 66.7(4)(a)(iii), or included in line 015167 (this SAME pool's own regular-side deduction line) if it has not. Neither route is auto-applied by this function; supply the appropriate override manually. See module doc comment.");
2804
+ else if (subtotal > 0) claim = claimUpToCap(input.claimed, CCOGPE_CLAIM_RATE * stepYearFactor(input.daysInTaxYear) * subtotal, issues, "Schedule 15 CCOGPE successor (015189)");
2805
+ const closingBalance = Math.max(0, subtotal - claim);
2806
+ return {
2807
+ openingBalance: opening.value,
2808
+ amalgamationTransfer: amalg.value,
2809
+ otherTransfer: other.value,
2810
+ receivableOnDisposition: receivable.value,
2811
+ transferredToSuccessor: toSuccessor.value,
2812
+ otherDeductions: otherDed.value,
2813
+ subtotal,
2814
+ claim,
2815
+ closingBalance,
2816
+ differsFromFederal: opening.differs || amalg.differs || other.differs || receivable.differs || toSuccessor.differs || otherDed.differs,
2817
+ issues
2818
+ };
2819
+ }
2820
+ function computeFedeRegular(input) {
2821
+ const issues = [];
2822
+ const f = input.federal;
2823
+ const o = input.albertaOverride ?? {};
2824
+ const opening = reconcile(f.openingBalance, o.openingBalance);
2825
+ const amalg = reconcile(f.amalgamationTransfer, o.amalgamationTransfer);
2826
+ const otherDed = reconcile(f.otherDeductions, o.otherDeductions);
2827
+ const foreignResourceIncome = num$1(f.foreignResourceIncome);
2828
+ const pool = opening.value + amalg.value - otherDed.value;
2829
+ let claim = 0;
2830
+ if (pool < 0) issues.push("Schedule 15 FEDE regular (015209): the pool balance is negative. Per source lines 14855-14858 this is included in federal T2 line 012040 — outside AT1 Schedule 15 and this engine's scope. Claim and closing balance are zeroed per the schedule's own instruction.");
2831
+ else if (pool > 0) {
2832
+ const cap = Math.max(CCOGPE_CLAIM_RATE * linearYearFactor(input.daysInTaxYear) * pool, foreignResourceIncome);
2833
+ claim = claimUpToCap(input.claimed, Math.min(pool, cap), issues, "Schedule 15 FEDE regular (015209)");
2834
+ }
2835
+ const closingBalance = pool - claim;
2836
+ return {
2837
+ openingBalance: opening.value,
2838
+ amalgamationTransfer: amalg.value,
2839
+ otherDeductions: otherDed.value,
2840
+ foreignResourceIncome,
2841
+ pool,
2842
+ claim,
2843
+ closingBalance,
2844
+ differsFromFederal: opening.differs || amalg.differs || otherDed.differs,
2845
+ issues
2846
+ };
2847
+ }
2848
+ function computeFedeSuccessor(input) {
2849
+ const issues = [];
2850
+ const f = input.federal;
2851
+ const o = input.albertaOverride ?? {};
2852
+ const opening = reconcile(f.openingBalance, o.openingBalance);
2853
+ const amalg = reconcile(f.amalgamationTransfer, o.amalgamationTransfer);
2854
+ const other = reconcile(f.otherTransfer, o.otherTransfer);
2855
+ const otherDed = reconcile(f.otherDeductions, o.otherDeductions);
2856
+ const foreignResourceIncome = num$1(f.foreignResourceIncome);
2857
+ const pool = opening.value + amalg.value + other.value - otherDed.value;
2858
+ let claim = 0;
2859
+ if (pool < 0) issues.push("Schedule 15 FEDE successor (015221): the pool balance is negative. Per source lines 14855-14858-style wording (successor variant, source lines ~15045-15048) this is included in federal T2 line 012040 — outside AT1 Schedule 15 and this engine's scope.");
2860
+ else if (pool > 0) claim = claimUpToCap(input.claimed, Math.min(pool, foreignResourceIncome), issues, "Schedule 15 FEDE successor (015221)");
2861
+ const closingBalance = pool - claim;
2862
+ return {
2863
+ openingBalance: opening.value,
2864
+ amalgamationTransfer: amalg.value,
2865
+ otherTransfer: other.value,
2866
+ otherDeductions: otherDed.value,
2867
+ foreignResourceIncome,
2868
+ pool,
2869
+ claim,
2870
+ closingBalance,
2871
+ differsFromFederal: opening.differs || amalg.differs || other.differs || otherDed.differs,
2872
+ issues
2873
+ };
2874
+ }
2875
+ function computeSfedeCountryRegular(input) {
2876
+ const issues = [];
2877
+ const f = input.federal;
2878
+ const o = input.albertaOverride ?? {};
2879
+ const opening = reconcile(f.openingBalance, o.openingBalance);
2880
+ const amalg = reconcile(f.amalgamationTransfer, o.amalgamationTransfer);
2881
+ const otherAdd = reconcile(f.otherAdditions, o.otherAdditions);
2882
+ const otherDed = reconcile(f.otherDeductions, o.otherDeductions);
2883
+ const foreignResourceIncome = num$1(f.foreignResourceIncome);
2884
+ const pool = opening.value + amalg.value + otherAdd.value - otherDed.value;
2885
+ let claim = 0;
2886
+ if (pool < 0) issues.push(`Schedule 15 SFEDE regular, country ${f.countryCode} (015253): the pool balance is negative. Per the schedule's pattern for foreign pools (source lines 15262-15265), this is included in federal T2 line 012040 — outside this engine's scope.`);
2887
+ else if (pool > 0) {
2888
+ const cap = Math.max(CCOGPE_CLAIM_RATE * linearYearFactor(input.daysInTaxYear) * pool, foreignResourceIncome);
2889
+ claim = claimUpToCap(input.claimed, Math.min(pool, cap), issues, `Schedule 15 SFEDE regular, country ${f.countryCode} (015253)`);
874
2890
  }
2891
+ const closingBalance = pool - claim;
875
2892
  return {
876
- scheduleId: "020",
877
- values
2893
+ countryCode: f.countryCode,
2894
+ openingBalance: opening.value,
2895
+ amalgamationTransfer: amalg.value,
2896
+ otherAdditions: otherAdd.value,
2897
+ otherDeductions: otherDed.value,
2898
+ foreignResourceIncome,
2899
+ pool,
2900
+ claim,
2901
+ closingBalance,
2902
+ differsFromFederal: opening.differs || amalg.differs || otherAdd.differs || otherDed.differs,
2903
+ issues
2904
+ };
2905
+ }
2906
+ function computeSfedeCountrySuccessor(input) {
2907
+ const issues = [];
2908
+ const f = input.federal;
2909
+ const o = input.albertaOverride ?? {};
2910
+ const opening = reconcile(f.openingBalance, o.openingBalance);
2911
+ const amalg = reconcile(f.amalgamationTransfer, o.amalgamationTransfer);
2912
+ const other = reconcile(f.otherTransfer, o.otherTransfer);
2913
+ const otherDed = reconcile(f.otherDeductions, o.otherDeductions);
2914
+ const foreignResourceIncome = num$1(f.foreignResourceIncome);
2915
+ const pool = opening.value + amalg.value + other.value - otherDed.value;
2916
+ let claim = 0;
2917
+ if (pool < 0) issues.push(`Schedule 15 SFEDE successor, country ${f.countryCode} (015273): the pool balance is negative. Per the schedule's pattern for foreign pools this is included in federal T2 line 012040 — outside this engine's scope.`);
2918
+ else if (pool > 0) claim = claimUpToCap(input.claimed, Math.min(pool, foreignResourceIncome), issues, `Schedule 15 SFEDE successor, country ${f.countryCode} (015273)`);
2919
+ const closingBalance = pool - claim;
2920
+ return {
2921
+ countryCode: f.countryCode,
2922
+ openingBalance: opening.value,
2923
+ amalgamationTransfer: amalg.value,
2924
+ otherTransfer: other.value,
2925
+ otherDeductions: otherDed.value,
2926
+ foreignResourceIncome,
2927
+ pool,
2928
+ claim,
2929
+ closingBalance,
2930
+ differsFromFederal: opening.differs || amalg.differs || other.differs || otherDed.differs,
2931
+ issues
878
2932
  };
879
2933
  }
880
2934
  /**
881
- * The SR&ED expenditure POOL a deduction against income, not the investment tax
882
- * credit and not the innovation grant.
883
- *
884
- * Line numbers and the subtotal formula verified against the live form, which
885
- * states it exactly as transcribed:
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"*.
2935
+ * CFRE regular claims need a second pass across all countries (line 015293's
2936
+ * "A" component caps at "total of all occurrences of 015297"), so this takes
2937
+ * the whole array and the pre-summed `sumForeignResourceIncome` across every
2938
+ * country's own 015297 rather than being called per-entry like the other
2939
+ * per-country pools.
891
2940
  */
892
- function schedule16Values(result) {
893
- const values = [];
894
- const put = (fieldId, value) => values.push({
895
- lineItemId: at1LineItemId("016", fieldId),
896
- value
2941
+ function computeCfreRegular(entries) {
2942
+ const issues = [];
2943
+ const pools = entries.map((e) => {
2944
+ const f = e.federal;
2945
+ const o = e.albertaOverride ?? {};
2946
+ const opening = reconcile(f.openingBalance, o.openingBalance);
2947
+ const currentYearExpenses = num$1(f.currentYearExpenses);
2948
+ const amalg = reconcile(f.amalgamationTransfer, o.amalgamationTransfer);
2949
+ const otherAdd = reconcile(f.otherAdditions, o.otherAdditions);
2950
+ const otherDed = reconcile(f.otherDeductions, o.otherDeductions);
2951
+ return {
2952
+ e,
2953
+ opening,
2954
+ currentYearExpenses,
2955
+ amalg,
2956
+ otherAdd,
2957
+ otherDed,
2958
+ foreignResourceIncome: num$1(f.foreignResourceIncome),
2959
+ pool: opening.value + currentYearExpenses + amalg.value + otherAdd.value - otherDed.value
2960
+ };
897
2961
  });
898
- put("002", result.currentYearExpenditures);
899
- put("016", result.subtotal);
900
- put("018", result.deductionAvailable);
901
- put("020", result.amountClaimed);
902
- put("022", result.unclaimedPoolBalance);
2962
+ const sumForeignResourceIncome = pools.reduce((s, p) => s + p.foreignResourceIncome, 0);
903
2963
  return {
904
- scheduleId: "016",
905
- values
2964
+ entries: pools.map((p) => {
2965
+ const { e, opening, currentYearExpenses, amalg, otherAdd, otherDed, foreignResourceIncome, pool } = p;
2966
+ let claim = 0;
2967
+ 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.`);
2968
+ else if (pool > 0) {
2969
+ const linear = linearYearFactor(e.daysInTaxYear);
2970
+ const partA = Math.max(CCOGPE_CLAIM_RATE * linear * pool, Math.min(CDE_CLAIM_RATE * linear * pool, foreignResourceIncome, sumForeignResourceIncome));
2971
+ const remainder = Math.max(0, pool - partA);
2972
+ if (e.globalForeignResourceLimit === void 0) issues.push(`Schedule 15 CFRE regular, country ${e.federal.countryCode} (015293): the "global foreign resource limit for the year designated for that country" (source lines 15703-15711) was not supplied — this quantity has no source anywhere in this engine, so the B-component of the claim is treated as 0 (conservative — the pool may be under-claimed relative to what the corporation is actually entitled to).`);
2973
+ const partB = Math.min(remainder, nn$25(e.globalForeignResourceLimit));
2974
+ claim = claimUpToCap(e.claimed, partA + partB, issues, `Schedule 15 CFRE regular, country ${e.federal.countryCode} (015293)`);
2975
+ }
2976
+ const closingBalance = pool - claim;
2977
+ return {
2978
+ countryCode: e.federal.countryCode,
2979
+ openingBalance: opening.value,
2980
+ currentYearExpenses,
2981
+ amalgamationTransfer: amalg.value,
2982
+ otherAdditions: otherAdd.value,
2983
+ otherDeductions: otherDed.value,
2984
+ foreignResourceIncome,
2985
+ pool,
2986
+ claim,
2987
+ closingBalance,
2988
+ differsFromFederal: opening.differs || amalg.differs || otherAdd.differs || otherDed.differs,
2989
+ issues
2990
+ };
2991
+ }),
2992
+ issues
906
2993
  };
907
2994
  }
908
- //#endregion
909
- //#region src/t2/at1/schedules/at4970-ieg-projects.ts
910
- const nn$25 = (v) => Math.max(0, Math.round(v ?? 0));
911
- function computeAt4970(input) {
912
- const projects = input.projects.map((p) => ({
913
- title: p.title,
914
- ...p.projectCode !== void 0 ? { projectCode: p.projectCode } : {},
915
- albertaPortion: nn$25(p.albertaPortion),
916
- otherPortion: nn$25(p.otherPortion),
917
- salariesAndWages: nn$25(p.salariesAndWages),
918
- federalProxyAmount: nn$25(p.federalProxyAmount),
919
- albertaProxyAmount: nn$25(p.albertaProxyAmount)
920
- }));
921
- const totals = {
922
- albertaPortion: projects.reduce((s, p) => s + p.albertaPortion, 0),
923
- otherPortion: projects.reduce((s, p) => s + p.otherPortion, 0),
924
- salariesAndWages: projects.reduce((s, p) => s + p.salariesAndWages, 0),
925
- federalProxyAmount: projects.reduce((s, p) => s + p.federalProxyAmount, 0),
926
- albertaProxyAmount: projects.reduce((s, p) => s + p.albertaProxyAmount, 0)
2995
+ function computeAlbertaSchedule15(input) {
2996
+ const issues = [];
2997
+ const differsFlags = [];
2998
+ const eda = input.eda ? {
2999
+ regular: computeEdaRegular(input.eda.regular),
3000
+ successor: computeEdaSuccessor(input.eda.successor)
3001
+ } : void 0;
3002
+ if (eda) {
3003
+ issues.push(...eda.regular.issues, ...eda.successor.issues);
3004
+ differsFlags.push(eda.regular.differsFromFederal, eda.successor.differsFromFederal);
3005
+ }
3006
+ const cmedb = input.cmedb ? computeCmedb(input.cmedb) : void 0;
3007
+ if (cmedb) {
3008
+ issues.push(...cmedb.issues);
3009
+ differsFlags.push(cmedb.differsFromFederal);
3010
+ }
3011
+ const cee = input.cee ? {
3012
+ regular: computeCeeRegular(input.cee.regular),
3013
+ successor: computeCeeSuccessor(input.cee.successor)
3014
+ } : void 0;
3015
+ if (cee) {
3016
+ issues.push(...cee.regular.issues, ...cee.successor.issues);
3017
+ differsFlags.push(cee.regular.differsFromFederal, cee.successor.differsFromFederal);
3018
+ }
3019
+ const ccogpe = input.ccogpe ? {
3020
+ regular: computeCcogpeRegular(input.ccogpe.regular),
3021
+ successor: computeCcogpeSuccessor(input.ccogpe.successor)
3022
+ } : void 0;
3023
+ if (ccogpe) {
3024
+ issues.push(...ccogpe.regular.issues, ...ccogpe.successor.issues);
3025
+ differsFlags.push(ccogpe.regular.differsFromFederal, ccogpe.successor.differsFromFederal);
3026
+ }
3027
+ const cde = input.cde ? {
3028
+ regular: computeCdeRegular(input.cde.regular, { subtotal: ccogpe?.regular.subtotal ?? 0 }),
3029
+ successor: computeCdeSuccessor(input.cde.successor, { subtotal: ccogpe?.successor.subtotal ?? 0 })
3030
+ } : void 0;
3031
+ if (cde) {
3032
+ issues.push(...cde.regular.issues, ...cde.successor.issues);
3033
+ differsFlags.push(cde.regular.differsFromFederal, cde.successor.differsFromFederal);
3034
+ 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.");
3035
+ }
3036
+ const fede = input.fede ? {
3037
+ regular: computeFedeRegular(input.fede.regular),
3038
+ successor: computeFedeSuccessor(input.fede.successor)
3039
+ } : void 0;
3040
+ if (fede) {
3041
+ issues.push(...fede.regular.issues, ...fede.successor.issues);
3042
+ differsFlags.push(fede.regular.differsFromFederal, fede.successor.differsFromFederal);
3043
+ }
3044
+ const sfede = input.sfede ? {
3045
+ regular: input.sfede.regular.map(computeSfedeCountryRegular),
3046
+ successor: input.sfede.successor.map(computeSfedeCountrySuccessor)
3047
+ } : void 0;
3048
+ if (sfede) {
3049
+ for (const r of sfede.regular) {
3050
+ issues.push(...r.issues);
3051
+ differsFlags.push(r.differsFromFederal);
3052
+ }
3053
+ for (const s of sfede.successor) {
3054
+ issues.push(...s.issues);
3055
+ differsFlags.push(s.differsFromFederal);
3056
+ }
3057
+ }
3058
+ const cfre = input.cfre ? {
3059
+ regular: computeCfreRegular(input.cfre.regular),
3060
+ successor: computeCfreSuccessor(input.cfre.successor)
3061
+ } : void 0;
3062
+ if (cfre) {
3063
+ issues.push(...cfre.regular.issues, ...cfre.successor.issues);
3064
+ for (const r of cfre.regular.entries) differsFlags.push(r.differsFromFederal);
3065
+ for (const s of cfre.successor.entries) differsFlags.push(s.differsFromFederal);
3066
+ }
3067
+ 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.");
3068
+ const formRequired = differsFlags.some(Boolean);
3069
+ const formPermitted = (input.reportsDifferentAlbertaIncome ?? false) || (input.electsDifferentDiscretionaryAmounts ?? false);
3070
+ 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.");
3071
+ return {
3072
+ ...eda ? { eda } : {},
3073
+ ...cmedb ? { cmedb } : {},
3074
+ ...cee ? { cee } : {},
3075
+ ...cde ? { cde } : {},
3076
+ ...ccogpe ? { ccogpe } : {},
3077
+ ...fede ? { fede } : {},
3078
+ ...sfede ? { sfede: {
3079
+ regular: sfede.regular,
3080
+ successor: sfede.successor
3081
+ } } : {},
3082
+ ...cfre ? { cfre: {
3083
+ regular: cfre.regular.entries,
3084
+ successor: cfre.successor.entries
3085
+ } } : {},
3086
+ formRequired,
3087
+ formPermitted,
3088
+ issues
927
3089
  };
928
- const jurisdictions = (input.jurisdictions ?? []).map((j) => ({
929
- jurisdiction: j.jurisdiction,
930
- amountIncurred: nn$25(j.amountIncurred)
931
- }));
3090
+ }
3091
+ /** Line 015313 caps at "total of all occurrence of 015317", so this also processes the whole array. */
3092
+ function computeCfreSuccessor(entries) {
3093
+ const issues = [];
3094
+ const pools = entries.map((e) => {
3095
+ const f = e.federal;
3096
+ const o = e.albertaOverride ?? {};
3097
+ const opening = reconcile(f.openingBalance, o.openingBalance);
3098
+ const amalg = reconcile(f.amalgamationTransfer, o.amalgamationTransfer);
3099
+ const other = reconcile(f.otherTransfer, o.otherTransfer);
3100
+ const otherDed = reconcile(f.otherDeductions, o.otherDeductions);
3101
+ return {
3102
+ e,
3103
+ opening,
3104
+ amalg,
3105
+ other,
3106
+ otherDed,
3107
+ foreignResourceIncome: num$1(f.foreignResourceIncome),
3108
+ pool: opening.value + amalg.value + other.value - otherDed.value
3109
+ };
3110
+ });
3111
+ const sumForeignResourceIncome = pools.reduce((s, p) => s + p.foreignResourceIncome, 0);
932
3112
  return {
933
- projects,
934
- totals,
935
- jurisdictions,
936
- jurisdictionTotal: jurisdictions.reduce((s, j) => s + j.amountIncurred, 0)
3113
+ entries: pools.map((p) => {
3114
+ const { e, opening, amalg, other, otherDed, foreignResourceIncome, pool } = p;
3115
+ let claim = 0;
3116
+ if (pool < 0) issues.push(`Schedule 15 CFRE successor, country ${e.federal.countryCode} (015313): the pool balance is negative. Per the schedule's pattern for foreign pools this is included in federal T2 line 012040 — outside this engine's scope.`);
3117
+ else if (pool > 0) {
3118
+ const cap = Math.min(CDE_CLAIM_RATE * linearYearFactor(e.daysInTaxYear) * pool, sumForeignResourceIncome);
3119
+ claim = claimUpToCap(e.claimed, cap, issues, `Schedule 15 CFRE successor, country ${e.federal.countryCode} (015313)`);
3120
+ }
3121
+ const closingBalance = pool - claim;
3122
+ return {
3123
+ countryCode: e.federal.countryCode,
3124
+ openingBalance: opening.value,
3125
+ amalgamationTransfer: amalg.value,
3126
+ otherTransfer: other.value,
3127
+ otherDeductions: otherDed.value,
3128
+ foreignResourceIncome,
3129
+ pool,
3130
+ claim,
3131
+ closingBalance,
3132
+ differsFromFederal: opening.differs || amalg.differs || other.differs || otherDed.differs,
3133
+ issues
3134
+ };
3135
+ }),
3136
+ issues
937
3137
  };
938
3138
  }
939
- //#endregion
940
- //#region src/t2/at1/schedules/schedule2.ts
941
- /** Round to six decimal places — the AT1 allocation-factor precision. */
942
- function round6(n) {
943
- return Math.round(n * 1e6) / 1e6;
3139
+ function schedule15LineItemId(fieldId, occurrence = 1) {
3140
+ return `015${fieldId}${String(occurrence).padStart(3, "0")}`;
944
3141
  }
945
- /** Single Alberta PE, none elsewhere → all income is Alberta income. */
946
- const SINGLE_JURISDICTION_ALBERTA_FACTOR = 1;
947
- function computeAllocationFactor(input) {
948
- const hasRevenue = input.totalGrossRevenue > 0;
949
- const hasSalaries = input.totalSalaries > 0;
950
- const revenueRatio = hasRevenue ? input.albertaGrossRevenue / input.totalGrossRevenue : 0;
951
- const salariesRatio = hasSalaries ? input.albertaSalaries / input.totalSalaries : 0;
952
- let factor;
953
- if (hasRevenue && hasSalaries) factor = (revenueRatio + salariesRatio) / 2;
954
- else if (hasRevenue) factor = revenueRatio;
955
- else if (hasSalaries) factor = salariesRatio;
956
- else factor = 0;
957
- return round6(factor);
3142
+ /**
3143
+ * Field ids per the spec transcription in the module doc comment:
3144
+ * EDA 001-021 CMEDB 023-033 CEE 041-083 CDE 091-143
3145
+ * CCOGPE 151-191 FEDE 201-233 SFEDE 241-277 (per country)
3146
+ * CFRE 281-317 (per country)
3147
+ * A pool absent from `result` (never supplied to `computeAlbertaSchedule15`)
3148
+ * emits NOTHING there is no zero-filled line for a pool the corporation
3149
+ * does not carry, matching every other reconciliation-style AT1 schedule
3150
+ * builder in this package (e.g. `schedule18Values` only emits categories that
3151
+ * were actually computed).
3152
+ */
3153
+ function schedule15Values(result) {
3154
+ const values = [];
3155
+ const put = (fieldId, value, occurrence = 1) => values.push({
3156
+ lineItemId: schedule15LineItemId(fieldId, occurrence),
3157
+ value
3158
+ });
3159
+ const putStr = (fieldId, value, occurrence = 1) => values.push({
3160
+ lineItemId: schedule15LineItemId(fieldId, occurrence),
3161
+ value
3162
+ });
3163
+ if (result.eda) {
3164
+ const { regular, successor } = result.eda;
3165
+ put("001", regular.openingBalance);
3166
+ put("003", regular.amalgamationTransfer);
3167
+ put("005", regular.saleTransfer);
3168
+ put("007", regular.claim);
3169
+ put("009", regular.closingBalance);
3170
+ put("011", successor.openingBalance);
3171
+ put("013", successor.amalgamationTransfer);
3172
+ put("015", successor.otherTransfer);
3173
+ put("017", successor.saleTransfer);
3174
+ put("019", successor.claim);
3175
+ put("021", successor.closingBalance);
3176
+ }
3177
+ if (result.cmedb) {
3178
+ const c = result.cmedb;
3179
+ put("023", c.openingBalance);
3180
+ put("025", c.amalgamationTransfer);
3181
+ put("027", c.otherTransfer);
3182
+ put("029", c.disposalTransfer);
3183
+ put("031", c.claim);
3184
+ put("033", c.closingBalance);
3185
+ }
3186
+ if (result.cee) {
3187
+ const { regular, successor } = result.cee;
3188
+ put("041", regular.openingBalance);
3189
+ put("043", regular.currentYearExpenses);
3190
+ put("044", regular.lookBackExpenses);
3191
+ put("045", regular.reclassifiedFromCde);
3192
+ put("047", regular.amalgamationTransfer);
3193
+ put("049", regular.renewableConservationExpenses);
3194
+ put("051", regular.otherAdditions);
3195
+ put("053", regular.governmentAssistance);
3196
+ put("055", regular.otherDeductions);
3197
+ put("058", regular.renouncedFlowThrough);
3198
+ put("059", regular.transferredToSuccessor);
3199
+ put("060", regular.renouncedLookBack);
3200
+ put("061", regular.claim);
3201
+ put("063", regular.closingBalance);
3202
+ put("064", successor.openingBalance);
3203
+ put("065", successor.reclassifiedFromCde);
3204
+ put("067", successor.amalgamationTransfer);
3205
+ put("069", successor.otherTransfer);
3206
+ put("077", successor.otherDeductions);
3207
+ put("079", successor.transferredToSuccessor);
3208
+ put("081", successor.claim);
3209
+ put("083", successor.closingBalance);
3210
+ }
3211
+ if (result.cde) {
3212
+ const { regular, successor } = result.cde;
3213
+ put("091", regular.openingBalance);
3214
+ put("093", regular.currentYearExpenses);
3215
+ put("094", regular.lookBackExpenses);
3216
+ put("095", regular.amalgamationTransfer);
3217
+ put("097", regular.otherAdditions);
3218
+ put("099", regular.reclassifiedFromCee);
3219
+ put("101", regular.governmentAssistance);
3220
+ put("103", regular.receivableOnDisposition);
3221
+ put("105", regular.creditBalanceInCogpePool);
3222
+ put("107", regular.otherDeductions);
3223
+ put("110", regular.renouncedFlowThrough);
3224
+ put("111", regular.transferredToSuccessor);
3225
+ put("112", regular.renouncedLookBack);
3226
+ put("115", regular.claim);
3227
+ put("117", regular.closingBalance);
3228
+ put("119", successor.openingBalance);
3229
+ put("121", successor.amalgamationTransfer);
3230
+ put("123", successor.otherTransfer);
3231
+ put("127", successor.reclassifiedFromCee);
3232
+ put("133", successor.creditBalanceInCogpePool);
3233
+ put("135", successor.otherDeductions);
3234
+ put("137", successor.transferredToSuccessor);
3235
+ put("141", successor.claim);
3236
+ put("143", successor.closingBalance);
3237
+ }
3238
+ if (result.ccogpe) {
3239
+ const { regular, successor } = result.ccogpe;
3240
+ put("151", regular.openingBalance);
3241
+ put("153", regular.currentYearExpenses);
3242
+ put("155", regular.amalgamationTransfer);
3243
+ put("157", regular.otherAdditions);
3244
+ put("159", regular.receivableOnDisposition);
3245
+ put("161", regular.governmentAssistance);
3246
+ put("165", regular.transferredToSuccessor);
3247
+ put("167", regular.otherDeductions);
3248
+ put("169", regular.claim);
3249
+ put("171", regular.closingBalance);
3250
+ put("173", successor.openingBalance);
3251
+ put("175", successor.amalgamationTransfer);
3252
+ put("177", successor.otherTransfer);
3253
+ put("181", successor.receivableOnDisposition);
3254
+ put("185", successor.transferredToSuccessor);
3255
+ put("187", successor.otherDeductions);
3256
+ put("189", successor.claim);
3257
+ put("191", successor.closingBalance);
3258
+ }
3259
+ if (result.fede) {
3260
+ const { regular, successor } = result.fede;
3261
+ put("201", regular.openingBalance);
3262
+ put("205", regular.amalgamationTransfer);
3263
+ put("207", regular.otherDeductions);
3264
+ put("209", regular.claim);
3265
+ put("211", regular.closingBalance);
3266
+ put("231", regular.foreignResourceIncome);
3267
+ put("213", successor.openingBalance);
3268
+ put("215", successor.amalgamationTransfer);
3269
+ put("217", successor.otherTransfer);
3270
+ put("219", successor.otherDeductions);
3271
+ put("221", successor.claim);
3272
+ put("223", successor.closingBalance);
3273
+ put("233", successor.foreignResourceIncome);
3274
+ }
3275
+ if (result.sfede) {
3276
+ result.sfede.regular.forEach((r, i) => {
3277
+ const occ = i + 1;
3278
+ putStr("241", r.countryCode, occ);
3279
+ put("243", r.openingBalance, occ);
3280
+ put("247", r.amalgamationTransfer, occ);
3281
+ put("249", r.otherAdditions, occ);
3282
+ put("251", r.otherDeductions, occ);
3283
+ put("253", r.claim, occ);
3284
+ put("255", r.closingBalance, occ);
3285
+ put("257", r.foreignResourceIncome, occ);
3286
+ });
3287
+ result.sfede.successor.forEach((s, i) => {
3288
+ const occ = i + 1;
3289
+ putStr("261", s.countryCode, occ);
3290
+ put("263", s.openingBalance, occ);
3291
+ put("265", s.amalgamationTransfer, occ);
3292
+ put("267", s.otherTransfer, occ);
3293
+ put("269", s.otherDeductions, occ);
3294
+ put("273", s.claim, occ);
3295
+ put("275", s.closingBalance, occ);
3296
+ put("277", s.foreignResourceIncome, occ);
3297
+ });
3298
+ }
3299
+ if (result.cfre) {
3300
+ result.cfre.regular.forEach((r, i) => {
3301
+ const occ = i + 1;
3302
+ putStr("281", r.countryCode, occ);
3303
+ put("283", r.openingBalance, occ);
3304
+ put("285", r.currentYearExpenses, occ);
3305
+ put("287", r.amalgamationTransfer, occ);
3306
+ put("289", r.otherAdditions, occ);
3307
+ put("291", r.otherDeductions, occ);
3308
+ put("293", r.claim, occ);
3309
+ put("295", r.closingBalance, occ);
3310
+ put("297", r.foreignResourceIncome, occ);
3311
+ });
3312
+ result.cfre.successor.forEach((s, i) => {
3313
+ const occ = i + 1;
3314
+ putStr("301", s.countryCode, occ);
3315
+ put("303", s.openingBalance, occ);
3316
+ put("305", s.amalgamationTransfer, occ);
3317
+ put("307", s.otherTransfer, occ);
3318
+ put("309", s.otherDeductions, occ);
3319
+ put("313", s.claim, occ);
3320
+ put("315", s.closingBalance, occ);
3321
+ put("317", s.foreignResourceIncome, occ);
3322
+ });
3323
+ }
3324
+ return {
3325
+ scheduleId: "015",
3326
+ values,
3327
+ issues: result.issues
3328
+ };
958
3329
  }
959
3330
  //#endregion
960
3331
  //#region src/t2/at1/schedules/schedule29-eligible-expenditures.ts
@@ -1147,15 +3518,17 @@ function computeIegBaseAmount(priorYearExpenditures, priorYears = IEG_2024.PRIOR
1147
3518
  function computeIeg(input) {
1148
3519
  const limit = input.expenditureLimit ?? IEG_2024.MAX_EXPENDITURE;
1149
3520
  const cappedExpenditures = Math.max(0, Math.min(input.eligibleExpenditures, limit));
1150
- const incrementalExpenditures = Math.max(0, cappedExpenditures - input.baseAmount);
1151
- const creditAtBaseRate = Math.round(IEG_2024.BASE_RATE * cappedExpenditures);
1152
3521
  const enhancedRateBasis = input.associatedAllowedAmount !== void 0 ? "associated" : "non-associated";
1153
- const creditAtEnhancedRate = enhancedRateBasis === "associated" ? Math.round(IEG_2024.ENHANCED_RATE * Math.min(limit, Math.max(0, input.associatedAllowedAmount ?? 0))) : Math.round(IEG_2024.ENHANCED_RATE * incrementalExpenditures);
3522
+ const creditAtBaseRate = Math.round(IEG_2024.BASE_RATE * cappedExpenditures);
3523
+ const incrementalExpenditures = input.associatedAllowedAmount === void 0 ? Math.max(0, cappedExpenditures - input.baseAmount) : void 0;
3524
+ const creditAtEnhancedRate = enhancedRateBasis === "associated" ? Math.round(IEG_2024.ENHANCED_RATE * Math.min(limit, Math.max(0, input.associatedAllowedAmount ?? 0))) : Math.round(IEG_2024.ENHANCED_RATE * (incrementalExpenditures ?? 0));
1154
3525
  const taxableCapital = Math.max(0, input.taxableCapital ?? 0);
1155
3526
  const reductionFactor = computeIegReductionFactor(taxableCapital);
1156
3527
  const grossIeg = Math.round((creditAtBaseRate + creditAtEnhancedRate) * reductionFactor);
1157
3528
  const recapture = Math.max(0, Math.round(input.recapture ?? 0));
1158
3529
  const ieg = Math.max(0, grossIeg - recapture);
3530
+ const issues = [];
3531
+ if (reductionFactor > 0 && reductionFactor < 1 && creditAtBaseRate > 0 && creditAtEnhancedRate > 0) issues.push(`AT1 Schedule 29: taxable capital of ${taxableCapital} falls inside the $10,000,000–$50,000,000 reduction band, where this engine's reading of the live Schedule 29 form (the base and enhanced credits summed, THEN scaled by the reduction factor) disagrees with the AT1 jacket's own older business-rule table (only the enhanced credit scaled). The two produce different filed dollar amounts for line 129/134 — confirm the correct treatment with TRA before filing.`);
1159
3532
  return {
1160
3533
  cappedExpenditures,
1161
3534
  baseAmount: input.baseAmount,
@@ -1167,7 +3540,8 @@ function computeIeg(input) {
1167
3540
  reductionFactor,
1168
3541
  grossIeg,
1169
3542
  recapture,
1170
- ieg
3543
+ ieg,
3544
+ issues
1171
3545
  };
1172
3546
  }
1173
3547
  //#endregion
@@ -1467,28 +3841,94 @@ function computeAlbertaReturn(input) {
1467
3841
  iegAgreement = computeIegAgreement(input.ieg.agreement);
1468
3842
  issues.push(...iegAgreement.issues);
1469
3843
  }
1470
- ieg = computeIeg({
3844
+ ieg = iegAgreement ? computeIeg({
1471
3845
  eligibleExpenditures: resolvedEligibleExpenditures,
1472
- baseAmount: iegGroup.groupBaseAmount,
1473
3846
  expenditureLimit: allocation.allocations[0]?.allocated ?? 0,
1474
- taxableCapital: iegAgreement ? iegAgreement.totalTaxableCapitalPriorYear : iegGroup.groupTaxableCapital,
3847
+ taxableCapital: iegAgreement.totalTaxableCapitalPriorYear,
1475
3848
  ...input.ieg.recapture !== void 0 ? { recapture: input.ieg.recapture } : {},
1476
- ...iegAgreement ? { associatedAllowedAmount: iegAgreement.claimantAllocatedAllowedAmount } : {}
3849
+ associatedAllowedAmount: iegAgreement.claimantAllocatedAllowedAmount
3850
+ }) : computeIeg({
3851
+ eligibleExpenditures: resolvedEligibleExpenditures,
3852
+ baseAmount: iegGroup.groupBaseAmount,
3853
+ expenditureLimit: allocation.allocations[0]?.allocated ?? 0,
3854
+ taxableCapital: iegGroup.groupTaxableCapital,
3855
+ ...input.ieg.recapture !== void 0 ? { recapture: input.ieg.recapture } : {}
1477
3856
  });
3857
+ issues.push(...ieg.issues);
1478
3858
  }
1479
3859
  }
1480
3860
  const schedulePayloads = [];
1481
3861
  const sched = input.schedules;
1482
- if (sched?.smallBusinessDeduction) schedulePayloads.push(schedule1Values(sched.smallBusinessDeduction));
3862
+ if (sched?.smallBusinessDeduction) {
3863
+ schedulePayloads.push(schedule1Values(sched.smallBusinessDeduction));
3864
+ issues.push(...sched.smallBusinessDeduction.result.issues);
3865
+ }
1483
3866
  if (sched?.allocation) schedulePayloads.push(schedule2Values(sched.allocation));
3867
+ if (sched?.otherDeductionsCredits) {
3868
+ schedulePayloads.push(schedule3Values(sched.otherDeductionsCredits));
3869
+ issues.push(...sched.otherDeductionsCredits.issues);
3870
+ }
3871
+ if (sched?.foreignInvestmentTaxCredit) {
3872
+ schedulePayloads.push(schedule4Values(sched.foreignInvestmentTaxCredit));
3873
+ issues.push(...sched.foreignInvestmentTaxCredit.issues);
3874
+ }
3875
+ if (sched?.royaltyTaxDeduction) {
3876
+ schedulePayloads.push(schedule5Values(sched.royaltyTaxDeduction));
3877
+ issues.push(...sched.royaltyTaxDeduction.issues);
3878
+ }
3879
+ if (sched?.royaltyTaxCredit) {
3880
+ schedulePayloads.push(schedule6Values(sched.royaltyTaxCredit));
3881
+ issues.push(...sched.royaltyTaxCredit.issues);
3882
+ }
3883
+ if (sched?.royaltySupplemental) {
3884
+ schedulePayloads.push(schedule7Values(sched.royaltySupplemental));
3885
+ issues.push(...sched.royaltySupplemental.issues);
3886
+ }
3887
+ if (sched?.politicalContributions) {
3888
+ schedulePayloads.push(schedule8Values(sched.politicalContributions));
3889
+ issues.push(...sched.politicalContributions.issues);
3890
+ }
3891
+ if (sched?.sredTaxCredit) {
3892
+ schedulePayloads.push(schedule9Values(sched.sredTaxCredit.result, sched.sredTaxCredit.group));
3893
+ issues.push(...sched.sredTaxCredit.result.issues);
3894
+ }
1484
3895
  if (sched?.lossCarryback) schedulePayloads.push(schedule10Values(sched.lossCarryback));
3896
+ if (sched?.manufacturingProcessing) {
3897
+ schedulePayloads.push(schedule11Values(sched.manufacturingProcessing));
3898
+ issues.push(...sched.manufacturingProcessing.issues);
3899
+ }
1485
3900
  if (sched?.reconciliation) schedulePayloads.push(schedule12Values(sched.reconciliation));
1486
- if (sched?.cca) schedulePayloads.push(schedule13Values(sched.cca));
1487
- if (sched?.scientificResearch) schedulePayloads.push(schedule16Values(sched.scientificResearch));
1488
- if (sched?.reserves) schedulePayloads.push(schedule17Values(sched.reserves));
1489
- if (sched?.dispositions) schedulePayloads.push(schedule18Values(sched.dispositions));
1490
- if (sched?.donations) schedulePayloads.push(schedule20Values(sched.donations));
1491
- if (sched?.losses) schedulePayloads.push(schedule21Values(sched.losses));
3901
+ if (sched?.cca) {
3902
+ schedulePayloads.push(schedule13Values(sched.cca));
3903
+ issues.push(...sched.cca.issues);
3904
+ }
3905
+ if (sched?.resourceDeductions) {
3906
+ schedulePayloads.push(schedule15Values(sched.resourceDeductions));
3907
+ issues.push(...sched.resourceDeductions.issues);
3908
+ }
3909
+ if (sched?.scientificResearch) {
3910
+ schedulePayloads.push(schedule16Values(sched.scientificResearch));
3911
+ issues.push(...sched.scientificResearch.issues);
3912
+ }
3913
+ if (sched?.reserves) {
3914
+ schedulePayloads.push(schedule17Values(sched.reserves));
3915
+ issues.push(...sched.reserves.issues);
3916
+ }
3917
+ if (sched?.dispositions) {
3918
+ schedulePayloads.push(schedule18Values(sched.dispositions));
3919
+ issues.push(...sched.dispositions.issues);
3920
+ }
3921
+ if (sched?.donations) {
3922
+ schedulePayloads.push(schedule20Values(sched.donations));
3923
+ issues.push(...sched.donations.charitable?.issues ?? []);
3924
+ issues.push(...sched.donations.gifts?.issues ?? []);
3925
+ }
3926
+ if (sched?.losses) {
3927
+ schedulePayloads.push(schedule21Values(sched.losses));
3928
+ issues.push(...sched.losses.limitedPartnershipLosses?.issues ?? []);
3929
+ issues.push(...sched.losses.nonCapitalByYearOfOrigin?.issues ?? []);
3930
+ issues.push(...sched.losses.otherLossesByYearOfOrigin?.issues ?? []);
3931
+ }
1492
3932
  if (ieg) schedulePayloads.push(schedule29Values(ieg, iegAgreement, iegEligibleExpenditures, input.ieg?.primaryFieldCode));
1493
3933
  if (at4970) schedulePayloads.push(schedule4970Values(at4970));
1494
3934
  return {
@@ -1649,6 +4089,14 @@ function assertAt1MandatoryComplete(d) {
1649
4089
  const blank = (v) => v === void 0 || v === null || String(v).trim() === "";
1650
4090
  const missing = AT1_MANDATORY_WITHOUT_DEFAULT.filter(([key]) => blank(d[key])).map(([, label]) => label);
1651
4091
  if (d.transmitter?.isAmended && blank(d.transmitter.amendmentDescription)) missing.push("EDI073 description of changes (required when the amended return indicator is set)");
4092
+ if (d.transmitter?.thirdPartyIndicator === "1") {
4093
+ if (blank(d.transmitter.organizationType)) missing.push("EDI023 type of organization (required when EDI017 third-party indicator = 1)");
4094
+ if (blank(d.transmitter.address?.street)) missing.push("EDI051 transmitter address line 1 (required when EDI017 third-party indicator = 1)");
4095
+ if (blank(d.transmitter.address?.city)) missing.push("EDI055 transmitter city/town (required when EDI017 third-party indicator = 1)");
4096
+ if (blank(d.transmitter.address?.province)) missing.push("EDI057 transmitter province/state (required when EDI017 third-party indicator = 1)");
4097
+ if (blank(d.transmitter.address?.postalCode)) missing.push("EDI059 transmitter postal/zip code (required when EDI017 third-party indicator = 1)");
4098
+ if (blank(d.transmitter.address?.country)) missing.push("EDI061 transmitter country (required when EDI017 third-party indicator = 1)");
4099
+ }
1652
4100
  if (missing.length > 0) throw new At1MandatoryFieldMissingError(missing);
1653
4101
  }
1654
4102
  /** Refuse to render when any critical mandatory field is absent. */
@@ -1984,6 +4432,11 @@ const AT1_EDI_LINE_ITEMS = [
1984
4432
  get: (t) => t.legalName,
1985
4433
  fmt: "text"
1986
4434
  },
4435
+ {
4436
+ id: "EDI023001",
4437
+ get: (t) => t.thirdPartyIndicator === "1" ? t.organizationType : void 0,
4438
+ fmt: "text"
4439
+ },
1987
4440
  {
1988
4441
  id: "EDI031001",
1989
4442
  get: (t) => t.contact.firstName,
@@ -2009,6 +4462,36 @@ const AT1_EDI_LINE_ITEMS = [
2009
4462
  get: (t) => t.contact.email,
2010
4463
  fmt: "text"
2011
4464
  },
4465
+ {
4466
+ id: "EDI051001",
4467
+ get: (t) => t.thirdPartyIndicator === "1" ? t.address?.street : void 0,
4468
+ fmt: "text"
4469
+ },
4470
+ {
4471
+ id: "EDI053001",
4472
+ get: (t) => t.address?.line2,
4473
+ fmt: "text"
4474
+ },
4475
+ {
4476
+ id: "EDI055001",
4477
+ get: (t) => t.thirdPartyIndicator === "1" ? t.address?.city : void 0,
4478
+ fmt: "text"
4479
+ },
4480
+ {
4481
+ id: "EDI057001",
4482
+ get: (t) => t.thirdPartyIndicator === "1" ? t.address?.province : void 0,
4483
+ fmt: "text"
4484
+ },
4485
+ {
4486
+ id: "EDI059001",
4487
+ get: (t) => t.thirdPartyIndicator === "1" ? t.address?.postalCode : void 0,
4488
+ fmt: "text"
4489
+ },
4490
+ {
4491
+ id: "EDI061001",
4492
+ get: (t) => t.thirdPartyIndicator === "1" ? t.address?.country : void 0,
4493
+ fmt: "text"
4494
+ },
2012
4495
  {
2013
4496
  id: "EDI071001",
2014
4497
  get: (t) => t.isAmended ? "1" : void 0,
@@ -3048,6 +5531,83 @@ function applyOverride(federal, o) {
3048
5531
  opt("applyHalfYearRule", federal.applyHalfYearRule);
3049
5532
  return merged;
3050
5533
  }
5534
+ /**
5535
+ * Adapts a straight-line {@link Class13Result}/{@link Class14Result} into the
5536
+ * SAME shape every declining-balance class uses, so `classes` stays one
5537
+ * homogeneous array and the filing layer (`schedule13Values`, which reads
5538
+ * only the shared `CcaClassResult` fields) needs no changes at all. Rate/
5539
+ * half-year/AIIP/immediate-expensing are inapplicable to a straight-line
5540
+ * class and reported as 0; neither mechanic produces recapture here.
5541
+ */
5542
+ function straightLineAsCcaClassResult(ccaClass, r) {
5543
+ return {
5544
+ ccaClass,
5545
+ rate: 0,
5546
+ uccBeforeCca: r.uccBeforeCca,
5547
+ immediateExpensingClaim: 0,
5548
+ halfYearAdjustment: 0,
5549
+ aiipEnhancement: 0,
5550
+ ccaBase: 0,
5551
+ maxCca: r.maxCca,
5552
+ ccaClaimed: r.ccaClaimed,
5553
+ closingUCC: r.closingUCC,
5554
+ recapture: 0,
5555
+ terminalLoss: 0
5556
+ };
5557
+ }
5558
+ /** Federal claims `federalClaim` (max if omitted); Alberta defaults to federal's ACTUAL claim, not federal's max. */
5559
+ function computeClass13Pair(input, issues) {
5560
+ const shared = {
5561
+ layers: input.layers,
5562
+ openingUCC: input.openingUCC
5563
+ };
5564
+ const applyHalfYearRule = input.applyHalfYearRule !== void 0 ? { applyHalfYearRule: input.applyHalfYearRule } : {};
5565
+ const federal = computeClass13({
5566
+ ...shared,
5567
+ ...applyHalfYearRule,
5568
+ ...input.federalClaim !== void 0 ? { claim: input.federalClaim } : {}
5569
+ });
5570
+ const albertaClaim = input.albertaClaim !== void 0 ? input.albertaClaim : federal.ccaClaimed;
5571
+ const alberta = computeClass13({
5572
+ ...shared,
5573
+ ...applyHalfYearRule,
5574
+ claim: albertaClaim
5575
+ });
5576
+ issues.push(...federal.issues, ...alberta.issues);
5577
+ return {
5578
+ ccaClass: "13",
5579
+ alberta: straightLineAsCcaClassResult("13", alberta),
5580
+ federal: straightLineAsCcaClassResult("13", federal),
5581
+ openingUccDiffers: false,
5582
+ claimDiffers: alberta.ccaClaimed !== federal.ccaClaimed,
5583
+ ccaDifference: alberta.ccaClaimed - federal.ccaClaimed
5584
+ };
5585
+ }
5586
+ function computeClass14Pair(input, issues) {
5587
+ const shared = {
5588
+ properties: input.properties,
5589
+ openingUCC: input.openingUCC,
5590
+ ...input.daysInTaxYear !== void 0 ? { daysInTaxYear: input.daysInTaxYear } : {}
5591
+ };
5592
+ const federal = computeClass14({
5593
+ ...shared,
5594
+ ...input.federalClaim !== void 0 ? { claim: input.federalClaim } : {}
5595
+ });
5596
+ const albertaClaim = input.albertaClaim !== void 0 ? input.albertaClaim : federal.ccaClaimed;
5597
+ const alberta = computeClass14({
5598
+ ...shared,
5599
+ claim: albertaClaim
5600
+ });
5601
+ issues.push(...federal.issues, ...alberta.issues);
5602
+ return {
5603
+ ccaClass: "14",
5604
+ alberta: straightLineAsCcaClassResult("14", alberta),
5605
+ federal: straightLineAsCcaClassResult("14", federal),
5606
+ openingUccDiffers: false,
5607
+ claimDiffers: alberta.ccaClaimed !== federal.ccaClaimed,
5608
+ ccaDifference: alberta.ccaClaimed - federal.ccaClaimed
5609
+ };
5610
+ }
3051
5611
  function computeAlbertaSchedule13(input) {
3052
5612
  const rates = input.rates ?? CCA_DECLINING_BALANCE_RATES_2024;
3053
5613
  const issues = [];
@@ -3068,6 +5628,8 @@ function computeAlbertaSchedule13(input) {
3068
5628
  ccaDifference: alberta.ccaClaimed - federal.ccaClaimed
3069
5629
  };
3070
5630
  });
5631
+ if (input.class13) classes.push(computeClass13Pair(input.class13, issues));
5632
+ if (input.class14) classes.push(computeClass14Pair(input.class14, issues));
3071
5633
  const sum = (pickFn) => classes.reduce((s, c) => s + pickFn(c), 0);
3072
5634
  const albertaTotalCca = sum((c) => c.alberta.ccaClaimed);
3073
5635
  const federalTotalCca = sum((c) => c.federal.ccaClaimed);
@@ -3662,19 +6224,58 @@ function computeDonationMaximum(input) {
3662
6224
  };
3663
6225
  }
3664
6226
  //#endregion
6227
+ //#region src/t2/at1/schedules/schedule21-limited-partnership.ts
6228
+ function computeLimitedPartnershipLossRow(row) {
6229
+ const issues = [];
6230
+ const precedingYearBalance = Math.max(0, row.precedingYearBalance);
6231
+ const transferredOnWindUp = Math.max(0, row.transferredOnWindUp ?? 0);
6232
+ const currentYearLoss = Math.max(0, row.currentYearLoss ?? 0);
6233
+ const maxApplied = precedingYearBalance + transferredOnWindUp;
6234
+ const requestedApplied = Math.max(0, row.applied ?? 0);
6235
+ 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}.`);
6236
+ const applied = Math.min(requestedApplied, maxApplied);
6237
+ const closingBalance = precedingYearBalance + transferredOnWindUp + currentYearLoss - applied;
6238
+ return {
6239
+ ...row.identifier !== void 0 ? { identifier: row.identifier } : {},
6240
+ precedingYearBalance,
6241
+ transferredOnWindUp,
6242
+ currentYearLoss,
6243
+ applied,
6244
+ closingBalance,
6245
+ issues
6246
+ };
6247
+ }
6248
+ function computeLimitedPartnershipLosses(rows) {
6249
+ const computedRows = rows.map(computeLimitedPartnershipLossRow);
6250
+ return {
6251
+ rows: computedRows,
6252
+ totalApplied: computedRows.reduce((s, r) => s + r.applied, 0),
6253
+ totalClosingBalance: computedRows.reduce((s, r) => s + r.closingBalance, 0),
6254
+ issues: computedRows.flatMap((r) => r.issues)
6255
+ };
6256
+ }
6257
+ //#endregion
3665
6258
  //#region src/t2/schedules/loss-continuity.ts
3666
6259
  function computeLossContinuity(input) {
3667
6260
  const currentYearLoss = input.currentYearLoss ?? 0;
3668
6261
  const carriedBack = input.carriedBack ?? 0;
3669
6262
  const appliedCurrentYear = input.appliedCurrentYear ?? 0;
3670
6263
  const expired = input.expired ?? 0;
3671
- const closingBalance = Math.max(0, input.openingBalance + currentYearLoss - carriedBack - appliedCurrentYear - expired);
6264
+ const windUpTransfer = input.windUpTransfer ?? 0;
6265
+ const section80Adjustment = input.section80Adjustment ?? 0;
6266
+ const otherAdjustments = input.otherAdjustments ?? 0;
6267
+ const balanceAtBeginningOfYear = input.openingBalance - expired;
6268
+ const closingBalance = Math.max(0, balanceAtBeginningOfYear + windUpTransfer + currentYearLoss - appliedCurrentYear - section80Adjustment - otherAdjustments - carriedBack);
3672
6269
  return {
3673
6270
  openingBalance: input.openingBalance,
3674
6271
  currentYearLoss,
3675
6272
  carriedBack,
3676
6273
  appliedCurrentYear,
3677
6274
  expired,
6275
+ windUpTransfer,
6276
+ section80Adjustment,
6277
+ otherAdjustments,
6278
+ balanceAtBeginningOfYear,
3678
6279
  closingBalance
3679
6280
  };
3680
6281
  }
@@ -3706,6 +6307,76 @@ function computeLossSchedule(input) {
3706
6307
  };
3707
6308
  }
3708
6309
  //#endregion
6310
+ //#region src/t2/at1/schedules/schedule21-year-of-origin.ts
6311
+ function sumRows(rows) {
6312
+ const sum = (f) => rows.reduce((s, r) => s + f(r), 0);
6313
+ return {
6314
+ balanceAtBeginning: sum((r) => r.balanceAtBeginning),
6315
+ lossIncurred: sum((r) => r.lossIncurred),
6316
+ adjustments: sum((r) => r.adjustments),
6317
+ carriedBack: sum((r) => r.carriedBack),
6318
+ applied: sum((r) => r.applied),
6319
+ balanceAtEnd: sum((r) => r.balanceAtEnd)
6320
+ };
6321
+ }
6322
+ function computeNonCapitalLossByYearOfOrigin(input) {
6323
+ const issues = [];
6324
+ const lossIncurred = Math.max(0, input.currentYearLoss);
6325
+ const carriedBack = Math.max(0, input.currentYearCarriedBack);
6326
+ const rows = [{
6327
+ yearIndex: 0,
6328
+ balanceAtBeginning: 0,
6329
+ lossIncurred,
6330
+ adjustments: 0,
6331
+ carriedBack,
6332
+ applied: 0,
6333
+ balanceAtEnd: Math.max(0, lossIncurred - carriedBack)
6334
+ }, ...(input.priorVintages ?? []).map((v) => {
6335
+ 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.`);
6336
+ const balanceAtBeginning = Math.max(0, v.balanceAtBeginning ?? 0);
6337
+ const adjustments = v.adjustments ?? 0;
6338
+ const applied = Math.max(0, v.applied ?? 0);
6339
+ return {
6340
+ yearIndex: v.yearsAgo,
6341
+ ...v.taxYearEnd !== void 0 ? { taxYearEnd: v.taxYearEnd } : {},
6342
+ balanceAtBeginning,
6343
+ lossIncurred: 0,
6344
+ adjustments,
6345
+ carriedBack: 0,
6346
+ applied,
6347
+ balanceAtEnd: Math.max(0, balanceAtBeginning + adjustments - applied)
6348
+ };
6349
+ })];
6350
+ return {
6351
+ rows,
6352
+ totals: sumRows(rows),
6353
+ issues
6354
+ };
6355
+ }
6356
+ function computeOtherLossByYearOfOrigin(rows) {
6357
+ const issues = [];
6358
+ const computed = rows.map((r) => {
6359
+ 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.`);
6360
+ const listedPersonalPropertyLosses = Math.max(0, r.listedPersonalPropertyLosses ?? 0);
6361
+ 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.`);
6362
+ return {
6363
+ yearIndex: r.yearIndex,
6364
+ farmLosses: Math.max(0, r.farmLosses ?? 0),
6365
+ restrictedFarmLosses: Math.max(0, r.restrictedFarmLosses ?? 0),
6366
+ listedPersonalPropertyLosses: r.yearIndex > 7 ? 0 : listedPersonalPropertyLosses
6367
+ };
6368
+ });
6369
+ return {
6370
+ rows: computed,
6371
+ totals: {
6372
+ farmLosses: computed.reduce((s, r) => s + r.farmLosses, 0),
6373
+ restrictedFarmLosses: computed.reduce((s, r) => s + r.restrictedFarmLosses, 0),
6374
+ listedPersonalPropertyLosses: computed.reduce((s, r) => s + r.listedPersonalPropertyLosses, 0)
6375
+ },
6376
+ issues
6377
+ };
6378
+ }
6379
+ //#endregion
3709
6380
  //#region src/t2/certification/fixtures.ts
3710
6381
  const T2_CERTIFICATION_FIXTURES = [
3711
6382
  {
@@ -5389,15 +8060,18 @@ function computeFederalT2(input) {
5389
8060
  const rates = input.rates ?? resolveCorpTaxRates(taxYear, book);
5390
8061
  const prorationFactor = shortYearProrationFactor(input.periodStart, input.periodEnd);
5391
8062
  const cca = input.ccaClasses?.length ? computeCcaSchedule(input.ccaClasses, resolveCcaRates(taxYear), prorationFactor) : void 0;
8063
+ const class13 = input.class13 ? computeClass13(input.class13) : void 0;
8064
+ const class14 = input.class14 ? computeClass14(input.class14) : void 0;
5392
8065
  const capitalGains = input.capitalDispositions?.length ? computeSchedule6(input.capitalDispositions, rates.CAPITAL_GAINS_INCLUSION_RATE) : void 0;
5393
8066
  const schedule1Additions = [...input.schedule1Additions ?? []];
5394
8067
  const schedule1Deductions = [...input.schedule1Deductions ?? []];
8068
+ const totalCcaDeduction = (cca?.totalCca ?? 0) + (class13?.ccaClaimed ?? 0) + (class14?.ccaClaimed ?? 0);
8069
+ if (totalCcaDeduction > 0) schedule1Deductions.push({
8070
+ line: "403",
8071
+ label: "Capital cost allowance from Schedule 8",
8072
+ amount: totalCcaDeduction
8073
+ });
5395
8074
  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
8075
  if (cca.totalTerminalLoss > 0) schedule1Deductions.push({
5402
8076
  line: "404",
5403
8077
  label: "Terminal loss from Schedule 8",
@@ -5597,6 +8271,8 @@ function computeFederalT2(input) {
5597
8271
  ...donations ? { donations } : {},
5598
8272
  ...lossCarryback ? { lossCarryback } : {},
5599
8273
  ...cca ? { cca } : {},
8274
+ ...class13 ? { class13 } : {},
8275
+ ...class14 ? { class14 } : {},
5600
8276
  ...capitalGains ? { capitalGains } : {},
5601
8277
  ...provincial ? { provincial } : {},
5602
8278
  ...provincialAllocation ? { provincialAllocation } : {},
@@ -6727,4 +9403,4 @@ function computeMpDeduction(input, rates = MP_RATES_2024) {
6727
9403
  };
6728
9404
  }
6729
9405
  //#endregion
6730
- export { computeProvincialAllocation as $, at1TaxPayableDeductions as $n, CEC_DEDUCTION_RATE as $t, runConformance as A, reconcileAlbertaNetIncome as An, schedule29Values as Ar, computeCcpcActiveBusinessTax as At, computeGrip as B, formatRsiText as Bn, earliestRateYear as Br, AT1_DONATION_GAIN_RATE as Bt, computeQuebecTax as C, albertaCcaScheduleAdjustments as Cn, schedule13Values as Cr, blendProvinceRateTable as Ct, T2_LINE_META as D, albertaReserveDifference as Dn, schedule1Values as Dr, dividendsDeductibleS112 as Dt, resolveQuebecTaxRates as E, albertaRecaptureDifference as En, schedule18Values as Er, computeTaxableIncome as Et, normalizeSchedule88 as F, RSI_NEGATIVE_PREFIX as Fn, AB_GENERAL_RATE_BANDS as Fr, CORP_TAX_RATE_BOOK as Ft, ITC_RECAPTURE_PERIOD_YEARS as G, AT1_CRITICAL_MANDATORY_FIELDS as Gn, SECTION_34_2_GROSS_UP as Gt, LARGE_CORPORATION_THRESHOLD as H, renderRsiHeader as Hn, hasExactRateYear as Hr, computeDonationMaximum as Ht, computeSchedule55 as I, RSI_WORD_GAP as In, computeDayWeightedGeneralTax as Ir, resolveCorpTaxRates as It, allocateEvenly as J, At1TaxPayableMismatchError as Jn, AT1_RESERVE_LINES as Jt, computeItcRecapture as K, At1CriticalFieldMissingError as Kn, computeAlbertaSchedule18 as Kt, LRIP_INVESTMENT_CORPORATION_MULTIPLE as L, RsiLineItemError as Ln, AB_TAX_2024 as Lr, T2_CERTIFICATION_FIXTURES as Lt, computeFederalT2 as M, computeLossCarryback as Mn, schedule4970Values as Mr, computeBusinessLimit as Mt, computeSchedule101 as N, RSI_COLUMN_GAP as Nn, computeAlbertaTax as Nr, computeSBD as Nt, foldT2Lines as O, albertaTerminalLossDifference as On, schedule20Values as Or, netCapitalLossApplied as Ot, SCHEDULE_88_MAX_URLS as P, RSI_DELIMITER as Pn, computeAlbertaSbd as Pr, CORP_TAX_2024 as Pt, computeSchedule6 as Q, assertCriticalFields as Qn, computeAlbertaSchedule16 as Qt, LRIP_INVESTMENT_INCOME_FACTOR as R, formatRsiAmount as Rn, AB_TAX_RATE_BOOK as Rr, computeLossSchedule as Rt, computeQuebecAllocationFactor as S, albertaCcaDifference as Sn, schedule12Values as Sr, resolveProvinceRates as St, QC_TAX_RATE_BOOK as T, albertaDispositionAdjustments as Tn, schedule17Values as Tr, charitableDonationsDeduction as Tt, computeTaxableCapital as U, renderRsiLineItem as Un, latestRateYear as Ur, computeSchedule20 as Ut, computeSchedule43 as V, renderAt1Rsi as Vn, extendRateBook as Vr, AT1_DONATION_INCOME_RATE as Vt, computeSchedule31 as W, renderAt1NetFile as Wn, resolveRates as Wr, AT1_DISPOSITION_CATEGORIES as Wt, computeSchedule21 as X, assertAt1MandatoryComplete as Xn, computeAlbertaSchedule17 as Xt, computeBusinessLimitAllocation as Y, albertaBalanceUnpaid as Yn, AT1_RESERVE_TOTAL_LINES as Yt, computeSchedule13 as Z, assertAt1TaxPayableReconciles as Zn, assistanceFrom as Zt, renderT2DraftReturn as _, CCA_RATE_BOOK as _n, AT1_SCHEDULES_WITHOUT_BUILDERS as _r, EIFEL_EFFECTIVE_FROM as _t, PART_VI_1_DEDUCTION_BANDS as a, computeCcaClass as an, allocateIegExpenditureLimit as ar, computeSchedule2 as at, co17Engine as b, albertaAbilDifference as bn, schedule10Values as br, PROVINCE_RATE_BOOK as bt, EIFEL_FIRST_YEAR_START as c, CLASS_14_1_MINIMUM_DEDUCTION as cn, IEG_2024 as cr, assertSchedule1Fileable as ct, EIFEL_TRANSITIONAL_RATIO as d, MIN_LEASEHOLD_PERIODS as dn, computeIegReductionFactor as dr, deferredIncomeTaxProvisionAddBack as dt, CEC_INCLUSION_RATE as en, at1YesNo as er, computeSchedule5 as et, computeEifelLimitation as f, computeClass13 as fn, computeIegEligibleExpenditures as fr, findSchedule1LineDefects as ft, computeT2Settlement as g, CCA_DECLINING_BALANCE_RATES_2024 as gn, computeAt4970 as gr, terminalLossDeduction as gt, computeAdjustedTaxableIncome as h, leaseholdPeriods as hn, computeAllocationFactor as hr, recaptureAddBack as ht, computeMpDeduction as i, UnsupportedCcaClassError as in, allocateIegEvenly as ir, computePart4Rdtoh as it, runConformanceSuite as j, LossCarrybackError as jn, schedule2Values as jr, computePartITax as jt, formatConformanceReport as k, computeSchedule12 as kn, schedule21Values as kr, nonCapitalLossApplied as kt, EIFEL_STANDARD_RATIO as l, CLASS_14_1_TRANSITIONAL_RATE as ln, computeIeg as lr, ccaDeduction as lt, FOREIGN_TAX_CREDIT_GROSS_UP as m, computeClass141AdditionalAllowance as mn, SINGLE_JURISDICTION_ALBERTA_FACTOR as mr, mealsAndEntertainmentAddBack as mt, MP_GROSS_REVENUE_THRESHOLD as n, computeAlbertaSchedule14 as nn, at1Engine as nr, PART_IV_RATE as nt, computePartVI1Deduction as o, computeCcaSchedule as on, computeIegAgreement as or, Schedule1NotFileableError as ot, ratioOfPermissibleExpenses as p, computeClass14 as pn, iegT661SourceLine as pr, incomeTaxProvisionAddBack as pt, computeZetm as q, At1MandatoryFieldMissingError as qn, AT1_RESERVE_KINDS as qt, MP_RATES_2024 as r, computeAlbertaSchedule13 as rn, computeAlbertaReturn as rr, REFUNDABLE_PART_I_RATE as rt, partVI1DeductionMultiple as s, computeSchedule8 as sn, computeIegGroupFigures as sr, amortizationAddBack as st, MP_EXCLUDED_ACTIVITIES as t, cecScheduleAppliesToTaxYear as tn, xmlEscape as tr, computeSchedule4Losses as tt, EIFEL_STANDARD_RATIO_FROM as u, MAX_LEASEHOLD_PERIODS as un, computeIegBaseAmount as ur, computeSchedule1 as ut, t2Engine as v, isDecliningBalanceClass as vn, AT1_SCHEDULES_WITH_BUILDERS as vr, assessEifel as vt, QC_TAX_2024 as w, albertaCurrentYearLoss as wn, schedule16Values as wr, dayWeightedRate as wt, computeQuebecReturn as x, albertaCapitalGainDifference as xn, schedule12LossDeductions as xr, isSchedule5Province as xt, renderCo17DraftReturn as y, resolveCcaRates as yn, at1LineItemId as yr, PROVINCE_RATES_2024 as yt, computeSchedule54 as z, formatRsiDate as zn, resolveAlbertaTaxRates as zr, computeLossContinuity as zt };
9406
+ 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 };