@jsdev_ninja/core 0.13.27 → 0.13.29

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 (145) hide show
  1. package/dist/core.cjs.js +2 -0
  2. package/dist/core.cjs.js.map +1 -0
  3. package/dist/core.es.js +3584 -0
  4. package/dist/core.es.js.map +1 -0
  5. package/dist/core.umd.js +2 -0
  6. package/dist/core.umd.js.map +1 -0
  7. package/dist/lib/entities/Address.d.ts +28 -0
  8. package/dist/lib/entities/Address.d.ts.map +1 -0
  9. package/dist/lib/entities/Address.js +10 -0
  10. package/dist/lib/entities/Atoms.d.ts +16 -0
  11. package/dist/lib/entities/Atoms.d.ts.map +1 -0
  12. package/{lib/entities/Atoms.ts → dist/lib/entities/Atoms.js} +2 -6
  13. package/dist/lib/entities/Cart.d.ts +1278 -0
  14. package/dist/lib/entities/Cart.d.ts.map +1 -0
  15. package/dist/lib/entities/Cart.js +18 -0
  16. package/dist/lib/entities/Category.d.ts +103 -0
  17. package/dist/lib/entities/Category.d.ts.map +1 -0
  18. package/dist/lib/entities/Category.js +20 -0
  19. package/dist/lib/entities/Company.d.ts +16 -0
  20. package/dist/lib/entities/Company.d.ts.map +1 -0
  21. package/dist/lib/entities/Company.js +6 -0
  22. package/dist/lib/entities/DeliveryNote.d.ts +248 -0
  23. package/dist/lib/entities/DeliveryNote.d.ts.map +1 -0
  24. package/dist/lib/entities/DeliveryNote.js +61 -0
  25. package/dist/lib/entities/Discount/__tests__/engine.test.d.ts +2 -0
  26. package/dist/lib/entities/Discount/__tests__/engine.test.d.ts.map +1 -0
  27. package/dist/lib/entities/Discount/__tests__/engine.test.js +298 -0
  28. package/dist/lib/entities/Discount/__tests__/factory.test.d.ts +2 -0
  29. package/dist/lib/entities/Discount/__tests__/factory.test.d.ts.map +1 -0
  30. package/dist/lib/entities/Discount/__tests__/factory.test.js +75 -0
  31. package/dist/lib/entities/Discount/__tests__/integration.test.d.ts +2 -0
  32. package/dist/lib/entities/Discount/__tests__/integration.test.d.ts.map +1 -0
  33. package/dist/lib/entities/Discount/__tests__/integration.test.js +115 -0
  34. package/dist/lib/entities/Discount/__tests__/simple.test.d.ts +2 -0
  35. package/dist/lib/entities/Discount/__tests__/simple.test.d.ts.map +1 -0
  36. package/dist/lib/entities/Discount/__tests__/simple.test.js +186 -0
  37. package/dist/lib/entities/Discount/__tests__/utils.test.d.ts +2 -0
  38. package/dist/lib/entities/Discount/__tests__/utils.test.d.ts.map +1 -0
  39. package/dist/lib/entities/Discount/__tests__/utils.test.js +55 -0
  40. package/dist/lib/entities/Discount/engine.d.ts +29 -0
  41. package/dist/lib/entities/Discount/engine.d.ts.map +1 -0
  42. package/dist/lib/entities/Discount/engine.js +85 -0
  43. package/dist/lib/entities/Discount/factory.d.ts +10 -0
  44. package/dist/lib/entities/Discount/factory.d.ts.map +1 -0
  45. package/dist/lib/entities/Discount/factory.js +18 -0
  46. package/dist/lib/entities/Discount/index.d.ts +9 -0
  47. package/dist/lib/entities/Discount/index.d.ts.map +1 -0
  48. package/{lib/entities/Discount/index.ts → dist/lib/entities/Discount/index.js} +0 -2
  49. package/dist/lib/entities/Discount/strategies/BundleStrategy.d.ts +12 -0
  50. package/dist/lib/entities/Discount/strategies/BundleStrategy.d.ts.map +1 -0
  51. package/dist/lib/entities/Discount/strategies/BundleStrategy.js +78 -0
  52. package/dist/lib/entities/Discount/strategies/__tests__/BundleStrategy.test.d.ts +2 -0
  53. package/dist/lib/entities/Discount/strategies/__tests__/BundleStrategy.test.d.ts.map +1 -0
  54. package/dist/lib/entities/Discount/strategies/__tests__/BundleStrategy.test.js +265 -0
  55. package/dist/lib/entities/Discount/strategy.d.ts +6 -0
  56. package/dist/lib/entities/Discount/strategy.d.ts.map +1 -0
  57. package/dist/lib/entities/Discount/types.d.ts +148 -0
  58. package/dist/lib/entities/Discount/types.d.ts.map +1 -0
  59. package/dist/lib/entities/Discount/types.js +29 -0
  60. package/dist/lib/entities/Discount/utils.d.ts +29 -0
  61. package/dist/lib/entities/Discount/utils.d.ts.map +1 -0
  62. package/{lib/entities/Discount/utils.ts → dist/lib/entities/Discount/utils.js} +12 -15
  63. package/dist/lib/entities/FavoriteProduct.d.ts +25 -0
  64. package/dist/lib/entities/FavoriteProduct.d.ts.map +1 -0
  65. package/dist/lib/entities/FavoriteProduct.js +9 -0
  66. package/dist/lib/entities/Invoice.d.ts +210 -0
  67. package/dist/lib/entities/Invoice.d.ts.map +1 -0
  68. package/dist/lib/entities/Invoice.js +49 -0
  69. package/dist/lib/entities/Locale.d.ts +22 -0
  70. package/dist/lib/entities/Locale.d.ts.map +1 -0
  71. package/{lib/entities/Locale.ts → dist/lib/entities/Locale.js} +2 -4
  72. package/dist/lib/entities/Order.d.ts +1806 -0
  73. package/dist/lib/entities/Order.d.ts.map +1 -0
  74. package/dist/lib/entities/Order.js +63 -0
  75. package/dist/lib/entities/Organization.d.ts +100 -0
  76. package/dist/lib/entities/Organization.d.ts.map +1 -0
  77. package/dist/lib/entities/Organization.js +17 -0
  78. package/dist/lib/entities/Payment/index.d.ts +4 -0
  79. package/dist/lib/entities/Payment/index.d.ts.map +1 -0
  80. package/dist/lib/entities/Payment/index.js +4 -0
  81. package/dist/lib/entities/Product.d.ts +694 -0
  82. package/dist/lib/entities/Product.d.ts.map +1 -0
  83. package/dist/lib/entities/Product.js +61 -0
  84. package/dist/lib/entities/Profile.d.ts +95 -0
  85. package/dist/lib/entities/Profile.d.ts.map +1 -0
  86. package/dist/lib/entities/Profile.js +22 -0
  87. package/dist/lib/entities/Store.d.ts +93 -0
  88. package/dist/lib/entities/Store.d.ts.map +1 -0
  89. package/dist/lib/entities/Store.js +21 -0
  90. package/dist/lib/entities/index.d.ts +16 -0
  91. package/dist/lib/entities/index.d.ts.map +1 -0
  92. package/{lib/entities/index.ts → dist/lib/entities/index.js} +1 -0
  93. package/dist/lib/firebase-api/app.d.ts +2 -0
  94. package/dist/lib/firebase-api/app.d.ts.map +1 -0
  95. package/dist/lib/firebase-api/app.js +16 -0
  96. package/dist/lib/firebase-api/index.d.ts +75 -0
  97. package/dist/lib/firebase-api/index.d.ts.map +1 -0
  98. package/dist/lib/firebase-api/index.js +33 -0
  99. package/dist/lib/index.d.ts +4 -0
  100. package/dist/lib/index.d.ts.map +1 -0
  101. package/dist/lib/utils/index.d.ts +109 -0
  102. package/dist/lib/utils/index.d.ts.map +1 -0
  103. package/dist/lib/utils/index.js +95 -0
  104. package/dist/tsconfig.app.tsbuildinfo +1 -0
  105. package/dist/tsconfig.node.tsbuildinfo +1 -0
  106. package/dist/vite.config.d.ts +3 -0
  107. package/dist/vite.config.d.ts.map +1 -0
  108. package/dist/vite.config.js +25 -0
  109. package/package.json +8 -1
  110. package/eslint.config.js +0 -28
  111. package/index.html +0 -13
  112. package/lib/entities/Address.ts +0 -13
  113. package/lib/entities/Cart.ts +0 -24
  114. package/lib/entities/Category.ts +0 -35
  115. package/lib/entities/Company.ts +0 -9
  116. package/lib/entities/DeliveryNote.ts +0 -70
  117. package/lib/entities/Discount/__tests__/engine.test.ts +0 -337
  118. package/lib/entities/Discount/__tests__/factory.test.ts +0 -91
  119. package/lib/entities/Discount/__tests__/integration.test.ts +0 -132
  120. package/lib/entities/Discount/__tests__/simple.test.ts +0 -215
  121. package/lib/entities/Discount/__tests__/utils.test.ts +0 -69
  122. package/lib/entities/Discount/engine.ts +0 -138
  123. package/lib/entities/Discount/factory.ts +0 -25
  124. package/lib/entities/Discount/strategies/BundleStrategy.ts +0 -119
  125. package/lib/entities/Discount/strategies/__tests__/BundleStrategy.test.ts +0 -295
  126. package/lib/entities/Discount/strategy.ts +0 -6
  127. package/lib/entities/Discount/types.ts +0 -68
  128. package/lib/entities/FavoriteProduct.ts +0 -12
  129. package/lib/entities/Invoice.ts +0 -57
  130. package/lib/entities/Order.ts +0 -67
  131. package/lib/entities/Organization.ts +0 -23
  132. package/lib/entities/Product.ts +0 -68
  133. package/lib/entities/Profile.ts +0 -56
  134. package/lib/entities/Store.ts +0 -24
  135. package/lib/firebase-api/app.ts +0 -18
  136. package/lib/firebase-api/index.ts +0 -46
  137. package/lib/utils/index.ts +0 -127
  138. package/src/vite-env.d.ts +0 -1
  139. package/tsconfig.app.json +0 -20
  140. package/tsconfig.json +0 -7
  141. package/tsconfig.node.json +0 -26
  142. package/vite.config.ts +0 -27
  143. package/vitest.config.ts +0 -10
  144. /package/{src/main.tsx → dist/lib/entities/Discount/strategy.js} +0 -0
  145. /package/{lib/index.tsx → dist/lib/index.js} +0 -0
