@darkpos/pricing 1.0.78 → 1.0.79

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.
@@ -873,4 +873,229 @@ describe('Modifier actions', () => {
873
873
  ]);
874
874
  });
875
875
  });
876
+
877
+ test('CU-86dve295v Should throw error when adding a modifier more times than the ones specified in properties.limits.maxAppliesItem', () => {
878
+ const order = {
879
+ id: 'ord-123',
880
+ items: [],
881
+ modifiers: [],
882
+ };
883
+ const modifier = {
884
+ _id: 1,
885
+ compute: {
886
+ amount: 10,
887
+ action: 'subtract',
888
+ type: 'fixed',
889
+ },
890
+ properties: {
891
+ isQuantityMultiplier: true,
892
+ limits: { maxAppliesItem: 1 },
893
+ },
894
+ };
895
+ order.items.push({
896
+ quantity: 2,
897
+ itemId: '123',
898
+ price: 100,
899
+ modifiers: [],
900
+ });
901
+
902
+ const conditionsBag = [];
903
+
904
+ const updatedOrder = pricingService.order.addItemModifier({
905
+ order,
906
+ modifier,
907
+ itemIndex: 0,
908
+ onConditionsNotMet: bag => {
909
+ bag.forEach(condition => {
910
+ conditionsBag.push(condition);
911
+ });
912
+ },
913
+ });
914
+
915
+ let error = '';
916
+ const updatedOrder2 = pricingService.order.addItemModifier({
917
+ order: { ...updatedOrder },
918
+ modifier,
919
+ itemIndex: 0,
920
+ onConditionsNotMet: bag => {
921
+ bag.forEach(condition => {
922
+ conditionsBag.push(condition);
923
+ });
924
+ },
925
+ onError: errorMessage => {
926
+ error = errorMessage;
927
+ },
928
+ });
929
+
930
+ expect(conditionsBag).toEqual([]);
931
+ expect(error).toEqual('modifier.has.reached.the.maximum.amount.of.applies');
932
+ expect(updatedOrder2.items).toEqual([
933
+ {
934
+ itemId: '123',
935
+ modifiers: [],
936
+ price: 100,
937
+ properties: { basePrice: 100 },
938
+ quantity: 2,
939
+ },
940
+ ]);
941
+ });
942
+
943
+ test('CU-86dve295v Should not throw error when adding a modifier less times than the ones specified in properties.limits.maxAppliesItem=5 and isQuantityMultiplier=false', () => {
944
+ const order = {
945
+ id: 'ord-123',
946
+ items: [],
947
+ modifiers: [],
948
+ };
949
+ const modifier = {
950
+ _id: 1,
951
+ compute: {
952
+ amount: 10,
953
+ action: 'subtract',
954
+ type: 'fixed',
955
+ },
956
+ properties: {
957
+ isQuantityMultiplier: false,
958
+ limits: { maxAppliesItem: 5 },
959
+ },
960
+ };
961
+ order.items.push({
962
+ quantity: 2,
963
+ itemId: '123',
964
+ price: 100,
965
+ modifiers: [],
966
+ });
967
+
968
+ const conditionsBag = [];
969
+
970
+ let error = '';
971
+ let currentOrder = { ...order };
972
+
973
+ for (let i = 0; i < 5; i += 1) {
974
+ currentOrder = pricingService.order.addItemModifier({
975
+ order: currentOrder,
976
+ modifier,
977
+ itemIndex: 0,
978
+ onConditionsNotMet: bag => {
979
+ bag.forEach(condition => {
980
+ conditionsBag.push(condition);
981
+ });
982
+ },
983
+ // eslint-disable-next-line no-loop-func
984
+ onError: errorMessage => {
985
+ error = errorMessage;
986
+ },
987
+ });
988
+ }
989
+
990
+ expect(conditionsBag).toEqual([]);
991
+ expect(error).toEqual('');
992
+
993
+ expect(currentOrder.items[0].modifiers.length).toBe(5);
994
+ });
995
+
996
+ test('CU-86dve295v Should not throw error when adding a modifier if properties.limits.isUnlimitedAppliesItem=true and isQuantityMultiplier=false', () => {
997
+ const order = {
998
+ id: 'ord-123',
999
+ items: [],
1000
+ modifiers: [],
1001
+ };
1002
+ const modifier = {
1003
+ _id: 1,
1004
+ compute: {
1005
+ amount: 10,
1006
+ action: 'subtract',
1007
+ type: 'fixed',
1008
+ },
1009
+ properties: {
1010
+ isQuantityMultiplier: false,
1011
+ limits: { isUnlimitedAppliesItem: true },
1012
+ },
1013
+ };
1014
+ order.items.push({
1015
+ quantity: 2,
1016
+ itemId: '123',
1017
+ price: 100,
1018
+ modifiers: [],
1019
+ });
1020
+
1021
+ const conditionsBag = [];
1022
+
1023
+ let error = '';
1024
+ let currentOrder = { ...order };
1025
+
1026
+ for (let i = 0; i < 5; i += 1) {
1027
+ currentOrder = pricingService.order.addItemModifier({
1028
+ order: currentOrder,
1029
+ modifier,
1030
+ itemIndex: 0,
1031
+ onConditionsNotMet: bag => {
1032
+ bag.forEach(condition => {
1033
+ conditionsBag.push(condition);
1034
+ });
1035
+ },
1036
+ // eslint-disable-next-line no-loop-func
1037
+ onError: errorMessage => {
1038
+ error = errorMessage;
1039
+ },
1040
+ });
1041
+ }
1042
+
1043
+ expect(conditionsBag).toEqual([]);
1044
+ expect(error).toEqual('');
1045
+
1046
+ expect(currentOrder.items[0].modifiers.length).toBe(5);
1047
+ });
1048
+
1049
+ test('CU-86dve295v Should not add the modifiers more times than item.quantity if modifier.properties.limits.isUnlimitedAppliesItem=false and modifier.properties.limits.maxAppliesItem is not set', () => {
1050
+ const order = {
1051
+ id: 'ord-123',
1052
+ items: [],
1053
+ modifiers: [],
1054
+ };
1055
+ const modifier = {
1056
+ _id: 1,
1057
+ compute: {
1058
+ amount: 10,
1059
+ action: 'subtract',
1060
+ type: 'fixed',
1061
+ },
1062
+ properties: {
1063
+ isQuantityMultiplier: false,
1064
+ limits: { isUnlimitedAppliesItem: false },
1065
+ },
1066
+ };
1067
+ order.items.push({
1068
+ quantity: 2,
1069
+ itemId: '123',
1070
+ price: 100,
1071
+ modifiers: [],
1072
+ });
1073
+
1074
+ const conditionsBag = [];
1075
+
1076
+ let error = '';
1077
+ let currentOrder = { ...order };
1078
+
1079
+ for (let i = 0; i < 5; i += 1) {
1080
+ currentOrder = pricingService.order.addItemModifier({
1081
+ order: currentOrder,
1082
+ modifier,
1083
+ itemIndex: 0,
1084
+ onConditionsNotMet: bag => {
1085
+ bag.forEach(condition => {
1086
+ conditionsBag.push(condition);
1087
+ });
1088
+ },
1089
+ // eslint-disable-next-line no-loop-func
1090
+ onError: errorMessage => {
1091
+ error = errorMessage;
1092
+ },
1093
+ });
1094
+ }
1095
+
1096
+ expect(conditionsBag).toEqual([]);
1097
+ expect(error).toEqual('');
1098
+
1099
+ expect(currentOrder.items[0].modifiers.length).toBe(2);
1100
+ });
876
1101
  });
