@jsdev_ninja/core 0.12.7 → 0.12.9

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.
Files changed (57) hide show
  1. package/dist/core.cjs.js +1 -1
  2. package/dist/core.cjs.js.map +1 -1
  3. package/dist/core.es.js +988 -837
  4. package/dist/core.es.js.map +1 -1
  5. package/dist/core.umd.js +1 -1
  6. package/dist/core.umd.js.map +1 -1
  7. package/dist/entities/Discount/__tests__/engine.test.d.ts +2 -0
  8. package/dist/entities/Discount/__tests__/engine.test.d.ts.map +1 -0
  9. package/dist/entities/Discount/__tests__/engine.test.js +298 -0
  10. package/dist/entities/Discount/__tests__/factory.test.d.ts +2 -0
  11. package/dist/entities/Discount/__tests__/factory.test.d.ts.map +1 -0
  12. package/dist/entities/Discount/__tests__/factory.test.js +75 -0
  13. package/dist/entities/Discount/__tests__/integration.test.d.ts +2 -0
  14. package/dist/entities/Discount/__tests__/integration.test.d.ts.map +1 -0
  15. package/dist/entities/Discount/__tests__/integration.test.js +115 -0
  16. package/dist/entities/Discount/__tests__/simple.test.d.ts +2 -0
  17. package/dist/entities/Discount/__tests__/simple.test.d.ts.map +1 -0
  18. package/dist/entities/Discount/__tests__/simple.test.js +186 -0
  19. package/dist/entities/Discount/__tests__/utils.test.d.ts +2 -0
  20. package/dist/entities/Discount/__tests__/utils.test.d.ts.map +1 -0
  21. package/dist/entities/Discount/__tests__/utils.test.js +55 -0
  22. package/dist/entities/Discount/engine.d.ts +29 -0
  23. package/dist/entities/Discount/engine.d.ts.map +1 -0
  24. package/dist/entities/Discount/engine.js +80 -0
  25. package/dist/entities/Discount/factory.d.ts +10 -0
  26. package/dist/entities/Discount/factory.d.ts.map +1 -0
  27. package/dist/entities/Discount/factory.js +18 -0
  28. package/dist/entities/Discount/index.d.ts +9 -0
  29. package/dist/entities/Discount/index.d.ts.map +1 -0
  30. package/dist/entities/Discount/index.js +8 -0
  31. package/dist/entities/Discount/strategies/BundleStrategy.d.ts +12 -0
  32. package/dist/entities/Discount/strategies/BundleStrategy.d.ts.map +1 -0
  33. package/dist/entities/Discount/strategies/BundleStrategy.js +78 -0
  34. package/dist/entities/Discount/strategies/__tests__/BundleStrategy.test.d.ts +2 -0
  35. package/dist/entities/Discount/strategies/__tests__/BundleStrategy.test.d.ts.map +1 -0
  36. package/dist/entities/Discount/strategies/__tests__/BundleStrategy.test.js +265 -0
  37. package/dist/entities/Discount/strategy.d.ts +6 -0
  38. package/dist/entities/Discount/strategy.d.ts.map +1 -0
  39. package/dist/entities/Discount/strategy.js +1 -0
  40. package/dist/entities/Discount/types.d.ts +148 -0
  41. package/dist/entities/Discount/types.d.ts.map +1 -0
  42. package/dist/entities/Discount/types.js +29 -0
  43. package/dist/entities/Discount/utils.d.ts +29 -0
  44. package/dist/entities/Discount/utils.d.ts.map +1 -0
  45. package/dist/entities/Discount/utils.js +39 -0
  46. package/dist/tsconfig.app.tsbuildinfo +1 -1
  47. package/dist/utils/index.d.ts.map +1 -1
  48. package/dist/utils/index.js +27 -63
  49. package/lib/entities/Discount/strategies/BundleStrategy.ts +115 -119
  50. package/lib/entities/Discount/strategies/__tests__/BundleStrategy.test.ts +12 -7
  51. package/lib/entities/Discount/types.ts +44 -44
  52. package/lib/utils/index.ts +32 -83
  53. package/package.json +1 -1
  54. package/dist/entities/Discount.d.ts +0 -71
  55. package/dist/entities/Discount.d.ts.map +0 -1
  56. package/dist/entities/Discount.js +0 -20
  57. package/lib/entities/Discount.ts +0 -23
