@jsdev_ninja/core 0.13.27 → 0.13.28
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/core.cjs.js +2 -0
- package/dist/core.cjs.js.map +1 -0
- package/dist/core.es.js +3614 -0
- package/dist/core.es.js.map +1 -0
- package/dist/core.umd.js +2 -0
- package/dist/core.umd.js.map +1 -0
- package/dist/lib/entities/Address.d.ts +28 -0
- package/dist/lib/entities/Address.d.ts.map +1 -0
- package/dist/lib/entities/Address.js +10 -0
- package/dist/lib/entities/Atoms.d.ts +16 -0
- package/dist/lib/entities/Atoms.d.ts.map +1 -0
- package/{lib/entities/Atoms.ts → dist/lib/entities/Atoms.js} +2 -6
- package/dist/lib/entities/Cart.d.ts +1278 -0
- package/dist/lib/entities/Cart.d.ts.map +1 -0
- package/dist/lib/entities/Cart.js +18 -0
- package/dist/lib/entities/Category.d.ts +103 -0
- package/dist/lib/entities/Category.d.ts.map +1 -0
- package/dist/lib/entities/Category.js +20 -0
- package/dist/lib/entities/Company.d.ts +16 -0
- package/dist/lib/entities/Company.d.ts.map +1 -0
- package/dist/lib/entities/Company.js +6 -0
- package/dist/lib/entities/DeliveryNote.d.ts +248 -0
- package/dist/lib/entities/DeliveryNote.d.ts.map +1 -0
- package/dist/lib/entities/DeliveryNote.js +61 -0
- package/dist/lib/entities/Discount/__tests__/engine.test.d.ts +2 -0
- package/dist/lib/entities/Discount/__tests__/engine.test.d.ts.map +1 -0
- package/dist/lib/entities/Discount/__tests__/engine.test.js +298 -0
- package/dist/lib/entities/Discount/__tests__/factory.test.d.ts +2 -0
- package/dist/lib/entities/Discount/__tests__/factory.test.d.ts.map +1 -0
- package/dist/lib/entities/Discount/__tests__/factory.test.js +75 -0
- package/dist/lib/entities/Discount/__tests__/integration.test.d.ts +2 -0
- package/dist/lib/entities/Discount/__tests__/integration.test.d.ts.map +1 -0
- package/dist/lib/entities/Discount/__tests__/integration.test.js +115 -0
- package/dist/lib/entities/Discount/__tests__/simple.test.d.ts +2 -0
- package/dist/lib/entities/Discount/__tests__/simple.test.d.ts.map +1 -0
- package/dist/lib/entities/Discount/__tests__/simple.test.js +186 -0
- package/dist/lib/entities/Discount/__tests__/utils.test.d.ts +2 -0
- package/dist/lib/entities/Discount/__tests__/utils.test.d.ts.map +1 -0
- package/dist/lib/entities/Discount/__tests__/utils.test.js +55 -0
- package/dist/lib/entities/Discount/engine.d.ts +29 -0
- package/dist/lib/entities/Discount/engine.d.ts.map +1 -0
- package/dist/lib/entities/Discount/engine.js +85 -0
- package/dist/lib/entities/Discount/factory.d.ts +10 -0
- package/dist/lib/entities/Discount/factory.d.ts.map +1 -0
- package/dist/lib/entities/Discount/factory.js +18 -0
- package/dist/lib/entities/Discount/index.d.ts +9 -0
- package/dist/lib/entities/Discount/index.d.ts.map +1 -0
- package/{lib/entities/Discount/index.ts → dist/lib/entities/Discount/index.js} +0 -2
- package/dist/lib/entities/Discount/strategies/BundleStrategy.d.ts +12 -0
- package/dist/lib/entities/Discount/strategies/BundleStrategy.d.ts.map +1 -0
- package/dist/lib/entities/Discount/strategies/BundleStrategy.js +78 -0
- package/dist/lib/entities/Discount/strategies/__tests__/BundleStrategy.test.d.ts +2 -0
- package/dist/lib/entities/Discount/strategies/__tests__/BundleStrategy.test.d.ts.map +1 -0
- package/dist/lib/entities/Discount/strategies/__tests__/BundleStrategy.test.js +265 -0
- package/dist/lib/entities/Discount/strategy.d.ts +6 -0
- package/dist/lib/entities/Discount/strategy.d.ts.map +1 -0
- package/dist/lib/entities/Discount/types.d.ts +148 -0
- package/dist/lib/entities/Discount/types.d.ts.map +1 -0
- package/dist/lib/entities/Discount/types.js +29 -0
- package/dist/lib/entities/Discount/utils.d.ts +29 -0
- package/dist/lib/entities/Discount/utils.d.ts.map +1 -0
- package/{lib/entities/Discount/utils.ts → dist/lib/entities/Discount/utils.js} +12 -15
- package/dist/lib/entities/FavoriteProduct.d.ts +25 -0
- package/dist/lib/entities/FavoriteProduct.d.ts.map +1 -0
- package/dist/lib/entities/FavoriteProduct.js +9 -0
- package/dist/lib/entities/Invoice.d.ts +210 -0
- package/dist/lib/entities/Invoice.d.ts.map +1 -0
- package/dist/lib/entities/Invoice.js +49 -0
- package/dist/lib/entities/Locale.d.ts +22 -0
- package/dist/lib/entities/Locale.d.ts.map +1 -0
- package/{lib/entities/Locale.ts → dist/lib/entities/Locale.js} +2 -4
- package/dist/lib/entities/Order.d.ts +1806 -0
- package/dist/lib/entities/Order.d.ts.map +1 -0
- package/dist/lib/entities/Order.js +62 -0
- package/dist/lib/entities/Organization.d.ts +100 -0
- package/dist/lib/entities/Organization.d.ts.map +1 -0
- package/dist/lib/entities/Organization.js +16 -0
- package/dist/lib/entities/Product.d.ts +694 -0
- package/dist/lib/entities/Product.d.ts.map +1 -0
- package/dist/lib/entities/Product.js +61 -0
- package/dist/lib/entities/Profile.d.ts +98 -0
- package/dist/lib/entities/Profile.d.ts.map +1 -0
- package/dist/lib/entities/Profile.js +50 -0
- package/dist/lib/entities/Store.d.ts +93 -0
- package/dist/lib/entities/Store.d.ts.map +1 -0
- package/dist/lib/entities/Store.js +20 -0
- package/dist/lib/entities/index.d.ts +15 -0
- package/dist/lib/entities/index.d.ts.map +1 -0
- package/dist/lib/firebase-api/app.d.ts +2 -0
- package/dist/lib/firebase-api/app.d.ts.map +1 -0
- package/dist/lib/firebase-api/app.js +16 -0
- package/dist/lib/firebase-api/index.d.ts +75 -0
- package/dist/lib/firebase-api/index.d.ts.map +1 -0
- package/dist/lib/firebase-api/index.js +33 -0
- package/dist/lib/index.d.ts +4 -0
- package/dist/lib/index.d.ts.map +1 -0
- package/dist/lib/utils/index.d.ts +109 -0
- package/dist/lib/utils/index.d.ts.map +1 -0
- package/dist/lib/utils/index.js +95 -0
- package/dist/tsconfig.app.tsbuildinfo +1 -0
- package/dist/tsconfig.node.tsbuildinfo +1 -0
- package/dist/vite.config.d.ts +3 -0
- package/dist/vite.config.d.ts.map +1 -0
- package/dist/vite.config.js +25 -0
- package/package.json +8 -1
- package/eslint.config.js +0 -28
- package/index.html +0 -13
- package/lib/entities/Address.ts +0 -13
- package/lib/entities/Cart.ts +0 -24
- package/lib/entities/Category.ts +0 -35
- package/lib/entities/Company.ts +0 -9
- package/lib/entities/DeliveryNote.ts +0 -70
- package/lib/entities/Discount/__tests__/engine.test.ts +0 -337
- package/lib/entities/Discount/__tests__/factory.test.ts +0 -91
- package/lib/entities/Discount/__tests__/integration.test.ts +0 -132
- package/lib/entities/Discount/__tests__/simple.test.ts +0 -215
- package/lib/entities/Discount/__tests__/utils.test.ts +0 -69
- package/lib/entities/Discount/engine.ts +0 -138
- package/lib/entities/Discount/factory.ts +0 -25
- package/lib/entities/Discount/strategies/BundleStrategy.ts +0 -119
- package/lib/entities/Discount/strategies/__tests__/BundleStrategy.test.ts +0 -295
- package/lib/entities/Discount/strategy.ts +0 -6
- package/lib/entities/Discount/types.ts +0 -68
- package/lib/entities/FavoriteProduct.ts +0 -12
- package/lib/entities/Invoice.ts +0 -57
- package/lib/entities/Order.ts +0 -67
- package/lib/entities/Organization.ts +0 -23
- package/lib/entities/Product.ts +0 -68
- package/lib/entities/Profile.ts +0 -56
- package/lib/entities/Store.ts +0 -24
- package/lib/firebase-api/app.ts +0 -18
- package/lib/firebase-api/index.ts +0 -46
- package/lib/utils/index.ts +0 -127
- package/src/vite-env.d.ts +0 -1
- package/tsconfig.app.json +0 -20
- package/tsconfig.json +0 -7
- package/tsconfig.node.json +0 -26
- package/vite.config.ts +0 -27
- package/vitest.config.ts +0 -10
- /package/{src/main.tsx → dist/lib/entities/Discount/strategy.js} +0 -0
- /package/{lib/entities/index.ts → dist/lib/entities/index.js} +0 -0
- /package/{lib/index.tsx → dist/lib/index.js} +0 -0
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach } from "vitest";
|
|
2
|
+
import { BundleDiscountStrategy } from "../BundleStrategy";
|
|
3
|
+
describe("BundleDiscountStrategy", () => {
|
|
4
|
+
let strategy;
|
|
5
|
+
let mockContext;
|
|
6
|
+
beforeEach(() => {
|
|
7
|
+
strategy = new BundleDiscountStrategy();
|
|
8
|
+
mockContext = {
|
|
9
|
+
cart: [
|
|
10
|
+
{
|
|
11
|
+
amount: 2,
|
|
12
|
+
product: {
|
|
13
|
+
id: "product1",
|
|
14
|
+
price: 10,
|
|
15
|
+
},
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
amount: 1,
|
|
19
|
+
product: {
|
|
20
|
+
id: "product2",
|
|
21
|
+
price: 15,
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
],
|
|
25
|
+
user: undefined,
|
|
26
|
+
appliedDiscounts: [],
|
|
27
|
+
};
|
|
28
|
+
});
|
|
29
|
+
describe("canApply", () => {
|
|
30
|
+
it("should return true for valid bundle discount", () => {
|
|
31
|
+
const discount = {
|
|
32
|
+
type: "Discount",
|
|
33
|
+
storeId: "store1",
|
|
34
|
+
companyId: "company1",
|
|
35
|
+
id: "bundle1",
|
|
36
|
+
name: [{ lang: "he", value: "Buy 3 for $25" }],
|
|
37
|
+
active: true,
|
|
38
|
+
startDate: Date.now() - 1000,
|
|
39
|
+
endDate: Date.now() + 1000,
|
|
40
|
+
variant: {
|
|
41
|
+
variantType: "bundle",
|
|
42
|
+
productsId: ["product1", "product2"],
|
|
43
|
+
requiredQuantity: 3,
|
|
44
|
+
bundlePrice: 25,
|
|
45
|
+
},
|
|
46
|
+
conditions: {
|
|
47
|
+
stackable: false,
|
|
48
|
+
},
|
|
49
|
+
};
|
|
50
|
+
expect(strategy.canApply(discount, mockContext)).toBe(true);
|
|
51
|
+
});
|
|
52
|
+
it("should return true for bundle variant type", () => {
|
|
53
|
+
const discount = {
|
|
54
|
+
...mockDiscount,
|
|
55
|
+
variant: {
|
|
56
|
+
variantType: "bundle",
|
|
57
|
+
productsId: ["product1", "product2"],
|
|
58
|
+
requiredQuantity: 3,
|
|
59
|
+
bundlePrice: 25,
|
|
60
|
+
},
|
|
61
|
+
};
|
|
62
|
+
// This should work since it's a bundle type and we have 3 items total
|
|
63
|
+
expect(strategy.canApply(discount, mockContext)).toBe(true);
|
|
64
|
+
});
|
|
65
|
+
it("should return false when not enough items", () => {
|
|
66
|
+
const discount = {
|
|
67
|
+
type: "Discount",
|
|
68
|
+
storeId: "store1",
|
|
69
|
+
companyId: "company1",
|
|
70
|
+
id: "bundle1",
|
|
71
|
+
name: [{ lang: "he", value: "Buy 5 for $40" }],
|
|
72
|
+
active: true,
|
|
73
|
+
startDate: Date.now() - 1000,
|
|
74
|
+
endDate: Date.now() + 1000,
|
|
75
|
+
variant: {
|
|
76
|
+
variantType: "bundle",
|
|
77
|
+
productsId: ["product1", "product2"],
|
|
78
|
+
requiredQuantity: 5, // Need 5, but cart only has 3
|
|
79
|
+
bundlePrice: 40,
|
|
80
|
+
},
|
|
81
|
+
conditions: {
|
|
82
|
+
stackable: false,
|
|
83
|
+
},
|
|
84
|
+
};
|
|
85
|
+
expect(strategy.canApply(discount, mockContext)).toBe(false);
|
|
86
|
+
});
|
|
87
|
+
it("should return false when discount is inactive", () => {
|
|
88
|
+
const discount = {
|
|
89
|
+
type: "Discount",
|
|
90
|
+
storeId: "store1",
|
|
91
|
+
companyId: "company1",
|
|
92
|
+
id: "bundle1",
|
|
93
|
+
name: [{ lang: "he", value: "Buy 3 for $25" }],
|
|
94
|
+
active: false, // Inactive
|
|
95
|
+
startDate: Date.now() - 1000,
|
|
96
|
+
endDate: Date.now() + 1000,
|
|
97
|
+
variant: {
|
|
98
|
+
variantType: "bundle",
|
|
99
|
+
productsId: ["product1", "product2"],
|
|
100
|
+
requiredQuantity: 3,
|
|
101
|
+
bundlePrice: 25,
|
|
102
|
+
},
|
|
103
|
+
conditions: {
|
|
104
|
+
stackable: false,
|
|
105
|
+
},
|
|
106
|
+
};
|
|
107
|
+
expect(strategy.canApply(discount, mockContext)).toBe(false);
|
|
108
|
+
});
|
|
109
|
+
it("should return false when discount is expired", () => {
|
|
110
|
+
const discount = {
|
|
111
|
+
type: "Discount",
|
|
112
|
+
storeId: "store1",
|
|
113
|
+
companyId: "company1",
|
|
114
|
+
id: "bundle1",
|
|
115
|
+
name: [{ lang: "he", value: "Buy 3 for $25" }],
|
|
116
|
+
active: true,
|
|
117
|
+
startDate: Date.now() - 2000,
|
|
118
|
+
endDate: Date.now() - 1000, // Expired
|
|
119
|
+
variant: {
|
|
120
|
+
variantType: "bundle",
|
|
121
|
+
productsId: ["product1", "product2"],
|
|
122
|
+
requiredQuantity: 3,
|
|
123
|
+
bundlePrice: 25,
|
|
124
|
+
},
|
|
125
|
+
conditions: {
|
|
126
|
+
stackable: false,
|
|
127
|
+
},
|
|
128
|
+
};
|
|
129
|
+
expect(strategy.canApply(discount, mockContext)).toBe(false);
|
|
130
|
+
});
|
|
131
|
+
});
|
|
132
|
+
describe("calculate", () => {
|
|
133
|
+
it("should calculate bundle discount correctly", () => {
|
|
134
|
+
const discount = {
|
|
135
|
+
type: "Discount",
|
|
136
|
+
storeId: "store1",
|
|
137
|
+
companyId: "company1",
|
|
138
|
+
id: "bundle1",
|
|
139
|
+
name: [{ lang: "he", value: "Buy 3 for $25" }],
|
|
140
|
+
active: true,
|
|
141
|
+
startDate: Date.now() - 1000,
|
|
142
|
+
endDate: Date.now() + 1000,
|
|
143
|
+
variant: {
|
|
144
|
+
variantType: "bundle",
|
|
145
|
+
productsId: ["product1", "product2"],
|
|
146
|
+
requiredQuantity: 3,
|
|
147
|
+
bundlePrice: 25,
|
|
148
|
+
},
|
|
149
|
+
conditions: {
|
|
150
|
+
stackable: false,
|
|
151
|
+
},
|
|
152
|
+
};
|
|
153
|
+
const result = strategy.calculate(discount, mockContext);
|
|
154
|
+
expect(result.applicable).toBe(true);
|
|
155
|
+
expect(result.discountAmount).toBe(10); // (2×10 + 1×15) - 25 = 35 - 25 = 10
|
|
156
|
+
expect(result.affectedItems).toHaveLength(2);
|
|
157
|
+
// Check product1 discount
|
|
158
|
+
const product1Item = result.affectedItems.find(item => item.productId === "product1");
|
|
159
|
+
expect(product1Item).toBeDefined();
|
|
160
|
+
expect(product1Item.discountAmount).toBeCloseTo(5.71, 2); // Proportional to 20/35
|
|
161
|
+
// Check product2 discount
|
|
162
|
+
const product2Item = result.affectedItems.find(item => item.productId === "product2");
|
|
163
|
+
expect(product2Item).toBeDefined();
|
|
164
|
+
expect(product2Item.discountAmount).toBeCloseTo(4.29, 2); // Proportional to 15/35
|
|
165
|
+
});
|
|
166
|
+
it("should handle multiple bundles", () => {
|
|
167
|
+
const contextWithMoreItems = {
|
|
168
|
+
cart: [
|
|
169
|
+
{
|
|
170
|
+
amount: 6, // 6 items
|
|
171
|
+
product: {
|
|
172
|
+
id: "product1",
|
|
173
|
+
price: 10,
|
|
174
|
+
},
|
|
175
|
+
},
|
|
176
|
+
],
|
|
177
|
+
user: undefined,
|
|
178
|
+
appliedDiscounts: [],
|
|
179
|
+
};
|
|
180
|
+
const discount = {
|
|
181
|
+
type: "Discount",
|
|
182
|
+
storeId: "store1",
|
|
183
|
+
companyId: "company1",
|
|
184
|
+
id: "bundle1",
|
|
185
|
+
name: [{ lang: "he", value: "Buy 3 for $25" }],
|
|
186
|
+
active: true,
|
|
187
|
+
startDate: Date.now() - 1000,
|
|
188
|
+
endDate: Date.now() + 1000,
|
|
189
|
+
variant: {
|
|
190
|
+
variantType: "bundle",
|
|
191
|
+
productsId: ["product1"],
|
|
192
|
+
requiredQuantity: 3,
|
|
193
|
+
bundlePrice: 25,
|
|
194
|
+
},
|
|
195
|
+
conditions: {
|
|
196
|
+
stackable: false,
|
|
197
|
+
},
|
|
198
|
+
};
|
|
199
|
+
const result = strategy.calculate(discount, contextWithMoreItems);
|
|
200
|
+
expect(result.applicable).toBe(true);
|
|
201
|
+
expect(result.discountAmount).toBe(10); // (6×10) - (2×25) = 60 - 50 = 10
|
|
202
|
+
expect(result.affectedItems).toHaveLength(1);
|
|
203
|
+
expect(result.affectedItems[0].discountAmount).toBe(10);
|
|
204
|
+
});
|
|
205
|
+
it("should return not applicable for invalid bundle", () => {
|
|
206
|
+
const discount = {
|
|
207
|
+
...mockDiscount,
|
|
208
|
+
variant: {
|
|
209
|
+
variantType: "bundle",
|
|
210
|
+
productsId: ["product1"],
|
|
211
|
+
requiredQuantity: 10, // Too many required
|
|
212
|
+
bundlePrice: 25,
|
|
213
|
+
},
|
|
214
|
+
};
|
|
215
|
+
const result = strategy.calculate(discount, mockContext);
|
|
216
|
+
expect(result.applicable).toBe(false);
|
|
217
|
+
expect(result.discountAmount).toBe(0);
|
|
218
|
+
expect(result.affectedItems).toHaveLength(0);
|
|
219
|
+
});
|
|
220
|
+
it("should return not applicable when not enough items", () => {
|
|
221
|
+
const discount = {
|
|
222
|
+
type: "Discount",
|
|
223
|
+
storeId: "store1",
|
|
224
|
+
companyId: "company1",
|
|
225
|
+
id: "bundle1",
|
|
226
|
+
name: [{ lang: "he", value: "Buy 5 for $40" }],
|
|
227
|
+
active: true,
|
|
228
|
+
startDate: Date.now() - 1000,
|
|
229
|
+
endDate: Date.now() + 1000,
|
|
230
|
+
variant: {
|
|
231
|
+
variantType: "bundle",
|
|
232
|
+
productsId: ["product1", "product2"],
|
|
233
|
+
requiredQuantity: 5,
|
|
234
|
+
bundlePrice: 40,
|
|
235
|
+
},
|
|
236
|
+
conditions: {
|
|
237
|
+
stackable: false,
|
|
238
|
+
},
|
|
239
|
+
};
|
|
240
|
+
const result = strategy.calculate(discount, mockContext);
|
|
241
|
+
expect(result.applicable).toBe(false);
|
|
242
|
+
expect(result.discountAmount).toBe(0);
|
|
243
|
+
expect(result.affectedItems).toHaveLength(0);
|
|
244
|
+
});
|
|
245
|
+
});
|
|
246
|
+
});
|
|
247
|
+
const mockDiscount = {
|
|
248
|
+
type: "Discount",
|
|
249
|
+
storeId: "store1",
|
|
250
|
+
companyId: "company1",
|
|
251
|
+
id: "bundle1",
|
|
252
|
+
name: [{ lang: "he", value: "Buy 3 for $25" }],
|
|
253
|
+
active: true,
|
|
254
|
+
startDate: Date.now() - 1000,
|
|
255
|
+
endDate: Date.now() + 1000,
|
|
256
|
+
variant: {
|
|
257
|
+
variantType: "bundle",
|
|
258
|
+
productsId: ["product1", "product2"],
|
|
259
|
+
requiredQuantity: 3,
|
|
260
|
+
bundlePrice: 25,
|
|
261
|
+
},
|
|
262
|
+
conditions: {
|
|
263
|
+
stackable: false,
|
|
264
|
+
},
|
|
265
|
+
};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { TDiscount, DiscountResult, DiscountContext } from "./types";
|
|
2
|
+
export interface DiscountStrategy {
|
|
3
|
+
canApply(discount: TDiscount, context: DiscountContext): boolean;
|
|
4
|
+
calculate(discount: TDiscount, context: DiscountContext): DiscountResult;
|
|
5
|
+
}
|
|
6
|
+
//# sourceMappingURL=strategy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"strategy.d.ts","sourceRoot":"","sources":["../../../../lib/entities/Discount/strategy.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAErE,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,QAAQ,EAAE,SAAS,EAAE,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC;IACjE,SAAS,CAAC,QAAQ,EAAE,SAAS,EAAE,OAAO,EAAE,eAAe,GAAG,cAAc,CAAC;CAC1E"}
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export declare const DiscountConditionsSchema: z.ZodOptional<z.ZodObject<{
|
|
3
|
+
minSpend: z.ZodOptional<z.ZodNumber>;
|
|
4
|
+
stackable: z.ZodDefault<z.ZodBoolean>;
|
|
5
|
+
}, "strip", z.ZodTypeAny, {
|
|
6
|
+
stackable: boolean;
|
|
7
|
+
minSpend?: number | undefined;
|
|
8
|
+
}, {
|
|
9
|
+
minSpend?: number | undefined;
|
|
10
|
+
stackable?: boolean | undefined;
|
|
11
|
+
}>>;
|
|
12
|
+
export declare const DiscountVariantSchema: z.ZodDiscriminatedUnion<"variantType", [z.ZodObject<{
|
|
13
|
+
variantType: z.ZodLiteral<"bundle">;
|
|
14
|
+
productsId: z.ZodArray<z.ZodString, "many">;
|
|
15
|
+
requiredQuantity: z.ZodNumber;
|
|
16
|
+
bundlePrice: z.ZodNumber;
|
|
17
|
+
}, "strip", z.ZodTypeAny, {
|
|
18
|
+
variantType: "bundle";
|
|
19
|
+
productsId: string[];
|
|
20
|
+
requiredQuantity: number;
|
|
21
|
+
bundlePrice: number;
|
|
22
|
+
}, {
|
|
23
|
+
variantType: "bundle";
|
|
24
|
+
productsId: string[];
|
|
25
|
+
requiredQuantity: number;
|
|
26
|
+
bundlePrice: number;
|
|
27
|
+
}>]>;
|
|
28
|
+
export declare const DiscountSchema: z.ZodObject<{
|
|
29
|
+
type: z.ZodLiteral<"Discount">;
|
|
30
|
+
storeId: z.ZodString;
|
|
31
|
+
companyId: z.ZodString;
|
|
32
|
+
id: z.ZodString;
|
|
33
|
+
name: z.ZodArray<z.ZodObject<{
|
|
34
|
+
lang: z.ZodEnum<["he"]>;
|
|
35
|
+
value: z.ZodString;
|
|
36
|
+
}, "strip", z.ZodTypeAny, {
|
|
37
|
+
value: string;
|
|
38
|
+
lang: "he";
|
|
39
|
+
}, {
|
|
40
|
+
value: string;
|
|
41
|
+
lang: "he";
|
|
42
|
+
}>, "many">;
|
|
43
|
+
active: z.ZodBoolean;
|
|
44
|
+
startDate: z.ZodNumber;
|
|
45
|
+
endDate: z.ZodNumber;
|
|
46
|
+
variant: z.ZodDiscriminatedUnion<"variantType", [z.ZodObject<{
|
|
47
|
+
variantType: z.ZodLiteral<"bundle">;
|
|
48
|
+
productsId: z.ZodArray<z.ZodString, "many">;
|
|
49
|
+
requiredQuantity: z.ZodNumber;
|
|
50
|
+
bundlePrice: z.ZodNumber;
|
|
51
|
+
}, "strip", z.ZodTypeAny, {
|
|
52
|
+
variantType: "bundle";
|
|
53
|
+
productsId: string[];
|
|
54
|
+
requiredQuantity: number;
|
|
55
|
+
bundlePrice: number;
|
|
56
|
+
}, {
|
|
57
|
+
variantType: "bundle";
|
|
58
|
+
productsId: string[];
|
|
59
|
+
requiredQuantity: number;
|
|
60
|
+
bundlePrice: number;
|
|
61
|
+
}>]>;
|
|
62
|
+
conditions: z.ZodOptional<z.ZodObject<{
|
|
63
|
+
minSpend: z.ZodOptional<z.ZodNumber>;
|
|
64
|
+
stackable: z.ZodDefault<z.ZodBoolean>;
|
|
65
|
+
}, "strip", z.ZodTypeAny, {
|
|
66
|
+
stackable: boolean;
|
|
67
|
+
minSpend?: number | undefined;
|
|
68
|
+
}, {
|
|
69
|
+
minSpend?: number | undefined;
|
|
70
|
+
stackable?: boolean | undefined;
|
|
71
|
+
}>>;
|
|
72
|
+
}, "strip", z.ZodTypeAny, {
|
|
73
|
+
type: "Discount";
|
|
74
|
+
id: string;
|
|
75
|
+
companyId: string;
|
|
76
|
+
storeId: string;
|
|
77
|
+
name: {
|
|
78
|
+
value: string;
|
|
79
|
+
lang: "he";
|
|
80
|
+
}[];
|
|
81
|
+
active: boolean;
|
|
82
|
+
startDate: number;
|
|
83
|
+
endDate: number;
|
|
84
|
+
variant: {
|
|
85
|
+
variantType: "bundle";
|
|
86
|
+
productsId: string[];
|
|
87
|
+
requiredQuantity: number;
|
|
88
|
+
bundlePrice: number;
|
|
89
|
+
};
|
|
90
|
+
conditions?: {
|
|
91
|
+
stackable: boolean;
|
|
92
|
+
minSpend?: number | undefined;
|
|
93
|
+
} | undefined;
|
|
94
|
+
}, {
|
|
95
|
+
type: "Discount";
|
|
96
|
+
id: string;
|
|
97
|
+
companyId: string;
|
|
98
|
+
storeId: string;
|
|
99
|
+
name: {
|
|
100
|
+
value: string;
|
|
101
|
+
lang: "he";
|
|
102
|
+
}[];
|
|
103
|
+
active: boolean;
|
|
104
|
+
startDate: number;
|
|
105
|
+
endDate: number;
|
|
106
|
+
variant: {
|
|
107
|
+
variantType: "bundle";
|
|
108
|
+
productsId: string[];
|
|
109
|
+
requiredQuantity: number;
|
|
110
|
+
bundlePrice: number;
|
|
111
|
+
};
|
|
112
|
+
conditions?: {
|
|
113
|
+
minSpend?: number | undefined;
|
|
114
|
+
stackable?: boolean | undefined;
|
|
115
|
+
} | undefined;
|
|
116
|
+
}>;
|
|
117
|
+
export type TDiscount = z.infer<typeof DiscountSchema>;
|
|
118
|
+
export type DiscountVariant = z.infer<typeof DiscountVariantSchema>;
|
|
119
|
+
export type DiscountConditions = z.infer<typeof DiscountConditionsSchema>;
|
|
120
|
+
export interface DiscountResult {
|
|
121
|
+
applicable: boolean;
|
|
122
|
+
discountAmount: number;
|
|
123
|
+
affectedItems: Array<{
|
|
124
|
+
productId: string;
|
|
125
|
+
quantity: number;
|
|
126
|
+
originalPrice: number;
|
|
127
|
+
discountedPrice: number;
|
|
128
|
+
discountAmount: number;
|
|
129
|
+
}>;
|
|
130
|
+
}
|
|
131
|
+
export interface AppliedDiscount {
|
|
132
|
+
discountId: string;
|
|
133
|
+
discountName: string;
|
|
134
|
+
discountAmount: number;
|
|
135
|
+
affectedItems: DiscountResult["affectedItems"];
|
|
136
|
+
}
|
|
137
|
+
export interface DiscountContext {
|
|
138
|
+
cart: Array<{
|
|
139
|
+
amount: number;
|
|
140
|
+
product: {
|
|
141
|
+
id: string;
|
|
142
|
+
price: number;
|
|
143
|
+
};
|
|
144
|
+
}>;
|
|
145
|
+
user?: Record<string, unknown>;
|
|
146
|
+
appliedDiscounts: AppliedDiscount[];
|
|
147
|
+
}
|
|
148
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../lib/entities/Discount/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,eAAO,MAAM,wBAAwB;;;;;;;;;GAKzB,CAAC;AAGb,eAAO,MAAM,qBAAqB;;;;;;;;;;;;;;;IAOhC,CAAC;AAEH,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAWzB,CAAC;AAEH,MAAM,MAAM,SAAS,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAC;AACvD,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAC;AACpE,MAAM,MAAM,kBAAkB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,wBAAwB,CAAC,CAAC;AAG1E,MAAM,WAAW,cAAc;IAC9B,UAAU,EAAE,OAAO,CAAC;IACpB,cAAc,EAAE,MAAM,CAAC;IACvB,aAAa,EAAE,KAAK,CAAC;QACpB,SAAS,EAAE,MAAM,CAAC;QAClB,QAAQ,EAAE,MAAM,CAAC;QACjB,aAAa,EAAE,MAAM,CAAC;QACtB,eAAe,EAAE,MAAM,CAAC;QACxB,cAAc,EAAE,MAAM,CAAC;KACvB,CAAC,CAAC;CACH;AAED,MAAM,WAAW,eAAe;IAC/B,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,EAAE,MAAM,CAAC;IACvB,aAAa,EAAE,cAAc,CAAC,eAAe,CAAC,CAAC;CAC/C;AAED,MAAM,WAAW,eAAe;IAC/B,IAAI,EAAE,KAAK,CAAC;QACX,MAAM,EAAE,MAAM,CAAC;QACf,OAAO,EAAE;YACR,EAAE,EAAE,MAAM,CAAC;YACX,KAAK,EAAE,MAAM,CAAC;SACd,CAAC;KACF,CAAC,CAAC;IACH,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,gBAAgB,EAAE,eAAe,EAAE,CAAC;CACpC"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
// Simple discount conditions
|
|
3
|
+
export const DiscountConditionsSchema = z
|
|
4
|
+
.object({
|
|
5
|
+
minSpend: z.number().positive().optional(),
|
|
6
|
+
stackable: z.boolean().default(false),
|
|
7
|
+
})
|
|
8
|
+
.optional();
|
|
9
|
+
// Bundle discount - buy X items for Y price
|
|
10
|
+
export const DiscountVariantSchema = z.discriminatedUnion("variantType", [
|
|
11
|
+
z.object({
|
|
12
|
+
variantType: z.literal("bundle"),
|
|
13
|
+
productsId: z.array(z.string().nonempty()).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
|
+
}),
|
|
17
|
+
]);
|
|
18
|
+
export const DiscountSchema = z.object({
|
|
19
|
+
type: z.literal("Discount"),
|
|
20
|
+
storeId: z.string().min(1),
|
|
21
|
+
companyId: z.string().min(1),
|
|
22
|
+
id: z.string().min(1),
|
|
23
|
+
name: z.array(z.object({ lang: z.enum(["he"]), value: z.string().nonempty() })),
|
|
24
|
+
active: z.boolean(),
|
|
25
|
+
startDate: z.number(),
|
|
26
|
+
endDate: z.number(),
|
|
27
|
+
variant: DiscountVariantSchema,
|
|
28
|
+
conditions: DiscountConditionsSchema,
|
|
29
|
+
});
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Utility functions for discount calculations
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Formats a number to 2 decimal places and returns as a number
|
|
6
|
+
* @param value - The number to format
|
|
7
|
+
* @returns The formatted number with 2 decimal places
|
|
8
|
+
*/
|
|
9
|
+
export declare function formatCurrency(value: number): number;
|
|
10
|
+
/**
|
|
11
|
+
* Formats a number to 2 decimal places and returns as a string
|
|
12
|
+
* @param value - The number to format
|
|
13
|
+
* @returns The formatted string with 2 decimal places
|
|
14
|
+
*/
|
|
15
|
+
export declare function formatCurrencyString(value: number): string;
|
|
16
|
+
/**
|
|
17
|
+
* Ensures a monetary value is never negative
|
|
18
|
+
* @param value - The value to check
|
|
19
|
+
* @returns The value, or 0 if negative
|
|
20
|
+
*/
|
|
21
|
+
export declare function ensureNonNegative(value: number): number;
|
|
22
|
+
/**
|
|
23
|
+
* Calculates the percentage discount
|
|
24
|
+
* @param originalPrice - The original price
|
|
25
|
+
* @param discountedPrice - The discounted price
|
|
26
|
+
* @returns The percentage discount (0-100)
|
|
27
|
+
*/
|
|
28
|
+
export declare function calculatePercentageDiscount(originalPrice: number, discountedPrice: number): number;
|
|
29
|
+
//# sourceMappingURL=utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../../lib/entities/Discount/utils.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEpD;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAE1D;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEvD;AAED;;;;;GAKG;AACH,wBAAgB,2BAA2B,CAAC,aAAa,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,GAAG,MAAM,CAIlG"}
|
|
@@ -1,42 +1,39 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Utility functions for discount calculations
|
|
3
3
|
*/
|
|
4
|
-
|
|
5
4
|
/**
|
|
6
5
|
* Formats a number to 2 decimal places and returns as a number
|
|
7
6
|
* @param value - The number to format
|
|
8
7
|
* @returns The formatted number with 2 decimal places
|
|
9
8
|
*/
|
|
10
|
-
export function formatCurrency(value
|
|
11
|
-
|
|
9
|
+
export function formatCurrency(value) {
|
|
10
|
+
return Number(value.toFixed(2));
|
|
12
11
|
}
|
|
13
|
-
|
|
14
12
|
/**
|
|
15
13
|
* Formats a number to 2 decimal places and returns as a string
|
|
16
14
|
* @param value - The number to format
|
|
17
15
|
* @returns The formatted string with 2 decimal places
|
|
18
16
|
*/
|
|
19
|
-
export function formatCurrencyString(value
|
|
20
|
-
|
|
17
|
+
export function formatCurrencyString(value) {
|
|
18
|
+
return value.toFixed(2);
|
|
21
19
|
}
|
|
22
|
-
|
|
23
20
|
/**
|
|
24
21
|
* Ensures a monetary value is never negative
|
|
25
22
|
* @param value - The value to check
|
|
26
23
|
* @returns The value, or 0 if negative
|
|
27
24
|
*/
|
|
28
|
-
export function ensureNonNegative(value
|
|
29
|
-
|
|
25
|
+
export function ensureNonNegative(value) {
|
|
26
|
+
return Math.max(0, formatCurrency(value));
|
|
30
27
|
}
|
|
31
|
-
|
|
32
28
|
/**
|
|
33
29
|
* Calculates the percentage discount
|
|
34
30
|
* @param originalPrice - The original price
|
|
35
31
|
* @param discountedPrice - The discounted price
|
|
36
32
|
* @returns The percentage discount (0-100)
|
|
37
33
|
*/
|
|
38
|
-
export function calculatePercentageDiscount(originalPrice
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
34
|
+
export function calculatePercentageDiscount(originalPrice, discountedPrice) {
|
|
35
|
+
if (originalPrice <= 0)
|
|
36
|
+
return 0;
|
|
37
|
+
const discount = originalPrice - discountedPrice;
|
|
38
|
+
return formatCurrency((discount / originalPrice) * 100);
|
|
39
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export declare const FavoriteProductSchema: z.ZodObject<{
|
|
3
|
+
type: z.ZodLiteral<"FavoriteProduct">;
|
|
4
|
+
id: z.ZodString;
|
|
5
|
+
companyId: z.ZodString;
|
|
6
|
+
storeId: z.ZodString;
|
|
7
|
+
userId: z.ZodString;
|
|
8
|
+
productId: z.ZodString;
|
|
9
|
+
}, "strip", z.ZodTypeAny, {
|
|
10
|
+
type: "FavoriteProduct";
|
|
11
|
+
id: string;
|
|
12
|
+
companyId: string;
|
|
13
|
+
storeId: string;
|
|
14
|
+
userId: string;
|
|
15
|
+
productId: string;
|
|
16
|
+
}, {
|
|
17
|
+
type: "FavoriteProduct";
|
|
18
|
+
id: string;
|
|
19
|
+
companyId: string;
|
|
20
|
+
storeId: string;
|
|
21
|
+
userId: string;
|
|
22
|
+
productId: string;
|
|
23
|
+
}>;
|
|
24
|
+
export type TFavoriteProduct = z.infer<typeof FavoriteProductSchema>;
|
|
25
|
+
//# sourceMappingURL=FavoriteProduct.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FavoriteProduct.d.ts","sourceRoot":"","sources":["../../../lib/entities/FavoriteProduct.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,eAAO,MAAM,qBAAqB;;;;;;;;;;;;;;;;;;;;;EAOhC,CAAC;AAEH,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export const FavoriteProductSchema = z.object({
|
|
3
|
+
type: z.literal("FavoriteProduct"),
|
|
4
|
+
id: z.string().uuid(),
|
|
5
|
+
companyId: z.string().uuid(),
|
|
6
|
+
storeId: z.string().uuid(),
|
|
7
|
+
userId: z.string().uuid(),
|
|
8
|
+
productId: z.string().uuid(),
|
|
9
|
+
});
|