@@ -1,6 +1,10 @@
1
1
  const usePricing = require('../../index');
2
+ const mockStores = require('../mocks/stores');
2
3
 
3
- const pricingService = usePricing();
4
+ const session = {
5
+ store: mockStores[0],
6
+ };
7
+ const pricingService = usePricing(session);
4
8
 
5
9
  describe('Conditions not met for the item', () => {
6
10
  test('#1: Item pieces condition is not met, errors bag populated', () => {
@@ -42,7 +46,6 @@ describe('Conditions not met for the item', () => {
42
46
  },
43
47
  ]);
44
48
  });
45
- // Write two more tests for the other conditions
46
49
  test('#2: Item quantity condition is not met, errors bag populated', () => {
47
50
  const order = {
48
51
  id: 'ord-123',
@@ -130,4 +133,551 @@ describe('Conditions not met for the item', () => {
130
133
  },
131
134
  ]);
132
135
  });
136
+
137
+ test('#4: Item number condition is met, errors bag empty', () => {
138
+ const mod3x2 = {
139
+ _id: '68069a18766f8687858461e7',
140
+ name: '3x2',
141
+ properties: {},
142
+ type: 'discount',
143
+ tags: ['default'],
144
+ conditions: {
145
+ valid: null,
146
+ rules: [
147
+ {
148
+ key: 'itemSet',
149
+ value: { itemSet: '3' },
150
+ operand: '$eq',
151
+ },
152
+ ],
153
+ },
154
+ compute: {
155
+ type: 'percentage',
156
+ action: 'subtract',
157
+ amount: 100,
158
+ },
159
+ };
160
+
161
+ const item = {
162
+ _id: 'abc',
163
+ price: 10,
164
+ quantity: 1,
165
+ };
166
+
167
+ let order = {
168
+ id: 'ord-123',
169
+ items: [],
170
+ modifiers: [],
171
+ };
172
+
173
+ order = pricingService.order.addItem({
174
+ order,
175
+ item: { ...item, price: 2 },
176
+ }).updatedOrder;
177
+
178
+ order = pricingService.order.addItem({
179
+ order,
180
+ item: { ...item, price: 50 },
181
+ }).updatedOrder;
182
+
183
+ order = pricingService.order.addItem({ order, item }).updatedOrder;
184
+
185
+ order = pricingService.order.addItemModifier({
186
+ order,
187
+ modifier: mod3x2,
188
+ itemIndex: 0,
189
+ });
190
+ order = pricingService.order.addItemModifier({
191
+ order,
192
+ modifier: mod3x2,
193
+ itemIndex: 1,
194
+ });
195
+ order = pricingService.order.addItemModifier({
196
+ order,
197
+ modifier: mod3x2,
198
+ itemIndex: 2,
199
+ });
200
+
201
+ expect(order.items.length).toEqual(3);
202
+
203
+ order = pricingService.order.calculate(order);
204
+
205
+ expect(order.total).toBe(60);
206
+ expect(order.items[0].total).toBe(10);
207
+ expect(order.items[0].modifiers.length).toBe(1);
208
+
209
+ expect(order.items[1].total).toBe(50);
210
+ expect(order.items[1].modifiers.length).toBe(1);
211
+
212
+ expect(order.items[2].total).toBe(0);
213
+ expect(order.items[2].modifiers.length).toBe(1);
214
+ });
215
+
216
+ test('#5: Item number condition is met 2 times, errors bag empty', () => {
217
+ const mod3x2 = {
218
+ _id: '68069a18766f8687858461e7',
219
+ name: '3x2',
220
+ properties: {},
221
+ type: 'discount',
222
+ tags: ['default'],
223
+ conditions: {
224
+ valid: null,
225
+ rules: [
226
+ {
227
+ key: 'itemSet',
228
+ value: { itemSet: '3' },
229
+ operand: '$eq',
230
+ },
231
+ ],
232
+ },
233
+ compute: {
234
+ type: 'percentage',
235
+ action: 'subtract',
236
+ amount: 100,
237
+ },
238
+ };
239
+
240
+ const item = {
241
+ _id: 'abc',
242
+ price: 10,
243
+ quantity: 1,
244
+ };
245
+
246
+ let order = {
247
+ id: 'ord-123',
248
+ items: [],
249
+ modifiers: [],
250
+ };
251
+
252
+ order = pricingService.order.addItem({
253
+ order,
254
+ item: { ...item, price: 5 },
255
+ }).updatedOrder;
256
+
257
+ order = pricingService.order.addItem({
258
+ order,
259
+ item: { ...item, price: 4 },
260
+ }).updatedOrder;
261
+
262
+ order = pricingService.order.addItem({ order, item }).updatedOrder;
263
+
264
+ order = pricingService.order.addItem({
265
+ order,
266
+ item: { ...item, price: 10 },
267
+ }).updatedOrder;
268
+
269
+ order = pricingService.order.addItem({
270
+ order,
271
+ item: { ...item, price: 10 },
272
+ }).updatedOrder;
273
+
274
+ order = pricingService.order.addItem({ order, item }).updatedOrder;
275
+
276
+ order = pricingService.order.addItemModifier({
277
+ order,
278
+ modifier: mod3x2,
279
+ itemIndex: 0,
280
+ });
281
+ order = pricingService.order.addItemModifier({
282
+ order,
283
+ modifier: mod3x2,
284
+ itemIndex: 1,
285
+ });
286
+ order = pricingService.order.addItemModifier({
287
+ order,
288
+ modifier: mod3x2,
289
+ itemIndex: 2,
290
+ });
291
+ order = pricingService.order.addItemModifier({
292
+ order,
293
+ modifier: mod3x2,
294
+ itemIndex: 3,
295
+ });
296
+ order = pricingService.order.addItemModifier({
297
+ order,
298
+ modifier: mod3x2,
299
+ itemIndex: 4,
300
+ });
301
+ order = pricingService.order.addItemModifier({
302
+ order,
303
+ modifier: mod3x2,
304
+ itemIndex: 5,
305
+ });
306
+
307
+ expect(order.items.length).toEqual(6);
308
+
309
+ order = pricingService.order.calculate(order);
310
+
311
+ expect(order.total).toBe(40);
312
+ expect(order.items[0].total).toBe(10);
313
+ expect(order.items[0].modifiers.length).toBe(1);
314
+
315
+ expect(order.items[1].total).toBe(10);
316
+ expect(order.items[1].modifiers.length).toBe(1);
317
+
318
+ expect(order.items[2].total).toBe(10);
319
+ expect(order.items[2].modifiers.length).toBe(1);
320
+
321
+ expect(order.items[3].total).toBe(10);
322
+ expect(order.items[3].modifiers.length).toBe(1);
323
+
324
+ expect(order.items[4].price).toBe(4);
325
+ expect(order.items[4].total).toBe(0);
326
+ expect(order.items[4].modifiers.length).toBe(1);
327
+
328
+ expect(order.items[5].price).toBe(5);
329
+ expect(order.items[5].total).toBe(0);
330
+ expect(order.items[5].modifiers.length).toBe(1);
331
+ });
332
+
333
+ test('#6: Item number condition is met, rule is highestPrice', () => {
334
+ const mod3x2 = {
335
+ _id: '68069a18766f8687858461e7',
336
+ name: '3x2',
337
+ properties: {},
338
+ type: 'discount',
339
+ tags: ['default'],
340
+ conditions: {
341
+ valid: null,
342
+ rules: [
343
+ {
344
+ key: 'itemSet',
345
+ value: { itemSet: '3', itemRule: 'highestPrice' },
346
+ operand: '$eq',
347
+ },
348
+ ],
349
+ },
350
+ compute: {
351
+ type: 'percentage',
352
+ action: 'subtract',
353
+ amount: 100,
354
+ },
355
+ };
356
+
357
+ const item = {
358
+ _id: 'abc',
359
+ price: 10,
360
+ quantity: 1,
361
+ };
362
+
363
+ let order = {
364
+ id: 'ord-123',
365
+ items: [],
366
+ modifiers: [],
367
+ };
368
+
369
+ order = pricingService.order.addItem({
370
+ order,
371
+ item: { ...item, price: 5 },
372
+ }).updatedOrder;
373
+
374
+ order = pricingService.order.addItem({
375
+ order,
376
+ item: { ...item, price: 4 },
377
+ }).updatedOrder;
378
+
379
+ order = pricingService.order.addItem({ order, item }).updatedOrder;
380
+
381
+ order = pricingService.order.addItem({
382
+ order,
383
+ item: { ...item, price: 10 },
384
+ }).updatedOrder;
385
+
386
+ order = pricingService.order.addItem({
387
+ order,
388
+ item: { ...item, price: 10 },
389
+ }).updatedOrder;
390
+
391
+ order = pricingService.order.addItem({ order, item }).updatedOrder;
392
+
393
+ order = pricingService.order.addItemModifier({
394
+ order,
395
+ modifier: mod3x2,
396
+ itemIndex: 0,
397
+ });
398
+ order = pricingService.order.addItemModifier({
399
+ order,
400
+ modifier: mod3x2,
401
+ itemIndex: 1,
402
+ });
403
+ order = pricingService.order.addItemModifier({
404
+ order,
405
+ modifier: mod3x2,
406
+ itemIndex: 2,
407
+ });
408
+ order = pricingService.order.addItemModifier({
409
+ order,
410
+ modifier: mod3x2,
411
+ itemIndex: 3,
412
+ });
413
+ order = pricingService.order.addItemModifier({
414
+ order,
415
+ modifier: mod3x2,
416
+ itemIndex: 4,
417
+ });
418
+ order = pricingService.order.addItemModifier({
419
+ order,
420
+ modifier: mod3x2,
421
+ itemIndex: 5,
422
+ });
423
+
424
+ expect(order.items.length).toEqual(6);
425
+
426
+ order = pricingService.order.calculate(order);
427
+
428
+ expect(order.total).toBe(29);
429
+ expect(order.items[0].total).toBe(0);
430
+ expect(order.items[0].modifiers.length).toBe(1);
431
+
432
+ expect(order.items[1].total).toBe(0);
433
+ expect(order.items[1].modifiers.length).toBe(1);
434
+
435
+ expect(order.items[2].total).toBe(10);
436
+ expect(order.items[2].modifiers.length).toBe(1);
437
+
438
+ expect(order.items[3].total).toBe(10);
439
+ expect(order.items[3].modifiers.length).toBe(1);
440
+
441
+ expect(order.items[4].price).toBe(4);
442
+ expect(order.items[4].total).toBe(4);
443
+ expect(order.items[4].modifiers.length).toBe(1);
444
+
445
+ expect(order.items[5].price).toBe(5);
446
+ expect(order.items[5].total).toBe(5);
447
+ expect(order.items[5].modifiers.length).toBe(1);
448
+ });
449
+
450
+ test('#7: Item number condition is met, rule is firstSelected', () => {
451
+ const mod3x2 = {
452
+ _id: '68069a18766f8687858461e7',
453
+ name: '3x2',
454
+ properties: {},
455
+ type: 'discount',
456
+ tags: ['default'],
457
+ conditions: {
458
+ valid: null,
459
+ rules: [
460
+ {
461
+ key: 'itemSet',
462
+ value: { itemSet: '3', itemRule: 'firstSelected' },
463
+ operand: '$eq',
464
+ },
465
+ ],
466
+ },
467
+ compute: {
468
+ type: 'percentage',
469
+ action: 'subtract',
470
+ amount: 100,
471
+ },
472
+ };
473
+
474
+ const item = {
475
+ _id: 'abc',
476
+ price: 10,
477
+ quantity: 1,
478
+ };
479
+
480
+ let order = {
481
+ id: 'ord-123',
482
+ items: [],
483
+ modifiers: [],
484
+ };
485
+
486
+ order = pricingService.order.addItem({
487
+ order,
488
+ item: { ...item, price: 5 },
489
+ }).updatedOrder;
490
+
491
+ order = pricingService.order.addItem({
492
+ order,
493
+ item: { ...item, price: 4 },
494
+ }).updatedOrder;
495
+
496
+ order = pricingService.order.addItem({ order, item }).updatedOrder;
497
+
498
+ order = pricingService.order.addItem({
499
+ order,
500
+ item: { ...item, price: 10 },
501
+ }).updatedOrder;
502
+
503
+ order = pricingService.order.addItem({
504
+ order,
505
+ item: { ...item, price: 10 },
506
+ }).updatedOrder;
507
+
508
+ order = pricingService.order.addItem({ order, item }).updatedOrder;
509
+
510
+ order = pricingService.order.addItemModifier({
511
+ order,
512
+ modifier: mod3x2,
513
+ itemIndex: 0,
514
+ });
515
+ order = pricingService.order.addItemModifier({
516
+ order,
517
+ modifier: mod3x2,
518
+ itemIndex: 1,
519
+ });
520
+ order = pricingService.order.addItemModifier({
521
+ order,
522
+ modifier: mod3x2,
523
+ itemIndex: 2,
524
+ });
525
+ order = pricingService.order.addItemModifier({
526
+ order,
527
+ modifier: mod3x2,
528
+ itemIndex: 3,
529
+ });
530
+ order = pricingService.order.addItemModifier({
531
+ order,
532
+ modifier: mod3x2,
533
+ itemIndex: 4,
534
+ });
535
+ order = pricingService.order.addItemModifier({
536
+ order,
537
+ modifier: mod3x2,
538
+ itemIndex: 5,
539
+ });
540
+
541
+ expect(order.items.length).toEqual(6);
542
+
543
+ order = pricingService.order.calculate(order);
544
+
545
+ expect(order.total).toBe(40);
546
+ expect(order.items[0].total).toBe(10);
547
+ expect(order.items[0].modifiers.length).toBe(1);
548
+
549
+ expect(order.items[1].total).toBe(10);
550
+ expect(order.items[1].modifiers.length).toBe(1);
551
+
552
+ expect(order.items[2].total).toBe(10);
553
+ expect(order.items[2].modifiers.length).toBe(1);
554
+
555
+ expect(order.items[3].total).toBe(10);
556
+ expect(order.items[3].modifiers.length).toBe(1);
557
+
558
+ expect(order.items[4].price).toBe(4);
559
+ expect(order.items[4].total).toBe(0);
560
+ expect(order.items[4].modifiers.length).toBe(1);
561
+
562
+ expect(order.items[5].price).toBe(5);
563
+ expect(order.items[5].total).toBe(0);
564
+ expect(order.items[5].modifiers.length).toBe(1);
565
+ });
566
+
567
+ test('#8: Item number condition is met, rule is lastSelected', () => {
568
+ const mod3x2 = {
569
+ _id: '68069a18766f8687858461e7',
570
+ name: '3x2',
571
+ properties: {},
572
+ type: 'discount',
573
+ tags: ['default'],
574
+ conditions: {
575
+ valid: null,
576
+ rules: [
577
+ {
578
+ key: 'itemSet',
579
+ value: { itemSet: '3', itemRule: 'lastSelected' },
580
+ operand: '$eq',
581
+ },
582
+ ],
583
+ },
584
+ compute: {
585
+ type: 'percentage',
586
+ action: 'subtract',
587
+ amount: 100,
588
+ },
589
+ };
590
+
591
+ const item = {
592
+ _id: 'abc',
593
+ price: 10,
594
+ quantity: 1,
595
+ };
596
+
597
+ let order = {
598
+ id: 'ord-123',
599
+ items: [],
600
+ modifiers: [],
601
+ };
602
+
603
+ order = pricingService.order.addItem({
604
+ order,
605
+ item: { ...item, price: 5 },
606
+ }).updatedOrder;
607
+
608
+ order = pricingService.order.addItem({
609
+ order,
610
+ item: { ...item, price: 4 },
611
+ }).updatedOrder;
612
+
613
+ order = pricingService.order.addItem({ order, item }).updatedOrder;
614
+
615
+ order = pricingService.order.addItem({
616
+ order,
617
+ item: { ...item, price: 10 },
618
+ }).updatedOrder;
619
+
620
+ order = pricingService.order.addItem({
621
+ order,
622
+ item: { ...item, price: 10 },
623
+ }).updatedOrder;
624
+
625
+ order = pricingService.order.addItem({ order, item }).updatedOrder;
626
+
627
+ order = pricingService.order.addItemModifier({
628
+ order,
629
+ modifier: mod3x2,
630
+ itemIndex: 0,
631
+ });
632
+ order = pricingService.order.addItemModifier({
633
+ order,
634
+ modifier: mod3x2,
635
+ itemIndex: 1,
636
+ });
637
+ order = pricingService.order.addItemModifier({
638
+ order,
639
+ modifier: mod3x2,
640
+ itemIndex: 2,
641
+ });
642
+ order = pricingService.order.addItemModifier({
643
+ order,
644
+ modifier: mod3x2,
645
+ itemIndex: 3,
646
+ });
647
+ order = pricingService.order.addItemModifier({
648
+ order,
649
+ modifier: mod3x2,
650
+ itemIndex: 4,
651
+ });
652
+ order = pricingService.order.addItemModifier({
653
+ order,
654
+ modifier: mod3x2,
655
+ itemIndex: 5,
656
+ });
657
+
658
+ expect(order.items.length).toEqual(6);
659
+
660
+ order = pricingService.order.calculate(order);
661
+
662
+ expect(order.total).toBe(29);
663
+ expect(order.items[0].total).toBe(0);
664
+ expect(order.items[0].modifiers.length).toBe(1);
665
+
666
+ expect(order.items[1].total).toBe(0);
667
+ expect(order.items[1].modifiers.length).toBe(1);
668
+
669
+ expect(order.items[2].total).toBe(10);
670
+ expect(order.items[2].modifiers.length).toBe(1);
671
+
672
+ expect(order.items[3].total).toBe(10);
673
+ expect(order.items[3].modifiers.length).toBe(1);
674
+
675
+ expect(order.items[4].price).toBe(4);
676
+ expect(order.items[4].total).toBe(4);
677
+ expect(order.items[4].modifiers.length).toBe(1);
678
+
679
+ expect(order.items[5].price).toBe(5);
680
+ expect(order.items[5].total).toBe(5);
681
+ expect(order.items[5].modifiers.length).toBe(1);
682
+ });
133
683
  });
