shareneus 1.4.95 → 1.4.97

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.
@@ -0,0 +1,573 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SalesReceiveTotalsService = void 0;
4
+ const tr_utils_1 = require("../utils/tr-utils");
5
+ const aggregation_1 = require("../aggregation/aggregation");
6
+ /**
7
+ * Service class for calculating sales receive totals including taxes, discounts and final amounts
8
+ */
9
+ class SalesReceiveTotalsService {
10
+ /**
11
+ * Main method to calculate totals for sales receive operations
12
+ * @param opCodesList - Array of operation codes/labor items
13
+ * @param PartsList - Array of parts/items to be processed
14
+ * @param IsIndependentTax - Whether tax is calculated independently
15
+ * @param DetailedInfo - Whether to include detailed breakdown information
16
+ * @param Disc - Discount amount
17
+ * @param Perc - Discount percentage
18
+ * @param TaxCodes - Available tax codes for GST calculations
19
+ * @param WithItems - Whether to include items in the response
20
+ * @param Settings - General settings object
21
+ * @param EntitySettings - Entity-specific settings including decimal places
22
+ * @returns Object containing calculated totals and breakdown information
23
+ */
24
+ static GetTotalsValue(opCodesList, PartsList, IsIndependentTax, DetailedInfo, Disc, Perc, TaxCodes, WithItems, Settings, EntitySettings = {}) {
25
+ // Sanitize input parameters to ensure valid values
26
+ Perc = tr_utils_1.TrUtils.SetPercToStringIfNull(Perc);
27
+ Disc = tr_utils_1.TrUtils.SetValueToZeroIfNull(Disc);
28
+ // Calculate labor part values with tax considerations
29
+ PartsList = this.CalculateLaborPartValues(PartsList, IsIndependentTax);
30
+ // Get the main totals data
31
+ let finalTotalsData = this.GetFinalRODataForSave(opCodesList, PartsList, IsIndependentTax, Disc, Perc, DetailedInfo, Settings, EntitySettings.DecimalsNumber);
32
+ // Add detailed breakdown if requested
33
+ if (DetailedInfo) {
34
+ finalTotalsData = this.GetDetailedTotalsData(finalTotalsData, IsIndependentTax, opCodesList, PartsList, TaxCodes, EntitySettings.DecimalsNumber);
35
+ }
36
+ // Include items in response if requested
37
+ if (WithItems) {
38
+ finalTotalsData.Items = PartsList;
39
+ }
40
+ return finalTotalsData;
41
+ }
42
+ /**
43
+ * Calculates labor part values including discounts and taxes
44
+ * @param PartsList - Array of parts to be processed
45
+ * @param IsIndependentTax - Whether tax is calculated independently
46
+ * @returns Processed parts list with calculated values
47
+ */
48
+ static CalculateLaborPartValues(PartsList, IsIndependentTax) {
49
+ PartsList = this.ResetLaborPartValues(PartsList, IsIndependentTax);
50
+ return PartsList;
51
+ }
52
+ /**
53
+ * Resets and recalculates labor part values including discounts and taxes
54
+ * @param PartsList - Array of parts to be processed
55
+ * @param IsIndependentTax - Whether tax is calculated independently
56
+ * @returns Parts list with reset and recalculated values
57
+ */
58
+ static ResetLaborPartValues(PartsList, IsIndependentTax) {
59
+ PartsList.forEach((Part) => {
60
+ // Reset invalid values to defaults
61
+ Part = this.ResetLaborPartValueIfInvalid(Part);
62
+ // Set minimum quantity to 1 if zero
63
+ if (tr_utils_1.TrUtils.IsZero(Part.Qty)) {
64
+ Part.Qty = 1;
65
+ }
66
+ // Calculate total discounted price
67
+ Part.DiscountedPrice = (0, aggregation_1.addition)(Part.Disc, Part.RecDisc);
68
+ // Calculate amount after discount
69
+ Part.AfterPartDisc = (0, aggregation_1.subtraction)(Part.UnAmt, Part.Disc, Part.RecDisc);
70
+ // Calculate amount after tax based on tax type
71
+ if (IsIndependentTax) {
72
+ Part.AfterPartTax = (0, aggregation_1.addition)(Part.AfterPartDisc, Part.CGST, Part.SGST, Part.IGST);
73
+ }
74
+ else {
75
+ Part.AfterPartTax = Part.AfterPartDisc;
76
+ }
77
+ });
78
+ return PartsList;
79
+ }
80
+ /**
81
+ * Resets part values to zero if they are null or invalid
82
+ * @param Part - Individual part item to reset
83
+ * @returns Part with reset values
84
+ */
85
+ static ResetLaborPartValueIfInvalid(Part) {
86
+ Part.UnPr = tr_utils_1.TrUtils.SetValueToZeroIfNull(Part.UnPr);
87
+ Part.Disc = tr_utils_1.TrUtils.SetValueToZeroIfNull(Part.Disc);
88
+ Part.RecDisc = tr_utils_1.TrUtils.SetValueToZeroIfNull(Part.RecDisc);
89
+ Part.CGST = tr_utils_1.TrUtils.SetValueToZeroIfNull(Part.CGST);
90
+ Part.SGST = tr_utils_1.TrUtils.SetValueToZeroIfNull(Part.SGST);
91
+ Part.IGST = tr_utils_1.TrUtils.SetValueToZeroIfNull(Part.IGST);
92
+ return Part;
93
+ }
94
+ /**
95
+ * Prepares final repair order data for saving with calculated totals
96
+ * @param LaborList - Array of labor items
97
+ * @param PartsList - Array of parts
98
+ * @param IsIndependentTax - Whether tax is calculated independently
99
+ * @param Disc - Discount amount
100
+ * @param Perc - Discount percentage
101
+ * @param DetailedInfo - Whether to include detailed information
102
+ * @param Settings - General settings
103
+ * @param DecimalsNumber - Number of decimal places for calculations
104
+ * @returns Final totals data object ready for saving
105
+ */
106
+ static GetFinalRODataForSave(LaborList, PartsList, IsIndependentTax, Disc, Perc, DetailedInfo, Settings, DecimalsNumber) {
107
+ let finalTotalsData = {};
108
+ // Set discount values
109
+ finalTotalsData = this.SetMainDiscountValues(Disc, Perc, finalTotalsData, DetailedInfo);
110
+ // Add settings to response
111
+ finalTotalsData.Settings = Settings;
112
+ // Calculate customer totals
113
+ finalTotalsData = this.GetFinalCustomerTotalsData(finalTotalsData, [], PartsList, IsIndependentTax, DetailedInfo, DecimalsNumber);
114
+ return finalTotalsData;
115
+ }
116
+ /**
117
+ * Sets main discount values in the totals data object
118
+ * @param Disc - Discount amount
119
+ * @param Perc - Discount percentage
120
+ * @param finalTotalsData - Totals data object to update
121
+ * @param DetailedInfo - Whether to include detailed information
122
+ * @returns Updated totals data with discount values
123
+ */
124
+ static SetMainDiscountValues(Disc, Perc, finalTotalsData, DetailedInfo) {
125
+ finalTotalsData.Disc = Disc;
126
+ finalTotalsData.Perc = Perc;
127
+ if (DetailedInfo) {
128
+ finalTotalsData.FixedDisc = Disc;
129
+ }
130
+ return finalTotalsData;
131
+ }
132
+ /**
133
+ * Calculates final customer totals including subtotals, taxes, and rounded amounts
134
+ * @param finalTotalsData - Existing totals data object
135
+ * @param LaborList - Array of labor items
136
+ * @param PartsList - Array of parts
137
+ * @param IsIndependentTax - Whether tax is calculated independently
138
+ * @param DetailedInfo - Whether to include detailed information
139
+ * @param DecimalsNumber - Number of decimal places for calculations
140
+ * @returns Updated totals data with customer calculations
141
+ */
142
+ static GetFinalCustomerTotalsData(finalTotalsData, LaborList, PartsList, IsIndependentTax, DetailedInfo, DecimalsNumber = 2) {
143
+ // Calculate subtotal after discounts
144
+ let CustomerAfterDiscTotals = this.GetSubTotalFor([], PartsList);
145
+ // Calculate parts tax total
146
+ let CustPartTaxTotal = this.GetPartsTaxTotalFor(PartsList, IsIndependentTax);
147
+ // Set subtotal with proper decimal formatting
148
+ finalTotalsData.SubTotal = tr_utils_1.TrUtils.FixedTo(CustomerAfterDiscTotals, DecimalsNumber);
149
+ // Calculate discount totals
150
+ let CustPartsDiscTotal = this.GetPartDiscountedTotal(PartsList, IsIndependentTax, finalTotalsData);
151
+ let CustPartsTotalAfterDisc = this.GetPartsTotalAfterDiscount(PartsList);
152
+ // Calculate sum total
153
+ finalTotalsData.STotal = (0, aggregation_1.addition)(CustPartsDiscTotal, CustPartsTotalAfterDisc);
154
+ // Calculate final customer total
155
+ let CustTotal = this.GetCustomerTotalBasedOnTaxType(finalTotalsData, 0, CustPartTaxTotal, [], PartsList, IsIndependentTax);
156
+ // Calculate rounding difference and final total
157
+ finalTotalsData.Round = (0, aggregation_1.subtraction)(Math.round(CustTotal), CustTotal);
158
+ finalTotalsData.Total = Math.round(CustTotal);
159
+ // Add detailed information if requested
160
+ if (DetailedInfo) {
161
+ finalTotalsData.FixedSubTotal = tr_utils_1.TrUtils.FixedTo(CustomerAfterDiscTotals, DecimalsNumber);
162
+ finalTotalsData.FixedTotal = tr_utils_1.TrUtils.FixedTo(CustTotal, DecimalsNumber);
163
+ }
164
+ return finalTotalsData;
165
+ }
166
+ /**
167
+ * Calculates subtotal for labor and parts combined
168
+ * @param LaborList - Array of labor items
169
+ * @param PartsList - Array of parts
170
+ * @returns Calculated subtotal amount
171
+ */
172
+ static GetSubTotalFor(LaborList, PartsList) {
173
+ let PartsTotalAfterDisc = this.GetPartsTotalAfterDiscount(PartsList);
174
+ return PartsTotalAfterDisc;
175
+ }
176
+ /**
177
+ * Calculates total amount for parts after applying discounts
178
+ * @param PartsList - Array of parts
179
+ * @returns Total parts amount after discounts
180
+ */
181
+ static GetPartsTotalAfterDiscount(PartsList) {
182
+ let PartsTotalAfterDisc = 0;
183
+ PartsList.forEach((Part) => {
184
+ PartsTotalAfterDisc = (0, aggregation_1.addition)(PartsTotalAfterDisc, Part.AfterPartDisc);
185
+ });
186
+ return PartsTotalAfterDisc;
187
+ }
188
+ /**
189
+ * Generates detailed totals data including tax breakdowns and groupings
190
+ * @param finalTotalsData - Existing totals data
191
+ * @param IsIndependentTax - Whether tax is calculated independently
192
+ * @param opCodesList - Array of operation codes
193
+ * @param PartsList - Array of parts
194
+ * @param TaxCodes - Available tax codes
195
+ * @param DecimalsNumber - Number of decimal places
196
+ * @returns Enhanced totals data with detailed breakdowns
197
+ */
198
+ static GetDetailedTotalsData(finalTotalsData, IsIndependentTax, opCodesList, PartsList, TaxCodes, DecimalsNumber = 2) {
199
+ // Add parts discount and total information
200
+ finalTotalsData.CustPartsDiscTotal = this.GetPartDiscountedTotal(PartsList, IsIndependentTax, finalTotalsData);
201
+ finalTotalsData.CustPartsTotalAfterDisc = this.GetPartsTotalAfterDiscount(PartsList);
202
+ finalTotalsData.CustPartsTotalBeforeDisc = (0, aggregation_1.addition)(finalTotalsData.CustPartsTotalAfterDisc, finalTotalsData.CustPartsDiscTotal);
203
+ // Get GST tax breakdown
204
+ let TaxInfo = this.GetPartGSTTaxTotal(PartsList, IsIndependentTax);
205
+ finalTotalsData.CustPartITax = tr_utils_1.TrUtils.SetValueToZeroIfNull(TaxInfo[3]);
206
+ finalTotalsData.CustPartCGST = tr_utils_1.TrUtils.SetValueToZeroIfNull(TaxInfo[0]);
207
+ finalTotalsData.CustPartIGST = tr_utils_1.TrUtils.SetValueToZeroIfNull(TaxInfo[2]);
208
+ finalTotalsData.CustPartSGST = tr_utils_1.TrUtils.SetValueToZeroIfNull(TaxInfo[1]);
209
+ // Calculate after tax amount
210
+ finalTotalsData.CustPartAfterTax = (0, aggregation_1.addition)(finalTotalsData.CustPartITax, finalTotalsData.CustPartsTotalAfterDisc);
211
+ // Add tax grouping information
212
+ finalTotalsData.CustTaxGroupData = this.GetTaxGroupingForPartsByHSN(tr_utils_1.TrUtils.Stringify(PartsList), TaxCodes, DecimalsNumber);
213
+ finalTotalsData.CustTaxGroupDataByPerc = this.GetTaxGroupingForPartsByPerc(PartsList, TaxCodes, DecimalsNumber);
214
+ // Add rounding information
215
+ finalTotalsData.CustTotalRoundedBy = tr_utils_1.TrUtils.FixedTo(finalTotalsData.Round, DecimalsNumber);
216
+ finalTotalsData.CustRoundedTotal = tr_utils_1.TrUtils.FixedTo(finalTotalsData.Total, DecimalsNumber);
217
+ // Format all numeric values to proper decimal places
218
+ for (var key in finalTotalsData) {
219
+ if (key !== 'Total' && key !== 'SubTotal' &&
220
+ key !== 'LDisc' && key !== 'LPerc' && key !== 'PDisc' &&
221
+ key !== 'PPerc' && key !== 'Disc' && key !== 'Perc' && key !== 'Tax'
222
+ && typeof finalTotalsData[key] === 'number') {
223
+ finalTotalsData[key] = tr_utils_1.TrUtils.FixPriceValue(finalTotalsData[key], DecimalsNumber);
224
+ }
225
+ }
226
+ return finalTotalsData;
227
+ }
228
+ /**
229
+ * Groups parts by tax percentage for consolidated tax reporting
230
+ * @param Parts - Array of parts to group
231
+ * @param TaxCodes - Available tax codes
232
+ * @param DecimalsNumber - Number of decimal places
233
+ * @returns Array of parts grouped by tax percentage
234
+ */
235
+ static GetTaxGroupingForPartsByPerc(Parts, TaxCodes, DecimalsNumber) {
236
+ // Add combined tax percentage to each part
237
+ Parts = this.GetCombinedTaxPercentage(tr_utils_1.TrUtils.Stringify(Parts), TaxCodes);
238
+ // Group parts with same tax percentages
239
+ let FinalMatchedParts = this.ComparePartsByPerc(Parts, TaxCodes);
240
+ // Generate tax grouping information
241
+ return this.GetTaxGroupingInfoByHSN(FinalMatchedParts, TaxCodes, DecimalsNumber);
242
+ }
243
+ /**
244
+ * Compares and groups parts by tax percentage rates
245
+ * @param Parts - Array of parts to compare
246
+ * @param TaxCodes - Available tax codes
247
+ * @returns Array of grouped parts with same tax percentages
248
+ */
249
+ static ComparePartsByPerc(Parts, TaxCodes) {
250
+ let FinalMatchedParts = [];
251
+ Parts === null || Parts === void 0 ? void 0 : Parts.forEach((Part) => {
252
+ // Find parts with matching tax amounts that haven't been grouped yet
253
+ let MatchedPartsBasedOnHSN = Parts.filter((argPart) => {
254
+ let PartFound = false;
255
+ // Check if part is already in a group
256
+ FinalMatchedParts.forEach((FinalArgParts) => {
257
+ let PartIndex = FinalArgParts.findIndex((FinalArgPart) => {
258
+ return FinalArgPart._id === argPart._id;
259
+ });
260
+ if (PartIndex !== -1) {
261
+ PartFound = true;
262
+ }
263
+ });
264
+ // Return parts with same tax percentages that aren't already grouped
265
+ return (!PartFound) &&
266
+ (argPart.CGSTAmt === Part.CGSTAmt) && (argPart.IGSTAmt === Part.IGSTAmt) &&
267
+ (argPart.SGSTAmt === Part.SGSTAmt);
268
+ });
269
+ // Add group if it contains parts
270
+ if (MatchedPartsBasedOnHSN.length !== 0) {
271
+ FinalMatchedParts.push(MatchedPartsBasedOnHSN);
272
+ }
273
+ });
274
+ return FinalMatchedParts;
275
+ }
276
+ /**
277
+ * Calculates total discounted amount for all parts
278
+ * @param PartsList - Array of parts
279
+ * @param isTaxable - Whether parts are taxable
280
+ * @param finalTotalsData - Existing totals data
281
+ * @returns Total discounted amount including overall part discount
282
+ */
283
+ static GetPartDiscountedTotal(PartsList, isTaxable, finalTotalsData) {
284
+ let PartsDiscountedTotal = 0;
285
+ let overallPartDisc = 0;
286
+ // Add overall part discount if not taxable
287
+ if (!isTaxable) {
288
+ overallPartDisc = tr_utils_1.TrUtils.SetValueToZeroIfNull(finalTotalsData.PDisc);
289
+ }
290
+ // Sum up individual part discounts
291
+ PartsList.forEach((Part) => {
292
+ PartsDiscountedTotal = (0, aggregation_1.addition)(PartsDiscountedTotal, Part.DiscountedPrice);
293
+ });
294
+ return (0, aggregation_1.addition)(PartsDiscountedTotal, overallPartDisc);
295
+ }
296
+ /**
297
+ * Calculates total tax amount for all parts
298
+ * @param PartsList - Array of parts
299
+ * @param IsIndependentTax - Whether tax is calculated independently
300
+ * @returns Total tax amount for all parts
301
+ */
302
+ static GetPartsTaxTotalFor(PartsList, IsIndependentTax) {
303
+ let TotalTaxAmt = 0;
304
+ if (IsIndependentTax) {
305
+ PartsList.forEach((Part) => {
306
+ TotalTaxAmt = (0, aggregation_1.addition)(TotalTaxAmt, Part.CGST, Part.SGST, Part.IGST);
307
+ });
308
+ }
309
+ return TotalTaxAmt;
310
+ }
311
+ /**
312
+ * Calculates customer total based on tax calculation type
313
+ * @param finalTotalsData - Existing totals data
314
+ * @param LaborTaxAmount - Total labor tax amount
315
+ * @param PartsTaxAmount - Total parts tax amount
316
+ * @param LaborList - Array of labor items
317
+ * @param PartsList - Array of parts
318
+ * @param IsIndependentTax - Whether tax is calculated independently
319
+ * @returns Final customer total based on tax type
320
+ */
321
+ static GetCustomerTotalBasedOnTaxType(finalTotalsData, LaborTaxAmount, PartsTaxAmount, LaborList, PartsList, IsIndependentTax) {
322
+ let PartsTotalAfterDisc = this.GetPartsTotalAfterDiscount(PartsList);
323
+ if (IsIndependentTax) {
324
+ // Add tax amounts to the total
325
+ return (0, aggregation_1.addition)(PartsTotalAfterDisc, LaborTaxAmount, PartsTaxAmount);
326
+ }
327
+ else {
328
+ // Subtract discount from the total
329
+ return (0, aggregation_1.subtraction)(PartsTotalAfterDisc, finalTotalsData.Disc);
330
+ }
331
+ }
332
+ /**
333
+ * Calculates items total after applying discounts (percentage or fixed)
334
+ * @param PartsTotalAfterDisc - Parts total after discount
335
+ * @param PartsTaxAmount - Parts tax amount
336
+ * @param MainPDisc - Main parts discount amount
337
+ * @param PDiscInPerc - Parts discount percentage
338
+ * @returns Final items total after all discounts
339
+ */
340
+ static ItemsTotalAfterDiscount(PartsTotalAfterDisc, PartsTaxAmount, MainPDisc, PDiscInPerc) {
341
+ let ItemsTotal = (0, aggregation_1.addition)(PartsTotalAfterDisc, PartsTaxAmount);
342
+ // Apply discount if present
343
+ if (!tr_utils_1.TrUtils.IsZero(MainPDisc)) {
344
+ if (!tr_utils_1.TrUtils.IsEmpty(PDiscInPerc)) {
345
+ // Apply percentage discount
346
+ ItemsTotal = (0, aggregation_1.subtraction)(ItemsTotal, (0, aggregation_1.division)((0, aggregation_1.multiply)(ItemsTotal, Number(PDiscInPerc)), 100));
347
+ }
348
+ else {
349
+ // Apply fixed discount
350
+ ItemsTotal = (0, aggregation_1.subtraction)(ItemsTotal, MainPDisc);
351
+ }
352
+ }
353
+ return ItemsTotal;
354
+ }
355
+ /**
356
+ * Calculates total CGST tax amount for labor items
357
+ * @param opCodesList - Array of operation codes/labor
358
+ * @param IsIndependentTax - Whether tax is calculated independently
359
+ * @returns Total CGST amount for labor
360
+ */
361
+ static GetLaborCGSTTaxTotal(opCodesList, IsIndependentTax) {
362
+ let TotalTaxAmt = 0;
363
+ if (IsIndependentTax) {
364
+ opCodesList.forEach((Labor) => {
365
+ TotalTaxAmt = (0, aggregation_1.addition)(TotalTaxAmt, Labor.CGST);
366
+ });
367
+ }
368
+ return TotalTaxAmt;
369
+ }
370
+ /**
371
+ * Calculates total IGST tax amount for labor items
372
+ * @param opCodesList - Array of operation codes/labor
373
+ * @param IsIndependentTax - Whether tax is calculated independently
374
+ * @returns Total IGST amount for labor
375
+ */
376
+ static GetLaborIGSTTaxTotal(opCodesList, IsIndependentTax) {
377
+ let TotalTaxAmt = 0;
378
+ if (IsIndependentTax) {
379
+ opCodesList.forEach((Labor) => {
380
+ TotalTaxAmt = (0, aggregation_1.addition)(TotalTaxAmt, Labor.IGST);
381
+ });
382
+ }
383
+ return TotalTaxAmt;
384
+ }
385
+ /**
386
+ * Calculates total SGST tax amount for labor items
387
+ * @param opCodesList - Array of operation codes/labor
388
+ * @param IsIndependentTax - Whether tax is calculated independently
389
+ * @returns Total SGST amount for labor
390
+ */
391
+ static GetLaborSGSTTaxTotal(opCodesList, IsIndependentTax) {
392
+ let TotalTaxAmt = 0;
393
+ if (IsIndependentTax) {
394
+ opCodesList.forEach((Labor) => {
395
+ TotalTaxAmt = (0, aggregation_1.addition)(TotalTaxAmt, Labor.SGST);
396
+ });
397
+ }
398
+ return TotalTaxAmt;
399
+ }
400
+ /**
401
+ * Calculates GST tax breakdown for all parts (CGST, SGST, IGST, Total)
402
+ * @param PartsList - Array of parts
403
+ * @param IsIndependentTax - Whether tax is calculated independently
404
+ * @returns Array containing [CGST, SGST, IGST, Total Tax] amounts
405
+ */
406
+ static GetPartGSTTaxTotal(PartsList, IsIndependentTax) {
407
+ let TotalCGSTAmt = 0;
408
+ let TotalSGSTAmt = 0;
409
+ let TotalIGSTAmt = 0;
410
+ let TotalTaxAmt = 0;
411
+ if (IsIndependentTax) {
412
+ PartsList.forEach((Part) => {
413
+ TotalCGSTAmt = (0, aggregation_1.addition)(TotalCGSTAmt, Part.CGST);
414
+ TotalIGSTAmt = (0, aggregation_1.addition)(TotalIGSTAmt, Part.IGST);
415
+ TotalSGSTAmt = (0, aggregation_1.addition)(TotalSGSTAmt, Part.SGST);
416
+ TotalTaxAmt = (0, aggregation_1.addition)(TotalTaxAmt, Part.CGST, Part.SGST, Part.IGST);
417
+ });
418
+ }
419
+ return [TotalCGSTAmt, TotalSGSTAmt, TotalIGSTAmt, TotalTaxAmt];
420
+ }
421
+ /**
422
+ * Groups parts by HSN code for tax reporting and compliance
423
+ * @param Parts - Array of parts to group
424
+ * @param TaxCodes - Available tax codes
425
+ * @param DecimalsNumber - Number of decimal places
426
+ * @returns Tax grouping information organized by HSN codes
427
+ */
428
+ static GetTaxGroupingForPartsByHSN(Parts, TaxCodes, DecimalsNumber) {
429
+ // Add combined tax percentage to parts
430
+ Parts = this.GetCombinedTaxPercentage(Parts, TaxCodes);
431
+ // Group parts by HSN code
432
+ let FinalMatchedParts = this.ComparePartsByHSN(Parts, TaxCodes);
433
+ // Generate HSN-based tax grouping information
434
+ return this.GetTaxGroupingInfoByHSN(FinalMatchedParts, TaxCodes, DecimalsNumber);
435
+ }
436
+ /**
437
+ * Adds combined tax percentage calculation to each part based on tax codes
438
+ * @param Parts - Array of parts to process
439
+ * @param TaxCodes - Available tax codes for lookup
440
+ * @returns Parts array with added tax percentage information
441
+ */
442
+ static GetCombinedTaxPercentage(Parts, TaxCodes) {
443
+ Parts.forEach((Part) => {
444
+ // Ensure HSN is not null
445
+ if (tr_utils_1.TrUtils.IsNull(Part.HSN)) {
446
+ Part.HSN = '';
447
+ }
448
+ // Get GST values based on tax code
449
+ let GSTValues = this.GetGSTValueBasedOnTaxCode(Part.TCode, TaxCodes);
450
+ Part.CGSTAmt = tr_utils_1.TrUtils.SetValueToZeroIfNull(GSTValues[0]);
451
+ Part.SGSTAmt = tr_utils_1.TrUtils.SetValueToZeroIfNull(GSTValues[1]);
452
+ Part.IGSTAmt = tr_utils_1.TrUtils.SetValueToZeroIfNull(GSTValues[2]);
453
+ // Calculate combined tax percentage
454
+ Part.CombinedTaxPercentage = (0, aggregation_1.addition)(Part.CGSTAmt, Part.SGSTAmt, Part.IGSTAmt);
455
+ });
456
+ return Parts;
457
+ }
458
+ /**
459
+ * Compares and groups parts by HSN code and tax rates
460
+ * @param Parts - Array of parts to compare
461
+ * @param TaxCodes - Available tax codes
462
+ * @returns Array of parts grouped by HSN code and tax rates
463
+ */
464
+ static ComparePartsByHSN(Parts, TaxCodes) {
465
+ let FinalMatchedParts = [];
466
+ Parts.forEach((Part) => {
467
+ // Find parts with same HSN and tax rates that haven't been grouped
468
+ let MatchedPartsBasedOnHSN = Parts.filter((argPart) => {
469
+ let PartFound = false;
470
+ // Check if part is already in a group
471
+ FinalMatchedParts.forEach((FinalArgParts) => {
472
+ let PartIndex = FinalArgParts.findIndex((FinalArgPart) => {
473
+ return FinalArgPart._id === argPart._id;
474
+ });
475
+ if (PartIndex !== -1) {
476
+ PartFound = true;
477
+ }
478
+ });
479
+ // Return parts with same HSN and tax rates that aren't grouped yet
480
+ return (argPart.HSN === Part.HSN) && (!PartFound) &&
481
+ (argPart.CGSTAmt === Part.CGSTAmt) && (argPart.IGSTAmt === Part.IGSTAmt) &&
482
+ (argPart.SGSTAmt === Part.SGSTAmt);
483
+ });
484
+ // Add group if it contains parts
485
+ if (MatchedPartsBasedOnHSN.length !== 0) {
486
+ FinalMatchedParts.push(MatchedPartsBasedOnHSN);
487
+ }
488
+ });
489
+ return FinalMatchedParts;
490
+ }
491
+ /**
492
+ * Generates detailed tax information grouped by HSN codes for compliance reporting
493
+ * @param FinalMatchedParts - Array of grouped parts by HSN
494
+ * @param TaxCodes - Available tax codes
495
+ * @param DecimalsNumber - Number of decimal places for formatting
496
+ * @returns Array of HSN-wise tax information objects
497
+ */
498
+ static GetTaxGroupingInfoByHSN(FinalMatchedParts, TaxCodes, DecimalsNumber) {
499
+ let HSNTaxInfo = [];
500
+ FinalMatchedParts.forEach((MatchedPart) => {
501
+ let TaxInfo = {};
502
+ let TaxOnAmount = 0;
503
+ let TaxAmount = 0;
504
+ let CGSTAmt = 0;
505
+ let SGSTAmt = 0;
506
+ let IGSTAmt = 0;
507
+ // Get HSN code and tax percentage from first item
508
+ let HSN = MatchedPart[0].HSN;
509
+ TaxInfo.CombinedTaxPercentage = MatchedPart[0].CombinedTaxPercentage;
510
+ // Calculate totals for all parts in this HSN group
511
+ MatchedPart.forEach((argMatchedGSTPart) => {
512
+ TaxOnAmount = (0, aggregation_1.addition)(TaxOnAmount, tr_utils_1.TrUtils.FixedTo(argMatchedGSTPart.AfterPartDisc, DecimalsNumber));
513
+ TaxAmount = (0, aggregation_1.addition)(TaxAmount, tr_utils_1.TrUtils.FixedTo(argMatchedGSTPart.CGST, DecimalsNumber));
514
+ TaxAmount = (0, aggregation_1.addition)(TaxAmount, tr_utils_1.TrUtils.FixedTo(argMatchedGSTPart.IGST, DecimalsNumber));
515
+ TaxAmount = (0, aggregation_1.addition)(TaxAmount, tr_utils_1.TrUtils.FixedTo(argMatchedGSTPart.SGST, DecimalsNumber));
516
+ CGSTAmt = (0, aggregation_1.addition)(CGSTAmt, tr_utils_1.TrUtils.FixedTo(argMatchedGSTPart.CGST, DecimalsNumber));
517
+ SGSTAmt = (0, aggregation_1.addition)(SGSTAmt, tr_utils_1.TrUtils.FixedTo(argMatchedGSTPart.SGST, DecimalsNumber));
518
+ IGSTAmt = (0, aggregation_1.addition)(IGSTAmt, tr_utils_1.TrUtils.FixedTo(argMatchedGSTPart.IGST, DecimalsNumber));
519
+ });
520
+ // Build tax information object
521
+ TaxInfo.HSN = HSN;
522
+ TaxInfo.CGSTAmt = CGSTAmt;
523
+ TaxInfo.SGSTAmt = SGSTAmt;
524
+ TaxInfo.IGSTAmt = IGSTAmt;
525
+ TaxInfo.TotalTaxableAmount = tr_utils_1.TrUtils.FixPriceValue(TaxOnAmount, DecimalsNumber);
526
+ TaxInfo.TotalTaxAmount = tr_utils_1.TrUtils.FixPriceValue(TaxAmount, DecimalsNumber);
527
+ TaxInfo.ItemsCount = MatchedPart.length;
528
+ TaxInfo.CGST = MatchedPart[0].CGSTAmt;
529
+ TaxInfo.IGST = MatchedPart[0].IGSTAmt;
530
+ TaxInfo.SGST = MatchedPart[0].SGSTAmt;
531
+ // Only add if there's a taxable amount
532
+ if (TaxOnAmount !== 0) {
533
+ HSNTaxInfo.push(TaxInfo);
534
+ }
535
+ });
536
+ return HSNTaxInfo;
537
+ }
538
+ /**
539
+ * Retrieves GST values (CGST, SGST, IGST) based on tax code lookup
540
+ * @param TCode - Tax code identifier
541
+ * @param TaxCodes - Array of available tax codes
542
+ * @returns Array containing [CGST, SGST, IGST] values for the tax code
543
+ */
544
+ static GetGSTValueBasedOnTaxCode(TCode, TaxCodes) {
545
+ let CGST = 0;
546
+ let SGST = 0;
547
+ let IGST = 0;
548
+ // Return zeros if tax code is null
549
+ if (tr_utils_1.TrUtils.IsNull(TCode)) {
550
+ return [CGST, SGST, IGST];
551
+ }
552
+ // Find tax code in the array
553
+ let TCodeIndex = TaxCodes.findIndex((TaxCode) => {
554
+ return TaxCode._id === Number(TCode);
555
+ });
556
+ // Return appropriate tax values based on tax type
557
+ if (TCodeIndex !== -1) {
558
+ if (TaxCodes[TCodeIndex].Type === 'Intra') {
559
+ // Intra-state: CGST + SGST
560
+ return [TaxCodes[TCodeIndex].CGST, TaxCodes[TCodeIndex].SGST, 0];
561
+ }
562
+ else {
563
+ // Inter-state: IGST only
564
+ return [0, 0, TaxCodes[TCodeIndex].IGST];
565
+ }
566
+ }
567
+ else {
568
+ // Tax code not found, return zeros
569
+ return [CGST, SGST, IGST];
570
+ }
571
+ }
572
+ }
573
+ exports.SalesReceiveTotalsService = SalesReceiveTotalsService;
@@ -0,0 +1,5 @@
1
+ export declare function SalesTotalCalculations(items?: any[], ops?: any[], isTaxable?: boolean): any;
2
+ /**
3
+ * Enhanced version with decimal places control
4
+ */
5
+ export declare function SalesTotalCalculationsWithDecimals(items?: any[], ops?: any[], isTaxable?: boolean, decimalPlaces?: number): any;