@@ -2,122 +2,118 @@ import { DiscountStrategy } from "../strategy";
2
2
  import { TDiscount, DiscountResult, DiscountContext } from "../types";
3
3
 
4
4
  export class BundleDiscountStrategy implements DiscountStrategy {
5
- canApply(discount: TDiscount, context: DiscountContext): boolean {
6
- if (discount.variant.variantType !== "bundle") return false;
7
-
8
- // Check if discount is active
9
- if (!this.isDiscountActive(discount)) return false;
10
-
11
- const { productsId, requiredQuantity } = discount.variant;
12
-
13
- // Check if cart has enough of the required products
14
- const totalQuantity = this.getTotalQuantity(context.cart, productsId);
15
-
16
- return totalQuantity >= requiredQuantity;
17
- }
18
-
19
- calculate(discount: TDiscount, context: DiscountContext): DiscountResult {
20
- if (discount.variant.variantType !== "bundle") {
21
- return { applicable: false, discountAmount: 0, affectedItems: [] };
22
- }
23
-
24
- const { productsId, requiredQuantity, bundlePrice } = discount.variant;
25
-
26
- // Get applicable items (only the products in the bundle)
27
- const applicableItems = context.cart.filter(item =>
28
- productsId.includes(item.product.id));
29
-
30
- const totalQuantity = this.getTotalQuantity(context.cart, productsId);
31
- const bundleCount = Math.floor(totalQuantity / requiredQuantity);
32
-
33
- if (bundleCount === 0) {
34
- return { applicable: false, discountAmount: 0, affectedItems: [] };
35
- }
36
-
37
- // Calculate original price for bundled items
38
- const originalPrice = this.calculateOriginalPrice(applicableItems);
39
-
40
- // Calculate discounted price
41
- const cartTotalQuantity = this.getTotalQuantity(context.cart, productsId);
42
- const discountedPrice = this.calculateDiscountedPrice(
43
- originalPrice,
44
- bundlePrice,
45
- bundleCount,
46
- requiredQuantity,
47
- cartTotalQuantity
48
- );
49
-
50
- const totalDiscount = originalPrice - discountedPrice;
51
-
52
- // Distribute discount proportionally among items
53
- const affectedItems = this.distributeDiscount(applicableItems, totalDiscount, originalPrice);
54
-
55
- return {
56
- applicable: true,
57
- discountAmount: Number(totalDiscount.toFixed(2)),
58
- affectedItems,
59
- };
60
- }
61
-
62
- private isDiscountActive(discount: TDiscount): boolean {
63
- const now = Date.now();
64
- return discount.active &&
65
- discount.startDate <= now &&
66
- discount.endDate >= now;
67
- }
68
-
69
- private getTotalQuantity(cart: DiscountContext["cart"], productIds: string[]): number {
70
- return cart
71
- .filter(item => productIds.includes(item.product.id))
72
- .reduce((sum, item) => sum + item.amount, 0);
73
- }
74
-
75
- private calculateOriginalPrice(items: DiscountContext["cart"]): number {
76
- return items.reduce((sum, item) =>
77
- sum + (item.product.price * item.amount), 0);
78
- }
79
-
80
- private calculateDiscountedPrice(
81
- originalPrice: number,
82
- bundlePrice: number,
83
- bundleCount: number,
84
- requiredQuantity: number,
85
- totalQuantity: number
86
- ): number {
87
- // For bundle discounts, we pay the bundle price for each complete bundle
88
- // and full price for any remaining items
89
- const bundledItemsPrice = bundlePrice * bundleCount;
90
-
91
- // For bundle discounts, we pay bundle price for complete bundles
92
- // and full price for remaining items
93
- // Since we're dealing with the total original price, we need to calculate
94
- // how much of the original price represents the bundled items vs remaining items
95
- const itemsInBundles = bundleCount * requiredQuantity;
96
- const remainingItems = Math.max(0, totalQuantity - itemsInBundles);
97
-
98
- // Calculate the proportion of original price that represents remaining items
99
- const remainingItemsPrice = (remainingItems / totalQuantity) * originalPrice;
100
-
101
- return bundledItemsPrice + remainingItemsPrice;
102
- }
103
-
104
- private distributeDiscount(
105
- items: DiscountContext["cart"],
106
- totalDiscount: number,
107
- originalPrice: number
108
- ): DiscountResult["affectedItems"] {
109
- const discountRatio = totalDiscount / originalPrice;
110
-
111
- return items.map(item => {
112
- const itemDiscount = (item.product.price * item.amount) * discountRatio;
113
-
114
- return {
115
- productId: item.product.id,
116
- quantity: item.amount,
117
- originalPrice: Number(item.product.price.toFixed(2)),
118
- discountedPrice: Number((item.product.price - (itemDiscount / item.amount)).toFixed(2)),
119
- discountAmount: Number(itemDiscount.toFixed(2)),
120
- };
121
- });
122
- }
123
- }
5
+ canApply(discount: TDiscount, context: DiscountContext): boolean {
6
+ if (discount.variant.variantType !== "bundle") return false;
7
+
8
+ // Check if discount is active
9
+ if (!this.isDiscountActive(discount)) return false;
10
+
11
+ const { productsId, requiredQuantity } = discount.variant;
12
+
13
+ // Check if cart has enough of the required products
14
+ const totalQuantity = this.getTotalQuantity(context.cart, productsId);
15
+
16
+ return totalQuantity >= requiredQuantity;
17
+ }
18
+
19
+ calculate(discount: TDiscount, context: DiscountContext): DiscountResult {
20
+ if (discount.variant.variantType !== "bundle") {
21
+ return { applicable: false, discountAmount: 0, affectedItems: [] };
22
+ }
23
+
24
+ const { productsId, requiredQuantity, bundlePrice } = discount.variant;
25
+
26
+ // Get applicable items (only the products in the bundle)
27
+ const applicableItems = context.cart.filter((item) => productsId.includes(item.product.id));
28
+
29
+ const totalQuantity = this.getTotalQuantity(context.cart, productsId);
30
+ const bundleCount = Math.floor(totalQuantity / requiredQuantity);
31
+
32
+ if (bundleCount === 0) {
33
+ return { applicable: false, discountAmount: 0, affectedItems: [] };
34
+ }
35
+
36
+ // Calculate original price for bundled items
37
+ const originalPrice = this.calculateOriginalPrice(applicableItems);
38
+
39
+ // Calculate discounted price
40
+ const cartTotalQuantity = this.getTotalQuantity(context.cart, productsId);
41
+ const discountedPrice = this.calculateDiscountedPrice(
42
+ originalPrice,
43
+ bundlePrice,
44
+ bundleCount,
45
+ requiredQuantity,
46
+ cartTotalQuantity
47
+ );
48
+
49
+ const totalDiscount = originalPrice - discountedPrice;
50
+
51
+ // Distribute discount proportionally among items
52
+ const affectedItems = this.distributeDiscount(applicableItems, totalDiscount, originalPrice);
53
+
54
+ return {
55
+ applicable: true,
56
+ discountAmount: Number(totalDiscount.toFixed(2)),
57
+ affectedItems,
58
+ };
59
+ }
60
+
61
+ private isDiscountActive(discount: TDiscount): boolean {
62
+ const now = Date.now();
63
+ return discount.active && discount.startDate <= now && discount.endDate >= now;
64
+ }
65
+
66
+ private getTotalQuantity(cart: DiscountContext["cart"], productIds: string[]): number {
67
+ return cart
68
+ .filter((item) => productIds.includes(item.product.id))
69
+ .reduce((sum, item) => sum + item.amount, 0);
70
+ }
71
+
72
+ private calculateOriginalPrice(items: DiscountContext["cart"]): number {
73
+ return items.reduce((sum, item) => sum + item.product.price * item.amount, 0);
74
+ }
75
+
76
+ private calculateDiscountedPrice(
77
+ originalPrice: number,
78
+ bundlePrice: number,
79
+ bundleCount: number,
80
+ requiredQuantity: number,
81
+ totalQuantity: number
82
+ ): number {
83
+ // For bundle discounts, we pay the bundle price for each complete bundle
84
+ // and full price for any remaining items
85
+ const bundledItemsPrice = bundlePrice * bundleCount;
86
+
87
+ // For bundle discounts, we pay bundle price for complete bundles
88
+ // and full price for remaining items
89
+ // Since we're dealing with the total original price, we need to calculate
90
+ // how much of the original price represents the bundled items vs remaining items
91
+ const itemsInBundles = bundleCount * requiredQuantity;
92
+ const remainingItems = Math.max(0, totalQuantity - itemsInBundles);
93
+
94
+ // Calculate the proportion of original price that represents remaining items
95
+ const remainingItemsPrice = (remainingItems / totalQuantity) * originalPrice;
96
+
97
+ return bundledItemsPrice + remainingItemsPrice;
98
+ }
99
+
100
+ private distributeDiscount(
101
+ items: DiscountContext["cart"],
102
+ totalDiscount: number,
103
+ originalPrice: number
104
+ ): DiscountResult["affectedItems"] {
105
+ const discountRatio = totalDiscount / originalPrice;
106
+
107
+ return items.map((item) => {
108
+ const itemDiscount = item.product.price * item.amount * discountRatio;
109
+
110
+ return {
111
+ productId: item.product.id,
112
+ quantity: item.amount,
113
+ originalPrice: Number(item.product.price.toFixed(2)),
114
+ discountedPrice: Number((item.product.price - itemDiscount / item.amount).toFixed(2)),
115
+ discountAmount: Number(itemDiscount.toFixed(2)),
116
+ };
117
+ });
118
+ }
119
+ }
@@ -56,16 +56,19 @@ describe("BundleDiscountStrategy", () => {
56
56
  expect(strategy.canApply(discount, mockContext)).toBe(true);
57
57
  });