@@ -3699,4 +3699,115 @@ describe('Order actions', () => {
3699
3699
  expect(splittedOrders[1].items[0].name).toEqual(item1.name);
3700
3700
  expect(splittedOrders[1].items[0].quantity).toEqual(6);
3701
3701
  });
3702
+
3703
+ test('CU-86dve295v Should continue to add a modifier while its quantity is less than the specified in properties.limits.maxAppliesOrder=5', () => {
3704
+ const order = {
3705
+ id: 'ord-123',
3706
+ items: [],
3707
+ modifiers: [],
3708
+ };
3709
+ const modifier = {
3710
+ _id: 1,
3711
+ compute: {
3712
+ amount: 10,
3713
+ action: 'subtract',
3714
+ type: 'fixed',
3715
+ },
3716
+ modifierId: 'abc123',
3717
+ properties: {
3718
+ limits: { maxAppliesOrder: 5 },
3719
+ },
3720
+ };
3721
+ order.items.push({
3722
+ quantity: 2,
3723
+ itemId: '123',
3724
+ price: 100,
3725
+ modifiers: [],
3726
+ });
3727
+
3728
+ let currentOrder = { ...order };
3729
+
3730
+ for (let i = 0; i < 5; i += 1) {
3731
+ currentOrder = pricingService.order.addModifier({
3732
+ order: currentOrder,
3733
+ modifier,
3734
+ });
3735
+ }
3736
+
3737
+ expect(currentOrder.modifiers.length).toBe(5);
3738
+ });
3739
+
3740
+ test('CU-86dve295v Should continue to add a modifier if properties.limits.isUnlimitedAppliesOrder=true', () => {
3741
+ const order = {
3742
+ id: 'ord-123',
3743
+ items: [],
3744
+ modifiers: [],
3745
+ };
3746
+ const modifier = {
3747
+ _id: 1,
3748
+ compute: {
3749
+ amount: 10,
3750
+ action: 'subtract',
3751
+ type: 'fixed',
3752
+ },
3753
+ modifierId: 'abc123',
3754
+ properties: {
3755
+ limits: { isUnlimitedAppliesOrder: true },
3756
+ },
3757
+ };
3758
+ order.items.push({
3759
+ quantity: 2,
3760
+ itemId: '123',
3761
+ price: 100,
3762
+ modifiers: [],
3763
+ });
3764
+
3765
+ let currentOrder = { ...order };
3766
+
3767
+ for (let i = 0; i < 5; i += 1) {
3768
+ currentOrder = pricingService.order.addModifier({
3769
+ order: currentOrder,
3770
+ modifier,
3771
+ });
3772
+ }
3773
+
3774
+ expect(currentOrder.modifiers.length).toBe(5);
3775
+ });
3776
+
3777
+ test('CU-86dve295v Should not add a modifier more than once if properties.limits.isUnlimitedAppliesOrder=false and properties.limits.maxAppliesOrder is not defined', () => {
3778
+ const order = {
3779
+ id: 'ord-123',
3780
+ items: [],
3781
+ modifiers: [],
3782
+ };
3783
+ const modifier = {
3784
+ _id: 1,
3785
+ compute: {
3786
+ amount: 10,
3787
+ action: 'subtract',
3788
+ type: 'fixed',
3789
+ },
3790
+ modifierId: 'abc123',
3791
+ properties: {
3792
+ limits: { isUnlimitedAppliesOrder: false, maxAppliesOrder: 0 },
3793
+ },
3794
+ };
3795
+ order.items.push({
3796
+ quantity: 2,
3797
+ itemId: '123',
3798
+ price: 100,
3799
+ modifiers: [],
3800
+ });
3801
+
3802
+ let currentOrder = { ...order };
3803
+
3804
+ for (let i = 0; i < 5; i += 1) {
3805
+ currentOrder = pricingService.order.addModifier({
3806
+ order: currentOrder,
3807
+ modifier,
3808
+ });
3809
+ }
3810
+
3811
+ expect(currentOrder.modifiers.length).toBe(1);
3812
+ });
3702
3813
  });
