@delicity/client-cart 1.2.11 → 1.2.13

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 (54) hide show
  1. package/README.md +1 -0
  2. package/coverage/clover.xml +71 -0
  3. package/coverage/coverage-final.json +3 -0
  4. package/coverage/lcov-report/base.css +224 -0
  5. package/coverage/lcov-report/block-navigation.js +87 -0
  6. package/coverage/lcov-report/classes/Cart.ts.html +340 -0
  7. package/coverage/lcov-report/classes/index.html +116 -0
  8. package/coverage/lcov-report/favicon.png +0 -0
  9. package/coverage/lcov-report/index.html +131 -0
  10. package/coverage/lcov-report/prettify.css +1 -0
  11. package/coverage/lcov-report/prettify.js +2 -0
  12. package/coverage/lcov-report/service/CartService.ts.html +238 -0
  13. package/coverage/lcov-report/service/index.html +116 -0
  14. package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
  15. package/coverage/lcov-report/sorter.js +196 -0
  16. package/coverage/lcov.info +129 -0
  17. package/jest.config.js +8 -0
  18. package/package.json +1 -1
  19. package/src/classes/Cart.ts +563 -0
  20. package/src/index.ts +3 -0
  21. package/src/service/CartService.ts +139 -0
  22. package/src/service/CategoryAvailabilityService.ts +121 -0
  23. package/src/service/DeliveryService.ts +17 -0
  24. package/src/service/HelperService.ts +9 -0
  25. package/src/test/availability.test.ts +346 -0
  26. package/src/test/class.test.ts +497 -0
  27. package/src/test/data/CartData.json +244 -0
  28. package/src/test/data/menu.json +5875 -0
  29. package/src/test/data/merchant.json +186 -0
  30. package/tsconfig.json +24 -0
  31. package/classes/Cart.d.ts +0 -129
  32. package/classes/Cart.d.ts.map +0 -1
  33. package/classes/Cart.js +0 -482
  34. package/classes/Cart.js.map +0 -1
  35. package/index.d.ts +0 -4
  36. package/index.d.ts.map +0 -1
  37. package/index.js +0 -20
  38. package/index.js.map +0 -1
  39. package/service/CartService.d.ts +0 -14
  40. package/service/CartService.d.ts.map +0 -1
  41. package/service/CartService.js +0 -130
  42. package/service/CartService.js.map +0 -1
  43. package/service/CategoryAvailabilityService.d.ts +0 -23
  44. package/service/CategoryAvailabilityService.d.ts.map +0 -1
  45. package/service/CategoryAvailabilityService.js +0 -103
  46. package/service/CategoryAvailabilityService.js.map +0 -1
  47. package/service/DeliveryService.d.ts +0 -4
  48. package/service/DeliveryService.d.ts.map +0 -1
  49. package/service/DeliveryService.js +0 -30
  50. package/service/DeliveryService.js.map +0 -1
  51. package/service/HelperService.d.ts +0 -2
  52. package/service/HelperService.d.ts.map +0 -1
  53. package/service/HelperService.js +0 -14
  54. package/service/HelperService.js.map +0 -1
package/jest.config.js ADDED
@@ -0,0 +1,8 @@
1
+ module.exports = {
2
+ transform: {
3
+ '^.+\\.(ts|tsx)$': 'ts-jest',
4
+ },
5
+ moduleNameMapper: {
6
+ '^@/(.*)$': '<rootDir>/src/$1'
7
+ },
8
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@delicity/client-cart",
3
- "version": "1.2.11",
3
+ "version": "1.2.13",
4
4
  "description": "Cart Client Package",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -0,0 +1,563 @@
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 ADDED
@@ -0,0 +1,3 @@
1
+ export * from './classes/Cart'
2
+ export * from './service/CartService'
3
+ export * from './service/CategoryAvailabilityService'