@@ -1,337 +0,0 @@
1
- import { describe, it, expect, beforeEach, afterEach } from "vitest";
2
- import { DiscountEngine } from "../engine";
3
- import { DiscountStrategyFactory } from "../factory";
4
- import { BundleDiscountStrategy } from "../strategies/BundleStrategy";
5
- import { TDiscount } from "../types";
6
-
7
- describe("DiscountEngine", () => {
8
- beforeEach(() => {
9
- DiscountStrategyFactory.clearStrategies();
10
- DiscountStrategyFactory.registerStrategy("bundle", new BundleDiscountStrategy());
11
- });
12
-
13
- afterEach(() => {
14
- DiscountStrategyFactory.clearStrategies();
15
- });
16
-
17
- describe("calculateDiscounts", () => {
18
- it("should apply bundle discount correctly", () => {
19
- const cart = [
20
- {
21
- amount: 2,
22
- product: {
23
- id: "product1",
24
- price: 10,
25
- },
26
- },
27
- {
28
- amount: 1,
29
- product: {
30
- id: "product2",
31
- price: 15,
32
- },
33
- },
34
- ];
35
-
36
- const discounts: TDiscount[] = [
37
- {
38
- type: "Discount",
39
- storeId: "store1",
40
- companyId: "company1",
41
- id: "bundle1",
42
- name: [{ lang: "he", value: "Buy 3 for $25" }],
43
- active: true,
44
- startDate: Date.now() - 1000,
45
- endDate: Date.now() + 1000,
46
- variant: {
47
- variantType: "bundle",
48
- productsId: ["product1", "product2"],
49
- requiredQuantity: 3,
50
- bundlePrice: 25,
51
- },
52
- conditions: {
53
- stackable: false,
54
- },
55
- },
56
- ];
57
-
58
- const result = DiscountEngine.calculateDiscounts(cart, discounts);
59
-
60
- expect(result.totalDiscount).toBe(10);
61
- expect(result.appliedDiscounts).toHaveLength(1);
62
- expect(result.appliedDiscounts[0].discountId).toBe("bundle1");
63
- expect(result.items).toHaveLength(2);
64
-
65
- // Check final prices
66
- const product1Item = result.items.find(item => item.product.id === "product1");
67
- expect(product1Item?.finalPrice).toBeCloseTo(7.14, 2); // 10 - (5.71/2) = 7.145
68
-
69
- const product2Item = result.items.find(item => item.product.id === "product2");
70
- expect(product2Item?.finalPrice).toBeCloseTo(10.71, 2); // 15 - 4.29 = 10.71
71
- });
72
-
73
- it("should handle multiple discounts", () => {
74
- const cart = [
75
- {
76
- amount: 4,
77
- product: {
78
- id: "product1",
79
- price: 10,
80
- },
81
- },
82
- ];
83
-
84
- const discounts: TDiscount[] = [
85
- {
86
- type: "Discount",
87
- storeId: "store1",
88
- companyId: "company1",
89
- id: "bundle1",
90
- name: [{ lang: "he", value: "Buy 3 for $25" }],
91
- active: true,
92
- startDate: Date.now() - 1000,
93
- endDate: Date.now() + 1000,
94
- variant: {
95
- variantType: "bundle",
96
- productsId: ["product1"],
97
- requiredQuantity: 3,
98
- bundlePrice: 25,
99
- },
100
- conditions: {
101
- stackable: true, // Allow stacking
102
- },
103
- },
104
- {
105
- type: "Discount",
106
- storeId: "store1",
107
- companyId: "company1",
108
- id: "bundle2",
109
- name: [{ lang: "he", value: "Buy 2 for $15" }],
110
- active: true,
111
- startDate: Date.now() - 1000,
112
- endDate: Date.now() + 1000,
113
- variant: {
114
- variantType: "bundle",
115
- productsId: ["product1"],
116
- requiredQuantity: 2,
117
- bundlePrice: 15,
118
- },
119
- conditions: {
120
- stackable: true,
121
- },
122
- },
123
- ];
124
-
125
- const result = DiscountEngine.calculateDiscounts(cart, discounts);
126
-
127
- expect(result.appliedDiscounts).toHaveLength(2);
128
- expect(result.totalDiscount).toBeGreaterThan(0);
129
- });
130
-
131
- it("should filter out inactive discounts", () => {
132
- const cart = [
133
- {
134
- amount: 3,
135
- product: {
136
- id: "product1",
137
- price: 10,
138
- },
139
- },
140
- ];
141
-
142
- const discounts: TDiscount[] = [
143
- {
144
- type: "Discount",
145
- storeId: "store1",
146
- companyId: "company1",
147
- id: "bundle1",
148
- name: [{ lang: "he", value: "Buy 3 for $25" }],
149
- active: false, // Inactive
150
- startDate: Date.now() - 1000,
151
- endDate: Date.now() + 1000,
152
- variant: {
153
- variantType: "bundle",
154
- productsId: ["product1"],
155
- requiredQuantity: 3,
156
- bundlePrice: 25,
157
- },
158
- conditions: {
159
- stackable: false,
160
- },
161
- },
162
- ];
163
-
164
- const result = DiscountEngine.calculateDiscounts(cart, discounts);
165
-
166
- expect(result.totalDiscount).toBe(0);
167
- expect(result.appliedDiscounts).toHaveLength(0);
168
- });
169
-
170
- it("should handle empty cart", () => {
171
- const cart: Array<{
172
- amount: number;
173
- product: {
174
- id: string;
175
- price: number;
176
- };
177
- }> = [];
178
- const discounts: TDiscount[] = [
179
- {
180
- type: "Discount",
181
- storeId: "store1",
182
- companyId: "company1",
183
- id: "bundle1",
184
- name: [{ lang: "he", value: "Buy 3 for $25" }],
185
- active: true,
186
- startDate: Date.now() - 1000,
187
- endDate: Date.now() + 1000,
188
- variant: {
189
- variantType: "bundle",
190
- productsId: ["product1"],
191
- requiredQuantity: 3,
192
- bundlePrice: 25,
193
- },
194
- conditions: {
195
- stackable: false,
196
- },
197
- },
198
- ];
199
-
200
- const result = DiscountEngine.calculateDiscounts(cart, discounts);
201
-
202
- expect(result.totalDiscount).toBe(0);
203
- expect(result.appliedDiscounts).toHaveLength(0);
204
- expect(result.items).toHaveLength(0);
205
- });
206
-
207
- it("should handle empty discounts", () => {
208
- const cart = [
209
- {
210
- amount: 2,
211
- product: {
212
- id: "product1",
213
- price: 10,
214
- },
215
- },
216
- ];
217
-
218
- const discounts: TDiscount[] = [];
219
-
220
- const result = DiscountEngine.calculateDiscounts(cart, discounts);
221
-
222
- expect(result.totalDiscount).toBe(0);
223
- expect(result.appliedDiscounts).toHaveLength(0);
224
- expect(result.items).toHaveLength(1);
225
- expect(result.items[0].finalPrice).toBe(10); // No discount applied
226
- });
227
- });
228
-
229
- describe("isDiscountActive", () => {
230
- it("should return true for active discount", () => {
231
- const discount: TDiscount = {
232
- type: "Discount",
233
- storeId: "store1",
234
- companyId: "company1",
235
- id: "bundle1",
236
- name: [{ lang: "he", value: "Buy 3 for $25" }],
237
- active: true,
238
- startDate: Date.now() - 1000,
239
- endDate: Date.now() + 1000,
240
- variant: {
241
- variantType: "bundle",
242
- productsId: ["product1"],
243
- requiredQuantity: 3,
244
- bundlePrice: 25,
245
- },
246
- };
247
-
248
- expect(DiscountEngine.isDiscountActive(discount)).toBe(true);
249
- });
250
-
251
- it("should return false for inactive discount", () => {
252
- const discount: TDiscount = {
253
- type: "Discount",
254
- storeId: "store1",
255
- companyId: "company1",
256
- id: "bundle1",
257
- name: [{ lang: "he", value: "Buy 3 for $25" }],
258
- active: false,
259
- startDate: Date.now() - 1000,
260
- endDate: Date.now() + 1000,
261
- variant: {
262
- variantType: "bundle",
263
- productsId: ["product1"],
264
- requiredQuantity: 3,
265
- bundlePrice: 25,
266
- },
267
- };
268
-
269
- expect(DiscountEngine.isDiscountActive(discount)).toBe(false);
270
- });
271
-
272
- it("should return false for expired discount", () => {
273
- const discount: TDiscount = {
274
- type: "Discount",
275
- storeId: "store1",
276
- companyId: "company1",
277
- id: "bundle1",
278
- name: [{ lang: "he", value: "Buy 3 for $25" }],
279
- active: true,
280
- startDate: Date.now() - 2000,
281
- endDate: Date.now() - 1000, // Expired
282
- variant: {
283
- variantType: "bundle",
284
- productsId: ["product1"],
285
- requiredQuantity: 3,
286
- bundlePrice: 25,
287
- },
288
- };
289
-
290
- expect(DiscountEngine.isDiscountActive(discount)).toBe(false);
291
- });
292
- });
293
-
294
- describe("getActiveDiscounts", () => {
295
- it("should filter active discounts", () => {
296
- const discounts: TDiscount[] = [
297
- {
298
- type: "Discount",
299
- storeId: "store1",
300
- companyId: "company1",
301
- id: "active1",
302
- name: [{ lang: "he", value: "Active Discount" }],
303
- active: true,
304
- startDate: Date.now() - 1000,
305
- endDate: Date.now() + 1000,
306
- variant: {
307
- variantType: "bundle",
308
- productsId: ["product1"],
309
- requiredQuantity: 3,
310
- bundlePrice: 25,
311
- },
312
- },
313
- {
314
- type: "Discount",
315
- storeId: "store1",
316
- companyId: "company1",
317
- id: "inactive1",
318
- name: [{ lang: "he", value: "Inactive Discount" }],
319
- active: false,
320
- startDate: Date.now() - 1000,
321
- endDate: Date.now() + 1000,
322
- variant: {
323
- variantType: "bundle",
324
- productsId: ["product1"],
325
- requiredQuantity: 3,
326
- bundlePrice: 25,
327
- },
328
- },
329
- ];
330
-
331
- const activeDiscounts = DiscountEngine.getActiveDiscounts(discounts);
332
-
333
- expect(activeDiscounts).toHaveLength(1);
334
- expect(activeDiscounts[0].id).toBe("active1");
335
- });
336
- });
337
- });
@@ -1,91 +0,0 @@
1
- import { describe, it, expect, beforeEach, afterEach } from "vitest";
2
- import { DiscountStrategyFactory } from "../factory";
3
- import { DiscountStrategy } from "../strategy";
4
- import { TDiscount } from "../types";
5
-
6
- describe("DiscountStrategyFactory", () => {
7
- beforeEach(() => {
8
- DiscountStrategyFactory.clearStrategies();
9
- });
10
-
11
- afterEach(() => {
12
- DiscountStrategyFactory.clearStrategies();
13
- });
14
-
15
- it("should register and get strategy", () => {
16
- const mockStrategy: DiscountStrategy = {
17
- canApply: () => false,
18
- calculate: () => ({ applicable: false, discountAmount: 0, affectedItems: [] }),
19
- };
20
-
21
- DiscountStrategyFactory.registerStrategy("bundle", mockStrategy);
22
-
23
- const discount: TDiscount = {
24
- type: "Discount",
25
- storeId: "store1",
26
- companyId: "company1",
27
- id: "test1",
28
- name: [{ lang: "he", value: "Test Discount" }],
29
- active: true,
30
- startDate: Date.now() - 1000,
31
- endDate: Date.now() + 1000,
32
- variant: {
33
- variantType: "bundle",
34
- productsId: ["product1"],
35
- requiredQuantity: 3,
36
- bundlePrice: 25,
37
- },
38
- };
39
-
40
- const result = DiscountStrategyFactory.getStrategy(discount);
41
- expect(result).toBe(mockStrategy);
42
- });
43
-
44
- it("should return null for unregistered strategy", () => {
45
- const discount: TDiscount = {
46
- type: "Discount",
47
- storeId: "store1",
48
- companyId: "company1",
49
- id: "test1",
50
- name: [{ lang: "he", value: "Test Discount" }],
51
- active: true,
52
- startDate: Date.now() - 1000,
53
- endDate: Date.now() + 1000,
54
- variant: {
55
- variantType: "bundle",
56
- productsId: ["product1"],
57
- requiredQuantity: 3,
58
- bundlePrice: 25,
59
- },
60
- };
61
-
62
- const result = DiscountStrategyFactory.getStrategy(discount);
63
- expect(result).toBeNull();
64
- });
65
-
66
- it("should get registered types", () => {
67
- const mockStrategy: DiscountStrategy = {
68
- canApply: () => false,
69
- calculate: () => ({ applicable: false, discountAmount: 0, affectedItems: [] }),
70
- };
71
-
72
- DiscountStrategyFactory.registerStrategy("bundle", mockStrategy);
73
- DiscountStrategyFactory.registerStrategy("percentage", mockStrategy);
74
-
75
- const types = DiscountStrategyFactory.getRegisteredTypes();
76
- expect(types).toEqual(["bundle", "percentage"]);
77
- });
78
-
79
- it("should clear strategies", () => {
80
- const mockStrategy: DiscountStrategy = {
81
- canApply: () => false,
82
- calculate: () => ({ applicable: false, discountAmount: 0, affectedItems: [] }),
83
- };
84
-
85
- DiscountStrategyFactory.registerStrategy("bundle", mockStrategy);
86
- expect(DiscountStrategyFactory.getRegisteredTypes()).toHaveLength(1);
87
-
88
- DiscountStrategyFactory.clearStrategies();
89
- expect(DiscountStrategyFactory.getRegisteredTypes()).toHaveLength(0);
90
- });
91
- });
@@ -1,132 +0,0 @@
1
- import { describe, it, expect, beforeEach, afterEach } from "vitest";
2
- import { DiscountEngine } from "../engine";
3
- import { DiscountStrategyFactory } from "../factory";
4
- import { BundleDiscountStrategy } from "../strategies/BundleStrategy";
5
- import { TDiscount } from "../types";
6
-
7
- describe("Discount System Integration", () => {
8
- beforeEach(() => {
9
- DiscountStrategyFactory.clearStrategies();
10
- DiscountStrategyFactory.registerStrategy("bundle", new BundleDiscountStrategy());
11
- });
12
-
13
- afterEach(() => {
14
- DiscountStrategyFactory.clearStrategies();
15
- });
16
-
17
- it("should handle real-world bundle scenario", () => {
18
- // Scenario: Buy 3 dairy products for $20
19
- const cart = [
20
- {
21
- amount: 2, // 2 milk
22
- product: {
23
- id: "milk",
24
- price: 8, // $8 each
25
- },
26
- },
27
- {
28
- amount: 1, // 1 yogurt
29
- product: {
30
- id: "yogurt",
31
- price: 6, // $6 each
32
- },
33
- },
34
- {
35
- amount: 1, // 1 bread (not in bundle)
36
- product: {
37
- id: "bread",
38
- price: 4, // $4 each
39
- },
40
- },
41
- ];
42
-
43
- const dairyBundle: TDiscount = {
44
- type: "Discount",
45
- storeId: "store1",
46
- companyId: "company1",
47
- id: "dairy-bundle",
48
- name: [{ lang: "he", value: "3 Dairy Products for $20" }],
49
- active: true,
50
- startDate: Date.now() - 1000,
51
- endDate: Date.now() + 1000,
52
- variant: {
53
- variantType: "bundle",
54
- productsId: ["milk", "yogurt", "cheese"], // Dairy products
55
- requiredQuantity: 3,
56
- bundlePrice: 20,
57
- },
58
- conditions: {
59
- stackable: false,
60
- },
61
- };
62
-
63
- const result = DiscountEngine.calculateDiscounts(cart, [dairyBundle]);
64
-
65
- // Original prices:
66
- // milk: 2 × $8 = $16
67
- // yogurt: 1 × $6 = $6
68
- // bread: 1 × $4 = $4
69
- // Total: $26
70
-
71
- // Bundle applies to milk + yogurt (3 items for $20)
72
- // Remaining: bread at $4
73
- // New total: $24
74
-
75
- expect(result.totalDiscount).toBe(2); // $26 - $24
76
- expect(result.appliedDiscounts).toHaveLength(1);
77
- expect(result.appliedDiscounts[0].discountId).toBe("dairy-bundle");
78
-
79
- // Check individual item prices
80
- const milkItem = result.items.find(item => item.product.id === "milk");
81
- expect(milkItem?.finalPrice).toBeCloseTo(7.28, 2); // 8 - (1.45/2) = 7.275
82
-
83
- const yogurtItem = result.items.find(item => item.product.id === "yogurt");
84
- expect(yogurtItem?.finalPrice).toBeCloseTo(5.45, 2); // 6 - 0.55 = 5.45
85
-
86
- const breadItem = result.items.find(item => item.product.id === "bread");
87
- expect(breadItem?.finalPrice).toBe(4); // No discount
88
- });
89
-
90
- it("should handle BOGO scenario", () => {
91
- // Scenario: Buy 2 Get 1 Free
92
- const cart = [
93
- {
94
- amount: 3, // Buy 3 items
95
- product: {
96
- id: "product1",
97
- price: 10, // $10 each
98
- },
99
- },
100
- ];
101
-
102
- const bogoDiscount: TDiscount = {
103
- type: "Discount",
104
- storeId: "store1",
105
- companyId: "company1",
106
- id: "bogo",
107
- name: [{ lang: "he", value: "Buy 2 Get 1 Free" }],
108
- active: true,
109
- startDate: Date.now() - 1000,
110
- endDate: Date.now() + 1000,
111
- variant: {
112
- variantType: "bundle",
113
- productsId: ["product1"],
114
- requiredQuantity: 3, // Buy 2 + get 1 free = 3 items
115
- bundlePrice: 20, // Price of 2 items (10 × 2)
116
- },
117
- conditions: {
118
- stackable: false,
119
- },
120
- };
121
-
122
- const result = DiscountEngine.calculateDiscounts(cart, [bogoDiscount]);
123
-
124
- // Original: 3 × $10 = $30
125
- // Bundle: 3 items for $20
126
- // Discount: $10
127
-
128
- expect(result.totalDiscount).toBe(10);
129
- expect(result.appliedDiscounts).toHaveLength(1);
130
- expect(result.items[0].finalPrice).toBeCloseTo(6.67, 2); // $20 / 3
131
- });
132
- });