@@ -6,4 +6,5 @@ module.exports = {
6
6
  LIST: 'list',
7
7
  DEPARTMENT: 'department',
8
8
  OVERRIDE: 'override',
9
+ LIMITS: 'limits',
9
10
  };
@@ -11,6 +11,8 @@ module.exports = ({ _, utils, actions, modifierActions }) => {
11
11
  const startRequestDate = opts.startRequestDate || null;
12
12
  const endRequestDate = opts.endRequestDate || null;
13
13
  const lockPaymentModifiers = !!opts.lockPaymentModifiers;
14
+ const allItems = Array.isArray(opts.items) ? opts.items : [];
15
+
14
16
  const { paymentId } = opts;
15
17
 
16
18
  if (!item) return item;
@@ -43,6 +45,7 @@ module.exports = ({ _, utils, actions, modifierActions }) => {
43
45
  item,
44
46
  startRequestDate,
45
47
  endRequestDate,
48
+ allItems,
46
49
  })
47
50
  );
48
51
 
@@ -195,10 +198,10 @@ module.exports = ({ _, utils, actions, modifierActions }) => {
195
198
 
196
199
  //
197
200
  const calculateMany = (items = [], opts = null) =>
198
- items.map(item => calculateOne(item, opts));
201
+ items.map(item => calculateOne(item, { ...opts, items }));
199
202
 
200
203
  return function calculate(item, opts) {
201
204
  if (Array.isArray(item)) return calculateMany(item, opts);
202
- return calculateOne(item, opts);
205
+ return calculateOne(item, { ...opts });
203
206
  };
204
207
  };
