shareneus 1.6.18 → 1.6.20
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/sales-receive/sales-total-calculation.js +107 -23
- package/dist/tax/index.d.ts +2 -2
- package/dist/tax/index.js +2 -1
- package/dist/tax/tax-calculator.d.ts +41 -17
- package/dist/tax/tax-calculator.js +58 -20
- package/dist/tax/tax.types.d.ts +24 -13
- package/package.json +1 -1
|
@@ -11,6 +11,86 @@ const util_1 = require("../shared/util");
|
|
|
11
11
|
function safeArray(arr) {
|
|
12
12
|
return Array.isArray(arr) ? arr : [];
|
|
13
13
|
}
|
|
14
|
+
function getLineNetAmount(line) {
|
|
15
|
+
return (0, math_operations_1.Subtract)((0, util_1.GetNumber)(line.UnAmt || line.Amt), (0, math_operations_1.Add)((0, util_1.GetNumber)(line.Disc), (0, util_1.GetNumber)(line.RecDisc)));
|
|
16
|
+
}
|
|
17
|
+
function getTaxCodeById(taxCodes, taxCodeId) {
|
|
18
|
+
const normalizedTaxCodeId = Number(taxCodeId);
|
|
19
|
+
if (!normalizedTaxCodeId) {
|
|
20
|
+
return null;
|
|
21
|
+
}
|
|
22
|
+
return taxCodes.find((taxCode) => Number(taxCode._id) === normalizedTaxCodeId) || null;
|
|
23
|
+
}
|
|
24
|
+
function getTaxComponentRate(taxCode, code) {
|
|
25
|
+
const component = safeArray(taxCode === null || taxCode === void 0 ? void 0 : taxCode.Components).find((item) => (item === null || item === void 0 ? void 0 : item.Code) === code);
|
|
26
|
+
if (component) {
|
|
27
|
+
return (0, util_1.GetNumber)(component.Rate);
|
|
28
|
+
}
|
|
29
|
+
return (0, util_1.GetNumber)(taxCode === null || taxCode === void 0 ? void 0 : taxCode[code]);
|
|
30
|
+
}
|
|
31
|
+
function buildTaxesFromFlatFields(line, taxCode, netAmount) {
|
|
32
|
+
const flatTaxes = [
|
|
33
|
+
{ Code: "CGST", Amt: (0, util_1.GetNumber)(line.CGST) },
|
|
34
|
+
{ Code: "SGST", Amt: (0, util_1.GetNumber)(line.SGST) },
|
|
35
|
+
{ Code: "IGST", Amt: (0, util_1.GetNumber)(line.IGST) }
|
|
36
|
+
];
|
|
37
|
+
return flatTaxes
|
|
38
|
+
.filter((tax) => tax.Amt > 0)
|
|
39
|
+
.map((tax) => ({
|
|
40
|
+
Code: tax.Code,
|
|
41
|
+
Amt: tax.Amt,
|
|
42
|
+
Rate: getTaxComponentRate(taxCode, tax.Code) || (netAmount > 0 ? (0, math_operations_1.Multiply)((0, math_operations_1.Divide)(tax.Amt, netAmount), 100) : 0),
|
|
43
|
+
TaxCodeId: (0, util_1.GetNumber)(line.TCode) || (0, util_1.GetNumber)(taxCode === null || taxCode === void 0 ? void 0 : taxCode._id)
|
|
44
|
+
}));
|
|
45
|
+
}
|
|
46
|
+
function buildTaxesFromTaxCode(line, taxCode, netAmount) {
|
|
47
|
+
if (!taxCode) {
|
|
48
|
+
return [];
|
|
49
|
+
}
|
|
50
|
+
const taxComponents = safeArray(taxCode.Components);
|
|
51
|
+
if (taxComponents.length > 0) {
|
|
52
|
+
return taxComponents
|
|
53
|
+
.filter((component) => ["CGST", "SGST", "IGST"].includes(component === null || component === void 0 ? void 0 : component.Code))
|
|
54
|
+
.map((component) => ({
|
|
55
|
+
Code: component.Code,
|
|
56
|
+
Amt: (0, math_operations_1.Multiply)(netAmount, (0, math_operations_1.Divide)((0, util_1.GetNumber)(component.Rate), 100)),
|
|
57
|
+
Rate: (0, util_1.GetNumber)(component.Rate),
|
|
58
|
+
TaxCodeId: (0, util_1.GetNumber)(taxCode._id)
|
|
59
|
+
}))
|
|
60
|
+
.filter((tax) => tax.Amt > 0);
|
|
61
|
+
}
|
|
62
|
+
const legacyTaxes = [
|
|
63
|
+
{ Code: "CGST", Rate: (0, util_1.GetNumber)(taxCode.CGST) },
|
|
64
|
+
{ Code: "SGST", Rate: (0, util_1.GetNumber)(taxCode.SGST) },
|
|
65
|
+
{ Code: "IGST", Rate: (0, util_1.GetNumber)(taxCode.IGST) }
|
|
66
|
+
];
|
|
67
|
+
return legacyTaxes
|
|
68
|
+
.filter((tax) => tax.Rate > 0)
|
|
69
|
+
.map((tax) => ({
|
|
70
|
+
Code: tax.Code,
|
|
71
|
+
Amt: (0, math_operations_1.Multiply)(netAmount, (0, math_operations_1.Divide)(tax.Rate, 100)),
|
|
72
|
+
Rate: tax.Rate,
|
|
73
|
+
TaxCodeId: (0, util_1.GetNumber)(taxCode._id)
|
|
74
|
+
}));
|
|
75
|
+
}
|
|
76
|
+
function getResolvedTaxes(line, taxCodes = []) {
|
|
77
|
+
const lineTaxes = safeArray(line === null || line === void 0 ? void 0 : line.Taxes);
|
|
78
|
+
if (lineTaxes.length > 0) {
|
|
79
|
+
return lineTaxes.map((tax) => (Object.assign(Object.assign({}, tax), { Code: tax === null || tax === void 0 ? void 0 : tax.Code, Amt: (0, util_1.GetNumber)(tax === null || tax === void 0 ? void 0 : tax.Amt), Rate: (0, util_1.GetNumber)(tax === null || tax === void 0 ? void 0 : tax.Rate), TaxCodeId: (0, util_1.GetNumber)(tax === null || tax === void 0 ? void 0 : tax.TaxCodeId) }))).filter((tax) => !!tax.Code);
|
|
80
|
+
}
|
|
81
|
+
const netAmount = getLineNetAmount(line);
|
|
82
|
+
const taxCode = getTaxCodeById(taxCodes, line === null || line === void 0 ? void 0 : line.TCode);
|
|
83
|
+
const taxesFromFlatFields = buildTaxesFromFlatFields(line, taxCode, netAmount);
|
|
84
|
+
if (taxesFromFlatFields.length > 0) {
|
|
85
|
+
return taxesFromFlatFields;
|
|
86
|
+
}
|
|
87
|
+
return buildTaxesFromTaxCode(line, taxCode, netAmount);
|
|
88
|
+
}
|
|
89
|
+
function getTaxAmountByCode(taxes, code) {
|
|
90
|
+
return taxes
|
|
91
|
+
.filter((tax) => tax.Code === code)
|
|
92
|
+
.reduce((sum, tax) => (0, math_operations_1.Add)(sum, (0, util_1.GetNumber)(tax.Amt)), 0);
|
|
93
|
+
}
|
|
14
94
|
function SalesTotalCalculations(items = [], ops = [], isTaxable = false, taxCodes = [], Adjust = 0) {
|
|
15
95
|
// Handle null/undefined arrays
|
|
16
96
|
const safeItems = safeArray(items);
|
|
@@ -60,9 +140,10 @@ function SalesTotalCalculations(items = [], ops = [], isTaxable = false, taxCode
|
|
|
60
140
|
// Add to return subtotal (net amount after discounts)
|
|
61
141
|
returnSubtotal = (0, math_operations_1.Add)(returnSubtotal, itemUnAmt);
|
|
62
142
|
if (isTaxable) {
|
|
63
|
-
const
|
|
64
|
-
const
|
|
65
|
-
const
|
|
143
|
+
const resolvedItemTaxes = getResolvedTaxes(item, safeTaxCodes);
|
|
144
|
+
const itemSGST = getTaxAmountByCode(resolvedItemTaxes, "SGST");
|
|
145
|
+
const itemCGST = getTaxAmountByCode(resolvedItemTaxes, "CGST");
|
|
146
|
+
const itemIGST = getTaxAmountByCode(resolvedItemTaxes, "IGST");
|
|
66
147
|
const itemTotalTax = (0, math_operations_1.Add)(itemSGST, itemCGST, itemIGST);
|
|
67
148
|
// Add to return tax
|
|
68
149
|
returnTax = (0, math_operations_1.Add)(returnTax, itemTotalTax);
|
|
@@ -80,9 +161,10 @@ function SalesTotalCalculations(items = [], ops = [], isTaxable = false, taxCode
|
|
|
80
161
|
subtotalOnItems = (0, math_operations_1.Add)(subtotalOnItems, itemUnAmt);
|
|
81
162
|
// Only calculate tax if taxable
|
|
82
163
|
if (isTaxable) {
|
|
83
|
-
const
|
|
84
|
-
const
|
|
85
|
-
const
|
|
164
|
+
const resolvedItemTaxes = getResolvedTaxes(item, safeTaxCodes);
|
|
165
|
+
const itemSGST = getTaxAmountByCode(resolvedItemTaxes, "SGST");
|
|
166
|
+
const itemCGST = getTaxAmountByCode(resolvedItemTaxes, "CGST");
|
|
167
|
+
const itemIGST = getTaxAmountByCode(resolvedItemTaxes, "IGST");
|
|
86
168
|
// Add individual tax amounts for items
|
|
87
169
|
totalSGSTOnItems = (0, math_operations_1.Add)(totalSGSTOnItems, itemSGST);
|
|
88
170
|
totalCGSTOnItems = (0, math_operations_1.Add)(totalCGSTOnItems, itemCGST);
|
|
@@ -100,9 +182,10 @@ function SalesTotalCalculations(items = [], ops = [], isTaxable = false, taxCode
|
|
|
100
182
|
subtotalOnLabor = (0, math_operations_1.Add)(subtotalOnLabor, opAmt);
|
|
101
183
|
// Only calculate tax if taxable
|
|
102
184
|
if (isTaxable) {
|
|
103
|
-
const
|
|
104
|
-
const
|
|
105
|
-
const
|
|
185
|
+
const resolvedOpTaxes = getResolvedTaxes(op, safeTaxCodes);
|
|
186
|
+
const opSGST = getTaxAmountByCode(resolvedOpTaxes, "SGST");
|
|
187
|
+
const opCGST = getTaxAmountByCode(resolvedOpTaxes, "CGST");
|
|
188
|
+
const opIGST = getTaxAmountByCode(resolvedOpTaxes, "IGST");
|
|
106
189
|
// Add individual tax amounts for operations/labor
|
|
107
190
|
totalSGSTOnLabor = (0, math_operations_1.Add)(totalSGSTOnLabor, opSGST);
|
|
108
191
|
totalCGSTOnLabor = (0, math_operations_1.Add)(totalCGSTOnLabor, opCGST);
|
|
@@ -180,11 +263,11 @@ function SalesTotalCalculations(items = [], ops = [], isTaxable = false, taxCode
|
|
|
180
263
|
result.totalSGSTOnLabor = totalSGSTOnLabor;
|
|
181
264
|
result.totalCGSTOnLabor = totalCGSTOnLabor;
|
|
182
265
|
result.totalIGSTOnLabor = totalIGSTOnLabor;
|
|
183
|
-
// Calculate tax summary
|
|
266
|
+
// Calculate tax summary for both new Taxes[] and legacy tax-code based records
|
|
184
267
|
// Filter out items where Ret is true (only include non-return items)
|
|
185
268
|
const nonReturnItems = safeItems.filter((item) => item.Ret !== true);
|
|
186
|
-
result.itemsTaxSummary =
|
|
187
|
-
result.opsTaxSummary =
|
|
269
|
+
result.itemsTaxSummary = CalculateTaxSummary(nonReturnItems, safeTaxCodes);
|
|
270
|
+
result.opsTaxSummary = CalculateTaxSummary(safeOps, safeTaxCodes);
|
|
188
271
|
}
|
|
189
272
|
return result;
|
|
190
273
|
}
|
|
@@ -242,15 +325,16 @@ function SalesTotalCalculationsWithDecimals(items = [], ops = [], isTaxable = fa
|
|
|
242
325
|
return roundedResult;
|
|
243
326
|
}
|
|
244
327
|
function CalculateTaxSummary(items, taxCodes) {
|
|
245
|
-
// Create lookup for tax codes
|
|
246
|
-
const taxMap = Object.fromEntries(taxCodes.map(tc => [tc._id, tc]));
|
|
247
328
|
return Object.values(items.reduce((acc, item) => {
|
|
248
|
-
const
|
|
249
|
-
if (
|
|
329
|
+
const taxes = getResolvedTaxes(item, taxCodes);
|
|
330
|
+
if (taxes.length === 0)
|
|
250
331
|
return acc;
|
|
251
|
-
const percent = (((tax
|
|
252
|
-
|
|
253
|
-
const
|
|
332
|
+
const percent = (taxes.reduce((sum, tax) => (0, math_operations_1.Add)(sum, (0, util_1.GetNumber)(tax.Rate)), 0) + "%");
|
|
333
|
+
const taxable = getLineNetAmount(item);
|
|
334
|
+
const cgstAmount = getTaxAmountByCode(taxes, "CGST");
|
|
335
|
+
const sgstAmount = getTaxAmountByCode(taxes, "SGST");
|
|
336
|
+
const igstAmount = getTaxAmountByCode(taxes, "IGST");
|
|
337
|
+
const totalTaxAmount = (0, math_operations_1.Add)(cgstAmount, sgstAmount, igstAmount);
|
|
254
338
|
if (!acc[percent]) {
|
|
255
339
|
acc[percent] = {
|
|
256
340
|
Tax: percent,
|
|
@@ -262,10 +346,10 @@ function CalculateTaxSummary(items, taxCodes) {
|
|
|
262
346
|
};
|
|
263
347
|
}
|
|
264
348
|
acc[percent].TaxableAmount = (0, math_operations_1.Add)(acc[percent].TaxableAmount, taxable);
|
|
265
|
-
acc[percent].TaxAmount = (0, math_operations_1.Add)(acc[percent].TaxAmount,
|
|
266
|
-
acc[percent].CGSTAmount = (0, math_operations_1.Add)(acc[percent].CGSTAmount,
|
|
267
|
-
acc[percent].SGSTAmount = (0, math_operations_1.Add)(acc[percent].SGSTAmount,
|
|
268
|
-
acc[percent].IGSTAmount = (0, math_operations_1.Add)(acc[percent].IGSTAmount,
|
|
349
|
+
acc[percent].TaxAmount = (0, math_operations_1.Add)(acc[percent].TaxAmount, totalTaxAmount);
|
|
350
|
+
acc[percent].CGSTAmount = (0, math_operations_1.Add)(acc[percent].CGSTAmount, cgstAmount);
|
|
351
|
+
acc[percent].SGSTAmount = (0, math_operations_1.Add)(acc[percent].SGSTAmount, sgstAmount);
|
|
352
|
+
acc[percent].IGSTAmount = (0, math_operations_1.Add)(acc[percent].IGSTAmount, igstAmount);
|
|
269
353
|
return acc;
|
|
270
354
|
}, {}));
|
|
271
355
|
}
|
package/dist/tax/index.d.ts
CHANGED
|
@@ -4,6 +4,6 @@
|
|
|
4
4
|
* This is the entry point for all tax-related functionality.
|
|
5
5
|
* Import from "shareneus/tax" in both UI and API code.
|
|
6
6
|
*/
|
|
7
|
-
export type { TaxComponentType, CalcMethod, AppliedOn, RoundingMethod, TaxCategory, SupplyType, ResolvedSupplyType, WithholdingType, ResolverType, IRegimeComponent, IRegimeFeatures, IRounding, ITreatment, ITaxRegime, ITaxCodeComponent, ITaxCode, ITaxComponent, ITaxSummaryLine, ITaxSummary, IWithholding, IWithholdingCalcInput, IComponentOverride, ITaxCalcLineInput, ITaxSummaryInput, IRoundingConfig, IDocumentTotalsInput, IDocumentTotals, ITaxIdLabel, ITaxIdEntry, ITaxExemption, ITaxAuthority, IExternalProvider, } from "./tax.types";
|
|
7
|
+
export type { TaxComponentType, CalcMethod, AppliedOn, RoundingMethod, TaxCategory, SupplyType, ResolvedSupplyType, WithholdingType, ResolverType, IRegimeComponent, IRegimeFeatures, IRounding, ITreatment, ITaxRegime, ITaxCodeComponent, ITaxCode, ITaxComponent, ITaxSummaryLine, ITaxSummary, IWithholding, IWithholdingCalcInput, ILineAmountFields, IComponentOverride, ITaxCalcLineInput, ITaxSummaryInput, IRoundingConfig, IDocumentTotalsInput, IDocumentTotals, ITaxIdLabel, ITaxIdEntry, ITaxExemption, ITaxAuthority, IExternalProvider, } from "./tax.types";
|
|
8
8
|
export type { IInclusiveResult } from "./tax-calculator";
|
|
9
|
-
export { CalculateLineTax, ExtractNetFromInclusive, SumTaxComponents, ComputeTaxSummary, ComputeDocumentTotals, DetermineSupplyType, FindTaxCodeByRateAndSupplyType, CalculateWithholding, RoundAmount, ValidateTaxId, ValidateHSNSACLength, ConvertFlatToTaxes, GetDefaultTaxIdLabels, GetPrintableTaxIds, } from "./tax-calculator";
|
|
9
|
+
export { CalculateNetAmt, CalculateLineTax, ExtractNetFromInclusive, SumTaxComponents, ComputeTaxSummary, ComputeDocumentTotals, DetermineSupplyType, FindTaxCodeByRateAndSupplyType, CalculateWithholding, RoundAmount, ValidateTaxId, ValidateHSNSACLength, ConvertFlatToTaxes, GetDefaultTaxIdLabels, GetPrintableTaxIds, } from "./tax-calculator";
|
package/dist/tax/index.js
CHANGED
|
@@ -6,8 +6,9 @@
|
|
|
6
6
|
* Import from "shareneus/tax" in both UI and API code.
|
|
7
7
|
*/
|
|
8
8
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
-
exports.GetPrintableTaxIds = exports.GetDefaultTaxIdLabels = exports.ConvertFlatToTaxes = exports.ValidateHSNSACLength = exports.ValidateTaxId = exports.RoundAmount = exports.CalculateWithholding = exports.FindTaxCodeByRateAndSupplyType = exports.DetermineSupplyType = exports.ComputeDocumentTotals = exports.ComputeTaxSummary = exports.SumTaxComponents = exports.ExtractNetFromInclusive = exports.CalculateLineTax = void 0;
|
|
9
|
+
exports.GetPrintableTaxIds = exports.GetDefaultTaxIdLabels = exports.ConvertFlatToTaxes = exports.ValidateHSNSACLength = exports.ValidateTaxId = exports.RoundAmount = exports.CalculateWithholding = exports.FindTaxCodeByRateAndSupplyType = exports.DetermineSupplyType = exports.ComputeDocumentTotals = exports.ComputeTaxSummary = exports.SumTaxComponents = exports.ExtractNetFromInclusive = exports.CalculateLineTax = exports.CalculateNetAmt = void 0;
|
|
10
10
|
var tax_calculator_1 = require("./tax-calculator");
|
|
11
|
+
Object.defineProperty(exports, "CalculateNetAmt", { enumerable: true, get: function () { return tax_calculator_1.CalculateNetAmt; } });
|
|
11
12
|
Object.defineProperty(exports, "CalculateLineTax", { enumerable: true, get: function () { return tax_calculator_1.CalculateLineTax; } });
|
|
12
13
|
Object.defineProperty(exports, "ExtractNetFromInclusive", { enumerable: true, get: function () { return tax_calculator_1.ExtractNetFromInclusive; } });
|
|
13
14
|
Object.defineProperty(exports, "SumTaxComponents", { enumerable: true, get: function () { return tax_calculator_1.SumTaxComponents; } });
|
|
@@ -14,36 +14,58 @@
|
|
|
14
14
|
* IMPORTANT: All monetary calculations use Big.js to avoid floating-point
|
|
15
15
|
* precision issues. Never use plain JS arithmetic (* / + -) for money.
|
|
16
16
|
*/
|
|
17
|
-
import { ITaxCode, ITaxComponent, ITaxSummary, ITaxCalcLineInput, ITaxSummaryInput, IRoundingConfig, IDocumentTotalsInput, IDocumentTotals, ResolvedSupplyType, IWithholding, IWithholdingCalcInput, ITaxIdLabel, ITaxIdEntry } from "./tax.types";
|
|
17
|
+
import { ITaxCode, ITaxComponent, ITaxSummary, ILineAmountFields, ITaxCalcLineInput, ITaxSummaryInput, IRoundingConfig, IDocumentTotalsInput, IDocumentTotals, ResolvedSupplyType, IWithholding, IWithholdingCalcInput, ITaxIdLabel, ITaxIdEntry } from "./tax.types";
|
|
18
|
+
/**
|
|
19
|
+
* Computes the net taxable amount from line item fields.
|
|
20
|
+
*
|
|
21
|
+
* Formula: NetAmt = (Qty × UnitPrice) - Disc - RecDisc
|
|
22
|
+
*
|
|
23
|
+
* Generic across both goods and services:
|
|
24
|
+
* For Items (goods): pass UnitPrice = item.UnPr
|
|
25
|
+
* For Ops (services): pass UnitPrice = op.Pr
|
|
26
|
+
*
|
|
27
|
+
* @param input - Line amount fields: Qty, UnitPrice, Disc, RecDisc
|
|
28
|
+
* @returns The net taxable amount
|
|
29
|
+
*
|
|
30
|
+
* @example
|
|
31
|
+
* // Item: 10 units × Rs 500, line discount Rs 200, record discount Rs 100
|
|
32
|
+
* CalculateNetAmt({ Qty: 10, UnitPrice: 500, Disc: 200, RecDisc: 100 });
|
|
33
|
+
* // Returns: 4700 (5000 - 200 - 100)
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* // Op: 2 hours × Rs 1500, no discounts
|
|
37
|
+
* CalculateNetAmt({ Qty: 2, UnitPrice: 1500 });
|
|
38
|
+
* // Returns: 3000
|
|
39
|
+
*/
|
|
40
|
+
export declare function CalculateNetAmt(input: ILineAmountFields): number;
|
|
18
41
|
/**
|
|
19
42
|
* Calculates tax for a single line item based on the provided TaxCode.
|
|
20
43
|
*
|
|
21
44
|
* This is the MAIN function used by the UI when a user selects a tax code
|
|
22
45
|
* and the system needs to compute CGST, SGST, IGST, Cess, etc.
|
|
23
46
|
*
|
|
24
|
-
* @param input - Line item context (
|
|
47
|
+
* @param input - Line item context (Qty, UnitPrice, Disc, RecDisc, TaxCode, RCM flag)
|
|
25
48
|
* @param rounding - Rounding configuration (from TaxRegime.Rounding)
|
|
26
49
|
* @returns Array of ITaxComponent — one entry per tax component
|
|
27
50
|
*
|
|
28
51
|
* @example
|
|
29
|
-
* // India GST 18% Intra-State
|
|
52
|
+
* // India GST 18% Intra-State: 10 units × Rs 500
|
|
30
53
|
* const result = CalculateLineTax({
|
|
31
|
-
*
|
|
54
|
+
* Qty: 10, UnitPrice: 500,
|
|
32
55
|
* TaxCode: gst18IntraTaxCode,
|
|
33
56
|
* });
|
|
34
|
-
* // Returns: [
|
|
57
|
+
* // NetAmt = 5000, Returns: [
|
|
35
58
|
* // { Code: "CGST", Rate: 9, Amt: 450, TaxCodeId: 106 },
|
|
36
59
|
* // { Code: "SGST", Rate: 9, Amt: 450, TaxCodeId: 106 },
|
|
37
60
|
* // ]
|
|
38
61
|
*
|
|
39
62
|
* @example
|
|
40
|
-
* // India GST 28% + Specific Cess (Rs 12/liter) on 100 liters
|
|
63
|
+
* // India GST 28% + Specific Cess (Rs 12/liter) on 100 liters × Rs 100
|
|
41
64
|
* const result = CalculateLineTax({
|
|
42
|
-
*
|
|
43
|
-
* Qty: 100,
|
|
65
|
+
* Qty: 100, UnitPrice: 100,
|
|
44
66
|
* TaxCode: gst28CessDrinkTaxCode,
|
|
45
67
|
* });
|
|
46
|
-
* // Returns: [
|
|
68
|
+
* // NetAmt = 10000, Returns: [
|
|
47
69
|
* // { Code: "CGST", Rate: 14, Amt: 1400, TaxCodeId: 201 },
|
|
48
70
|
* // { Code: "SGST", Rate: 14, Amt: 1400, TaxCodeId: 201 },
|
|
49
71
|
* // { Code: "CESS", Rate: 0, Amt: 1200, TaxCodeId: 201 },
|
|
@@ -103,7 +125,7 @@ export declare function SumTaxComponents(taxes: ITaxComponent[] | undefined | nu
|
|
|
103
125
|
* Computes the document-level TaxSummary by aggregating all line items' Taxes[].
|
|
104
126
|
*
|
|
105
127
|
* This is a PURE FUNCTION — it does not read from database.
|
|
106
|
-
*
|
|
128
|
+
* Computes NetAmt per line internally from Qty/UnitPrice/Disc/RecDisc.
|
|
107
129
|
*
|
|
108
130
|
* Groups tax amounts by Code+Rate (e.g., CGST@9 and CGST@14 are separate buckets).
|
|
109
131
|
* TaxableAmt per bucket = sum of line NetAmt for lines that have that Code+Rate.
|
|
@@ -113,14 +135,14 @@ export declare function SumTaxComponents(taxes: ITaxComponent[] | undefined | nu
|
|
|
113
135
|
* - TaxComponentTotal ON: each bucket's Amt is rounded to Precision
|
|
114
136
|
* - Otherwise: Amts are at currency precision (from CalculateLineTax)
|
|
115
137
|
*
|
|
116
|
-
* @param input - All line items with Taxes[]
|
|
138
|
+
* @param input - All line items with Qty/UnitPrice/Disc/RecDisc and Taxes[], plus regime code and optional rounding
|
|
117
139
|
* @returns ITaxSummary — the aggregated summary (stored on the document)
|
|
118
140
|
*
|
|
119
141
|
* @example
|
|
120
142
|
* const summary = ComputeTaxSummary({
|
|
121
143
|
* Lines: invoice.Items.map(item => ({
|
|
144
|
+
* Qty: item.Qty, UnitPrice: item.UnPr, Disc: item.Disc, RecDisc: item.RecDisc,
|
|
122
145
|
* Taxes: item.Taxes,
|
|
123
|
-
* NetAmt: item.UnAmt - item.Disc - item.RecDisc,
|
|
124
146
|
* })),
|
|
125
147
|
* RegimeCode: "IN_GST",
|
|
126
148
|
* Rounding: { Method: "Round", Precision: 0, TaxComponentTotal: true },
|
|
@@ -155,17 +177,19 @@ export declare function ComputeTaxSummary(input: ITaxSummaryInput): ITaxSummary;
|
|
|
155
177
|
* The caller applies those after this function returns:
|
|
156
178
|
* FinalPayable = Total + Adjust - Withholding.Amt
|
|
157
179
|
*
|
|
158
|
-
* @param input - Line items with
|
|
180
|
+
* @param input - Line items with Qty/UnitPrice/Disc/RecDisc and Taxes[], plus RoundingConfig
|
|
159
181
|
* @returns IDocumentTotals — all stored financial fields
|
|
160
182
|
*
|
|
161
183
|
* @example
|
|
162
184
|
* // India GST invoice with 2 lines
|
|
163
185
|
* const totals = ComputeDocumentTotals({
|
|
164
186
|
* Lines: [
|
|
165
|
-
* {
|
|
166
|
-
*
|
|
167
|
-
*
|
|
168
|
-
*
|
|
187
|
+
* { Qty: 10, UnitPrice: 500,
|
|
188
|
+
* Taxes: [{ Code: "CGST", Rate: 9, Amt: 450, TaxCodeId: 1 },
|
|
189
|
+
* { Code: "SGST", Rate: 9, Amt: 450, TaxCodeId: 1 }] },
|
|
190
|
+
* { Qty: 6, UnitPrice: 500,
|
|
191
|
+
* Taxes: [{ Code: "CGST", Rate: 9, Amt: 270, TaxCodeId: 1 },
|
|
192
|
+
* { Code: "SGST", Rate: 9, Amt: 270, TaxCodeId: 1 }] },
|
|
169
193
|
* ],
|
|
170
194
|
* Rounding: { Method: "Round", Precision: 0, TaxComponentTotal: true, DocTotal: true },
|
|
171
195
|
* RegimeCode: "IN_GST",
|
|
@@ -19,6 +19,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
19
19
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
20
20
|
};
|
|
21
21
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
22
|
+
exports.CalculateNetAmt = CalculateNetAmt;
|
|
22
23
|
exports.CalculateLineTax = CalculateLineTax;
|
|
23
24
|
exports.ExtractNetFromInclusive = ExtractNetFromInclusive;
|
|
24
25
|
exports.SumTaxComponents = SumTaxComponents;
|
|
@@ -37,6 +38,42 @@ const big_js_1 = __importDefault(require("big.js"));
|
|
|
37
38
|
const util_1 = require("../shared/util");
|
|
38
39
|
const math_operations_1 = require("../shared/math-operations");
|
|
39
40
|
// ============================================================
|
|
41
|
+
// Net Amount Calculation
|
|
42
|
+
// ============================================================
|
|
43
|
+
/**
|
|
44
|
+
* Computes the net taxable amount from line item fields.
|
|
45
|
+
*
|
|
46
|
+
* Formula: NetAmt = (Qty × UnitPrice) - Disc - RecDisc
|
|
47
|
+
*
|
|
48
|
+
* Generic across both goods and services:
|
|
49
|
+
* For Items (goods): pass UnitPrice = item.UnPr
|
|
50
|
+
* For Ops (services): pass UnitPrice = op.Pr
|
|
51
|
+
*
|
|
52
|
+
* @param input - Line amount fields: Qty, UnitPrice, Disc, RecDisc
|
|
53
|
+
* @returns The net taxable amount
|
|
54
|
+
*
|
|
55
|
+
* @example
|
|
56
|
+
* // Item: 10 units × Rs 500, line discount Rs 200, record discount Rs 100
|
|
57
|
+
* CalculateNetAmt({ Qty: 10, UnitPrice: 500, Disc: 200, RecDisc: 100 });
|
|
58
|
+
* // Returns: 4700 (5000 - 200 - 100)
|
|
59
|
+
*
|
|
60
|
+
* @example
|
|
61
|
+
* // Op: 2 hours × Rs 1500, no discounts
|
|
62
|
+
* CalculateNetAmt({ Qty: 2, UnitPrice: 1500 });
|
|
63
|
+
* // Returns: 3000
|
|
64
|
+
*/
|
|
65
|
+
function CalculateNetAmt(input) {
|
|
66
|
+
const grossAmt = (0, math_operations_1.Multiply)((0, util_1.GetNumber)(input.Qty), (0, util_1.GetNumber)(input.UnitPrice));
|
|
67
|
+
let netAmt = grossAmt;
|
|
68
|
+
if (input.Disc) {
|
|
69
|
+
netAmt = (0, math_operations_1.Subtract)(netAmt, (0, util_1.GetNumber)(input.Disc));
|
|
70
|
+
}
|
|
71
|
+
if (input.RecDisc) {
|
|
72
|
+
netAmt = (0, math_operations_1.Subtract)(netAmt, (0, util_1.GetNumber)(input.RecDisc));
|
|
73
|
+
}
|
|
74
|
+
return netAmt;
|
|
75
|
+
}
|
|
76
|
+
// ============================================================
|
|
40
77
|
// Core Tax Calculation
|
|
41
78
|
// ============================================================
|
|
42
79
|
/**
|
|
@@ -45,29 +82,28 @@ const math_operations_1 = require("../shared/math-operations");
|
|
|
45
82
|
* This is the MAIN function used by the UI when a user selects a tax code
|
|
46
83
|
* and the system needs to compute CGST, SGST, IGST, Cess, etc.
|
|
47
84
|
*
|
|
48
|
-
* @param input - Line item context (
|
|
85
|
+
* @param input - Line item context (Qty, UnitPrice, Disc, RecDisc, TaxCode, RCM flag)
|
|
49
86
|
* @param rounding - Rounding configuration (from TaxRegime.Rounding)
|
|
50
87
|
* @returns Array of ITaxComponent — one entry per tax component
|
|
51
88
|
*
|
|
52
89
|
* @example
|
|
53
|
-
* // India GST 18% Intra-State
|
|
90
|
+
* // India GST 18% Intra-State: 10 units × Rs 500
|
|
54
91
|
* const result = CalculateLineTax({
|
|
55
|
-
*
|
|
92
|
+
* Qty: 10, UnitPrice: 500,
|
|
56
93
|
* TaxCode: gst18IntraTaxCode,
|
|
57
94
|
* });
|
|
58
|
-
* // Returns: [
|
|
95
|
+
* // NetAmt = 5000, Returns: [
|
|
59
96
|
* // { Code: "CGST", Rate: 9, Amt: 450, TaxCodeId: 106 },
|
|
60
97
|
* // { Code: "SGST", Rate: 9, Amt: 450, TaxCodeId: 106 },
|
|
61
98
|
* // ]
|
|
62
99
|
*
|
|
63
100
|
* @example
|
|
64
|
-
* // India GST 28% + Specific Cess (Rs 12/liter) on 100 liters
|
|
101
|
+
* // India GST 28% + Specific Cess (Rs 12/liter) on 100 liters × Rs 100
|
|
65
102
|
* const result = CalculateLineTax({
|
|
66
|
-
*
|
|
67
|
-
* Qty: 100,
|
|
103
|
+
* Qty: 100, UnitPrice: 100,
|
|
68
104
|
* TaxCode: gst28CessDrinkTaxCode,
|
|
69
105
|
* });
|
|
70
|
-
* // Returns: [
|
|
106
|
+
* // NetAmt = 10000, Returns: [
|
|
71
107
|
* // { Code: "CGST", Rate: 14, Amt: 1400, TaxCodeId: 201 },
|
|
72
108
|
* // { Code: "SGST", Rate: 14, Amt: 1400, TaxCodeId: 201 },
|
|
73
109
|
* // { Code: "CESS", Rate: 0, Amt: 1200, TaxCodeId: 201 },
|
|
@@ -75,7 +111,7 @@ const math_operations_1 = require("../shared/math-operations");
|
|
|
75
111
|
*/
|
|
76
112
|
function CalculateLineTax(input, rounding = { Method: "Round", Precision: 2 }) {
|
|
77
113
|
const { TaxCode, RCM, ComponentOverrides } = input;
|
|
78
|
-
const netAmt = (
|
|
114
|
+
const netAmt = CalculateNetAmt(input);
|
|
79
115
|
const qty = (0, util_1.GetNumber)(input.Qty, 1);
|
|
80
116
|
// Exempt / Nil / NonTaxable — no components
|
|
81
117
|
if (!TaxCode.Components || TaxCode.Components.length === 0) {
|
|
@@ -300,7 +336,7 @@ function SumTaxComponents(taxes) {
|
|
|
300
336
|
* Computes the document-level TaxSummary by aggregating all line items' Taxes[].
|
|
301
337
|
*
|
|
302
338
|
* This is a PURE FUNCTION — it does not read from database.
|
|
303
|
-
*
|
|
339
|
+
* Computes NetAmt per line internally from Qty/UnitPrice/Disc/RecDisc.
|
|
304
340
|
*
|
|
305
341
|
* Groups tax amounts by Code+Rate (e.g., CGST@9 and CGST@14 are separate buckets).
|
|
306
342
|
* TaxableAmt per bucket = sum of line NetAmt for lines that have that Code+Rate.
|
|
@@ -310,14 +346,14 @@ function SumTaxComponents(taxes) {
|
|
|
310
346
|
* - TaxComponentTotal ON: each bucket's Amt is rounded to Precision
|
|
311
347
|
* - Otherwise: Amts are at currency precision (from CalculateLineTax)
|
|
312
348
|
*
|
|
313
|
-
* @param input - All line items with Taxes[]
|
|
349
|
+
* @param input - All line items with Qty/UnitPrice/Disc/RecDisc and Taxes[], plus regime code and optional rounding
|
|
314
350
|
* @returns ITaxSummary — the aggregated summary (stored on the document)
|
|
315
351
|
*
|
|
316
352
|
* @example
|
|
317
353
|
* const summary = ComputeTaxSummary({
|
|
318
354
|
* Lines: invoice.Items.map(item => ({
|
|
355
|
+
* Qty: item.Qty, UnitPrice: item.UnPr, Disc: item.Disc, RecDisc: item.RecDisc,
|
|
319
356
|
* Taxes: item.Taxes,
|
|
320
|
-
* NetAmt: item.UnAmt - item.Disc - item.RecDisc,
|
|
321
357
|
* })),
|
|
322
358
|
* RegimeCode: "IN_GST",
|
|
323
359
|
* Rounding: { Method: "Round", Precision: 0, TaxComponentTotal: true },
|
|
@@ -340,7 +376,7 @@ function ComputeTaxSummary(input) {
|
|
|
340
376
|
for (const line of Lines) {
|
|
341
377
|
if (!line.Taxes || line.Taxes.length === 0)
|
|
342
378
|
continue;
|
|
343
|
-
const lineNetAmt = (
|
|
379
|
+
const lineNetAmt = CalculateNetAmt(line);
|
|
344
380
|
// Track this line's taxable amount at document level (once per line, not per component)
|
|
345
381
|
totalTaxable = (0, math_operations_1.Add)(totalTaxable, lineNetAmt);
|
|
346
382
|
// Track which Code+Rate buckets we've already added this line's NetAmt to
|
|
@@ -411,17 +447,19 @@ function ComputeTaxSummary(input) {
|
|
|
411
447
|
* The caller applies those after this function returns:
|
|
412
448
|
* FinalPayable = Total + Adjust - Withholding.Amt
|
|
413
449
|
*
|
|
414
|
-
* @param input - Line items with
|
|
450
|
+
* @param input - Line items with Qty/UnitPrice/Disc/RecDisc and Taxes[], plus RoundingConfig
|
|
415
451
|
* @returns IDocumentTotals — all stored financial fields
|
|
416
452
|
*
|
|
417
453
|
* @example
|
|
418
454
|
* // India GST invoice with 2 lines
|
|
419
455
|
* const totals = ComputeDocumentTotals({
|
|
420
456
|
* Lines: [
|
|
421
|
-
* {
|
|
422
|
-
*
|
|
423
|
-
*
|
|
424
|
-
*
|
|
457
|
+
* { Qty: 10, UnitPrice: 500,
|
|
458
|
+
* Taxes: [{ Code: "CGST", Rate: 9, Amt: 450, TaxCodeId: 1 },
|
|
459
|
+
* { Code: "SGST", Rate: 9, Amt: 450, TaxCodeId: 1 }] },
|
|
460
|
+
* { Qty: 6, UnitPrice: 500,
|
|
461
|
+
* Taxes: [{ Code: "CGST", Rate: 9, Amt: 270, TaxCodeId: 1 },
|
|
462
|
+
* { Code: "SGST", Rate: 9, Amt: 270, TaxCodeId: 1 }] },
|
|
425
463
|
* ],
|
|
426
464
|
* Rounding: { Method: "Round", Precision: 0, TaxComponentTotal: true, DocTotal: true },
|
|
427
465
|
* RegimeCode: "IN_GST",
|
|
@@ -437,10 +475,10 @@ function ComputeTaxSummary(input) {
|
|
|
437
475
|
*/
|
|
438
476
|
function ComputeDocumentTotals(input) {
|
|
439
477
|
const { Lines, Rounding, RegimeCode } = input;
|
|
440
|
-
// 1. SubTotal = sum of line NetAmts
|
|
478
|
+
// 1. SubTotal = sum of line NetAmts (computed from Qty × UnitPrice - Disc - RecDisc)
|
|
441
479
|
let subTotal = 0;
|
|
442
480
|
for (const line of Lines) {
|
|
443
|
-
subTotal = (0, math_operations_1.Add)(subTotal, (
|
|
481
|
+
subTotal = (0, math_operations_1.Add)(subTotal, CalculateNetAmt(line));
|
|
444
482
|
}
|
|
445
483
|
// 2. TaxSummary (handles TaxComponentTotal rounding internally)
|
|
446
484
|
const taxSummary = ComputeTaxSummary({
|
package/dist/tax/tax.types.d.ts
CHANGED
|
@@ -235,12 +235,26 @@ export interface IComponentOverride {
|
|
|
235
235
|
PerUnitAmt?: number;
|
|
236
236
|
Unit?: string;
|
|
237
237
|
}
|
|
238
|
+
/**
|
|
239
|
+
* Base fields for computing taxable amount (NetAmt) from line item quantities and prices.
|
|
240
|
+
* NetAmt = (Qty × UnitPrice) - Disc - RecDisc
|
|
241
|
+
*
|
|
242
|
+
* Generic across both goods and services:
|
|
243
|
+
* For Items (goods): UnitPrice maps to UnPr (unit price)
|
|
244
|
+
* For Ops (services): UnitPrice maps to Pr (operation rate)
|
|
245
|
+
*/
|
|
246
|
+
export interface ILineAmountFields {
|
|
247
|
+
/** Quantity */
|
|
248
|
+
Qty: number;
|
|
249
|
+
/** Unit price — Items: UnPr, Ops: Pr */
|
|
250
|
+
UnitPrice: number;
|
|
251
|
+
/** Line-level discount amount */
|
|
252
|
+
Disc?: number;
|
|
253
|
+
/** Record-level (document-level) discount allocated to this line */
|
|
254
|
+
RecDisc?: number;
|
|
255
|
+
}
|
|
238
256
|
/** Input context for calculating tax on a single line item */
|
|
239
|
-
export interface ITaxCalcLineInput {
|
|
240
|
-
/** Net amount after discounts (taxable value) */
|
|
241
|
-
NetAmt: number;
|
|
242
|
-
/** Quantity — needed for PerUnit calculations (excise, specific cess) */
|
|
243
|
-
Qty?: number;
|
|
257
|
+
export interface ITaxCalcLineInput extends ILineAmountFields {
|
|
244
258
|
/** The TaxCode to apply */
|
|
245
259
|
TaxCode: ITaxCode;
|
|
246
260
|
/** Is this a reverse charge line? */
|
|
@@ -264,14 +278,12 @@ export interface ITaxCalcLineInput {
|
|
|
264
278
|
/** Input context for computing document-level TaxSummary.
|
|
265
279
|
*
|
|
266
280
|
* Since TaxableAmt is NOT stored on TaxComponent (it's derivable from line item fields),
|
|
267
|
-
* each line
|
|
268
|
-
* This is a pure function — caller derives NetAmt from line item fields and passes it in.
|
|
281
|
+
* each line provides Qty/UnitPrice/Disc/RecDisc and shareneus computes NetAmt internally.
|
|
269
282
|
*/
|
|
270
283
|
export interface ITaxSummaryInput {
|
|
271
|
-
/** All line items with
|
|
272
|
-
Lines: Array<{
|
|
284
|
+
/** All line items with amount fields and calculated Taxes[] arrays */
|
|
285
|
+
Lines: Array<ILineAmountFields & {
|
|
273
286
|
Taxes?: ITaxComponent[];
|
|
274
|
-
NetAmt: number;
|
|
275
287
|
}>;
|
|
276
288
|
/** Tax regime code for the snapshot */
|
|
277
289
|
RegimeCode?: string;
|
|
@@ -303,9 +315,8 @@ export interface IRoundingConfig {
|
|
|
303
315
|
}
|
|
304
316
|
/** Input for computing all document-level totals in one call */
|
|
305
317
|
export interface IDocumentTotalsInput {
|
|
306
|
-
/** All line items
|
|
307
|
-
Lines: Array<{
|
|
308
|
-
NetAmt: number;
|
|
318
|
+
/** All line items with amount fields (Qty, UnitPrice, Disc, RecDisc) and Taxes[] */
|
|
319
|
+
Lines: Array<ILineAmountFields & {
|
|
309
320
|
Taxes?: ITaxComponent[];
|
|
310
321
|
}>;
|
|
311
322
|
/** Rounding configuration (from TaxRegime.Rounding or Entity Settings) */
|