@mudraforge/statutory 2.8.0 → 2.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +47 -0
- package/README.md +8 -7
- package/SECURITY.md +2 -2
- package/calculators.d.ts +1 -0
- package/calculators.js +1 -0
- package/docs/CATALOG.md +258 -63
- package/docs/CORPUS_QUALITY.md +12 -7
- package/docs/PROVENANCE.md +1 -1
- package/okf/corporate_ma_restructuring/loss_carryforward_sec79/circulars/cbdt_circular_09_2020_startup_loss_continuity.md +37 -0
- package/okf/corporate_ma_restructuring/loss_carryforward_sec79/forms/section_79_shareholding_continuity_schedule.json +51 -0
- package/okf/corporate_ma_restructuring/loss_carryforward_sec79/section.json +66 -0
- package/okf/corporate_ma_restructuring/slump_sale_50b/circulars/cbdt_notification_68_2021_rule_11uae_fmv.md +1 -1
- package/okf/corporate_ma_restructuring/slump_sale_50b/circulars/cbic_notification_12_2017_going_concern_exemption.md +1 -1
- package/okf/corporate_ma_restructuring/slump_sale_50b/section.json +2 -2
- package/okf/direct_tax/corporate_tax_115baa_115jb/circulars/cbdt_circular_29_2019_concessional_tax_regime.md +35 -0
- package/okf/direct_tax/corporate_tax_115baa_115jb/forms/form_10ic_concessional_tax_election.json +31 -0
- package/okf/direct_tax/corporate_tax_115baa_115jb/section.json +72 -0
- package/okf/direct_tax/special_rates_non_filer_206ab/circulars/cbdt_circular_11_2021_compliance_check.md +1 -1
- package/okf/direct_tax/special_rates_non_filer_206ab/section.json +8 -7
- package/okf/direct_tax/tcs_goods_206c_1h/circulars/finance_act_2025_sunset_memo.md +1 -1
- package/okf/direct_tax/tcs_goods_206c_1h/section.json +3 -3
- package/okf/direct_tax/tds_commission_194h/circulars/finance_act_2024_rate_cut_memo.md +1 -1
- package/okf/direct_tax/tds_commission_194h/section.json +6 -6
- package/okf/direct_tax/tds_contractor_194c/circulars/cbdt_circular_23_2017_gst_unbundling.md +1 -1
- package/okf/direct_tax/tds_contractor_194c/section.json +6 -6
- package/okf/direct_tax/tds_goods_194q/circulars/cbdt_circular_13_2021_guidelines.md +1 -1
- package/okf/direct_tax/tds_goods_194q/circulars/cbdt_circular_23_2017_gst_unbundling.md +1 -1
- package/okf/direct_tax/tds_goods_194q/section.json +3 -3
- package/okf/direct_tax/tds_goods_393/section.json +3 -3
- package/okf/direct_tax/tds_perquisites_194r/circulars/cbdt_circular_12_2022_perquisites.md +1 -1
- package/okf/direct_tax/tds_perquisites_194r/section.json +4 -4
- package/okf/direct_tax/tds_rent_194i/circulars/cbdt_circular_23_2017_gst_unbundling.md +1 -1
- package/okf/direct_tax/tds_rent_194i/section.json +6 -6
- package/okf/direct_tax/tds_services_194j/circulars/cbdt_circular_03_2020_fts_rate_cut.md +1 -1
- package/okf/direct_tax/tds_services_194j/section.json +3 -3
- package/okf/indirect_tax_gst/blocked_itc_17_5/circulars/cbic_circular_172_2022_employer_obligations.md +1 -1
- package/okf/indirect_tax_gst/blocked_itc_17_5/section.json +4 -4
- package/okf/indirect_tax_gst/composite_mixed_supplies_sec8/circulars/cbic_circular_47_2018_composite_mixed_supplies.md +1 -1
- package/okf/indirect_tax_gst/composite_mixed_supplies_sec8/section.json +3 -3
- package/okf/indirect_tax_gst/composition_levy_sec10/circulars/cbic_notification_14_2019_composition.md +1 -1
- package/okf/indirect_tax_gst/composition_levy_sec10/section.json +2 -2
- package/okf/indirect_tax_gst/credit_debit_notes_sec34/circulars/cbic_circular_137_2020_credit_notes.md +1 -1
- package/okf/indirect_tax_gst/credit_debit_notes_sec34/section.json +2 -2
- package/okf/indirect_tax_gst/e_invoicing_rule48_4/circulars/cbic_notification_10_2023_einvoicing.md +1 -1
- package/okf/indirect_tax_gst/e_invoicing_rule48_4/section.json +2 -2
- package/okf/indirect_tax_gst/export_services_lut_sec16/circulars/cbic_circular_161_2021_intermediary_clarification.md +37 -0
- package/okf/indirect_tax_gst/export_services_lut_sec16/forms/lut_form_gst_rfnd_11_declaration.json +58 -0
- package/okf/indirect_tax_gst/export_services_lut_sec16/section.json +66 -0
- package/okf/indirect_tax_gst/gst_tds_sec51/circulars/cbic_notification_50_2018_gst_tds.md +1 -1
- package/okf/indirect_tax_gst/gst_tds_sec51/section.json +6 -6
- package/okf/indirect_tax_gst/itc_eligibility_16_2/circulars/cbic_circular_170_2022_itc_reporting.md +1 -1
- package/okf/indirect_tax_gst/itc_eligibility_16_2/section.json +4 -4
- package/okf/indirect_tax_gst/rcm_liability_sec9_3/circulars/cbic_circular_102_2019_rcm_clarifications.md +1 -1
- package/okf/indirect_tax_gst/rcm_liability_sec9_3/section.json +3 -3
- package/okf/international_tax/cross_border_remittance_195/circulars/cbdt_circular_03_2022_form10f_electronic.md +1 -1
- package/okf/international_tax/cross_border_remittance_195/circulars/supreme_court_engineering_analysis_doctrine.md +1 -1
- package/okf/international_tax/cross_border_remittance_195/section.json +3 -3
- package/okf/international_tax/foreign_exchange_indas_21_109/circulars/mca_indas_21_foreign_exchange_rates.md +39 -0
- package/okf/international_tax/foreign_exchange_indas_21_109/forms/indas_109_cash_flow_hedge_reserve_schedule.json +45 -0
- package/okf/international_tax/foreign_exchange_indas_21_109/section.json +63 -0
- package/okf/international_tax/transfer_pricing_alp_92c/circulars/cbdt_notification_86_2015_range_concept_rule_10ca.md +54 -0
- package/okf/international_tax/transfer_pricing_alp_92c/forms/form_3ceb_transfer_pricing_report.json +67 -0
- package/okf/international_tax/transfer_pricing_alp_92c/section.json +72 -0
- package/okf/manifest.json +81 -56
- package/okf/msme_commercial/delayed_payments_15_16/circulars/msme_om_2021_trader_exclusion.md +1 -1
- package/okf/msme_commercial/delayed_payments_15_16/forms/schedule_iii_msme_disclosure.md +1 -1
- package/okf/msme_commercial/delayed_payments_15_16/section.json +5 -5
- package/okf/msme_commercial/enterprise_classification_sec7/circulars/msme_notification_2119_e_composite_criteria.md +1 -1
- package/okf/msme_commercial/enterprise_classification_sec7/section.json +2 -2
- package/okf/msme_commercial/mca_msme_1_filing/circulars/mca_order_2019_specified_companies.md +1 -1
- package/okf/msme_commercial/mca_msme_1_filing/section.json +2 -2
- package/okf/msme_commercial/statutory_disclosures_sec22/circulars/icai_guidance_note_schedule_iii_trade_payables.md +1 -1
- package/okf/msme_commercial/statutory_disclosures_sec22/section.json +3 -3
- package/okf.publication.json +1 -1
- package/package.json +31 -1
- package/src/calculators.js +780 -0
- package/src/index.js +146 -35
- package/types/index.d.ts +14 -0
|
@@ -0,0 +1,780 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ═══════════════════════════════════════════════════════════════════════════
|
|
3
|
+
* @mudraforge/statutory — Deterministic Statutory Calculators
|
|
4
|
+
* ═══════════════════════════════════════════════════════════════════════════
|
|
5
|
+
* Pure, zero-dependency, mathematically deterministic calculation engines
|
|
6
|
+
* for Corporate Finance, Direct Tax, Indirect Tax (GST), International Tax,
|
|
7
|
+
* and Restructuring.
|
|
8
|
+
*
|
|
9
|
+
* Invariant Envelopes:
|
|
10
|
+
* 1. Zero dependencies. Native ES Modules.
|
|
11
|
+
* 2. Integer/paisa-level rounding preventing floating-point precision drift.
|
|
12
|
+
* 3. Enforces isAuthorizedToDisburse: false across all calculations (statutory
|
|
13
|
+
* computation never authorizes payment disbursement autonomously).
|
|
14
|
+
* 4. Grounded in primary statutory citations, gazette notifications, and judicial rulings.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Rounds a financial number to exactly 2 decimal places (paisa).
|
|
19
|
+
* Safeguards against -0, NaN, and non-finite inputs.
|
|
20
|
+
*
|
|
21
|
+
* @param {number|string} amount
|
|
22
|
+
* @returns {number}
|
|
23
|
+
*/
|
|
24
|
+
export function roundToPaisa(amount) {
|
|
25
|
+
const n = Number(amount);
|
|
26
|
+
if (!Number.isFinite(n) || isNaN(n) || Object.is(n, -0)) return 0;
|
|
27
|
+
return Math.round(n * 100) / 100;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Section 288B Rounding (Rounding off of tax):
|
|
32
|
+
* The amount of tax under the Income-tax Act is rounded off to the nearest rupee,
|
|
33
|
+
* and if the fraction is 50 paise or more, it is rounded up; otherwise ignored.
|
|
34
|
+
*
|
|
35
|
+
* @param {number|string} amount
|
|
36
|
+
* @returns {number}
|
|
37
|
+
*/
|
|
38
|
+
export function roundSection288B(amount) {
|
|
39
|
+
const n = Number(amount);
|
|
40
|
+
if (!Number.isFinite(n) || isNaN(n) || Object.is(n, -0)) return 0;
|
|
41
|
+
return Math.round(n);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* ─────────────────────────────────────────────────────────────────────────────
|
|
46
|
+
* 1. CORPORATE TAX: MAT (SECTION 115JB) VS CONCESSIONAL REGIME (SECTION 115BAA)
|
|
47
|
+
* ─────────────────────────────────────────────────────────────────────────────
|
|
48
|
+
* Evaluates:
|
|
49
|
+
* 1. Normal Corporate Tax: 25% (turnover <= 400 Cr) or 30%, plus 7%/12% surcharge, plus 4% cess.
|
|
50
|
+
* 2. Minimum Alternate Tax (MAT u/s 115JB): 15% on Adjusted Book Profit, plus 7%/12% surcharge, plus 4% cess.
|
|
51
|
+
* 3. Section 115JAA MAT Credit: Set-off against normal tax or newly generated.
|
|
52
|
+
* 4. Section 115BAA Concessional Regime: Flat 22% + 10% surcharge + 4% cess = 25.168% effective.
|
|
53
|
+
* Exempt from Section 115JB MAT u/s 115JB(5A). Forfeits accumulated MAT credit.
|
|
54
|
+
*/
|
|
55
|
+
export function calculateCorporateTaxMatVsConcessional({
|
|
56
|
+
financialYear = '2025-26',
|
|
57
|
+
assessmentYear = null,
|
|
58
|
+
turnoverPrecedingFyInr = 0,
|
|
59
|
+
netProfitBeforeTaxInr = 0,
|
|
60
|
+
normalTaxAdditionsInr = 0,
|
|
61
|
+
normalTaxDeductionsInr = 0,
|
|
62
|
+
accumulatedMatCreditInr = 0,
|
|
63
|
+
bookProfitAdjustments = null,
|
|
64
|
+
adjustedBookProfitInr = null,
|
|
65
|
+
optedSection115BAA = null
|
|
66
|
+
} = {}) {
|
|
67
|
+
const fy = financialYear || '2025-26';
|
|
68
|
+
const ay = assessmentYear || (fy === '2025-26' ? '2026-27' : '2027-28');
|
|
69
|
+
const turnover = Number(turnoverPrecedingFyInr) || 0;
|
|
70
|
+
const npbt = Number(netProfitBeforeTaxInr) || 0;
|
|
71
|
+
const additions = Number(normalTaxAdditionsInr) || 0;
|
|
72
|
+
const deductions = Number(normalTaxDeductionsInr) || 0;
|
|
73
|
+
const priorMatCredit = Number(accumulatedMatCreditInr) || 0;
|
|
74
|
+
|
|
75
|
+
// A. Normal Corporate Tax Regime
|
|
76
|
+
const taxableIncomeNormal = Math.max(0, roundToPaisa(npbt + additions - deductions));
|
|
77
|
+
const baseRateNormal = turnover <= 4000000000 ? 0.25 : 0.30;
|
|
78
|
+
const baseTaxNormal = roundToPaisa(taxableIncomeNormal * baseRateNormal);
|
|
79
|
+
|
|
80
|
+
let surchargeRateNormal = 0;
|
|
81
|
+
if (taxableIncomeNormal > 100000000) {
|
|
82
|
+
surchargeRateNormal = 0.12;
|
|
83
|
+
} else if (taxableIncomeNormal > 10000000) {
|
|
84
|
+
surchargeRateNormal = 0.07;
|
|
85
|
+
}
|
|
86
|
+
const surchargeNormal = roundToPaisa(baseTaxNormal * surchargeRateNormal);
|
|
87
|
+
const cessNormal = roundToPaisa((baseTaxNormal + surchargeNormal) * 0.04);
|
|
88
|
+
const grossNormalTax = roundToPaisa(baseTaxNormal + surchargeNormal + cessNormal);
|
|
89
|
+
|
|
90
|
+
// B. Minimum Alternate Tax (Section 115JB)
|
|
91
|
+
let adjBookProfit = 0;
|
|
92
|
+
if (adjustedBookProfitInr !== null && adjustedBookProfitInr !== undefined) {
|
|
93
|
+
adjBookProfit = Math.max(0, Number(adjustedBookProfitInr) || 0);
|
|
94
|
+
} else if (bookProfitAdjustments && typeof bookProfitAdjustments === 'object') {
|
|
95
|
+
const bpAdditions = (Number(bookProfitAdjustments.incomeTaxProvision) || 0) +
|
|
96
|
+
(Number(bookProfitAdjustments.reservesTransfer) || 0) +
|
|
97
|
+
(Number(bookProfitAdjustments.contingentLiabilities) || 0) +
|
|
98
|
+
(Number(bookProfitAdjustments.diminutionInAssetValue) || 0) +
|
|
99
|
+
(Number(bookProfitAdjustments.exemptIncomeExpenses) || 0);
|
|
100
|
+
const bfLoss = Number(bookProfitAdjustments.broughtForwardLoss) || 0;
|
|
101
|
+
const unabsDep = Number(bookProfitAdjustments.unabsorbedDepreciation) || 0;
|
|
102
|
+
const lossDepDeduction = (bfLoss > 0 && unabsDep > 0) ? Math.min(bfLoss, unabsDep) : Math.max(bfLoss, unabsDep);
|
|
103
|
+
const bpDeductions = lossDepDeduction + (Number(bookProfitAdjustments.exemptIncome) || 0);
|
|
104
|
+
adjBookProfit = Math.max(0, roundToPaisa(npbt + bpAdditions - bpDeductions));
|
|
105
|
+
} else {
|
|
106
|
+
adjBookProfit = npbt;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
const baseMatRate = 0.15;
|
|
110
|
+
const baseMatTax = roundToPaisa(adjBookProfit * baseMatRate);
|
|
111
|
+
let surchargeRateMat = 0;
|
|
112
|
+
if (adjBookProfit > 100000000) {
|
|
113
|
+
surchargeRateMat = 0.12;
|
|
114
|
+
} else if (adjBookProfit > 10000000) {
|
|
115
|
+
surchargeRateMat = 0.07;
|
|
116
|
+
}
|
|
117
|
+
const surchargeMat = roundToPaisa(baseMatTax * surchargeRateMat);
|
|
118
|
+
const cessMat = roundToPaisa((baseMatTax + surchargeMat) * 0.04);
|
|
119
|
+
const grossMatTax = roundToPaisa(baseMatTax + surchargeMat + cessMat);
|
|
120
|
+
|
|
121
|
+
// C. Old Regime Set-off & MAT Credit Determination (Section 115JAA)
|
|
122
|
+
let matCreditUtilized = 0;
|
|
123
|
+
let newMatCreditGenerated = 0;
|
|
124
|
+
let netNormalTaxPayable = grossNormalTax;
|
|
125
|
+
let taxPayableOldRegime = 0;
|
|
126
|
+
|
|
127
|
+
if (grossMatTax > grossNormalTax) {
|
|
128
|
+
taxPayableOldRegime = grossMatTax;
|
|
129
|
+
newMatCreditGenerated = roundToPaisa(grossMatTax - grossNormalTax);
|
|
130
|
+
} else {
|
|
131
|
+
const maxCreditAllowable = roundToPaisa(grossNormalTax - grossMatTax);
|
|
132
|
+
matCreditUtilized = Math.min(priorMatCredit, maxCreditAllowable);
|
|
133
|
+
netNormalTaxPayable = roundToPaisa(grossNormalTax - matCreditUtilized);
|
|
134
|
+
taxPayableOldRegime = netNormalTaxPayable;
|
|
135
|
+
}
|
|
136
|
+
const closingMatCreditOldRegime = roundToPaisa(priorMatCredit - matCreditUtilized + newMatCreditGenerated);
|
|
137
|
+
|
|
138
|
+
// D. Section 115BAA Concessional Regime
|
|
139
|
+
const taxableIncome115BAA = Math.max(0, roundToPaisa(npbt + additions));
|
|
140
|
+
const baseRate115BAA = 0.22;
|
|
141
|
+
const baseTax115BAA = roundToPaisa(taxableIncome115BAA * baseRate115BAA);
|
|
142
|
+
const surcharge115BAA = roundToPaisa(baseTax115BAA * 0.10); // Flat 10% surcharge u/s 115BAA(1) proviso
|
|
143
|
+
const cess115BAA = roundToPaisa((baseTax115BAA + surcharge115BAA) * 0.04);
|
|
144
|
+
const totalTax115BAA = roundToPaisa(baseTax115BAA + surcharge115BAA + cess115BAA);
|
|
145
|
+
|
|
146
|
+
// Under Section 115JB(5A), MAT does not apply to 115BAA companies
|
|
147
|
+
// Under Section 115JAA, accumulated MAT credit cannot be utilized and is forfeited
|
|
148
|
+
const forfeitedMatCredit115BAA = priorMatCredit;
|
|
149
|
+
|
|
150
|
+
// E. Strategic Comparative Recommendation
|
|
151
|
+
let recommendedRegime = 'SECTION_115BAA';
|
|
152
|
+
let recommendationRationale = '';
|
|
153
|
+
let netCashSavingsInr = 0;
|
|
154
|
+
|
|
155
|
+
if (optedSection115BAA === true) {
|
|
156
|
+
recommendedRegime = 'SECTION_115BAA';
|
|
157
|
+
netCashSavingsInr = roundToPaisa(taxPayableOldRegime - totalTax115BAA);
|
|
158
|
+
recommendationRationale = `Assessee has explicitly opted for Section 115BAA (25.168% effective rate). Section 115JB MAT is inapplicable u/s 115JB(5A). Accumulated MAT credit of INR ${forfeitedMatCredit115BAA.toLocaleString('en-IN')} is forfeited.`;
|
|
159
|
+
} else if (optedSection115BAA === false) {
|
|
160
|
+
recommendedRegime = 'OLD_REGIME';
|
|
161
|
+
netCashSavingsInr = roundToPaisa(totalTax115BAA - taxPayableOldRegime);
|
|
162
|
+
recommendationRationale = `Assessee remains under Old Regime. Applicable tax is INR ${taxPayableOldRegime.toLocaleString('en-IN')} (Normal Tax: INR ${grossNormalTax.toLocaleString('en-IN')}, MAT: INR ${grossMatTax.toLocaleString('en-IN')}). Closing MAT credit balance: INR ${closingMatCreditOldRegime.toLocaleString('en-IN')}.`;
|
|
163
|
+
} else {
|
|
164
|
+
if (taxPayableOldRegime < totalTax115BAA) {
|
|
165
|
+
recommendedRegime = 'OLD_REGIME';
|
|
166
|
+
netCashSavingsInr = roundToPaisa(totalTax115BAA - taxPayableOldRegime);
|
|
167
|
+
recommendationRationale = `Old Regime is optimal for FY ${fy}: Net cash outflow is INR ${taxPayableOldRegime.toLocaleString('en-IN')} vs INR ${totalTax115BAA.toLocaleString('en-IN')} under Section 115BAA (Net saving: INR ${netCashSavingsInr.toLocaleString('en-IN')}). Utilizing MAT credit or Chapter VI-A deductions yields lower current cash drain.`;
|
|
168
|
+
} else {
|
|
169
|
+
recommendedRegime = 'SECTION_115BAA';
|
|
170
|
+
netCashSavingsInr = roundToPaisa(taxPayableOldRegime - totalTax115BAA);
|
|
171
|
+
recommendationRationale = `Section 115BAA is optimal for FY ${fy}: Net tax payable is INR ${totalTax115BAA.toLocaleString('en-IN')} vs INR ${taxPayableOldRegime.toLocaleString('en-IN')} under Old Regime (Net saving: INR ${netCashSavingsInr.toLocaleString('en-IN')}). Form 10-IC must be filed before the due date u/s 139(1). Note: INR ${forfeitedMatCredit115BAA.toLocaleString('en-IN')} in accumulated MAT credit will lapse.`;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
return {
|
|
176
|
+
status: 'SUCCESS',
|
|
177
|
+
statutoryDetermination: 'APPLICABLE',
|
|
178
|
+
governingLaw: 'Income-tax Act, 1961 Sections 115BAA, 115JB & 115JAA',
|
|
179
|
+
financialYear: fy,
|
|
180
|
+
assessmentYear: ay,
|
|
181
|
+
taxableIncomeNormalInr: taxableIncomeNormal,
|
|
182
|
+
adjustedBookProfitInr: adjBookProfit,
|
|
183
|
+
normalTaxRegime: {
|
|
184
|
+
turnoverPrecedingFyInr: turnover,
|
|
185
|
+
baseTaxRate: baseRateNormal,
|
|
186
|
+
baseTaxInr: baseTaxNormal,
|
|
187
|
+
surchargeRate: surchargeRateNormal,
|
|
188
|
+
surchargeInr: surchargeNormal,
|
|
189
|
+
cessInr: cessNormal,
|
|
190
|
+
grossNormalTaxInr: grossNormalTax,
|
|
191
|
+
effectiveRate: taxableIncomeNormal > 0 ? roundToPaisa((grossNormalTax / taxableIncomeNormal) * 100) : 0
|
|
192
|
+
},
|
|
193
|
+
minimumAlternateTaxSec115JB: {
|
|
194
|
+
baseMatRate: baseMatRate,
|
|
195
|
+
baseMatTaxInr: baseMatTax,
|
|
196
|
+
surchargeRate: surchargeRateMat,
|
|
197
|
+
surchargeInr: surchargeMat,
|
|
198
|
+
cessInr: cessMat,
|
|
199
|
+
grossMatTaxInr: grossMatTax,
|
|
200
|
+
effectiveMatRate: adjBookProfit > 0 ? roundToPaisa((grossMatTax / adjBookProfit) * 100) : 0
|
|
201
|
+
},
|
|
202
|
+
matCreditScheduleSec115JAA: {
|
|
203
|
+
openingMatCreditInr: priorMatCredit,
|
|
204
|
+
matCreditUtilizedInr: matCreditUtilized,
|
|
205
|
+
newMatCreditGeneratedInr: newMatCreditGenerated,
|
|
206
|
+
closingMatCreditInr: closingMatCreditOldRegime,
|
|
207
|
+
expiryYears: '15 Assessment Years'
|
|
208
|
+
},
|
|
209
|
+
concessionalRegimeSec115BAA: {
|
|
210
|
+
taxableIncomeInr: taxableIncome115BAA,
|
|
211
|
+
baseTaxRate: 0.22,
|
|
212
|
+
baseTaxInr: baseTax115BAA,
|
|
213
|
+
surchargeRate: 0.10,
|
|
214
|
+
surchargeInr: surcharge115BAA,
|
|
215
|
+
cessInr: cess115BAA,
|
|
216
|
+
totalTaxInr: totalTax115BAA,
|
|
217
|
+
effectiveRate: 25.168,
|
|
218
|
+
matApplicable: false,
|
|
219
|
+
matExemptionClause: 'Section 115JB(5A)',
|
|
220
|
+
forfeitedMatCreditInr: forfeitedMatCredit115BAA
|
|
221
|
+
},
|
|
222
|
+
comparisonSummary: {
|
|
223
|
+
cashOutflowOldRegimeInr: taxPayableOldRegime,
|
|
224
|
+
cashOutflowSection115BAAInr: totalTax115BAA,
|
|
225
|
+
recommendedRegime,
|
|
226
|
+
netCashSavingsInr,
|
|
227
|
+
form10IcRequired: recommendedRegime === 'SECTION_115BAA'
|
|
228
|
+
},
|
|
229
|
+
isAuthorizedToDisburse: false,
|
|
230
|
+
statutoryRationale: recommendationRationale,
|
|
231
|
+
citations: [
|
|
232
|
+
'Income-tax Act, 1961 Section 115BAA (Tax on income of certain domestic companies)',
|
|
233
|
+
'Income-tax Act, 1961 Section 115JB (Special provision for payment of tax by certain companies)',
|
|
234
|
+
'Income-tax Act, 1961 Section 115JB(5A) (Non-applicability of MAT to Section 115BAA)',
|
|
235
|
+
'Income-tax Act, 1961 Section 115JAA (Tax credit in respect of tax paid on deemed income)'
|
|
236
|
+
]
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* ─────────────────────────────────────────────────────────────────────────────
|
|
242
|
+
* 2. PLACE OF SUPPLY (POS) & ZERO-RATED EXPORT UNDER LUT (IGST ACT SECTIONS 10, 12, 16)
|
|
243
|
+
* ─────────────────────────────────────────────────────────────────────────────
|
|
244
|
+
* Evaluates:
|
|
245
|
+
* 1. Domestic B2B / B2C POS (Sec 10 for Goods, Sec 12 for Services).
|
|
246
|
+
* 2. Intra-State (CGST + SGST) vs Inter-State (IGST) classification.
|
|
247
|
+
* 3. Export of Services under Section 16 & Section 2(6) cumulative 5 conditions.
|
|
248
|
+
* 4. Letter of Undertaking (LUT) zero-rate export vs tax payment refund.
|
|
249
|
+
*/
|
|
250
|
+
export function evaluatePlaceOfSupplyAndLut({
|
|
251
|
+
transactionType = 'DOMESTIC_SERVICES',
|
|
252
|
+
supplierStateCode = null,
|
|
253
|
+
supplierGstin = null,
|
|
254
|
+
recipientStateCode = null,
|
|
255
|
+
recipientGstin = null,
|
|
256
|
+
recipientCountryCode = 'IN',
|
|
257
|
+
invoiceAmountInr = 0,
|
|
258
|
+
gstRate = 0.18,
|
|
259
|
+
isB2B = true,
|
|
260
|
+
placeOfSupplyStateCode = null,
|
|
261
|
+
immovablePropertyLocationStateCode = null,
|
|
262
|
+
isSupplierInIndia = true,
|
|
263
|
+
isRecipientOutsideIndia = null,
|
|
264
|
+
isPlaceOfSupplyOutsideIndia = null,
|
|
265
|
+
isConvertibleForexReceivedOrRbiInr = null,
|
|
266
|
+
isDistinctPersonEstablishment = false,
|
|
267
|
+
isIntermediaryService = false,
|
|
268
|
+
hasValidLut = false,
|
|
269
|
+
lutArn = null
|
|
270
|
+
} = {}) {
|
|
271
|
+
const amount = Number(invoiceAmountInr) || 0;
|
|
272
|
+
const rate = Number(gstRate) || 0.18;
|
|
273
|
+
const isTransExport = transactionType === 'EXPORT_SERVICES' || transactionType === 'EXPORT_GOODS' || (recipientCountryCode && recipientCountryCode.toUpperCase() !== 'IN');
|
|
274
|
+
|
|
275
|
+
// Extract state codes
|
|
276
|
+
let supState = supplierStateCode;
|
|
277
|
+
if (!supState && supplierGstin && typeof supplierGstin === 'string' && supplierGstin.length >= 2) {
|
|
278
|
+
supState = supplierGstin.slice(0, 2);
|
|
279
|
+
}
|
|
280
|
+
let recState = recipientStateCode;
|
|
281
|
+
if (!recState && recipientGstin && typeof recipientGstin === 'string' && recipientGstin.length >= 2) {
|
|
282
|
+
recState = recipientGstin.slice(0, 2);
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
if (isTransExport) {
|
|
286
|
+
// Evaluate Section 2(6) 5 Cumulative Conditions for Export of Services
|
|
287
|
+
const cond1SupplierInIndia = isSupplierInIndia === true;
|
|
288
|
+
const cond2RecipientOutsideIndia = recipientCountryCode.toUpperCase() !== 'IN' && (isRecipientOutsideIndia === null || isRecipientOutsideIndia === true);
|
|
289
|
+
// Intermediary services under Section 13(8)(b) have POS at supplier location in India
|
|
290
|
+
const cond3PosOutsideIndia = !isIntermediaryService && (isPlaceOfSupplyOutsideIndia === null || isPlaceOfSupplyOutsideIndia === true);
|
|
291
|
+
const cond4ForexReceived = isConvertibleForexReceivedOrRbiInr === true;
|
|
292
|
+
const cond5NotDistinctPersons = isDistinctPersonEstablishment === false;
|
|
293
|
+
|
|
294
|
+
const conditionAudit = [
|
|
295
|
+
{ condition: '1. Supplier located in India (Sec 2(6)(i))', status: cond1SupplierInIndia ? 'PASS' : 'FAIL' },
|
|
296
|
+
{ condition: '2. Recipient located outside India (Sec 2(6)(ii))', status: cond2RecipientOutsideIndia ? 'PASS' : 'FAIL' },
|
|
297
|
+
{ condition: '3. Place of supply outside India (Sec 2(6)(iii) & Sec 13)', status: cond3PosOutsideIndia ? 'PASS' : (isIntermediaryService ? 'FAIL_INTERMEDIARY_SEC_13_8_B' : 'FAIL') },
|
|
298
|
+
{ condition: '4. Convertible forex / RBI permitted INR received (Sec 2(6)(iv))', status: cond4ForexReceived ? 'PASS' : 'FAIL_NO_FIRC_EBRC' },
|
|
299
|
+
{ condition: '5. Not merely establishments of distinct persons (Sec 2(6)(v))', status: cond5NotDistinctPersons ? 'PASS' : 'FAIL_DISTINCT_PERSON_BRANCH' }
|
|
300
|
+
];
|
|
301
|
+
|
|
302
|
+
const isFullyQualifiedExport = cond1SupplierInIndia && cond2RecipientOutsideIndia && cond3PosOutsideIndia && cond4ForexReceived && cond5NotDistinctPersons;
|
|
303
|
+
|
|
304
|
+
if (isFullyQualifiedExport) {
|
|
305
|
+
if (hasValidLut) {
|
|
306
|
+
return {
|
|
307
|
+
status: 'SUCCESS',
|
|
308
|
+
statutoryDetermination: 'ZERO_RATED_EXPORT_UNDER_LUT',
|
|
309
|
+
governingLaw: 'IGST Act, 2017 Sections 2(6), 16(1)(a) & 16(3)(a); CGST Rules, 2017 Rule 96A',
|
|
310
|
+
transactionType: 'EXPORT_SERVICES',
|
|
311
|
+
invoiceAmountInr: amount,
|
|
312
|
+
gstRate: 0,
|
|
313
|
+
igstPayableInr: 0,
|
|
314
|
+
cgstPayableInr: 0,
|
|
315
|
+
sgstPayableInr: 0,
|
|
316
|
+
lutArn: lutArn || 'LUT_ARN_ACTIVE_ON_RECORD',
|
|
317
|
+
isZeroRated: true,
|
|
318
|
+
itcRefundEligible: true,
|
|
319
|
+
reportingTable: 'GSTR-1 Table 6A (Export without payment of tax)',
|
|
320
|
+
conditionAudit,
|
|
321
|
+
isAuthorizedToDisburse: false,
|
|
322
|
+
statutoryRationale: `Zero-Rated Export of Services under LUT: All 5 conditions of Section 2(6) IGST Act verified. Export proceeds in convertible foreign exchange/RBI INR confirmed. Supply is zero-rated at 0% IGST under valid LUT ARN ${lutArn || 'ACTIVE'}. Accumulated unutilized ITC is eligible for refund under Section 54(3).`
|
|
323
|
+
};
|
|
324
|
+
} else {
|
|
325
|
+
const igstTax = roundToPaisa(amount * rate);
|
|
326
|
+
return {
|
|
327
|
+
status: 'SUCCESS',
|
|
328
|
+
statutoryDetermination: 'ZERO_RATED_EXPORT_WITH_TAX_PAYMENT',
|
|
329
|
+
governingLaw: 'IGST Act, 2017 Sections 2(6), 16(1)(a) & 16(3)(b); CGST Act Section 54',
|
|
330
|
+
transactionType: 'EXPORT_SERVICES',
|
|
331
|
+
invoiceAmountInr: amount,
|
|
332
|
+
gstRate: rate,
|
|
333
|
+
igstPayableInr: igstTax,
|
|
334
|
+
cgstPayableInr: 0,
|
|
335
|
+
sgstPayableInr: 0,
|
|
336
|
+
isZeroRated: true,
|
|
337
|
+
itcRefundEligible: true,
|
|
338
|
+
reportingTable: 'GSTR-1 Table 6A (Export with payment of tax)',
|
|
339
|
+
conditionAudit,
|
|
340
|
+
isAuthorizedToDisburse: false,
|
|
341
|
+
statutoryRationale: `Zero-Rated Export with payment of tax: All 5 conditions of Section 2(6) satisfied, but no valid LUT on record. IGST of INR ${igstTax.toLocaleString('en-IN')} (at ${(rate * 100)}%) is charged and eligible for refund under Section 54(1).`
|
|
342
|
+
};
|
|
343
|
+
}
|
|
344
|
+
} else {
|
|
345
|
+
const igstTax = roundToPaisa(amount * rate);
|
|
346
|
+
const failedReasons = conditionAudit.filter(c => c.status !== 'PASS').map(c => c.condition);
|
|
347
|
+
return {
|
|
348
|
+
status: 'SUCCESS',
|
|
349
|
+
statutoryDetermination: 'DISQUALIFIED_FROM_ZERO_RATING',
|
|
350
|
+
governingLaw: 'IGST Act, 2017 Sections 2(6), 7(5)(a) & 13',
|
|
351
|
+
transactionType: 'DISQUALIFIED_EXPORT_SERVICES',
|
|
352
|
+
invoiceAmountInr: amount,
|
|
353
|
+
gstRate: rate,
|
|
354
|
+
igstPayableInr: igstTax,
|
|
355
|
+
cgstPayableInr: 0,
|
|
356
|
+
sgstPayableInr: 0,
|
|
357
|
+
isZeroRated: false,
|
|
358
|
+
itcRefundEligible: false,
|
|
359
|
+
disqualificationReasons: failedReasons,
|
|
360
|
+
conditionAudit,
|
|
361
|
+
isAuthorizedToDisburse: false,
|
|
362
|
+
statutoryRationale: `Disqualified from Zero-Rated Export: Supply failed statutory condition(s): ${failedReasons.join('; ')}. Treated as standard domestic inter-state supply to foreign person subject to standard ${(rate * 100)}% IGST (INR ${igstTax.toLocaleString('en-IN')}).`
|
|
363
|
+
};
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
// Domestic Transaction Place of Supply Determination
|
|
368
|
+
let posState = placeOfSupplyStateCode;
|
|
369
|
+
let posLegalRule = '';
|
|
370
|
+
|
|
371
|
+
if (immovablePropertyLocationStateCode) {
|
|
372
|
+
posState = immovablePropertyLocationStateCode;
|
|
373
|
+
posLegalRule = 'IGST Act Section 12(3) (Directly related to immovable property - location of property)';
|
|
374
|
+
} else if (transactionType === 'DOMESTIC_GOODS') {
|
|
375
|
+
posState = posState || recState || supState;
|
|
376
|
+
posLegalRule = 'IGST Act Section 10(1)(a) (Location of goods at termination of delivery)';
|
|
377
|
+
} else {
|
|
378
|
+
if (isB2B && recState) {
|
|
379
|
+
posState = recState;
|
|
380
|
+
posLegalRule = 'IGST Act Section 12(2)(a) (B2B supply - location of registered recipient)';
|
|
381
|
+
} else if (recState) {
|
|
382
|
+
posState = recState;
|
|
383
|
+
posLegalRule = 'IGST Act Section 12(2)(b) (B2C supply with address on record)';
|
|
384
|
+
} else {
|
|
385
|
+
posState = supState;
|
|
386
|
+
posLegalRule = 'IGST Act Section 12(2)(b) proviso (B2C supply without address - location of supplier)';
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
const isIntraState = supState && posState && (supState === posState);
|
|
391
|
+
let cgstRate = 0, sgstRate = 0, igstRate = 0;
|
|
392
|
+
let cgstAmountInr = 0, sgstAmountInr = 0, igstAmountInr = 0;
|
|
393
|
+
|
|
394
|
+
if (isIntraState) {
|
|
395
|
+
cgstRate = rate / 2;
|
|
396
|
+
sgstRate = rate / 2;
|
|
397
|
+
cgstAmountInr = roundToPaisa(amount * cgstRate);
|
|
398
|
+
sgstAmountInr = roundToPaisa(amount * sgstRate);
|
|
399
|
+
} else {
|
|
400
|
+
igstRate = rate;
|
|
401
|
+
igstAmountInr = roundToPaisa(amount * igstRate);
|
|
402
|
+
}
|
|
403
|
+
const totalGstInr = roundToPaisa(cgstAmountInr + sgstAmountInr + igstAmountInr);
|
|
404
|
+
|
|
405
|
+
return {
|
|
406
|
+
status: 'SUCCESS',
|
|
407
|
+
statutoryDetermination: isIntraState ? 'INTRA_STATE_SUPPLY' : 'INTER_STATE_SUPPLY',
|
|
408
|
+
governingLaw: isIntraState ? 'CGST Act Section 9 & SGST Act Section 9' : 'IGST Act Section 5 & Section 7',
|
|
409
|
+
posLegalRule,
|
|
410
|
+
supplierStateCode: supState,
|
|
411
|
+
placeOfSupplyStateCode: posState,
|
|
412
|
+
recipientStateCode: recState,
|
|
413
|
+
invoiceAmountInr: amount,
|
|
414
|
+
supplyNature: isIntraState ? 'INTRA_STATE' : 'INTER_STATE',
|
|
415
|
+
taxBreakdown: {
|
|
416
|
+
cgstRate,
|
|
417
|
+
cgstAmountInr,
|
|
418
|
+
sgstRate,
|
|
419
|
+
sgstAmountInr,
|
|
420
|
+
igstRate,
|
|
421
|
+
igstAmountInr,
|
|
422
|
+
totalGstAmountInr: totalGstInr
|
|
423
|
+
},
|
|
424
|
+
isAuthorizedToDisburse: false,
|
|
425
|
+
statutoryRationale: isIntraState
|
|
426
|
+
? `Intra-State Supply: Supplier state (${supState}) matches Place of Supply (${posState}). CGST (${(cgstRate * 100)}%: INR ${cgstAmountInr.toLocaleString('en-IN')}) and SGST (${(sgstRate * 100)}%: INR ${sgstAmountInr.toLocaleString('en-IN')}) levied under Section 9.`
|
|
427
|
+
: `Inter-State Supply: Supplier state (${supState}) differs from Place of Supply (${posState}). IGST (${(igstRate * 100)}%: INR ${igstAmountInr.toLocaleString('en-IN')}) levied under Section 5 of IGST Act.`
|
|
428
|
+
};
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
/**
|
|
432
|
+
* ─────────────────────────────────────────────────────────────────────────────
|
|
433
|
+
* 3. TRANSFER PRICING ARM'S LENGTH PRICE (ALP) ENGINE (SECTION 92C & RULE 10CA)
|
|
434
|
+
* ─────────────────────────────────────────────────────────────────────────────
|
|
435
|
+
* Computes Transfer Pricing compliance:
|
|
436
|
+
* 1. Associated Enterprise (AE) transaction validation under Section 92A.
|
|
437
|
+
* 2. 3% tolerance band for wholesale traders vs 1% for other businesses (proviso to Sec 92C(2)).
|
|
438
|
+
* 3. Rule 10CA Percentile Range: 35th to 65th percentile dataset evaluation for >= 6 comparables.
|
|
439
|
+
* 4. Rule 10CA(7) Median (50th percentile) primary adjustment if tested margin is outside range.
|
|
440
|
+
* 5. Section 92CE Secondary Adjustment threshold warning (> 1 Cr).
|
|
441
|
+
*/
|
|
442
|
+
export function calculateTransferPricingAlp({
|
|
443
|
+
transactionDescription = 'International Transaction with Associated Enterprise',
|
|
444
|
+
testedParty = 'Indian Enterprise',
|
|
445
|
+
associatedEnterpriseName = 'Foreign AE',
|
|
446
|
+
isAssociatedEnterprise = true,
|
|
447
|
+
internationalTransactionAmountInr = 0,
|
|
448
|
+
testedPartyOperatingMarginPercent = 0,
|
|
449
|
+
isWholesaleTrading = false,
|
|
450
|
+
comparablesData = [],
|
|
451
|
+
transferPricingMethod = 'TNMM'
|
|
452
|
+
} = {}) {
|
|
453
|
+
const amount = Number(internationalTransactionAmountInr) || 0;
|
|
454
|
+
const testedMargin = Number(testedPartyOperatingMarginPercent) || 0;
|
|
455
|
+
const tolerancePercent = isWholesaleTrading ? 3.0 : 1.0;
|
|
456
|
+
|
|
457
|
+
if (!isAssociatedEnterprise) {
|
|
458
|
+
return {
|
|
459
|
+
status: 'SUCCESS',
|
|
460
|
+
statutoryDetermination: 'NOT_APPLICABLE',
|
|
461
|
+
governingLaw: 'Income-tax Act, 1961 Section 92A & 92C',
|
|
462
|
+
transactionDescription,
|
|
463
|
+
isAssociatedEnterprise: false,
|
|
464
|
+
statutoryRationale: 'Counterparty is not an Associated Enterprise under Section 92A. Transfer Pricing provisions u/s 92C do not apply to third-party transactions.',
|
|
465
|
+
isAuthorizedToDisburse: false
|
|
466
|
+
};
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
const comparables = Array.isArray(comparablesData)
|
|
470
|
+
? comparablesData.map(x => Number(typeof x === 'object' && x !== null ? (x.operatingMargin || x.margin || 0) : x)).filter(x => !isNaN(x)).sort((a, b) => a - b)
|
|
471
|
+
: [];
|
|
472
|
+
|
|
473
|
+
let isArmLengthCompliant = false;
|
|
474
|
+
let primaryAdjustmentInr = 0;
|
|
475
|
+
let percentile35 = null;
|
|
476
|
+
let percentile65 = null;
|
|
477
|
+
let median50 = null;
|
|
478
|
+
let arithmeticMean = null;
|
|
479
|
+
let appliedRule = '';
|
|
480
|
+
|
|
481
|
+
if (comparables.length >= 6) {
|
|
482
|
+
appliedRule = 'Rule 10CA Percentile Range (Dataset >= 6 Comparables)';
|
|
483
|
+
const n = comparables.length;
|
|
484
|
+
|
|
485
|
+
const getPercentileValue = (p) => {
|
|
486
|
+
const index = (n * p);
|
|
487
|
+
if (Number.isInteger(index)) {
|
|
488
|
+
const i = index - 1;
|
|
489
|
+
return (comparables[i] + comparables[Math.min(i + 1, n - 1)]) / 2;
|
|
490
|
+
} else {
|
|
491
|
+
const i = Math.floor(index);
|
|
492
|
+
return comparables[Math.min(i, n - 1)];
|
|
493
|
+
}
|
|
494
|
+
};
|
|
495
|
+
|
|
496
|
+
percentile35 = roundToPaisa(getPercentileValue(0.35));
|
|
497
|
+
percentile65 = roundToPaisa(getPercentileValue(0.65));
|
|
498
|
+
median50 = roundToPaisa(getPercentileValue(0.50));
|
|
499
|
+
|
|
500
|
+
if (testedMargin >= percentile35 && testedMargin <= percentile65) {
|
|
501
|
+
isArmLengthCompliant = true;
|
|
502
|
+
primaryAdjustmentInr = 0;
|
|
503
|
+
} else if (testedMargin > percentile65) {
|
|
504
|
+
isArmLengthCompliant = true;
|
|
505
|
+
primaryAdjustmentInr = 0;
|
|
506
|
+
} else {
|
|
507
|
+
isArmLengthCompliant = false;
|
|
508
|
+
const marginShortfall = roundToPaisa(median50 - testedMargin);
|
|
509
|
+
primaryAdjustmentInr = roundToPaisa(amount * (marginShortfall / 100));
|
|
510
|
+
}
|
|
511
|
+
} else if (comparables.length > 0) {
|
|
512
|
+
appliedRule = 'Proviso to Section 92C(2) Arithmetic Mean & Tolerance Band (< 6 Comparables)';
|
|
513
|
+
arithmeticMean = roundToPaisa(comparables.reduce((sum, x) => sum + x, 0) / comparables.length);
|
|
514
|
+
const variationPercent = Math.abs(testedMargin - arithmeticMean);
|
|
515
|
+
|
|
516
|
+
if (variationPercent <= tolerancePercent || testedMargin >= arithmeticMean) {
|
|
517
|
+
isArmLengthCompliant = true;
|
|
518
|
+
primaryAdjustmentInr = 0;
|
|
519
|
+
} else {
|
|
520
|
+
isArmLengthCompliant = false;
|
|
521
|
+
const marginShortfall = roundToPaisa(arithmeticMean - testedMargin);
|
|
522
|
+
primaryAdjustmentInr = roundToPaisa(amount * (marginShortfall / 100));
|
|
523
|
+
}
|
|
524
|
+
} else {
|
|
525
|
+
appliedRule = 'Single Transaction Assessment (No Dataset)';
|
|
526
|
+
isArmLengthCompliant = true;
|
|
527
|
+
primaryAdjustmentInr = 0;
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
const requiresSecondaryAdjustment = primaryAdjustmentInr > 10000000;
|
|
531
|
+
|
|
532
|
+
return {
|
|
533
|
+
status: 'SUCCESS',
|
|
534
|
+
statutoryDetermination: isArmLengthCompliant ? 'ARM_LENGTH_COMPLIANT' : 'PRIMARY_ADJUSTMENT_REQUIRED',
|
|
535
|
+
governingLaw: 'Income-tax Act, 1961 Section 92C, Rule 10B & Rule 10CA',
|
|
536
|
+
testedParty,
|
|
537
|
+
associatedEnterpriseName,
|
|
538
|
+
transferPricingMethod,
|
|
539
|
+
internationalTransactionAmountInr: amount,
|
|
540
|
+
testedPartyOperatingMarginPercent: testedMargin,
|
|
541
|
+
appliedRule,
|
|
542
|
+
toleranceBandPercent: tolerancePercent,
|
|
543
|
+
datasetSummary: {
|
|
544
|
+
comparablesCount: comparables.length,
|
|
545
|
+
percentile35,
|
|
546
|
+
percentile65,
|
|
547
|
+
median50,
|
|
548
|
+
arithmeticMean,
|
|
549
|
+
armLengthRange: percentile35 !== null ? [percentile35, percentile65] : null
|
|
550
|
+
},
|
|
551
|
+
primaryAdjustmentInr,
|
|
552
|
+
secondaryAdjustmentAlert: requiresSecondaryAdjustment ? {
|
|
553
|
+
applicable: true,
|
|
554
|
+
section: 'Section 92CE',
|
|
555
|
+
threshold: 'Exceeds INR 1,00,00,000',
|
|
556
|
+
repatriationPeriodDays: 90,
|
|
557
|
+
statutoryConsequence: 'Excess money must be repatriated into India within 90 days, failing which interest at SBI 1-yr MCLR + 325 bps applies.'
|
|
558
|
+
} : { applicable: false },
|
|
559
|
+
isAuthorizedToDisburse: false,
|
|
560
|
+
statutoryRationale: isArmLengthCompliant
|
|
561
|
+
? `Transfer Pricing Compliant: Tested party operating margin of ${testedMargin}% is within the statutory arm's length range [${percentile35 ?? arithmeticMean}%, ${percentile65 ?? arithmeticMean}%]. Primary adjustment is INR 0.`
|
|
562
|
+
: `Primary Adjustment Required: Tested margin (${testedMargin}%) falls below statutory arm's length range. Under Rule 10CA(7), adjustment is made to the Median (50th percentile: ${median50}%). Primary TP addition to income: INR ${primaryAdjustmentInr.toLocaleString('en-IN')}.${requiresSecondaryAdjustment ? ' Section 92CE secondary adjustment mandatory.' : ''}`
|
|
563
|
+
};
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
/**
|
|
567
|
+
* ─────────────────────────────────────────────────────────────────────────────
|
|
568
|
+
* 4. SECTION 79 TAX LOSS CARRY-FORWARD & SHAREHOLDING CONTINUITY
|
|
569
|
+
* ─────────────────────────────────────────────────────────────────────────────
|
|
570
|
+
* Evaluates carry forward and set off of accumulated business losses:
|
|
571
|
+
* 1. General Rule (Sec 79(1)): Denied if >= 51% change in voting power.
|
|
572
|
+
* 2. Startup Carve-Out (Sec 79(2)): Preserved for DPIIT startups u/s 80-IAC if all original shareholders continue.
|
|
573
|
+
* 3. IBC Carve-Out (Sec 79(2)(c)): Preserved for NCLT resolution plans.
|
|
574
|
+
* 4. Section 32(2) Invariant: Unabsorbed depreciation carries forward INDEFINITELY regardless of Section 79.
|
|
575
|
+
*/
|
|
576
|
+
export function evaluateSection79LossContinuity({
|
|
577
|
+
companyType = 'CLOSELY_HELD_COMPANY',
|
|
578
|
+
isDpiitRecognizedStartup = false,
|
|
579
|
+
isIbcResolutionPlan = false,
|
|
580
|
+
accumulatedBroughtForwardLossInr = 0,
|
|
581
|
+
unabsorbedDepreciationInr = 0,
|
|
582
|
+
shareholdingInLossYear = [],
|
|
583
|
+
shareholdingInSetOffYear = [],
|
|
584
|
+
votingPowerHeldByOriginalShareholdersPercent = null
|
|
585
|
+
} = {}) {
|
|
586
|
+
const bfLoss = Math.max(0, Number(accumulatedBroughtForwardLossInr) || 0);
|
|
587
|
+
const unabsDep = Math.max(0, Number(unabsorbedDepreciationInr) || 0);
|
|
588
|
+
|
|
589
|
+
let continuityPercent = votingPowerHeldByOriginalShareholdersPercent !== null
|
|
590
|
+
? Number(votingPowerHeldByOriginalShareholdersPercent)
|
|
591
|
+
: null;
|
|
592
|
+
|
|
593
|
+
let allOriginalShareholdersContinue = false;
|
|
594
|
+
|
|
595
|
+
if (continuityPercent === null && Array.isArray(shareholdingInLossYear) && shareholdingInLossYear.length > 0 && Array.isArray(shareholdingInSetOffYear)) {
|
|
596
|
+
let commonVotingPower = 0;
|
|
597
|
+
let originalFoundCount = 0;
|
|
598
|
+
|
|
599
|
+
for (const orig of shareholdingInLossYear) {
|
|
600
|
+
const pan = orig.shareholderPan || orig.pan || orig.name;
|
|
601
|
+
const origPct = Number(orig.percentage || orig.votingPower || 0);
|
|
602
|
+
const current = shareholdingInSetOffYear.find(x => (x.shareholderPan || x.pan || x.name) === pan);
|
|
603
|
+
|
|
604
|
+
if (current && Number(current.percentage || current.votingPower || 0) > 0) {
|
|
605
|
+
originalFoundCount++;
|
|
606
|
+
commonVotingPower += Math.min(origPct, Number(current.percentage || current.votingPower || 0));
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
continuityPercent = roundToPaisa(commonVotingPower);
|
|
610
|
+
allOriginalShareholdersContinue = (originalFoundCount === shareholdingInLossYear.length);
|
|
611
|
+
} else if (continuityPercent !== null) {
|
|
612
|
+
allOriginalShareholdersContinue = continuityPercent > 0;
|
|
613
|
+
} else {
|
|
614
|
+
continuityPercent = 100;
|
|
615
|
+
allOriginalShareholdersContinue = true;
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
let isLossCarryForwardAllowed = false;
|
|
619
|
+
let governingClause = 'Section 79(1)';
|
|
620
|
+
let rationale = '';
|
|
621
|
+
|
|
622
|
+
if (isIbcResolutionPlan) {
|
|
623
|
+
isLossCarryForwardAllowed = true;
|
|
624
|
+
governingClause = 'Section 79(2)(c) (Insolvency and Bankruptcy Code Resolution Plan)';
|
|
625
|
+
rationale = 'Accumulated business losses are protected under Section 79(2)(c): Change in shareholding pursuant to NCLT approved resolution plan under the IBC, 2016 is exempt from Section 79 restrictions.';
|
|
626
|
+
} else if (isDpiitRecognizedStartup) {
|
|
627
|
+
governingClause = 'Section 79(2) (DPIIT Recognized Startup under Section 80-IAC)';
|
|
628
|
+
if (allOriginalShareholdersContinue) {
|
|
629
|
+
isLossCarryForwardAllowed = true;
|
|
630
|
+
rationale = `Accumulated business losses protected under Section 79(2) startup carve-out: Although original voting power is ${continuityPercent}%, all original shareholders continue to hold shares in the company.`;
|
|
631
|
+
} else {
|
|
632
|
+
isLossCarryForwardAllowed = continuityPercent >= 51.0;
|
|
633
|
+
rationale = isLossCarryForwardAllowed
|
|
634
|
+
? `Section 79 satisfied: Original shareholders retain ${continuityPercent}% voting power (>= 51%).`
|
|
635
|
+
: `Section 79(2) startup carve-out failed: Not all original shareholders continue to hold shares, and retained voting power (${continuityPercent}%) is below 51%. Business loss lapsed.`;
|
|
636
|
+
}
|
|
637
|
+
} else {
|
|
638
|
+
governingClause = 'Section 79(1) General Corporate Rule';
|
|
639
|
+
if (continuityPercent >= 51.0) {
|
|
640
|
+
isLossCarryForwardAllowed = true;
|
|
641
|
+
rationale = `Section 79(1) compliant: Original shareholders hold ${continuityPercent}% of voting power on the last day of the financial year (threshold: >= 51%). Business losses can be set off.`;
|
|
642
|
+
} else {
|
|
643
|
+
isLossCarryForwardAllowed = false;
|
|
644
|
+
rationale = `Section 79(1) violation: Voting power held by original shareholders has fallen to ${continuityPercent}% (< 51%). Accumulated business losses of INR ${bfLoss.toLocaleString('en-IN')} are legally lapsed and forfeited.`;
|
|
645
|
+
}
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
const allowableLossSetOffInr = isLossCarryForwardAllowed ? bfLoss : 0;
|
|
649
|
+
const lapsedBusinessLossInr = isLossCarryForwardAllowed ? 0 : bfLoss;
|
|
650
|
+
|
|
651
|
+
return {
|
|
652
|
+
status: 'SUCCESS',
|
|
653
|
+
statutoryDetermination: isLossCarryForwardAllowed ? 'LOSS_CARRYFORWARD_ALLOWED' : 'LOSS_CARRYFORWARD_DENIED',
|
|
654
|
+
governingLaw: 'Income-tax Act, 1961 Section 79 & Section 32(2)',
|
|
655
|
+
governingClause,
|
|
656
|
+
companyType,
|
|
657
|
+
isDpiitRecognizedStartup,
|
|
658
|
+
isIbcResolutionPlan,
|
|
659
|
+
beneficialOwnershipContinuityPercent: continuityPercent,
|
|
660
|
+
allOriginalShareholdersContinue,
|
|
661
|
+
lossSchedule: {
|
|
662
|
+
broughtForwardBusinessLossInr: bfLoss,
|
|
663
|
+
allowableLossSetOffInr,
|
|
664
|
+
lapsedBusinessLossInr,
|
|
665
|
+
unabsorbedDepreciationInr: unabsDep,
|
|
666
|
+
unabsorbedDepreciationStatutoryStatus: 'Fully protected under Section 32(2) -- Indefinite carry forward unaffected by shareholding changes.'
|
|
667
|
+
},
|
|
668
|
+
isAuthorizedToDisburse: false,
|
|
669
|
+
statutoryRationale: `${rationale} Note: Unabsorbed depreciation of INR ${unabsDep.toLocaleString('en-IN')} is unaffected by Section 79 per Supreme Court precedent (CIT v. Virmani Industries) and carries forward indefinitely.`
|
|
670
|
+
};
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
/**
|
|
674
|
+
* ─────────────────────────────────────────────────────────────────────────────
|
|
675
|
+
* 5. FOREIGN EXCHANGE MONETARY REVALUATION (IND AS 21 & IND AS 109)
|
|
676
|
+
* ─────────────────────────────────────────────────────────────────────────────
|
|
677
|
+
* Revalues foreign currency monetary items at closing reporting spot rates:
|
|
678
|
+
* 1. Monetary Assets (Receivables, Bank) vs Monetary Liabilities (Payables, Loans).
|
|
679
|
+
* 2. Net Unrealized Gain/Loss routing: P&L vs Other Comprehensive Income (OCI - Cash Flow Hedge Reserve).
|
|
680
|
+
* 3. Ind AS 109 Balance Sheet schedule generation.
|
|
681
|
+
*/
|
|
682
|
+
export function revalueForeignExchangeIndAs109({
|
|
683
|
+
asOfDate = null,
|
|
684
|
+
reportingCurrency = 'INR',
|
|
685
|
+
items = []
|
|
686
|
+
} = {}) {
|
|
687
|
+
const dAsOf = asOfDate ? new Date(asOfDate) : new Date();
|
|
688
|
+
const asOfIso = !isNaN(dAsOf.getTime()) ? dAsOf.toISOString().split('T')[0] : new Date().toISOString().split('T')[0];
|
|
689
|
+
|
|
690
|
+
const revaluedItems = [];
|
|
691
|
+
let totalPnlGainInr = 0;
|
|
692
|
+
let totalPnlLossInr = 0;
|
|
693
|
+
let totalOciGainInr = 0;
|
|
694
|
+
let totalOciLossInr = 0;
|
|
695
|
+
|
|
696
|
+
const itemList = Array.isArray(items) ? items : [];
|
|
697
|
+
|
|
698
|
+
for (const item of itemList) {
|
|
699
|
+
const desc = item.description || item.itemDescription || 'FX Item';
|
|
700
|
+
const itemType = (item.itemType || 'MONETARY_ASSET').toUpperCase();
|
|
701
|
+
const ccy = item.foreignCurrency || item.currency || 'USD';
|
|
702
|
+
const fcyAmt = Number(item.foreignAmount || item.amount || 0);
|
|
703
|
+
const bookRate = Number(item.bookingRate || item.historicalRate || 1);
|
|
704
|
+
const closeRate = Number(item.closingRate || item.spotRate || bookRate);
|
|
705
|
+
const isHedge = item.isDesignatedCashFlowHedge === true;
|
|
706
|
+
|
|
707
|
+
if (itemType === 'NON_MONETARY') {
|
|
708
|
+
revaluedItems.push({
|
|
709
|
+
description: desc,
|
|
710
|
+
itemType: 'NON_MONETARY',
|
|
711
|
+
foreignCurrency: ccy,
|
|
712
|
+
foreignAmount: fcyAmt,
|
|
713
|
+
bookingRate: bookRate,
|
|
714
|
+
closingRate: closeRate,
|
|
715
|
+
carryingAmountInr: roundToPaisa(fcyAmt * bookRate),
|
|
716
|
+
unrealizedGainLossInr: 0,
|
|
717
|
+
accountingTreatment: 'Carried at historical cost per Ind AS 21.23(b) -- No closing rate revaluation.'
|
|
718
|
+
});
|
|
719
|
+
continue;
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
const carryingAmountInr = roundToPaisa(fcyAmt * bookRate);
|
|
723
|
+
const revaluedAmountInr = roundToPaisa(fcyAmt * closeRate);
|
|
724
|
+
|
|
725
|
+
let gainLoss = 0;
|
|
726
|
+
if (itemType === 'MONETARY_ASSET') {
|
|
727
|
+
gainLoss = roundToPaisa(revaluedAmountInr - carryingAmountInr);
|
|
728
|
+
} else {
|
|
729
|
+
gainLoss = roundToPaisa(carryingAmountInr - revaluedAmountInr);
|
|
730
|
+
}
|
|
731
|
+
|
|
732
|
+
let routing = '';
|
|
733
|
+
if (isHedge) {
|
|
734
|
+
routing = 'OTHER_COMPREHENSIVE_INCOME (Cash Flow Hedge Reserve)';
|
|
735
|
+
if (gainLoss >= 0) totalOciGainInr += gainLoss;
|
|
736
|
+
else totalOciLossInr += Math.abs(gainLoss);
|
|
737
|
+
} else {
|
|
738
|
+
routing = 'PROFIT_AND_LOSS (Foreign Exchange Fluctuation Account)';
|
|
739
|
+
if (gainLoss >= 0) totalPnlGainInr += gainLoss;
|
|
740
|
+
else totalPnlLossInr += Math.abs(gainLoss);
|
|
741
|
+
}
|
|
742
|
+
|
|
743
|
+
revaluedItems.push({
|
|
744
|
+
description: desc,
|
|
745
|
+
itemType,
|
|
746
|
+
foreignCurrency: ccy,
|
|
747
|
+
foreignAmount: fcyAmt,
|
|
748
|
+
bookingRate: bookRate,
|
|
749
|
+
closingRate: closeRate,
|
|
750
|
+
carryingAmountInr,
|
|
751
|
+
revaluedAmountInr,
|
|
752
|
+
unrealizedGainLossInr: gainLoss,
|
|
753
|
+
isGain: gainLoss >= 0,
|
|
754
|
+
accountingTreatment: routing
|
|
755
|
+
});
|
|
756
|
+
}
|
|
757
|
+
|
|
758
|
+
const netPnlGainLossInr = roundToPaisa(totalPnlGainInr - totalPnlLossInr);
|
|
759
|
+
const netOciGainLossInr = roundToPaisa(totalOciGainInr - totalOciLossInr);
|
|
760
|
+
|
|
761
|
+
return {
|
|
762
|
+
status: 'SUCCESS',
|
|
763
|
+
statutoryDetermination: 'APPLICABLE',
|
|
764
|
+
governingLaw: 'Ind AS 21 (The Effects of Changes in Foreign Exchange Rates) & Ind AS 109 (Financial Instruments)',
|
|
765
|
+
asOfDate: asOfIso,
|
|
766
|
+
reportingCurrency,
|
|
767
|
+
totalItemsEvaluated: revaluedItems.length,
|
|
768
|
+
summary: {
|
|
769
|
+
netPnlImpactInr: netPnlGainLossInr,
|
|
770
|
+
netPnlStatus: netPnlGainLossInr >= 0 ? 'NET_UNREALIZED_GAIN' : 'NET_UNREALIZED_LOSS',
|
|
771
|
+
netOciImpactInr: netOciGainLossInr,
|
|
772
|
+
netOciStatus: netOciGainLossInr >= 0 ? 'NET_HEDGE_RESERVE_GAIN' : 'NET_HEDGE_RESERVE_LOSS',
|
|
773
|
+
totalPnlGainInr: roundToPaisa(totalPnlGainInr),
|
|
774
|
+
totalPnlLossInr: roundToPaisa(totalPnlLossInr)
|
|
775
|
+
},
|
|
776
|
+
revaluedItems,
|
|
777
|
+
isAuthorizedToDisburse: false,
|
|
778
|
+
statutoryRationale: `Ind AS 21 & 109 Revaluation: ${revaluedItems.length} items evaluated as of ${asOfIso}. Net P&L FX impact: INR ${netPnlGainLossInr.toLocaleString('en-IN')}; Net OCI Hedge impact: INR ${netOciGainLossInr.toLocaleString('en-IN')}. Accounting revaluations do not authorize payment disbursement.`
|
|
779
|
+
};
|
|
780
|
+
}
|