@@ -8,9 +8,10 @@ module.exports = ({ modifierActions, settings }) =>
8
8
  let modifierTags = item.modifiers
9
9
  .filter(
10
10
  each =>
11
- modifierActions.isValid(each) &&
11
+ (modifierActions.isValid(each) || modifierActions.isItemSet(each)) &&
12
12
  (!modifierActions.isGroup(each) || modifierActions.isDepartment(each))
13
13
  )
14
+
14
15
  .map(modifier => {
15
16
  const { name, _id } = modifier;
16
17
 
@@ -14,13 +14,17 @@ module.exports = ({ modifierActions }) =>
14
14
  modifierActions.isCalculatedPaymentModifier(modifier) ||
15
15
  modifierActions.isGroupOfModifiers(modifier) ||
16
16
  !modifier.modifierId ||
17
- !modifierActions.isDirect(modifier)
17
+ !modifierActions.isDirect(modifier) ||
18
+ modifierActions.isUnlimitedAppliesItem(modifier)
18
19
  )
19
20
  return true;
20
21
 
21
22
  const count = modifierCounts[modifier.modifierId] || 0;
22
23
 
23
- if (count < item.quantity) {
24
+ const maxApplies = modifierActions.getMaxAppliesItem(modifier);
25
+ const maxQuantity = maxApplies || item.quantity;
26
+
27
+ if (count < maxQuantity) {
24
28
  modifierCounts[modifier.modifierId] = count + 1;
25
29
  return true;
26
30
  }
@@ -1,11 +1,64 @@
1
- module.exports = ({ actions }) => {
1
+ module.exports = ({ actions, utils }) => {
2
2
  const modifierConditionPass = (
3
3
  modifier,
4
- { item, startRequestDate, endRequestDate }
4
+ { item, startRequestDate, endRequestDate, allItems }
5
5
  ) =>
6
6
  modifier.conditions && Array.isArray(modifier.conditions.rules)
7
7
  ? modifier.conditions.rules.every(condition => {
8
8
  switch (condition.key) {
9
+ case 'itemSet': {
10
+ if (!Array.isArray(allItems)) return true;
11
+ const conditionValue = Number(condition.value.itemSet || 0);
12
+ const conditionRule = condition.value.itemRule || 'lowestPrice';
13
+
14
+ const matchingItems = allItems
15
+ .filter(eachItem =>
16
+ eachItem.modifiers.some(
17
+ mod => mod.modifierId === modifier.modifierId
18
+ )
19
+ )
20
+ .sort((a, b) => {
21
+ switch (conditionRule) {
22
+ case 'lowestPrice':
23
+ return a.price - b.price;
24
+ case 'highestPrice':
25
+ return b.price - a.price;
26
+ case 'firstSelected':
27
+ return a._id.localeCompare(b._id);
28
+ case 'lastSelected':
29
+ return b._id.localeCompare(a._id);
30
+ default:
31
+ return 0;
32
+ }
33
+ });
34
+
35
+ const itemIndexInSorted = matchingItems.findIndex(
36
+ entry => entry._id === item._id
37
+ );
38
+
39
+ const itemSet =
40
+ itemIndexInSorted >= 0 ? itemIndexInSorted + 1 : null;
41
+
42
+ const matchingItemsLength = matchingItems.length;
43
+
44
+ if (
45
+ condition.operand === '$eq' &&
46
+ conditionValue &&
47
+ matchingItemsLength >= conditionValue
48
+ ) {
49
+ const result = Math.floor(
50
+ utils.math.div(matchingItemsLength, conditionValue)
51
+ );
52
+ if (itemSet <= result) {
53
+ return true;
54
+ }
55
+ }
56
+ return actions.validateItemNumber(
57
+ itemSet,
58
+ conditionValue,
59
+ condition.operand
60
+ );
61
+ }
9
62
  case 'itemPieces':
10
63
  return actions.validateNumberCondition(
11
64
  item.pieces,
@@ -46,6 +99,7 @@ module.exports = ({ actions }) => {
46
99
  item = null,
47
100
  endRequestDate = null,
48
101
  startRequestDate = null,
102
+ allItems = null,
49
103
  } = opts;
50
104
  // const recommendedEndDate = storeActions.getRecommendedEndDate();
51
105
  return (
@@ -54,6 +108,7 @@ module.exports = ({ actions }) => {
54
108
  item,
55
109
  startRequestDate,
56
110
  endRequestDate,
111
+ allItems,
57
112
  })
58
113
  );
59
114
  }
@@ -0,0 +1,5 @@
1
+ module.exports = ({ actions }) =>
2
+ function getMaxAppliesItem(modifier) {
3
+ if (!actions.isLimits(modifier)) return false;
4
+ return modifier.properties.limits.maxAppliesItem;
5
+ };
@@ -0,0 +1,5 @@
1
+ module.exports = ({ actions }) =>
2
+ function getMaxAppliesOrder(modifier) {
3
+ if (!actions.isLimits(modifier)) return false;
4
+ return modifier.properties.limits.maxAppliesOrder;
5
+ };
@@ -150,6 +150,13 @@ const isGroupPath = require('./isGroupPath');
150
150
  const isSpreadFrom = require('./isSpreadFrom');
151
151
  const getRelatedModifiers = require('./getRelatedModifiers');
152
152
  const isRelatedModifier = require('./isRelatedModifier');
153
+ const getMaxAppliesItem = require('./getMaxAppliesItem');
154
+ const getMaxAppliesOrder = require('./getMaxAppliesOrder');
155
+ const isUnlimitedAppliesItem = require('./isUnlimitedAppliesItem');
156
+ const isUnlimitedAppliesOrder = require('./isUnlimitedAppliesOrder');
157
+ const validateItemNumber = require('./validateItemNumber');
158
+ const isLimits = require('./isLimits');
159
+ const isItemSet = require('./isItemSet');
153
160
 
154
161
  const modifierActions = (deps = {}) => {
155
162
  const actions = {};
@@ -281,6 +288,7 @@ const modifierActions = (deps = {}) => {
281
288
  getGroupedModifierLabels: getGroupedModifierLabels(innerDeps),
282
289
  validate: validate(innerDeps),
283
290
  validateNumberCondition: validateNumberCondition(innerDeps),
291
+ validateItemNumber: validateItemNumber(innerDeps),
284
292
  validateRequiredModifiers: validateRequiredModifiers(innerDeps),
285
293
  validateDateHoursDiff: validateDateHoursDiff(innerDeps),
286
294
  validateInArr: validateInArr(innerDeps),
@@ -313,6 +321,12 @@ const modifierActions = (deps = {}) => {
313
321
  isSpreadFrom: isSpreadFrom(innerDeps),
314
322
  getRelatedModifiers: getRelatedModifiers(innerDeps),
315
323
  isRelatedModifier: isRelatedModifier(innerDeps),
324
+ getMaxAppliesItem: getMaxAppliesItem(innerDeps),
325
+ getMaxAppliesOrder: getMaxAppliesOrder(innerDeps),
326
+ isUnlimitedAppliesItem: isUnlimitedAppliesItem(innerDeps),
327
+ isUnlimitedAppliesOrder: isUnlimitedAppliesOrder(innerDeps),
328
+ isLimits: isLimits(innerDeps),
329
+ isItemSet: isItemSet(innerDeps),
316
330
  });
317
331
 
318
332
  Object.keys(freezedActions).forEach(actionName => {
@@ -0,0 +1,11 @@
1
+ module.exports = () =>
2
+ function isItemSet(modifier) {
3
+ if (
4
+ !modifier ||
5
+ !modifier.conditions ||
6
+ !Array.isArray(modifier.conditions.rules)
7
+ )
8
+ return false;
9
+
10
+ return modifier.conditions.rules.some(rule => rule.key === 'itemSet');
11
+ };
@@ -0,0 +1,9 @@
1
+ module.exports = ({ actions, constants }) => {
2
+ const { Modifier } = constants;
3
+ return function isLimits(modifier) {
4
+ return (
5
+ actions.hasAttribute(modifier, Modifier.Attributes.LIMITS) ||
6
+ !!actions.getProperty(modifier, Modifier.Attributes.LIMITS)
7
+ );
8
+ };
9
+ };
@@ -0,0 +1,6 @@
1
+ module.exports = ({ actions }) =>
2
+ function isUnlimitedAppliesItem(modifier) {
3
+ if (!actions.isLimits(modifier)) return false;
4
+
5
+ return !!modifier.properties.limits.isUnlimitedAppliesItem;
6
+ };
@@ -0,0 +1,6 @@
1
+ module.exports = ({ actions }) =>
2
+ function isUnlimitedAppliesOrder(modifier) {
3
+ if (!actions.isLimits(modifier)) return false;
4
+
5
+ return !!modifier.properties.limits.isUnlimitedAppliesOrder;
6
+ };
@@ -0,0 +1,18 @@
1
+ module.exports = () =>
2
+ function validateItemNumber(itemSet, conditionNumber, operand) {
3
+ if (!conditionNumber && !operand) return true;
4
+ switch (operand) {
5
+ case '$ne':
6
+ return Number(conditionNumber) !== itemSet;
7
+ case '$gt':
8
+ return Number(conditionNumber) < itemSet;
9
+ case '$gte':
10
+ return Number(conditionNumber) <= itemSet;
11
+ case '$lt':
12
+ return Number(conditionNumber) > itemSet;
13
+ case '$lte':
14
+ return Number(conditionNumber) >= itemSet;
15
+ default:
16
+ return false;
17
+ }
18
+ };
@@ -190,11 +190,19 @@ module.exports = ({ actions, itemActions, modifierActions, utils, _ }) => {
190
190
  return order;
191
191
  }
192
192
  // Remove if it has it already only if it is not group of value or override modifier
193
+
194
+ const maxApplies = modifierActions.getMaxAppliesItem(modifier);
195
+ const maxQuantity = maxApplies || item.quantity;
196
+
193
197
  if (
198
+ !modifierActions.isUnlimitedAppliesItem(modifier) &&
194
199
  contains &&
195
- usingCount >= item.quantity &&
200
+ usingCount >= maxQuantity &&
196
201
  !modifierActions.isOverride(modifier)
197
202
  ) {
203
+ if (maxApplies && onError)
204
+ onError('modifier.has.reached.the.maximum.amount.of.applies');
205
+
198
206
  order = actions.removeItemModifier({
199
207
  order,
200
208
  modifier,
@@ -1,23 +1,25 @@
1
- module.exports = ({ actions, modifierActions }) => {
2
- const { getComputeModField } = require('../modifier/utils');
3
- return function addModifier({ order, modifier }) {
1
+ module.exports = ({ modifierActions }) =>
2
+ function addModifier({ order, modifier }) {
4
3
  if (!modifier) return order;
5
4
  const { modifiers = [] } = order;
6
- if (modifierActions.isFixedDiscount(modifier)) {
7
- const compute = getComputeModField(modifier);
8
- const orderDue = actions.calculateDue(order);
9
- if (compute.amount > orderDue) {
10
- const err = new Error();
11
- err.valid = false;
12
- err.orderDue = orderDue;
13
- err.message = 'discount.can.not.be.applied.order.due.is.this.amount';
14
- throw err;
5
+
6
+ let usingCount = 0;
7
+
8
+ modifiers.forEach(orderMod => {
9
+ if (orderMod.modifierId === modifier.modifierId) {
10
+ usingCount += 1;
15
11
  }
16
- }
12
+ });
13
+ const maxQty = modifierActions.getMaxAppliesOrder(modifier) || 1;
14
+
15
+ if (
16
+ modifierActions.isUnlimitedAppliesOrder(modifier) ||
17
+ usingCount < maxQty
18
+ )
19
+ return {
20
+ ...order,
21
+ modifiers: [...modifiers, { ...modifier }],
22
+ };
17
23
 
18
- return {
19
- ...order,
20
- modifiers: [...modifiers, { ...modifier }],
21
- };
24
+ return order;
22
25
  };
23
- };
@@ -3,7 +3,7 @@ module.exports = ({ _ }) =>
3
3
  if (!orders || !Array.isArray(orders)) return 0;
4
4
  const sum = orders.reduce((acc, order) => {
5
5
  const items = _.get(order, 'items', []);
6
- return acc + items.lenght;
6
+ return acc + items.length;
7
7
  }, 0);
8
8
 
9
9
  return sum;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@darkpos/pricing",
3
- "version": "1.0.78",
3
+ "version": "1.0.79",
4
4
  "description": "Pricing calculator",
5
5
  "author": "Dark POS",
6
6
  "license": "ISC",
@@ -51,5 +51,5 @@
51
51
  "supertest": "^6.2.3",
52
52
  "supervisor": "^0.12.0"
53
53
  },
54
- "gitHead": "4e966b805abc74cc31cb0b3a0754e71f9bb913e5"
54
+ "gitHead": "1ebec123fd5b4e7d3aaa6b259cd4467c9dccb74b"
55
55
  }