washday-sdk 0.0.160 → 0.0.162

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.
@@ -1,8 +1,8 @@
1
1
  // myModule.test.js
2
2
  import { calculateOrderTotal } from "./index";
3
3
 
4
- describe("sum function", () => {
5
- const ORDER_DEMO = {
4
+ describe("Calculate Order Total tests", () => {
5
+ let ORDER_DEMO = {
6
6
  orderDto: {
7
7
  deliveryDateFormatted: "lunes 08 abr.",
8
8
  pickupInfo: null,
@@ -347,9 +347,394 @@ describe("sum function", () => {
347
347
  };
348
348
  beforeEach(() => {
349
349
  // Run this setup function before each test case
350
+ ORDER_DEMO = {
351
+ orderDto: {
352
+ deliveryDateFormatted: "lunes 08 abr.",
353
+ pickupInfo: null,
354
+ deliveryInfo: {
355
+ date: "2024-04-09T05:00:00.000Z",
356
+ fromTime: "2024-04-08T21:00:00.000Z",
357
+ },
358
+ express: false,
359
+ products: [
360
+ {
361
+ extraAmount: 0,
362
+ type: "weight",
363
+ showInApp: true,
364
+ order: 0,
365
+ invoice_description: "",
366
+ invoice_product_key: "",
367
+ invoice_product_unit_key: "",
368
+ invoice_product_unit_name: "",
369
+ productType: "storeProduct",
370
+ _id: "62d186387ec9330016319594",
371
+ name: "Lavado por kilo",
372
+ price: 17,
373
+ expressPrice: 20,
374
+ pieces: "1",
375
+ sku: "lavxkilo",
376
+ overlayText: "Lavado por kilo",
377
+ image: "6184782c3927a40018e36dea",
378
+ taxExemptOne: false,
379
+ taxExemptTwo: false,
380
+ taxExemptThree: false,
381
+ isActive: true,
382
+ store: "629c267812db5b001692adae",
383
+ owner: "629c267812db5b001692ada4",
384
+ productSupplies: [
385
+ {
386
+ usageAmount: 25,
387
+ _id: "62d6151fac2fc200166d0304",
388
+ supplyId: "62d35942c642440016cfcda8",
389
+ },
390
+ ],
391
+ __v: 1,
392
+ discountAmount: 0,
393
+ quantity: 3.7,
394
+ productId: "62d186387ec9330016319594",
395
+ qty: 3.7,
396
+ },
397
+ ],
398
+ taxesType: "included",
399
+ total: 62.9,
400
+ customer: "66147eecae83bb001540dd96",
401
+ store: "629c267812db5b001692adae",
402
+ paymentMethod: "delivery",
403
+ notifyBy: "none",
404
+ pickup: false,
405
+ delivery: false,
406
+ phone: "",
407
+ email: "",
408
+ address: "",
409
+ notes: "",
410
+ privateNotes: "",
411
+ creditApplied: 0,
412
+ amountPaid: 0,
413
+ customerInfo: {
414
+ password: "",
415
+ google: false,
416
+ facebook: false,
417
+ apple: false,
418
+ useStoreApp: false,
419
+ discount: 0,
420
+ credit: 0,
421
+ isActive: true,
422
+ createdDate: "2024-04-08T23:34:04.586Z",
423
+ stripeCustomerId: "",
424
+ invoiceInfo: {
425
+ _id: "66147eecae83bb001540dd95",
426
+ legal_name: "",
427
+ tax_system: "",
428
+ zipCode: "",
429
+ },
430
+ _id: "66147eecae83bb001540dd96",
431
+ name: "Carlos Piña 🍍",
432
+ phone: "",
433
+ address: "",
434
+ notes: "",
435
+ privateNotes: "",
436
+ rfc: "",
437
+ createdBy: "62d194d77ec933001631e831",
438
+ createdIn: "629c267812db5b001692adae",
439
+ company: "629c267712db5b001692ad9e",
440
+ paymentMethods: [],
441
+ __v: 0,
442
+ title: "Carlos Piña 🍍",
443
+ id: "66147eecae83bb001540dd96",
444
+ },
445
+ customerName: "Carlos Piña 🍍",
446
+ pickingUpDateTime: null,
447
+ cleanedDateTime: null,
448
+ readyDateTime: null,
449
+ deliveringDateTime: null,
450
+ collectedDateTime: null,
451
+ cancelledDateTime: null,
452
+ paidDateTime: null,
453
+ status: "cleaning",
454
+ prepaidAmount: 0,
455
+ prepaidPaymentMethod: "",
456
+ customerDiscount: 0,
457
+ productTotal: 54.22,
458
+ taxesTotal: 8.68,
459
+ productTotalWithoutDiscount: 54.22,
460
+ totalDiscountAmount: 0,
461
+ shippingServiceTotal: 0,
462
+ discountsToApply: [],
463
+ usePrepaid: false,
464
+ cashierBox: "629c267812db5b001692adb3",
465
+ discountCode: "",
466
+ buyAndGetProducts: [],
467
+ deliveryRoute: null,
468
+ pickupRoute: null,
469
+ createdDate: "2024-04-08T23:34:48.950Z",
470
+ },
471
+ customer: {
472
+ customer: {
473
+ password: "",
474
+ google: false,
475
+ facebook: false,
476
+ apple: false,
477
+ useStoreApp: false,
478
+ discount: 0,
479
+ credit: 0,
480
+ isActive: true,
481
+ createdDate: "2024-04-08T23:34:04.586Z",
482
+ stripeCustomerId: "",
483
+ invoiceInfo: {
484
+ _id: "66147eecae83bb001540dd95",
485
+ legal_name: "",
486
+ tax_system: "",
487
+ zipCode: "",
488
+ },
489
+ _id: "66147eecae83bb001540dd96",
490
+ name: "Carlos Piña 🍍",
491
+ phone: "",
492
+ address: "",
493
+ notes: "",
494
+ privateNotes: "",
495
+ rfc: "",
496
+ createdBy: "62d194d77ec933001631e831",
497
+ createdIn: "629c267812db5b001692adae",
498
+ company: "629c267712db5b001692ad9e",
499
+ paymentMethods: [],
500
+ __v: 0,
501
+ },
502
+ },
503
+ store: {
504
+ taxesType: "included",
505
+ notificationConfig: {
506
+ notifyOrderCreated: false,
507
+ notifyPickedUp: false,
508
+ notifyCleaned: true,
509
+ notifyCollected: false,
510
+ notifyDelivered: false,
511
+ notifyOwnerOnOrderCreated: false,
512
+ notifyEmail: "",
513
+ _id: "62a2d05fd0a7c800160869bc",
514
+ },
515
+ paymentConfig: {
516
+ defaultPaymentMethod: "delivery",
517
+ _id: "63650e8dcfa0e30016729776",
518
+ },
519
+ orderPageConfig: {
520
+ defaultDeliveryDate: "0",
521
+ defaultDeliveryTime: "18:00",
522
+ defaultNotifyMethod: "none",
523
+ printTicketAfterOrder: true,
524
+ shippingServiceCost: 0,
525
+ showProductSearchBarWeb: true,
526
+ _id: "6407b53301a1aa00141b217e",
527
+ },
528
+ _id: "629c267812db5b001692adae",
529
+ name: "Clean & Go",
530
+ phone: "9983524573",
531
+ inventory: [],
532
+ discountCodes: [
533
+ {
534
+ type: "percentage",
535
+ value: 14,
536
+ products: [
537
+ "62d1893f7ec933001631ab24",
538
+ "62d189697ec933001631acab",
539
+ "62d19a287ec933001632156f",
540
+ "62d199117ec9330016320ec0",
541
+ "62d198e07ec9330016320cc7",
542
+ "62d191d67ec933001631cd76",
543
+ "62d191747ec933001631c9cc",
544
+ "62d191ad7ec933001631cbef",
545
+ ],
546
+ applyToAllProducts: false,
547
+ applyOnceOnOrder: false,
548
+ hasUseLimit: false,
549
+ useLimitQty: 0,
550
+ usedCounter: 0,
551
+ onePerCustomer: true,
552
+ isActive: true,
553
+ buyAndGetConditions: [],
554
+ _id: "62d1ae1b7ec9330016328166",
555
+ name: "Anfitriones Airbnb",
556
+ code: "AIRBNBANF",
557
+ fromDate: "2022-07-01T05:00:00.000Z",
558
+ toDate: "2022-08-01T04:59:59.999Z",
559
+ fromTime: "00:00",
560
+ toTime: "23:59",
561
+ createdBy: "629c267812db5b001692ada4",
562
+ createdAt: "2022-07-15T18:12:43.506Z",
563
+ updatedAt: "2022-07-15T18:12:43.506Z",
564
+ },
565
+ {
566
+ type: "percentage",
567
+ value: 20,
568
+ products: [],
569
+ applyToAllProducts: true,
570
+ applyOnceOnOrder: false,
571
+ hasUseLimit: false,
572
+ useLimitQty: 0,
573
+ usedCounter: 0,
574
+ onePerCustomer: true,
575
+ isActive: true,
576
+ buyAndGetConditions: [],
577
+ _id: "635821305b689d0016c97f8c",
578
+ name: "Descuento por comentarios",
579
+ code: "20DESC01",
580
+ fromDate: "2022-01-01T05:00:00.000Z",
581
+ toDate: "2023-01-01T04:59:59.999Z",
582
+ fromTime: "00:00",
583
+ toTime: "23:59",
584
+ createdBy: "629c267812db5b001692ada4",
585
+ createdAt: "2022-10-25T17:47:28.314Z",
586
+ updatedAt: "2022-10-25T17:47:28.314Z",
587
+ },
588
+ {
589
+ type: "percentage",
590
+ value: 20,
591
+ products: [],
592
+ applyToAllProducts: true,
593
+ applyOnceOnOrder: false,
594
+ hasUseLimit: false,
595
+ useLimitQty: 0,
596
+ usedCounter: 0,
597
+ onePerCustomer: true,
598
+ isActive: true,
599
+ buyAndGetConditions: [],
600
+ _id: "6359c5d21332cf00168c5008",
601
+ name: "Descuento por comentario",
602
+ code: "20DESC02",
603
+ fromDate: "2022-01-01T05:00:00.000Z",
604
+ toDate: "2023-01-01T04:59:59.999Z",
605
+ fromTime: "00:00",
606
+ toTime: "23:59",
607
+ createdBy: "62d194d77ec933001631e831",
608
+ createdAt: "2022-10-26T23:42:10.732Z",
609
+ updatedAt: "2022-10-26T23:42:10.732Z",
610
+ },
611
+ {
612
+ type: "percentage",
613
+ value: 19,
614
+ products: [],
615
+ applyToAllProducts: true,
616
+ applyOnceOnOrder: false,
617
+ hasUseLimit: false,
618
+ useLimitQty: 0,
619
+ usedCounter: 0,
620
+ onePerCustomer: true,
621
+ isActive: true,
622
+ buyAndGetConditions: [],
623
+ _id: "6359c5ef1332cf00168c516d",
624
+ name: "Descuento por comentario",
625
+ code: "20DESC03",
626
+ fromDate: "2022-01-01T05:00:00.000Z",
627
+ toDate: "2023-01-01T04:59:59.999Z",
628
+ fromTime: "00:00",
629
+ toTime: "23:59",
630
+ createdBy: "62d194d77ec933001631e831",
631
+ createdAt: "2022-10-26T23:42:39.555Z",
632
+ updatedAt: "2022-10-26T23:42:39.555Z",
633
+ },
634
+ {
635
+ type: "percentage",
636
+ value: 20,
637
+ products: [],
638
+ applyToAllProducts: true,
639
+ applyOnceOnOrder: false,
640
+ hasUseLimit: false,
641
+ useLimitQty: 0,
642
+ usedCounter: 0,
643
+ onePerCustomer: true,
644
+ isActive: true,
645
+ buyAndGetConditions: [],
646
+ _id: "6359c60c1332cf00168c52c6",
647
+ name: "Descuento por comentario",
648
+ code: "20DESC04",
649
+ fromDate: "2022-01-01T05:00:00.000Z",
650
+ toDate: "2023-01-01T04:59:59.999Z",
651
+ fromTime: "00:00",
652
+ toTime: "23:59",
653
+ createdBy: "62d194d77ec933001631e831",
654
+ createdAt: "2022-10-26T23:43:08.577Z",
655
+ updatedAt: "2022-10-26T23:43:08.577Z",
656
+ },
657
+ {
658
+ type: "percentage",
659
+ value: 20,
660
+ products: [],
661
+ applyToAllProducts: true,
662
+ applyOnceOnOrder: false,
663
+ hasUseLimit: false,
664
+ useLimitQty: 0,
665
+ usedCounter: 0,
666
+ onePerCustomer: true,
667
+ isActive: true,
668
+ buyAndGetConditions: [],
669
+ _id: "6359c6261332cf00168c5468",
670
+ name: "Descuento por comentario",
671
+ code: "20DESC05",
672
+ fromDate: "2022-01-01T05:00:00.000Z",
673
+ toDate: "2023-01-01T04:59:59.999Z",
674
+ fromTime: "00:00",
675
+ toTime: "23:59",
676
+ createdBy: "62d194d77ec933001631e831",
677
+ createdAt: "2022-10-26T23:43:34.663Z",
678
+ updatedAt: "2022-10-26T23:43:34.663Z",
679
+ },
680
+ ],
681
+ taxOne: {
682
+ _id: "658bb2f376aa7b001482888c",
683
+ value: 16,
684
+ name: "IVA",
685
+ },
686
+ taxThree: null,
687
+ taxTwo: null,
688
+ },
689
+ hasShippingCost: false,
690
+ storeDiscounts: [],
691
+ discountCodeObj: null,
692
+ };
350
693
  });
351
- it("test calculateOrderTotal taxes included", () => {
694
+
695
+ it("test calculateOrderTotal taxes included no extra amount", () => {
352
696
  // Test case
697
+ ORDER_DEMO.store.taxesType = "included";
698
+ ORDER_DEMO.taxesType = "included";
699
+ const { orderDto, customer, store, storeDiscounts, discountCodeObj } =
700
+ ORDER_DEMO;
701
+
702
+ const { ...informationNewPackage } = calculateOrderTotal(
703
+ orderDto,
704
+ { customer },
705
+ store,
706
+ orderDto.delivery || orderDto.pickup,
707
+ // storeDiscounts.data?.discounts || [],
708
+ storeDiscounts,
709
+ discountCodeObj
710
+ );
711
+
712
+ const res = {
713
+ totalDiscountAmount: informationNewPackage.totalDiscountAmount,
714
+ totalQuantity: informationNewPackage.totalQuantity,
715
+ totalImportWithDiscount: informationNewPackage.productTotal,
716
+ totalImportWithoutDiscount:
717
+ informationNewPackage.productTotalWithoutDiscount,
718
+ totalImporTaxes: informationNewPackage.taxesTotal,
719
+ shippingCost: informationNewPackage.shippingServiceTotal,
720
+ total: informationNewPackage.total,
721
+ };
722
+ expect(res).toEqual({
723
+ totalDiscountAmount: 0,
724
+ totalQuantity: 3.7,
725
+ totalImportWithDiscount: 54.22,
726
+ totalImportWithoutDiscount: 54.22,
727
+ totalImporTaxes: 8.68,
728
+ shippingCost: 0,
729
+ total: 54.22 + 8.68,
730
+ });
731
+ });
732
+
733
+
734
+ it("test calculateOrderTotal taxes over_price no extra amount", () => {
735
+ // Test case
736
+ ORDER_DEMO.store.taxesType = "over_price";
737
+ ORDER_DEMO.taxesType = "over_price";
353
738
  const {
354
739
  orderDto,
355
740
  customer,
@@ -377,21 +762,169 @@ describe("sum function", () => {
377
762
  informationNewPackage.productTotalWithoutDiscount,
378
763
  totalImporTaxes: informationNewPackage.taxesTotal,
379
764
  shippingCost: informationNewPackage.shippingServiceTotal,
765
+ total: informationNewPackage.total,
380
766
  };
767
+ expect(res).toEqual(
768
+ {
769
+ totalDiscountAmount: 0,
770
+ totalQuantity: 3.7,
771
+ totalImportWithDiscount: 62.9,
772
+ totalImportWithoutDiscount: 62.9,
773
+ totalImporTaxes: 10.06,
774
+ shippingCost: 0,
775
+ total: 72.96,
776
+ });
777
+ });
778
+
779
+ it("test calculateOrderTotal taxes included with extra amount", () => {
780
+ // Test case
781
+ ORDER_DEMO.orderDto.products[0].extraAmount = 50;
782
+ const {
783
+ orderDto,
784
+ customer,
785
+ store,
786
+ hasShippingCost,
787
+ storeDiscounts,
788
+ discountCodeObj,
789
+ } = ORDER_DEMO;
790
+
791
+ const { ...informationNewPackage } = calculateOrderTotal(
792
+ orderDto,
793
+ { customer },
794
+ store,
795
+ orderDto.delivery || orderDto.pickup,
796
+ // storeDiscounts.data?.discounts || [],
797
+ storeDiscounts,
798
+ discountCodeObj
799
+ );
800
+
801
+ const res = {
802
+ totalDiscountAmount: informationNewPackage.totalDiscountAmount,
803
+ totalQuantity: informationNewPackage.totalQuantity,
804
+ totalImportWithDiscount: informationNewPackage.productTotal,
805
+ totalImportWithoutDiscount:
806
+ informationNewPackage.productTotalWithoutDiscount,
807
+ totalImporTaxes: informationNewPackage.taxesTotal,
808
+ shippingCost: informationNewPackage.shippingServiceTotal,
809
+ total: informationNewPackage.total,
810
+ total: informationNewPackage.total,
811
+ };
812
+
381
813
  expect(res).toEqual({
814
+ total: 112.9,
382
815
  totalDiscountAmount: 0,
383
816
  totalQuantity: 3.7,
384
- totalImportWithDiscount: 54.22,
385
- totalImportWithoutDiscount: 54.22,
386
- totalImporTaxes: 8.68,
817
+ totalImportWithDiscount: 97.33,
818
+ totalImportWithoutDiscount: 97.33,
819
+ totalImporTaxes: 15.57,
387
820
  shippingCost: 0,
388
821
  });
389
822
  });
390
823
 
391
- it("should return 0 when adding two zeros", () => {
824
+ it("test calculateOrderTotal taxes over_price with extra amount", () => {
392
825
  // Test case
393
- expect(sum(0, 0)).toBe(0);
826
+ ORDER_DEMO.orderDto.products[0].extraAmount = 50;
827
+ ORDER_DEMO.store.taxesType = "over_price";
828
+ ORDER_DEMO.taxesType = "over_price";
829
+ const {
830
+ orderDto,
831
+ customer,
832
+ store,
833
+ storeDiscounts,
834
+ discountCodeObj,
835
+ } = ORDER_DEMO;
836
+
837
+ const { ...informationNewPackage } = calculateOrderTotal(
838
+ orderDto,
839
+ { customer },
840
+ store,
841
+ orderDto.delivery || orderDto.pickup,
842
+ // storeDiscounts.data?.discounts || [],
843
+ storeDiscounts,
844
+ discountCodeObj
845
+ );
846
+
847
+ const res = {
848
+ totalDiscountAmount: informationNewPackage.totalDiscountAmount,
849
+ totalQuantity: informationNewPackage.totalQuantity,
850
+ totalImportWithDiscount: informationNewPackage.productTotal,
851
+ totalImportWithoutDiscount:
852
+ informationNewPackage.productTotalWithoutDiscount,
853
+ totalImporTaxes: informationNewPackage.taxesTotal,
854
+ shippingCost: informationNewPackage.shippingServiceTotal,
855
+ total: informationNewPackage.total,
856
+ total: informationNewPackage.total,
857
+ };
858
+
859
+ expect(res).toEqual({
860
+ total: 112.9 + 18.06,
861
+ totalDiscountAmount: 0,
862
+ totalQuantity: 3.7,
863
+ totalImportWithDiscount: 112.9,
864
+ totalImportWithoutDiscount: 112.9,
865
+ totalImporTaxes: 18.06,
866
+ shippingCost: 0,
867
+ });
868
+ });
869
+
870
+ it("test calculateOrderTotal taxes over_price with discount and sin extra amount", () => {
871
+ // Configurar el escenario:
872
+ // - Se asigna extraAmount = 0
873
+ // - Se activa un discountCode en orderDto y se provee un objeto discountCodeObj con descuento del 20%
874
+ ORDER_DEMO.orderDto.products[0].extraAmount = 0;
875
+ ORDER_DEMO.orderDto.discountCode = "DISCOUNT20";
876
+ ORDER_DEMO.discountCodeObj = {
877
+ type: "percentage",
878
+ value: 20,
879
+ applyToAllProducts: true,
880
+ products: [] // para todos, se ignora el filtrado
881
+ };
882
+ ORDER_DEMO.store.taxesType = "over_price";
883
+ ORDER_DEMO.taxesType = "over_price";
884
+
885
+ const { orderDto, customer, store, storeDiscounts, discountCodeObj } = ORDER_DEMO;
886
+
887
+ const informationNewPackage = calculateOrderTotal(
888
+ orderDto,
889
+ { customer },
890
+ store,
891
+ orderDto.delivery || orderDto.pickup,
892
+ storeDiscounts,
893
+ ORDER_DEMO.discountCodeObj
894
+ );
895
+
896
+ // Con un precio base de 17, cantidad 3.7 y sin extraAmount:
897
+ // - Importe original sin descuento: 17 x 3.7 = 62.9
898
+ // - Con descuento del 20%: descuento por unidad = 17 x 0.20 = 3.4,
899
+ // precio descontado = 17 - 3.4 = 13.6,
900
+ // importe de producto con descuento = 13.6 x 3.7 = 50.32.
901
+ // - Impuestos (16% sobre subtotal): 112.9 es el subtotal si no se aplica descuento;
902
+ // pero en "over_price" se calcula sobre (precio descontado x qty + extraAmount):
903
+ // subtotal = 50.32, impuestos = 50.32 x 0.16 = 8.0512 ≈ 8.05.
904
+ // - Total a cobrar = 50.32 + 8.05 = 58.37.
905
+ // - El totalDiscountAmount (total de descuento aplicado) es 3.4 x 3.7 = 12.58.
906
+
907
+ const res = {
908
+ totalDiscountAmount: informationNewPackage.totalDiscountAmount,
909
+ totalQuantity: informationNewPackage.totalQuantity,
910
+ totalImportWithDiscount: informationNewPackage.productTotal,
911
+ totalImportWithoutDiscount: informationNewPackage.productTotalWithoutDiscount,
912
+ totalImporTaxes: informationNewPackage.taxesTotal,
913
+ shippingCost: informationNewPackage.shippingServiceTotal,
914
+ total: informationNewPackage.total,
915
+ };
916
+
917
+ expect(res).toEqual({
918
+ totalDiscountAmount: 12.58,
919
+ totalQuantity: 3.7,
920
+ totalImportWithDiscount: 50.32,
921
+ totalImportWithoutDiscount: 62.9,
922
+ totalImporTaxes: 8.05,
923
+ shippingCost: 0,
924
+ total: 58.37,
925
+ });
394
926
  });
395
927
 
928
+
396
929
  // Add more test cases as needed
397
930
  });
@@ -8,25 +8,32 @@ export const calculateTotalTaxesIncluded = (
8
8
  storeDiscounts: any[],
9
9
  appliedOrderDiscounts: any,
10
10
  discountCodeObj: any | null
11
- ) => {
11
+ ): any => {
12
12
  const productTableImports = [...order.products, ...order.buyAndGetProducts].map((current: IOrderProduct) => {
13
+ const qty = current.qty || 0;
14
+ const taxPercentage = getProductTaxesPercentage(current, storeSettings);
15
+ const taxFactor = 1 + taxPercentage / 100;
16
+
17
+ // Convert extraAmount from gross to net (assume extraAmount is not discounted)
18
+ const extraAmountGross = current.extraAmount || 0;
19
+ const extraAmountNet = extraAmountGross / taxFactor;
20
+
21
+ // Get the product’s gross price (excluding extraAmount)
22
+ const productGrossPrice = order.express ? current.expressPrice : current.price;
23
+ // Convert product gross price to net
24
+ const unitNetPrice = productGrossPrice / taxFactor;
25
+
26
+ // Determine discount percentage (if any) – discount is applied only on product net price.
13
27
  let discPercentageInteger = 0;
14
28
  let productPercentageDiscount = 0;
15
29
  let customerDiscount = 0;
16
- let qty = current.qty || 0;
17
- const extraAmountPerUnit = current.extraAmount / qty;
18
- const prodPrice = (order.express ? current.expressPrice : current.price) + extraAmountPerUnit;
19
-
20
30
  if (!order.discountCode) {
21
31
  const discountsToApply = storeDiscounts.filter(
22
32
  (discount) => discount.products.includes(current._id) && discount.isActive
23
33
  );
24
34
  customerDiscount = selectedCustomer?.customer?.discount || 0;
25
- productPercentageDiscount = discountsToApply.reduce((prev, next) => {
26
- if (next.type === 'percentage') {
27
- return prev + next.value;
28
- }
29
- return prev;
35
+ productPercentageDiscount = discountsToApply.reduce((prev: number, next: any) => {
36
+ return next.type === 'percentage' ? prev + next.value : prev;
30
37
  }, 0);
31
38
  discPercentageInteger = +((productPercentageDiscount + customerDiscount) / 100).toFixed(2);
32
39
  discountsToApply.forEach((discount) => (appliedOrderDiscounts[discount._id] = discount));
@@ -47,26 +54,35 @@ export const calculateTotalTaxesIncluded = (
47
54
  }
48
55
  }
49
56
  }
50
-
51
- const taxPercentage = getProductTaxesPercentage(current, storeSettings);
52
- const taxPercentageInteger = taxPercentage / 100;
53
-
54
- const unitPrice = prodPrice / (1 + taxPercentageInteger);
55
- const discountAmountPerUnit = discPercentageInteger
56
- ? unitPrice * discPercentageInteger
57
- : (current.discountAmount || 0) / (1 + taxPercentageInteger);
58
-
59
- const prodPriceWithDiscountPerUnit = unitPrice - discountAmountPerUnit;
60
- const taxesAmountPerUnit = prodPriceWithDiscountPerUnit * taxPercentageInteger;
61
- const totalTaxesApplied = +(taxesAmountPerUnit * qty).toFixed(2);
62
- const lineDiscount = qty * discountAmountPerUnit;
63
- const prodLinePriceWithDiscount = +(qty * prodPriceWithDiscountPerUnit).toFixed(2);
64
-
57
+
58
+ // Calculate discount on product net price only.
59
+ const discountAmountPerUnit = discPercentageInteger ? unitNetPrice * discPercentageInteger : 0;
60
+ const discountedUnitNetPrice = unitNetPrice - discountAmountPerUnit;
61
+ // Reapply VAT to get discounted product gross price.
62
+ const discountedUnitGrossPrice = discountedUnitNetPrice * taxFactor;
63
+
64
+ // Now, calculate the final totals:
65
+ // For the product part:
66
+ const productNetTotalWithoutDiscount = unitNetPrice * qty;
67
+ const productNetTotalWithDiscount = discountedUnitNetPrice * qty;
68
+ // Add the extraAmount net (since it is not discounted):
69
+ const totalNetWithoutDiscount = productNetTotalWithoutDiscount + extraAmountNet;
70
+ const totalNetWithDiscount = productNetTotalWithDiscount + extraAmountNet;
71
+
72
+ // Reapply VAT to both totals:
73
+ const productLineImportTotal = + (totalNetWithoutDiscount * taxFactor).toFixed(2);
74
+ const productLineTotalWithDiscount = + (totalNetWithDiscount * taxFactor).toFixed(2);
75
+
76
+ // Calculate the taxes as the difference between gross and net:
77
+ const totalTaxesApplied = + (productLineImportTotal - totalNetWithoutDiscount).toFixed(2);
78
+
79
+ const lineDiscount = + (discountAmountPerUnit * qty).toFixed(2);
80
+
65
81
  return {
66
82
  product: current,
67
- qty: qty,
68
- productLineImportTotal: unitPrice * qty,
69
- productLineTotalWithDiscount: prodLinePriceWithDiscount,
83
+ qty,
84
+ productLineImportTotal, // original gross total (no discount)
85
+ productLineTotalWithDiscount, // gross total after discount on product (extra not discounted)
70
86
  productLineTaxesTotal: totalTaxesApplied,
71
87
  lineDiscountAmount: lineDiscount
72
88
  };