@delicity/client-cart 1.2.13 → 1.2.14
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/classes/Cart.d.ts +129 -0
- package/classes/Cart.d.ts.map +1 -0
- package/classes/Cart.js +482 -0
- package/classes/Cart.js.map +1 -0
- package/index.d.ts +4 -0
- package/index.d.ts.map +1 -0
- package/index.js +20 -0
- package/index.js.map +1 -0
- package/package.json +1 -1
- package/service/CartService.d.ts +14 -0
- package/service/CartService.d.ts.map +1 -0
- package/service/CartService.js +130 -0
- package/service/CartService.js.map +1 -0
- package/service/CategoryAvailabilityService.d.ts +23 -0
- package/service/CategoryAvailabilityService.d.ts.map +1 -0
- package/service/CategoryAvailabilityService.js +103 -0
- package/service/CategoryAvailabilityService.js.map +1 -0
- package/service/DeliveryService.d.ts +4 -0
- package/service/DeliveryService.d.ts.map +1 -0
- package/service/DeliveryService.js +30 -0
- package/service/DeliveryService.js.map +1 -0
- package/service/HelperService.d.ts +2 -0
- package/service/HelperService.d.ts.map +1 -0
- package/service/HelperService.js +14 -0
- package/service/HelperService.js.map +1 -0
- package/README.md +0 -1
- package/coverage/clover.xml +0 -71
- package/coverage/coverage-final.json +0 -3
- package/coverage/lcov-report/base.css +0 -224
- package/coverage/lcov-report/block-navigation.js +0 -87
- package/coverage/lcov-report/classes/Cart.ts.html +0 -340
- package/coverage/lcov-report/classes/index.html +0 -116
- package/coverage/lcov-report/favicon.png +0 -0
- package/coverage/lcov-report/index.html +0 -131
- package/coverage/lcov-report/prettify.css +0 -1
- package/coverage/lcov-report/prettify.js +0 -2
- package/coverage/lcov-report/service/CartService.ts.html +0 -238
- package/coverage/lcov-report/service/index.html +0 -116
- package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
- package/coverage/lcov-report/sorter.js +0 -196
- package/coverage/lcov.info +0 -129
- package/jest.config.js +0 -8
- package/src/classes/Cart.ts +0 -563
- package/src/index.ts +0 -3
- package/src/service/CartService.ts +0 -139
- package/src/service/CategoryAvailabilityService.ts +0 -121
- package/src/service/DeliveryService.ts +0 -17
- package/src/service/HelperService.ts +0 -9
- package/src/test/availability.test.ts +0 -346
- package/src/test/class.test.ts +0 -497
- package/src/test/data/CartData.json +0 -244
- package/src/test/data/menu.json +0 -5875
- package/src/test/data/merchant.json +0 -186
- package/tsconfig.json +0 -24
package/src/classes/Cart.ts
DELETED
|
@@ -1,563 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
IAddress,
|
|
3
|
-
ICart,
|
|
4
|
-
ICartDelivery, ICartDiscount,
|
|
5
|
-
ICartItem,
|
|
6
|
-
ICartModifierGroup,
|
|
7
|
-
ICartPaymentMethod,
|
|
8
|
-
ICartPrice,
|
|
9
|
-
IClientConfig,
|
|
10
|
-
Menu,
|
|
11
|
-
MenuItem, MenuModifierGroup,
|
|
12
|
-
Merchant,
|
|
13
|
-
OrderModesEnum
|
|
14
|
-
} from "@delicity/client-types";
|
|
15
|
-
import {DateTime} from 'luxon';
|
|
16
|
-
|
|
17
|
-
import {v4 as uuidv4} from 'uuid';
|
|
18
|
-
|
|
19
|
-
import {
|
|
20
|
-
addDiscountCode,
|
|
21
|
-
getProductCount,
|
|
22
|
-
getProductPrice,
|
|
23
|
-
getProductPriceSum,
|
|
24
|
-
getTotalModifiersUnitPrice,
|
|
25
|
-
isItemAlreadyInCart,
|
|
26
|
-
isItemAvailable,
|
|
27
|
-
mandatoryModifierCheck, removeDiscountCode,
|
|
28
|
-
synchronizeCart
|
|
29
|
-
} from "../service/CartService";
|
|
30
|
-
|
|
31
|
-
import {getDeliveryDetails} from "../service/DeliveryService";
|
|
32
|
-
import {formatPrice} from "../service/HelperService";
|
|
33
|
-
// @ts-ignore
|
|
34
|
-
import ScheduleManagement from "@delicity/backend-schedule-management";
|
|
35
|
-
import {categoryAvailable} from "../service/CategoryAvailabilityService";
|
|
36
|
-
|
|
37
|
-
export interface CartClass {
|
|
38
|
-
// Setters
|
|
39
|
-
setMenu(menu:Menu): Cart
|
|
40
|
-
setCart(cart:ICart): Cart
|
|
41
|
-
setWhen(when:string|null): Cart
|
|
42
|
-
setOrderMode(mode:OrderModesEnum): Cart
|
|
43
|
-
setAddress(address:IAddress): Promise<Cart>
|
|
44
|
-
setAddressComment(comment: string|null): Cart
|
|
45
|
-
setCartComment(comment:string|null): Cart
|
|
46
|
-
setAcceptCondition(acceptCondition:boolean):Cart
|
|
47
|
-
setPaymentMethods(paymentMethod:ICartPaymentMethod[]):Cart
|
|
48
|
-
pushError(field:string, code:string, vars:any): Cart
|
|
49
|
-
setErrors(errors:{field:string, code:string, vars:any}[]): Cart
|
|
50
|
-
|
|
51
|
-
// Getters
|
|
52
|
-
getCart(): ICart
|
|
53
|
-
getItems(): ICartItem[]
|
|
54
|
-
getTotalItems(): number
|
|
55
|
-
getTotalItemPrice(): number
|
|
56
|
-
getMerchantId():number
|
|
57
|
-
getCartUUID():string|undefined
|
|
58
|
-
getOrderMode(): OrderModesEnum
|
|
59
|
-
getCartComment():string|null
|
|
60
|
-
getDeliveryInfos():ICartDelivery|undefined
|
|
61
|
-
getPrices():null|ICartPrice
|
|
62
|
-
getWhen():null|string
|
|
63
|
-
getAcceptCondition():boolean
|
|
64
|
-
getPreparationDurationBetween():number[]|null
|
|
65
|
-
getPaymentMethods(): ICartPaymentMethod[]
|
|
66
|
-
getErrors(): {field:string, code:string, vars:any}[]
|
|
67
|
-
getDiscounts(): ICartDiscount[]
|
|
68
|
-
getCoupons(): ICartDiscount[]
|
|
69
|
-
canBePayOnsite(): boolean
|
|
70
|
-
getRemoteErrors(): any
|
|
71
|
-
|
|
72
|
-
// Methods
|
|
73
|
-
synchronize(): Promise<Cart>
|
|
74
|
-
addToCart(item: MenuItem, modifierGroup:ICartModifierGroup[], quantity:number, comment?:string): Cart
|
|
75
|
-
updateCart(cartItem:ICartItem, modifierGroup:ICartModifierGroup[], quantity:number, comment?:string): Cart
|
|
76
|
-
removeFromCart(cartItem: ICartItem): Cart
|
|
77
|
-
paymentMethodCard(type: 'card_token' | 'payment_method_id', token: string, brand:string, last4:string, expiration: string, amount?:number): Cart
|
|
78
|
-
paymentMethodWallet(type: 'apple_pay' | 'google_pay', amount?:number): Cart
|
|
79
|
-
paymentMethodOnsite(amount?:number): Cart
|
|
80
|
-
validateCart(): Cart
|
|
81
|
-
validateMerchantSchedule(): Cart
|
|
82
|
-
validateCartIfError(): Cart
|
|
83
|
-
resetErrors(): Cart
|
|
84
|
-
cartIntegrity(): void
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
export class Cart implements CartClass{
|
|
88
|
-
private cart: ICart
|
|
89
|
-
private merchant: Merchant
|
|
90
|
-
private menu: Menu
|
|
91
|
-
private config: IClientConfig;
|
|
92
|
-
private acceptCondition: boolean = false;
|
|
93
|
-
private errors:{field:string, code:string, vars: any}[] = []
|
|
94
|
-
private listeners:any = {};
|
|
95
|
-
private isPriceLoading: boolean = false;
|
|
96
|
-
private isDeliveryLoading: boolean = false;
|
|
97
|
-
private merchantSchedule: ScheduleManagement | undefined;
|
|
98
|
-
private remoteErrors: any;
|
|
99
|
-
|
|
100
|
-
constructor(config: IClientConfig, merchant: Merchant, menu: Menu, OrderMode: OrderModesEnum, when: string|null) {
|
|
101
|
-
this.merchant = merchant
|
|
102
|
-
this.menu = JSON.parse(JSON.stringify(menu))
|
|
103
|
-
this.config = config;
|
|
104
|
-
this.remoteErrors = {};
|
|
105
|
-
|
|
106
|
-
if(this.merchant.schedule){
|
|
107
|
-
this.merchantSchedule = new ScheduleManagement(this.merchant.schedule.slots, this.merchant.schedule.closes, this.merchant.schedule.options);
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
this.cart = {
|
|
111
|
-
uuid: uuidv4(),
|
|
112
|
-
createdAt: DateTime.now().toISO(),
|
|
113
|
-
merchantId: merchant.id,
|
|
114
|
-
preparationDurationBetween: null,
|
|
115
|
-
items: [],
|
|
116
|
-
totalItems: 0,
|
|
117
|
-
totalItemPrice: 0,
|
|
118
|
-
when: when,
|
|
119
|
-
comment: null,
|
|
120
|
-
type: OrderMode,
|
|
121
|
-
} as ICart;
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
on(event:string, callback:any) {
|
|
126
|
-
if (!this.listeners[event]) {
|
|
127
|
-
this.listeners[event] = [];
|
|
128
|
-
}
|
|
129
|
-
this.listeners[event].push(callback);
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
off(event:string, callback:any) {
|
|
133
|
-
if (!this.listeners[event]) return;
|
|
134
|
-
this.listeners[event] = [];
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
trigger(event:string, ...args:any) {
|
|
138
|
-
if (this.listeners[event]) {
|
|
139
|
-
this.listeners[event].forEach((callback: (arg0: any) => void) => {
|
|
140
|
-
// @ts-ignore
|
|
141
|
-
callback(...args);
|
|
142
|
-
});
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
setMenu(menu:Menu): Cart{
|
|
148
|
-
this.menu = JSON.parse(JSON.stringify(menu));
|
|
149
|
-
this.cartIntegrity();
|
|
150
|
-
this.updateCartProductPrices();
|
|
151
|
-
this.trigger('update-cart');
|
|
152
|
-
return this;
|
|
153
|
-
}
|
|
154
|
-
setCart(cart:ICart): Cart{
|
|
155
|
-
this.cart = cart;
|
|
156
|
-
this.cartIntegrity();
|
|
157
|
-
this.trigger('update-cart');
|
|
158
|
-
return this;
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
getPrices():null|ICartPrice{
|
|
162
|
-
return this.cart.prices||null;
|
|
163
|
-
}
|
|
164
|
-
getAcceptCondition():boolean{
|
|
165
|
-
return this.acceptCondition;
|
|
166
|
-
}
|
|
167
|
-
setAcceptCondition(acceptCondition:boolean):Cart{
|
|
168
|
-
this.acceptCondition = acceptCondition;
|
|
169
|
-
return this;
|
|
170
|
-
}
|
|
171
|
-
getPreparationDurationBetween():number[]|null{
|
|
172
|
-
return this.cart.preparationDurationBetween;
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
getIsDeliveryLoading():boolean{
|
|
176
|
-
return this.isDeliveryLoading
|
|
177
|
-
}
|
|
178
|
-
getIsPriceLoading():boolean{
|
|
179
|
-
return this.isPriceLoading
|
|
180
|
-
}
|
|
181
|
-
getRemoteErrors(): any{
|
|
182
|
-
return this.remoteErrors;
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
async setAddress(address:IAddress):Promise<Cart>{
|
|
186
|
-
if(this.cart.type !== OrderModesEnum.DELIVERY) throw new Error('invalid_order_mode');
|
|
187
|
-
this.isDeliveryLoading = true;
|
|
188
|
-
const delivery:ICartDelivery = await getDeliveryDetails(this.config, this.merchant.id, address.position);
|
|
189
|
-
this.cart.delivery = {
|
|
190
|
-
address,
|
|
191
|
-
...delivery
|
|
192
|
-
};
|
|
193
|
-
this.isDeliveryLoading = false;
|
|
194
|
-
this.trigger('update-cart');
|
|
195
|
-
return this;
|
|
196
|
-
}
|
|
197
|
-
getDeliveryInfos():ICartDelivery|undefined{
|
|
198
|
-
return this.cart.delivery;
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
setCartComment(comment:string|null): Cart{
|
|
202
|
-
this.cart.comment = comment;
|
|
203
|
-
return this;
|
|
204
|
-
}
|
|
205
|
-
getCartComment():string|null{
|
|
206
|
-
return this.cart.comment;
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
updateCartProductPrices(){
|
|
210
|
-
|
|
211
|
-
for(let index in this.cart.items){
|
|
212
|
-
const menuItem: MenuItem = this.menu.items.find(m => m.id === this.cart.items[index].item.id) as MenuItem;
|
|
213
|
-
if(!menuItem) this.cart.items.splice(parseInt(index), 1);
|
|
214
|
-
|
|
215
|
-
const modifierGroups = this.cart.items[index].modifierGroups;
|
|
216
|
-
const quantity: number = this.cart.items[index].quantity;
|
|
217
|
-
|
|
218
|
-
this.cart.items[index].item = menuItem;
|
|
219
|
-
this.cart.items[index].unitPrice = getProductPrice(menuItem, this.cart.type) + getTotalModifiersUnitPrice(modifierGroups)
|
|
220
|
-
this.cart.items[index].totalPrice = (getProductPrice(menuItem, this.cart.type) + getTotalModifiersUnitPrice(modifierGroups)) * quantity
|
|
221
|
-
}
|
|
222
|
-
this.cart.totalItems = getProductCount(this.cart);
|
|
223
|
-
this.cart.totalItemPrice = getProductPriceSum(this.cart);
|
|
224
|
-
if(this.cart.paymentMethods && this.cart.paymentMethods.length>0){
|
|
225
|
-
this.updatePaymentMethodAmount();
|
|
226
|
-
}
|
|
227
|
-
this.validateCartIfError();
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
setOrderMode(mode:OrderModesEnum): Cart{
|
|
231
|
-
this.cart.type = mode;
|
|
232
|
-
if(!this.canBePayOnsite() && this.getPaymentMethods().some(e => e.type === 'cash')){
|
|
233
|
-
this.cart.paymentMethods = [];
|
|
234
|
-
}
|
|
235
|
-
this.updateCartProductPrices();
|
|
236
|
-
this.trigger('update-cart');
|
|
237
|
-
return this;
|
|
238
|
-
}
|
|
239
|
-
setWhen(when:string|null): Cart{
|
|
240
|
-
this.cart.when = when;
|
|
241
|
-
this.trigger('update-cart');
|
|
242
|
-
this.cartIntegrity(true);
|
|
243
|
-
this.validateCartIfError();
|
|
244
|
-
return this;
|
|
245
|
-
}
|
|
246
|
-
setAddressComment(comment: string|null): Cart {
|
|
247
|
-
if(this.cart.delivery?.address){
|
|
248
|
-
this.cart.delivery.address.additional_informations = comment;
|
|
249
|
-
}
|
|
250
|
-
return this;
|
|
251
|
-
}
|
|
252
|
-
getMerchantId():number{
|
|
253
|
-
return this.merchant.id;
|
|
254
|
-
}
|
|
255
|
-
getCartUUID():string|undefined{
|
|
256
|
-
return this.cart.uuid;
|
|
257
|
-
}
|
|
258
|
-
getOrderMode(): OrderModesEnum {
|
|
259
|
-
return this.cart.type;
|
|
260
|
-
}
|
|
261
|
-
getWhen(): null|string {
|
|
262
|
-
return this.cart.when;
|
|
263
|
-
}
|
|
264
|
-
getPaymentMethods(): ICartPaymentMethod[]{
|
|
265
|
-
return this.cart.paymentMethods||[];
|
|
266
|
-
}
|
|
267
|
-
setPaymentMethods(paymentMethods:ICartPaymentMethod[]):Cart{
|
|
268
|
-
this.cart.paymentMethods = paymentMethods;
|
|
269
|
-
return this;
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
getPaymentMethodTotalAmount():number{
|
|
274
|
-
if(!this.cart.paymentMethods) return 0;
|
|
275
|
-
return this.cart.paymentMethods.reduce((a, b) => a + b.amount, 0)
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
paymentMethodCard(type: 'card_token' | 'payment_method_id', token: string, brand:string, last4:string, expiration: string, amount?:number): Cart{
|
|
279
|
-
let leftToPay = this.getTotalPrice();
|
|
280
|
-
if(!this.cart.paymentMethods) this.cart.paymentMethods = [];
|
|
281
|
-
|
|
282
|
-
if(this.cart.paymentMethods){
|
|
283
|
-
const sum = this.getPaymentMethodTotalAmount();
|
|
284
|
-
if(sum === this.getTotalPrice()) this.cart.paymentMethods = [];
|
|
285
|
-
else leftToPay -= sum;
|
|
286
|
-
}
|
|
287
|
-
if(amount && leftToPay < amount){
|
|
288
|
-
this.cart.paymentMethods = [];
|
|
289
|
-
}
|
|
290
|
-
this.cart.paymentMethods.push({
|
|
291
|
-
type: 'card',
|
|
292
|
-
amount: amount ? amount : leftToPay,
|
|
293
|
-
card: {type, token, brand, last4, expiration}
|
|
294
|
-
});
|
|
295
|
-
return this;
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
paymentMethodWallet(type: 'apple_pay' | 'google_pay', amount?:number): Cart{
|
|
299
|
-
let leftToPay = this.getTotalPrice();
|
|
300
|
-
if(!this.cart.paymentMethods) this.cart.paymentMethods = [];
|
|
301
|
-
|
|
302
|
-
if(this.cart.paymentMethods){
|
|
303
|
-
const sum = this.getPaymentMethodTotalAmount();
|
|
304
|
-
if(sum === this.getTotalPrice()) this.cart.paymentMethods = [];
|
|
305
|
-
else leftToPay -= sum;
|
|
306
|
-
}
|
|
307
|
-
if(amount && leftToPay < amount){
|
|
308
|
-
this.cart.paymentMethods = [];
|
|
309
|
-
}
|
|
310
|
-
this.cart.paymentMethods.push({
|
|
311
|
-
type: "wallet",
|
|
312
|
-
wallet: {type},
|
|
313
|
-
amount: amount ? amount : leftToPay,
|
|
314
|
-
});
|
|
315
|
-
return this;
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
paymentMethodOnsite(amount?:number): Cart{
|
|
319
|
-
let leftToPay:number = this.getTotalPrice();
|
|
320
|
-
if(!this.cart.paymentMethods) this.cart.paymentMethods = [];
|
|
321
|
-
if(this.cart.paymentMethods){
|
|
322
|
-
const sum = this.getPaymentMethodTotalAmount();
|
|
323
|
-
if(sum === this.getTotalPrice()) this.cart.paymentMethods = [];
|
|
324
|
-
else leftToPay -= sum;
|
|
325
|
-
}
|
|
326
|
-
if(amount && leftToPay < amount){
|
|
327
|
-
this.cart.paymentMethods = [];
|
|
328
|
-
}
|
|
329
|
-
this.cart.paymentMethods.push({
|
|
330
|
-
type: 'cash',
|
|
331
|
-
amount: amount ? amount : leftToPay,
|
|
332
|
-
});
|
|
333
|
-
return this;
|
|
334
|
-
}
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
addToCart(item: MenuItem, modifierGroups:ICartModifierGroup[], quantity: number, comment?:string, replace?:ICartItem): Cart {
|
|
339
|
-
// Check if item have mandatory modifiers
|
|
340
|
-
if(!mandatoryModifierCheck(item, modifierGroups, this.menu)){
|
|
341
|
-
throw new Error('mandatory_field_missing');
|
|
342
|
-
}
|
|
343
|
-
// Check if item is available
|
|
344
|
-
if(!isItemAvailable(item, this.menu)){
|
|
345
|
-
throw new Error('item_not_available');
|
|
346
|
-
}
|
|
347
|
-
|
|
348
|
-
const index = isItemAlreadyInCart(item, modifierGroups, this.cart, comment);
|
|
349
|
-
if(index !== -1 && !replace){
|
|
350
|
-
this.cart.items[index].quantity += quantity;
|
|
351
|
-
this.cart.items[index].totalPrice = (getProductPrice(item, this.cart.type) + getTotalModifiersUnitPrice(modifierGroups)) * this.cart.items[index].quantity;
|
|
352
|
-
}
|
|
353
|
-
else{
|
|
354
|
-
const cartItem: ICartItem = {
|
|
355
|
-
uuid: uuidv4(),
|
|
356
|
-
item,
|
|
357
|
-
modifierGroups,
|
|
358
|
-
quantity,
|
|
359
|
-
comment: comment || null,
|
|
360
|
-
unitPrice: getProductPrice(item, this.cart.type) + getTotalModifiersUnitPrice(modifierGroups),
|
|
361
|
-
totalPrice: (getProductPrice(item, this.cart.type) + getTotalModifiersUnitPrice(modifierGroups)) * quantity
|
|
362
|
-
}
|
|
363
|
-
if(replace){
|
|
364
|
-
const index = this.cart.items.findIndex(i => i.uuid === replace.uuid);
|
|
365
|
-
this.cart.items.splice(index, 1, cartItem);
|
|
366
|
-
}
|
|
367
|
-
else{
|
|
368
|
-
this.cart.items.push(cartItem);
|
|
369
|
-
}
|
|
370
|
-
}
|
|
371
|
-
|
|
372
|
-
this.cart.totalItems = getProductCount(this.cart);
|
|
373
|
-
this.cart.totalItemPrice = getProductPriceSum(this.cart);
|
|
374
|
-
if(this.cart.paymentMethods && this.cart.paymentMethods.length>0){
|
|
375
|
-
this.updatePaymentMethodAmount();
|
|
376
|
-
}
|
|
377
|
-
this.validateCartIfError();
|
|
378
|
-
this.cartIntegrity(true);
|
|
379
|
-
this.trigger('update-cart');
|
|
380
|
-
return this;
|
|
381
|
-
}
|
|
382
|
-
|
|
383
|
-
removeFromCart(cartItem: ICartItem): Cart {
|
|
384
|
-
this.cart.items = this.cart.items.filter((item) => item.uuid !== cartItem.uuid);
|
|
385
|
-
this.cart.totalItems = getProductCount(this.cart);
|
|
386
|
-
this.cart.totalItemPrice = getProductPriceSum(this.cart);
|
|
387
|
-
if(this.cart.paymentMethods){
|
|
388
|
-
this.updatePaymentMethodAmount();
|
|
389
|
-
}
|
|
390
|
-
this.cartIntegrity(true);
|
|
391
|
-
this.trigger('update-cart');
|
|
392
|
-
return this;
|
|
393
|
-
}
|
|
394
|
-
|
|
395
|
-
updateCart(cartItem: ICartItem, modifierGroup:ICartModifierGroup[], quantity: number, comment?:string): Cart {
|
|
396
|
-
return this.addToCart(cartItem.item, modifierGroup, quantity, comment, cartItem);
|
|
397
|
-
}
|
|
398
|
-
|
|
399
|
-
getCart(): ICart {
|
|
400
|
-
return this.cart;
|
|
401
|
-
}
|
|
402
|
-
getItems(): ICartItem[] {
|
|
403
|
-
return this.cart.items;
|
|
404
|
-
}
|
|
405
|
-
getTotalItems(): number {
|
|
406
|
-
return this.cart.totalItems;
|
|
407
|
-
}
|
|
408
|
-
getTotalItemPrice(): number {
|
|
409
|
-
return this.cart.totalItemPrice;
|
|
410
|
-
}
|
|
411
|
-
getTotalPrice(): number {
|
|
412
|
-
return this.cart.prices?.total || this.cart.totalItemPrice;
|
|
413
|
-
}
|
|
414
|
-
|
|
415
|
-
canBePayOnsite(): boolean {
|
|
416
|
-
return [OrderModesEnum.PICKUP, OrderModesEnum.ON_SITE_COUNTER].includes(this.cart.type) && this.merchant.features.onsitePayment;
|
|
417
|
-
}
|
|
418
|
-
|
|
419
|
-
async synchronize(): Promise<Cart>{
|
|
420
|
-
if(this.cart.type === OrderModesEnum.DELIVERY && !this.cart.delivery){
|
|
421
|
-
throw new Error('no_delivery_address')
|
|
422
|
-
}
|
|
423
|
-
this.isPriceLoading = true;
|
|
424
|
-
const request:any = await synchronizeCart(this.config, this.cart);
|
|
425
|
-
if(this.cart.delivery && request.delivery){
|
|
426
|
-
this.cart.delivery = {
|
|
427
|
-
address: this.cart.delivery?.address,
|
|
428
|
-
...request.delivery
|
|
429
|
-
};
|
|
430
|
-
}
|
|
431
|
-
this.cart.preparationDurationBetween = request.preparationDurationBetween;
|
|
432
|
-
this.cart.discounts = request.discounts;
|
|
433
|
-
this.cart.prices = request.prices;
|
|
434
|
-
this.remoteErrors = request.errors;
|
|
435
|
-
if(this.cart.paymentMethods && this.cart.paymentMethods.length>0){
|
|
436
|
-
this.updatePaymentMethodAmount();
|
|
437
|
-
}
|
|
438
|
-
this.isPriceLoading = false;
|
|
439
|
-
return this;
|
|
440
|
-
}
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
validateMerchantSchedule(): Cart{
|
|
444
|
-
this.errors = this.errors.filter(e => e.field !== 'schedule')
|
|
445
|
-
if(this.merchantSchedule){
|
|
446
|
-
const when = this.getWhen() !== null ? DateTime.fromISO(<string>this.getWhen()) : DateTime.now();
|
|
447
|
-
if(!this.merchantSchedule.isOpenAt(when)) this.errors.push({field: 'schedule', code: 'merchant_currently_close', vars: {}});
|
|
448
|
-
}
|
|
449
|
-
return this;
|
|
450
|
-
}
|
|
451
|
-
validateCart(): Cart{
|
|
452
|
-
this.errors = [];
|
|
453
|
-
if(this.cart.type === OrderModesEnum.DELIVERY && !this.cart.delivery) this.errors.push({field: 'address', code: 'no_address_defined', vars: {}});
|
|
454
|
-
if(this.cart.type === OrderModesEnum.DELIVERY && this.cart.delivery && !this.cart.delivery.available) this.errors.push({field: 'address', code: 'address_not_available', vars: {}});
|
|
455
|
-
if(!this.cart.paymentMethods || this.cart.paymentMethods?.length === 0) this.errors.push({field: 'payment_method', code: 'missing_payment_method', vars: {}});
|
|
456
|
-
if(!this.acceptCondition) this.errors.push({field: 'conditions', code: 'condition_not_accepted', vars: {}});
|
|
457
|
-
if(this.cart.type === OrderModesEnum.DELIVERY && this.merchant.settings.minDeliveryOrderPrice > this.cart.totalItemPrice) this.errors.push({field: 'prices', code: 'minium_delivery_product_price', vars: {min: formatPrice(this.merchant.settings.minDeliveryOrderPrice)}});
|
|
458
|
-
this.validateMerchantSchedule();
|
|
459
|
-
return this;
|
|
460
|
-
}
|
|
461
|
-
validateCartIfError(): Cart{
|
|
462
|
-
if(this.errors.length>0) this.validateCart();
|
|
463
|
-
return this;
|
|
464
|
-
}
|
|
465
|
-
resetErrors(): Cart{
|
|
466
|
-
this.errors = [];
|
|
467
|
-
return this;
|
|
468
|
-
}
|
|
469
|
-
getErrors(): {field:string, code:string, vars:any}[]{
|
|
470
|
-
return this.errors;
|
|
471
|
-
}
|
|
472
|
-
pushError(field:string, code:string, vars:any): Cart{
|
|
473
|
-
this.errors.push({field, code, vars});
|
|
474
|
-
return this;
|
|
475
|
-
}
|
|
476
|
-
setErrors(errors:{field:string, code:string, vars:any}[]): Cart{
|
|
477
|
-
this.errors = errors;
|
|
478
|
-
return this;
|
|
479
|
-
}
|
|
480
|
-
updatePaymentMethodAmount(){
|
|
481
|
-
const totalPrice = this.getTotalPrice();
|
|
482
|
-
if(this.cart.paymentMethods?.length === 1){
|
|
483
|
-
this.cart.paymentMethods[0].amount = totalPrice;
|
|
484
|
-
}
|
|
485
|
-
else if(this.cart.paymentMethods?.length === 2 && this.cart.paymentMethods?.some(p => p.type === 'meal-voucher')){
|
|
486
|
-
// if voucher, product price = voucher (max voucher limit)
|
|
487
|
-
// rest = payment method
|
|
488
|
-
}
|
|
489
|
-
else{
|
|
490
|
-
// If multiple payment methods, split amount
|
|
491
|
-
}
|
|
492
|
-
}
|
|
493
|
-
|
|
494
|
-
async addDiscountCoupon(code:string): Promise<Cart>{
|
|
495
|
-
await addDiscountCode(this.config, this.cart, code);
|
|
496
|
-
this.trigger('update-cart');
|
|
497
|
-
return this;
|
|
498
|
-
}
|
|
499
|
-
getDiscounts(): ICartDiscount[]{
|
|
500
|
-
return this.cart.discounts ?? [];
|
|
501
|
-
}
|
|
502
|
-
getCoupons(): ICartDiscount[]{
|
|
503
|
-
return this.cart.discounts?.filter(d => d.type === 'coupon') ?? [];
|
|
504
|
-
}
|
|
505
|
-
async removeDiscount(discount: number): Promise<Cart>{
|
|
506
|
-
await removeDiscountCode(this.config, this.cart, discount);
|
|
507
|
-
this.trigger('update-cart');
|
|
508
|
-
return this;
|
|
509
|
-
}
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
cartIntegrity(event:boolean=false): void{
|
|
513
|
-
// Check if cart products are still available in menu
|
|
514
|
-
if(this.cart.items.length>0){
|
|
515
|
-
const merchantSchedule = new ScheduleManagement(this.merchant.schedule.slots, this.merchant.schedule.closes, this.merchant.schedule.options);
|
|
516
|
-
|
|
517
|
-
const toRemove:ICartItem[] = [];
|
|
518
|
-
for(const i in this.cart.items){
|
|
519
|
-
// Remove from cart if item not in menu anymore
|
|
520
|
-
const menuItem = this.menu.items.find(m => m.id === this.cart.items[i].item.id);
|
|
521
|
-
const category = this.menu.categories.find(c => c.itemIds?.includes(this.cart.items[i].item.uid))
|
|
522
|
-
if(!menuItem){
|
|
523
|
-
toRemove.push(this.cart.items[i]);
|
|
524
|
-
continue;
|
|
525
|
-
}
|
|
526
|
-
// Remove from cart if item not available
|
|
527
|
-
if(menuItem.unavailable){
|
|
528
|
-
toRemove.push(this.cart.items[i]);
|
|
529
|
-
continue;
|
|
530
|
-
}
|
|
531
|
-
// Check if product is available
|
|
532
|
-
if(category?.availability){
|
|
533
|
-
const atDate = this.cart.when ? DateTime.fromISO(this.cart.when) : DateTime.now();
|
|
534
|
-
// @ts-ignore
|
|
535
|
-
const categoryAvailability = categoryAvailable(category.availability, atDate, merchantSchedule);
|
|
536
|
-
if(!categoryAvailability.isAvailable){
|
|
537
|
-
toRemove.push(this.cart.items[i]);
|
|
538
|
-
if(event){
|
|
539
|
-
// Used when cart update check.
|
|
540
|
-
this.trigger('product-removed:not-available-at-date', this.cart.items[i])
|
|
541
|
-
}
|
|
542
|
-
continue;
|
|
543
|
-
}
|
|
544
|
-
}
|
|
545
|
-
// Update from menu
|
|
546
|
-
this.cart.items[i].item = menuItem;
|
|
547
|
-
}
|
|
548
|
-
|
|
549
|
-
// Remove item from cart when necessary
|
|
550
|
-
toRemove.forEach((cartItem) => {
|
|
551
|
-
this.cart.items = this.cart.items.filter((item) => item.uuid !== cartItem.uuid);
|
|
552
|
-
});
|
|
553
|
-
|
|
554
|
-
// Update cart
|
|
555
|
-
this.cart.totalItems = getProductCount(this.cart);
|
|
556
|
-
this.cart.totalItemPrice = getProductPriceSum(this.cart);
|
|
557
|
-
if(this.cart.paymentMethods && this.cart.paymentMethods.length>0){
|
|
558
|
-
this.updatePaymentMethodAmount();
|
|
559
|
-
}
|
|
560
|
-
}
|
|
561
|
-
}
|
|
562
|
-
|
|
563
|
-
}
|
package/src/index.ts
DELETED
|
@@ -1,139 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
ICart,
|
|
3
|
-
ICartItem,
|
|
4
|
-
ICartModifierGroup,
|
|
5
|
-
IClientConfig,
|
|
6
|
-
Menu,
|
|
7
|
-
MenuItem,
|
|
8
|
-
OrderModesEnum
|
|
9
|
-
} from "@delicity/client-types";
|
|
10
|
-
import axios from "axios";
|
|
11
|
-
|
|
12
|
-
export function getProductPriceSum(cart:ICart): number{
|
|
13
|
-
return cart.items.reduce((acc, item) => acc + item.totalPrice, 0);
|
|
14
|
-
}
|
|
15
|
-
export function getProductCount(cart:ICart): number{
|
|
16
|
-
return cart.items.reduce((acc, item) => acc + item.quantity, 0);
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
export function getItemModifierValue(item:ICartItem): string {
|
|
20
|
-
return getItemModifierValueArray(item).join(', ');
|
|
21
|
-
}
|
|
22
|
-
export function getItemModifierValueArray(item:ICartItem): string[] {
|
|
23
|
-
return item.modifierGroups
|
|
24
|
-
.filter(mg => mg.modifiers.length > 0)
|
|
25
|
-
.map(mg => {
|
|
26
|
-
return mg.item.name + ': ' + mg.modifiers.map(m => m.item.name).join(', ');
|
|
27
|
-
})
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
export function mandatoryModifierCheck(item: MenuItem, cartModifier: ICartModifierGroup[], menu: Menu): boolean{
|
|
31
|
-
if(!item.children) return true;
|
|
32
|
-
|
|
33
|
-
// get all mandatory modifiers in this item.
|
|
34
|
-
const modifierGroups = menu.modifierGroups.filter((m:any) => item.children?.includes(m.uid) && m.min>0 && m.min);
|
|
35
|
-
|
|
36
|
-
for(let modifier of modifierGroups){
|
|
37
|
-
const m = cartModifier.find((m:any) => m.item.uid === modifier.uid);
|
|
38
|
-
if(!m) return false;
|
|
39
|
-
if(modifier.min === null) continue;
|
|
40
|
-
|
|
41
|
-
const selectedOption = m.modifiers.reduce((acc:any, m:any) => acc + m.quantity, 0);
|
|
42
|
-
if(selectedOption < modifier.min) return false;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
return true;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
export function isItemAvailable(item: MenuItem, menu: Menu){
|
|
49
|
-
const menuItem = menu.items.find((i:any) => i.uid === item.uid);
|
|
50
|
-
if(!menuItem) return false;
|
|
51
|
-
return !menuItem.unavailable;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
export function getProductPrice(item:MenuItem, mode:OrderModesEnum): number{
|
|
56
|
-
if(!item.price){
|
|
57
|
-
throw new Error('price_not_set');
|
|
58
|
-
}
|
|
59
|
-
if(typeof item.price === 'number'){
|
|
60
|
-
return item.price;
|
|
61
|
-
}
|
|
62
|
-
if(mode === 'delivery'){
|
|
63
|
-
return item.price.delivery;
|
|
64
|
-
}
|
|
65
|
-
else if(mode === 'pickup'){
|
|
66
|
-
return item.price.pickup;
|
|
67
|
-
}
|
|
68
|
-
else if(mode === 'on_site_counter'){
|
|
69
|
-
return item.price.onsite;
|
|
70
|
-
}
|
|
71
|
-
return item.price.delivery;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
export function getTotalModifiersUnitPrice(modifierGroup:ICartModifierGroup[]): number{
|
|
75
|
-
return modifierGroup.reduce((acc, mg) => acc + mg.modifiers.reduce((bcc, m) => bcc + m.price, 0), 0);
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
export function isItemAlreadyInCart(item:MenuItem, modifierGroups:ICartModifierGroup[], cart:ICart, comment?:string): number{
|
|
79
|
-
// Check if item is already in cart
|
|
80
|
-
const sameCartProducts = cart.items
|
|
81
|
-
.filter((i) => i.item.uid === item.uid)
|
|
82
|
-
.filter((i) => i.comment === (comment||null))
|
|
83
|
-
.filter((c) => {
|
|
84
|
-
if(c.modifierGroups.length !== modifierGroups.length) return false;
|
|
85
|
-
const newItemModifierGroupsKey = modifierGroups.flatMap((m) => {
|
|
86
|
-
return m.modifiers.map((o) => {return {id: o.item.id, quantity: o.quantity}});
|
|
87
|
-
}).sort((a, b) => a.id - b.id).map((m) => m.id + ':' + m.quantity).join('|');
|
|
88
|
-
const CartItemModifierGroupsKey = c.modifierGroups.flatMap((m) => {
|
|
89
|
-
return m.modifiers.map((o) => {return {id: o.item.id, quantity: o.quantity}});
|
|
90
|
-
}).sort((a, b) => a.id - b.id).map((m) => m.id + ':' + m.quantity).join('|');
|
|
91
|
-
return newItemModifierGroupsKey === CartItemModifierGroupsKey;
|
|
92
|
-
})
|
|
93
|
-
|
|
94
|
-
// If not existing in cart, return -1
|
|
95
|
-
if(sameCartProducts.length === 0) return -1;
|
|
96
|
-
|
|
97
|
-
return cart.items.findIndex((c) => c.uuid === sameCartProducts[0].uuid);
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
export function synchronizeCart(config:IClientConfig, cart: ICart){
|
|
102
|
-
return new Promise(((resolve, reject) => {
|
|
103
|
-
config.axiosClient.post(config.apiUrl+'/v1/client/cart/'+cart.uuid, cart)
|
|
104
|
-
.then((response) => {
|
|
105
|
-
resolve(response.data);
|
|
106
|
-
})
|
|
107
|
-
.catch((error) => {
|
|
108
|
-
reject(error);
|
|
109
|
-
})
|
|
110
|
-
}));
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
export function addDiscountCode(config:IClientConfig, cart: ICart, code: string){
|
|
115
|
-
return new Promise(((resolve, reject) => {
|
|
116
|
-
config.axiosClient.put(config.apiUrl+'/v1/client/cart/'+cart.uuid+"/coupon", {code})
|
|
117
|
-
.then((response) => {
|
|
118
|
-
resolve(response.data);
|
|
119
|
-
})
|
|
120
|
-
.catch((error) => {
|
|
121
|
-
reject(error);
|
|
122
|
-
})
|
|
123
|
-
}));
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
export function removeDiscountCode(config:IClientConfig, cart: ICart, discountId: number){
|
|
128
|
-
return new Promise(((resolve, reject) => {
|
|
129
|
-
config.axiosClient.delete(config.apiUrl+'/v1/client/cart/'+cart.uuid+'/coupon/'+discountId)
|
|
130
|
-
.then((response) => {
|
|
131
|
-
resolve(response.data);
|
|
132
|
-
})
|
|
133
|
-
.catch((error) => {
|
|
134
|
-
reject(error);
|
|
135
|
-
})
|
|
136
|
-
}));
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
|