58
58
 
59
- it("should return false for wrong variant type", () => {
59
+ it("should return true for bundle variant type", () => {
60
60
  const discount = {
61
61
  ...mockDiscount,
62
62
  variant: {
63
- variantType: "percentage" as any,
64
- percentage: 20,
63
+ variantType: "bundle" as const,
64
+ productsId: ["product1", "product2"],
65
+ requiredQuantity: 3,
66
+ bundlePrice: 25,
65
67
  },
66
68
  };
67
69
 
68
- expect(strategy.canApply(discount, mockContext)).toBe(false);
70
+ // This should work since it's a bundle type and we have 3 items total
71
+ expect(strategy.canApply(discount, mockContext)).toBe(true);
69
72
  });
70
73
 
71
74
  it("should return false when not enough items", () => {
@@ -223,12 +226,14 @@ describe("BundleDiscountStrategy", () => {
223
226
  expect(result.affectedItems[0].discountAmount).toBe(10);
224
227
  });
225
228
 
226
- it("should return not applicable for wrong variant type", () => {
229
+ it("should return not applicable for invalid bundle", () => {
227
230
  const discount = {
228
231
  ...mockDiscount,
229
232
  variant: {
230
- variantType: "percentage" as any,
231
- percentage: 20,
233
+ variantType: "bundle" as const,
234
+ productsId: ["product1"],
235
+ requiredQuantity: 10, // Too many required
236
+ bundlePrice: 25,
232
237
  },
233
238
  };
234
239
 
@@ -1,32 +1,34 @@
1
1
  import { z } from "zod";
2
2
 
3
3
  // Simple discount conditions
4
- export const DiscountConditionsSchema = z.object({
5
- minSpend: z.number().positive().optional(),
6
- stackable: z.boolean().default(false),
7
- }).optional();
4
+ export const DiscountConditionsSchema = z
5
+ .object({
6
+ minSpend: z.number().positive().optional(),
7
+ stackable: z.boolean().default(false),
8
+ })
9
+ .optional();
8
10
 
9
11
  // Bundle discount - buy X items for Y price
10
12
  export const DiscountVariantSchema = z.discriminatedUnion("variantType", [
11
- z.object({
12
- variantType: z.literal("bundle"),
13
- productsId: z.array(z.string()).min(1), // Which products are included
14
- requiredQuantity: z.number().positive(), // How many items needed (e.g., 3)
15
- bundlePrice: z.number().positive(), // Total price for the bundle (e.g., $25)
16
- }),
13
+ z.object({
14
+ variantType: z.literal("bundle"),
15
+ productsId: z.array(z.string().nonempty()).min(1), // Which products are included
16
+ requiredQuantity: z.number().positive(), // How many items needed (e.g., 3)
17
+ bundlePrice: z.number().positive(), // Total price for the bundle (e.g., $25)
18
+ }),
17
19
  ]);
18
20
 
19
21
  export const DiscountSchema = z.object({
20
- type: z.literal("Discount"),
21
- storeId: z.string().min(1),
22
- companyId: z.string().min(1),
23
- id: z.string().min(1),
24
- name: z.array(z.object({ lang: z.enum(["he"]), value: z.string() })),
25
- active: z.boolean(),
26
- startDate: z.number(),
27
- endDate: z.number(),
28
- variant: DiscountVariantSchema,
29
- conditions: DiscountConditionsSchema,
22
+ type: z.literal("Discount"),
23
+ storeId: z.string().min(1),
24
+ companyId: z.string().min(1),
25
+ id: z.string().min(1),
26
+ name: z.array(z.object({ lang: z.enum(["he"]), value: z.string().nonempty() })),
27
+ active: z.boolean(),
28
+ startDate: z.number(),
29
+ endDate: z.number(),
30
+ variant: DiscountVariantSchema,
31
+ conditions: DiscountConditionsSchema,
30
32
  });
31
33
 
32
34
  export type TDiscount = z.infer<typeof DiscountSchema>;
@@ -35,34 +37,32 @@ export type DiscountConditions = z.infer<typeof DiscountConditionsSchema>;
35
37
 
36
38
  // Simple result types
37
39
  export interface DiscountResult {
38
- applicable: boolean;
39
- discountAmount: number;
40
- affectedItems: Array<{
41
- productId: string;
42
- quantity: number;
43
- originalPrice: number;
44
- discountedPrice: number;
45
- discountAmount: number;
46
- }>;
40
+ applicable: boolean;
41
+ discountAmount: number;
42
+ affectedItems: Array<{
43
+ productId: string;
44
+ quantity: number;
45
+ originalPrice: number;
46
+ discountedPrice: number;
47
+ discountAmount: number;
48
+ }>;
47
49
  }
48
50
 
49
51
  export interface AppliedDiscount {
50
- discountId: string;
51
- discountName: string;
52
- discountAmount: number;
53
- affectedItems: DiscountResult["affectedItems"];
52
+ discountId: string;
53
+ discountName: string;
54
+ discountAmount: number;
55
+ affectedItems: DiscountResult["affectedItems"];
54
56
  }
55
57
 
56
58
  export interface DiscountContext {
57
- cart: Array<{
58
- amount: number;
59
- product: {
60
- id: string;
61
- price: number;
62
- };
63
- }>;
64
- user?: Record<string, unknown>;
65
- appliedDiscounts: AppliedDiscount[];
59
+ cart: Array<{
60
+ amount: number;
61
+ product: {
62
+ id: string;
63
+ price: number;
64
+ };
65
+ }>;
66
+ user?: Record<string, unknown>;
67
+ appliedDiscounts: AppliedDiscount[];
66
68
  }
67
-
68
-
@@ -1,4 +1,5 @@
1
1
  import { TCart, TDiscount, TProduct, TStore } from "../entities";
2
+ import { DiscountEngine } from "../entities/Discount/engine";
2
3
 
3
4
  const CONFIG = {
4
5
  VAT: 18,
@@ -26,10 +27,6 @@ function getPriceAfterDiscount(product: TProduct) {
26
27
  return product.price;
27
28
  }
28
29
 
29
- // mark product that used in discount
30
- // get final price for product and discount id
31
- // filter better discount
32
-
33
30
  // main
34
31
  export function getCartCost({
35
32
  cart,
@@ -41,89 +38,31 @@ export function getCartCost({
41
38
  store: TStore;
42
39
  }) {
43
40
  const { isVatIncludedInPrice } = store;
44
- let result = cart.map((item) => {
41
+
42
+ // Convert cart items to the format expected by the discount engine
43
+ const cartForEngine = cart.map((item) => ({
44
+ amount: item.amount,
45
+ product: {
46
+ id: item.product.id,
47
+ price: item.product.price,
48
+ },
49
+ }));
50
+
51
+ // Apply discounts using the new discount engine
52
+ const discountResult = DiscountEngine.calculateDiscounts(cartForEngine, discounts);
53
+
54
+ // Map the results back to the original format with additional product info
55
+ const result = cart.map((item, index) => {
56
+ const engineItem = discountResult.items[index];
45
57
  return {
46
58
  amount: item.amount,
47
59
  product: { ...item.product },
48
60
  originalPrice: item.product.price,
49
- finalPrice: getPriceAfterDiscount(item.product),
50
- finalDiscount: calculateDiscount(item.product),
61
+ finalPrice: engineItem ? engineItem.finalPrice : getPriceAfterDiscount(item.product),
62
+ finalDiscount: engineItem ? engineItem.finalDiscount : calculateDiscount(item.product),
51
63
  };
52
64
  });
53
65
 
54
- // calculate delivery price before
55
- // check if cart cost is greater than free delivery price
56
-
57
- const activeDiscounts = discounts.filter((discount) => {
58
- if (discount.variant.variantType === "bundle") {
59
- const productsTotal =
60
- cart?.reduce((total, item) => {
61
- if (discount.variant.productsId.includes(item.product.id)) {
62
- total += item.amount;
63
- return total;
64
- }
65
- return total;
66
- }, 0) ?? 0;
67
- if (productsTotal >= discount.variant.requiredQuantity) {
68
- // const times = Math.floor(productsTotal / discount.variant.requiredQuantity);
69
- // console.log("yes", times, discount.variant.discountPrice);
70
- return true;
71
- }
72
- }
73
- return false;
74
- });
75
- console.log("activeDiscounts", activeDiscounts);
76
-
77
- activeDiscounts.forEach((discount) => {
78
- if (discount.variant.variantType === "bundle") {
79
- // get all products in cart
80
- const products = cart.filter((item) =>
81
- discount.variant.productsId.includes(item.product.id)
82
- );
83
- const productsTotal =
84
- products?.reduce((total, item) => {
85
- if (discount.variant.productsId.includes(item.product.id)) {
86
- total += item.amount;
87
- return total;
88
- }
89
- return total;
90
- }, 0) ?? 0;
91
-
92
- const times = Math.floor(productsTotal / discount.variant.requiredQuantity);
93
- const price = getPriceAfterDiscount(products[0]?.product);
94
- const _discount = calculateDiscount(products[0]?.product);
95
- console.log("price", price, _discount);
96
- const discountPrice =
97
- Number(
98
- (discount.variant.discountPrice / discount.variant.requiredQuantity).toFixed(2)
99
- ) * 1;
100
-
101
- console.log("discountPrice", discountPrice);
102
- const totalDiscount =
103
- (price * discount.variant.requiredQuantity - discount.variant.discountPrice) * times;
104
-
105
- const originalPrice = productsTotal * price;
106
- const discountPriceFinal = originalPrice - totalDiscount;
107
-
108
- const averagePrice = Number((discountPriceFinal / productsTotal).toFixed(2));
109
-
110
- result = result.map((item) => {
111
- if (discount.variant.productsId.includes(item.product.id)) {
112
- return {
113
- ...item,
114
- finalPrice: averagePrice,
115
- originalPrice: item.product.price,
116
- discountPrice: price,
117
- finalDiscount: item.finalDiscount + (item.product.price - averagePrice),
118
- };
119
- }
120
- return item;
121
- });
122
-
123
- // find average price
124
- }
125
- });
126
-
127
66
  const cartDetails = result.reduce(
128
67
  (acc, item) => {
129
68
  const { product, amount, finalPrice, finalDiscount } = item;
@@ -147,10 +86,20 @@ export function getCartCost({
147
86
  acc.vat = Number((acc.vat + vat).toFixed(2));
148
87
  }
149
88
 
150
- acc.cost += amount * finalPrice;
89
+ // Round finalPrice to prevent floating point errors from discount engine
90
+ const roundedFinalPrice = Number(finalPrice.toFixed(2));
91
+
92
+ acc.cost += amount * roundedFinalPrice;
151
93
  acc.discount += finalDiscount ? amount * finalDiscount : finalDiscount;
152
- acc.finalCost += amount * finalPrice + (isVatIncludedInPrice ? 0 : productVatValue);
153
- acc.productsCost += amount * finalPrice + (isVatIncludedInPrice ? 0 : productVatValue);
94
+ acc.finalCost += amount * roundedFinalPrice + (isVatIncludedInPrice ? 0 : productVatValue);
95
+ acc.productsCost +=
96
+ amount * roundedFinalPrice + (isVatIncludedInPrice ? 0 : productVatValue);
97
+
98
+ // Round all accumulated values to prevent floating point errors
99
+ acc.cost = Number(acc.cost.toFixed(2));
100
+ acc.discount = Number(acc.discount.toFixed(2));
101
+ acc.finalCost = Number(acc.finalCost.toFixed(2));
102
+ acc.productsCost = Number(acc.productsCost.toFixed(2));
154
103
 
155
104
  return acc;
156
105
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jsdev_ninja/core",
3
- "version": "0.12.7",
3
+ "version": "0.12.9",
4
4
  "main": "dist/core.cjs.js",
5
5
  "module": "dist/core.es.js",
6
6
  "types": "dist/index.d.ts",
@@ -1,71 +0,0 @@
1
- import { z } from "zod";
2
- export declare const DiscountSchema: z.ZodObject<{
3
- type: z.ZodLiteral<"Discount">;
4
- storeId: z.ZodString;
5
- companyId: z.ZodString;
6
- id: z.ZodString;
7
- name: z.ZodArray<z.ZodObject<{
8
- lang: z.ZodEnum<["he"]>;
9
- value: z.ZodString;
10
- }, "strip", z.ZodTypeAny, {
11
- value: string;
12
- lang: "he";
13
- }, {
14
- value: string;
15
- lang: "he";
16
- }>, "many">;
17
- active: z.ZodBoolean;
18
- variant: z.ZodDiscriminatedUnion<"variantType", [z.ZodObject<{
19
- variantType: z.ZodLiteral<"bundle">;
20
- productsId: z.ZodArray<z.ZodString, "many">;
21
- requiredQuantity: z.ZodNumber;
22
- discountPrice: z.ZodNumber;
23
- }, "strip", z.ZodTypeAny, {
24
- variantType: "bundle";
25
- productsId: string[];
26
- requiredQuantity: number;
27
- discountPrice: number;
28
- }, {
29
- variantType: "bundle";
30
- productsId: string[];
31
- requiredQuantity: number;
32
- discountPrice: number;
33
- }>]>;
34
- images: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
35
- }, "strip", z.ZodTypeAny, {
36
- type: "Discount";
37
- id: string;
38
- companyId: string;
39
- storeId: string;
40
- name: {
41
- value: string;
42
- lang: "he";
43
- }[];
44
- active: boolean;
45
- variant: {
46
- variantType: "bundle";
47
- productsId: string[];
48
- requiredQuantity: number;
49
- discountPrice: number;
50
- };
51
- images?: string[] | undefined;
52
- }, {
53
- type: "Discount";
54
- id: string;
55
- companyId: string;
56
- storeId: string;
57
- name: {
58
- value: string;
59
- lang: "he";
60
- }[];
61
- active: boolean;
62
- variant: {
63
- variantType: "bundle";
64
- productsId: string[];
65
- requiredQuantity: number;
66
- discountPrice: number;
67
- };
68
- images?: string[] | undefined;
69
- }>;
70
- export type TDiscount = z.infer<typeof DiscountSchema>;
71
- //# sourceMappingURL=Discount.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"Discount.d.ts","sourceRoot":"","sources":["../../lib/entities/Discount.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAKxB,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAgBzB,CAAC;AACH,MAAM,MAAM,SAAS,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAC"}
@@ -1,20 +0,0 @@
1
- import { z } from "zod";
2
- import { LocaleSchema } from "./Locale";
3
- const text = z.string().min(1);
4
- export const DiscountSchema = z.object({
5
- type: z.literal("Discount"),
6
- storeId: text,
7
- companyId: text,
8
- id: text,
9
- name: z.array(LocaleSchema),
10
- active: z.boolean(),
11
- variant: z.discriminatedUnion("variantType", [
12
- z.object({
13
- variantType: z.literal("bundle"),
14
- productsId: z.array(z.string()).min(1),
15
- requiredQuantity: z.number().positive(),
16
- discountPrice: z.number().positive(),
17
- }),
18
- ]),
19
- images: z.array(z.string().nonempty()).optional(),
20
- });