@lyxa.ai/marketing 1.0.32 → 1.0.36
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/lib/index.d.ts +29 -0
- package/dist/lib/index.d.ts.map +1 -1
- package/dist/lib/index.js.map +1 -1
- package/dist/lib/modules/coupon/routers/coupon.router.d.ts +29 -0
- package/dist/lib/modules/coupon/routers/coupon.router.d.ts.map +1 -1
- package/dist/lib/modules/coupon/routers/coupon.router.js +23 -4
- package/dist/lib/modules/coupon/routers/coupon.router.js.map +1 -1
- package/dist/lib/modules/coupon/services/coupon.service.d.ts +9 -1
- package/dist/lib/modules/coupon/services/coupon.service.d.ts.map +1 -1
- package/dist/lib/modules/coupon/services/coupon.service.js +109 -25
- package/dist/lib/modules/coupon/services/coupon.service.js.map +1 -1
- package/dist/lib/modules/coupon/services/helper.service.d.ts +2 -0
- package/dist/lib/modules/coupon/services/helper.service.d.ts.map +1 -1
- package/dist/lib/modules/coupon/services/helper.service.js +13 -0
- package/dist/lib/modules/coupon/services/helper.service.js.map +1 -1
- package/dist/lib/modules/coupon/services/patterns/repository/CouponRepository.d.ts.map +1 -1
- package/dist/lib/modules/coupon/services/patterns/repository/CouponRepository.js +9 -32
- package/dist/lib/modules/coupon/services/patterns/repository/CouponRepository.js.map +1 -1
- package/dist/lib/modules/coupon/validations/coupon.validation.d.ts +19 -0
- package/dist/lib/modules/coupon/validations/coupon.validation.d.ts.map +1 -1
- package/dist/lib/modules/coupon/validations/coupon.validation.js +6 -4
- package/dist/lib/modules/coupon/validations/coupon.validation.js.map +1 -1
- package/dist/lib/modules/deal-setting/services/deal-setting.service.d.ts +1 -1
- package/dist/lib/modules/deal-setting/services/deal-setting.service.d.ts.map +1 -1
- package/dist/lib/modules/deal-setting/services/deal-setting.service.js +6 -5
- package/dist/lib/modules/deal-setting/services/deal-setting.service.js.map +1 -1
- package/dist/lib/modules/marketing/services/marketing.service.d.ts.map +1 -1
- package/dist/lib/modules/marketing/services/marketing.service.js +17 -1
- package/dist/lib/modules/marketing/services/marketing.service.js.map +1 -1
- package/dist/lib/modules/marketing/services/product-marketing.service.js +1 -1
- package/dist/lib/modules/marketing/services/product-marketing.service.js.map +1 -1
- package/dist/types/index.d.ts +29 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/modules/coupon/routers/coupon.router.d.ts +29 -0
- package/dist/types/modules/coupon/routers/coupon.router.d.ts.map +1 -1
- package/dist/types/modules/coupon/services/coupon.service.d.ts +9 -1
- package/dist/types/modules/coupon/services/coupon.service.d.ts.map +1 -1
- package/dist/types/modules/coupon/services/helper.service.d.ts +2 -0
- package/dist/types/modules/coupon/services/helper.service.d.ts.map +1 -1
- package/dist/types/modules/coupon/services/patterns/repository/CouponRepository.d.ts.map +1 -1
- package/dist/types/modules/coupon/validations/coupon.validation.d.ts +19 -0
- package/dist/types/modules/coupon/validations/coupon.validation.d.ts.map +1 -1
- package/dist/types/modules/deal-setting/services/deal-setting.service.d.ts +1 -1
- package/dist/types/modules/deal-setting/services/deal-setting.service.d.ts.map +1 -1
- package/dist/types/modules/marketing/services/marketing.service.d.ts.map +1 -1
- package/package.json +2 -2
|
@@ -67,6 +67,7 @@ let CouponService = class CouponService {
|
|
|
67
67
|
referralRewardModel;
|
|
68
68
|
punchHistoryService;
|
|
69
69
|
_coreUserModel = null;
|
|
70
|
+
couponHelper;
|
|
70
71
|
constructor() {
|
|
71
72
|
this.model = models_1.CouponModel;
|
|
72
73
|
this.baseCouponModel = models_2.BaseCouponModel;
|
|
@@ -75,6 +76,7 @@ let CouponService = class CouponService {
|
|
|
75
76
|
this.shopModel = models_1.ShopModel;
|
|
76
77
|
this.referralRewardModel = models_1.ReferralRewardCouponModel;
|
|
77
78
|
this.punchHistoryService = services_1.punchMarketingHistoryService;
|
|
79
|
+
this.couponHelper = helper_service_1.couponHelperService;
|
|
78
80
|
}
|
|
79
81
|
get coreUserModel() {
|
|
80
82
|
if (!this._coreUserModel) {
|
|
@@ -84,6 +86,11 @@ let CouponService = class CouponService {
|
|
|
84
86
|
}
|
|
85
87
|
async create(data) {
|
|
86
88
|
let coupon;
|
|
89
|
+
if (data.couponType != enum_1.CouponType.REFERRAL_CODE &&
|
|
90
|
+
data?.duration &&
|
|
91
|
+
!this.couponHelper.isDurationValid((0, dayjs_1.dayjs)(data?.duration?.start), (0, dayjs_1.dayjs)(data?.duration?.end))) {
|
|
92
|
+
(0, error_common_1.conflictError)(`Start date/time cannot be in the past `);
|
|
93
|
+
}
|
|
87
94
|
const checkCoupon = await this.model.findOne({
|
|
88
95
|
code: data.code,
|
|
89
96
|
deletedAt: null,
|
|
@@ -262,18 +269,18 @@ let CouponService = class CouponService {
|
|
|
262
269
|
}
|
|
263
270
|
async update(id, data) {
|
|
264
271
|
let coupon;
|
|
265
|
-
const [oldCoupon,
|
|
272
|
+
const [oldCoupon, checkCouponCode, usersWithOldCoupon] = await Promise.all([
|
|
266
273
|
this.baseCouponModel.findById(id),
|
|
267
|
-
this.orderModel
|
|
268
|
-
.find({
|
|
269
|
-
'finance.coupon.coupon': id,
|
|
270
|
-
})
|
|
271
|
-
.select(['user', 'finance']),
|
|
272
274
|
this.model.findOne({
|
|
273
275
|
code: data.code,
|
|
274
276
|
_id: { $ne: id },
|
|
275
277
|
updatedVersion: { $exists: false },
|
|
276
278
|
}),
|
|
279
|
+
this.userModel
|
|
280
|
+
.find({
|
|
281
|
+
coupons: new typegoose_1.mongoose.Types.ObjectId(id),
|
|
282
|
+
})
|
|
283
|
+
.select(['_id', 'coupons']),
|
|
277
284
|
]);
|
|
278
285
|
if (!oldCoupon) {
|
|
279
286
|
throw new server_1.TRPCError({
|
|
@@ -281,20 +288,35 @@ let CouponService = class CouponService {
|
|
|
281
288
|
message: `Coupon not found`,
|
|
282
289
|
});
|
|
283
290
|
}
|
|
291
|
+
if (data.couponType != enum_1.CouponType.REFERRAL_CODE &&
|
|
292
|
+
oldCoupon?.duration &&
|
|
293
|
+
(0, dayjs_1.dayjs)(oldCoupon?.duration?.start) > (0, dayjs_1.dayjs)(data?.duration.start)) {
|
|
294
|
+
throw new server_1.TRPCError({
|
|
295
|
+
code: 'BAD_REQUEST',
|
|
296
|
+
message: `Don't allow updating coupon to have earlier start date/time than the original coupon`,
|
|
297
|
+
});
|
|
298
|
+
}
|
|
299
|
+
if (data.couponType != enum_1.CouponType.REFERRAL_CODE &&
|
|
300
|
+
data?.duration &&
|
|
301
|
+
(0, dayjs_1.dayjs)(data?.duration?.start) > (0, dayjs_1.dayjs)(data?.duration.end)) {
|
|
302
|
+
throw new server_1.TRPCError({
|
|
303
|
+
code: 'BAD_REQUEST',
|
|
304
|
+
message: `End date/time must be after start date/time`,
|
|
305
|
+
});
|
|
306
|
+
}
|
|
284
307
|
if (checkCouponCode) {
|
|
285
308
|
throw new server_1.TRPCError({
|
|
286
309
|
code: 'CONFLICT',
|
|
287
310
|
message: `Coupon code already exists`,
|
|
288
311
|
});
|
|
289
312
|
}
|
|
290
|
-
const oldCouponUsers = oldOrders.map(order => order.user);
|
|
291
313
|
switch (data.couponType) {
|
|
292
314
|
case enum_1.CouponType.GLOBAL: {
|
|
293
315
|
coupon = await _1.globalCouponService.create(data);
|
|
294
316
|
if (coupon) {
|
|
295
317
|
const globalCoupon = coupon;
|
|
296
318
|
if (!globalCoupon.forNewUserOnly) {
|
|
297
|
-
await this.exchangeCouponForMultipleUser({ _id: { $
|
|
319
|
+
await this.exchangeCouponForMultipleUser({ _id: { $in: usersWithOldCoupon?.map(u => u._id) } }, oldCoupon._id, coupon._id);
|
|
298
320
|
}
|
|
299
321
|
}
|
|
300
322
|
break;
|
|
@@ -304,7 +326,7 @@ let CouponService = class CouponService {
|
|
|
304
326
|
if (coupon) {
|
|
305
327
|
const shopsCategoriesCoupon = coupon;
|
|
306
328
|
if (!shopsCategoriesCoupon.forNewUserOnly) {
|
|
307
|
-
await this.exchangeCouponForMultipleUser({ _id: { $
|
|
329
|
+
await this.exchangeCouponForMultipleUser({ _id: { $in: usersWithOldCoupon?.map(u => u._id) } }, oldCoupon._id, shopsCategoriesCoupon._id);
|
|
308
330
|
}
|
|
309
331
|
}
|
|
310
332
|
break;
|
|
@@ -314,7 +336,7 @@ let CouponService = class CouponService {
|
|
|
314
336
|
if (coupon) {
|
|
315
337
|
const individualStoreCoupon = coupon;
|
|
316
338
|
if (!individualStoreCoupon.forNewUserOnly) {
|
|
317
|
-
await this.exchangeCouponForMultipleUser({ _id: { $
|
|
339
|
+
await this.exchangeCouponForMultipleUser({ _id: { $in: usersWithOldCoupon?.map(u => u._id) } }, oldCoupon._id, individualStoreCoupon._id);
|
|
318
340
|
}
|
|
319
341
|
}
|
|
320
342
|
break;
|
|
@@ -323,13 +345,19 @@ let CouponService = class CouponService {
|
|
|
323
345
|
coupon = await _1.individualUserCouponService.create(data);
|
|
324
346
|
if (coupon) {
|
|
325
347
|
const individualUserCoupon = coupon;
|
|
326
|
-
await this.removeCouponFromMultipleUser({ _id: { $
|
|
348
|
+
await this.removeCouponFromMultipleUser({ _id: { $in: usersWithOldCoupon?.map(u => u._id) } }, oldCoupon._id);
|
|
327
349
|
await this.assignCouponToMultipleUser({ _id: { $in: individualUserCoupon.users } }, individualUserCoupon._id);
|
|
328
350
|
}
|
|
329
351
|
break;
|
|
330
352
|
}
|
|
331
353
|
case enum_1.CouponType.CUSTOM_COUPON: {
|
|
332
354
|
coupon = await _1.customCouponService.create(data);
|
|
355
|
+
if (coupon) {
|
|
356
|
+
const customCoupon = coupon;
|
|
357
|
+
if (!customCoupon.forNewUserOnly) {
|
|
358
|
+
await this.exchangeCouponForMultipleUser({ _id: { $in: usersWithOldCoupon?.map(u => u._id) } }, oldCoupon._id, coupon._id);
|
|
359
|
+
}
|
|
360
|
+
}
|
|
333
361
|
break;
|
|
334
362
|
}
|
|
335
363
|
default: {
|
|
@@ -424,7 +452,7 @@ let CouponService = class CouponService {
|
|
|
424
452
|
if (shop && user) {
|
|
425
453
|
const punch = await this.punchHistoryService.getPunchCoupon(user, shop);
|
|
426
454
|
if (punch) {
|
|
427
|
-
coupons.available.
|
|
455
|
+
coupons.available.push(punch);
|
|
428
456
|
}
|
|
429
457
|
}
|
|
430
458
|
return couponRepository.addLabelsToAllCoupons(coupons);
|
|
@@ -456,7 +484,7 @@ let CouponService = class CouponService {
|
|
|
456
484
|
return await _1.referralCodeCouponService.validateCoupon(data, coupon);
|
|
457
485
|
}
|
|
458
486
|
const baseCoupon = coupon;
|
|
459
|
-
const { isValid, invalidMessage } = await this.validateBaseCoupon(baseCoupon, user._id, data.amountBeforeCoupon);
|
|
487
|
+
const { isValid, invalidMessage } = await this.validateBaseCoupon(baseCoupon, user._id, data.amountBeforeCoupon, Boolean(data.scheduledAt) ? (0, dayjs_1.dayjs)(data.scheduledAt) : undefined);
|
|
460
488
|
if (!isValid) {
|
|
461
489
|
return {
|
|
462
490
|
isValid,
|
|
@@ -486,7 +514,7 @@ let CouponService = class CouponService {
|
|
|
486
514
|
}
|
|
487
515
|
return false;
|
|
488
516
|
}
|
|
489
|
-
async validateBaseCoupon(coupon, user, orderAmount) {
|
|
517
|
+
async validateBaseCoupon(coupon, user, orderAmount, scheduledAt = undefined) {
|
|
490
518
|
const invalidConditions = [
|
|
491
519
|
this.isCouponExpired(coupon),
|
|
492
520
|
coupon.duration.start > (0, dayjs_1.dayjs)().toDate(),
|
|
@@ -495,6 +523,7 @@ let CouponService = class CouponService {
|
|
|
495
523
|
coupon.isOrderLimitPerUserEnabled &&
|
|
496
524
|
coupon.orderLimitPerUser &&
|
|
497
525
|
(await this.getCouponOrdersForUser(user, coupon.code)) >= coupon.orderLimitPerUser,
|
|
526
|
+
scheduledAt && Boolean(coupon.duration.end) && (0, dayjs_1.dayjs)(coupon.duration.end).isBefore(scheduledAt),
|
|
498
527
|
];
|
|
499
528
|
const invalidMessages = [
|
|
500
529
|
'This coupon is expired',
|
|
@@ -502,6 +531,7 @@ let CouponService = class CouponService {
|
|
|
502
531
|
'The minimum order amount for this coupon is not met',
|
|
503
532
|
'This coupon is for new users only',
|
|
504
533
|
'You have reached the order limit for this coupon',
|
|
534
|
+
'This coupon is not valid for this scheduled orders',
|
|
505
535
|
];
|
|
506
536
|
const isValid = invalidConditions.every(value => Boolean(value) == false);
|
|
507
537
|
const invalidMessage = invalidMessages.filter((_, index) => invalidConditions[index])?.[0];
|
|
@@ -537,8 +567,11 @@ let CouponService = class CouponService {
|
|
|
537
567
|
return;
|
|
538
568
|
}
|
|
539
569
|
const typedCoupon = coupon;
|
|
570
|
+
await this.processCouponForExpiry(typedCoupon);
|
|
571
|
+
}
|
|
572
|
+
async processCouponForExpiry(coupon) {
|
|
540
573
|
let expirationReason = null;
|
|
541
|
-
if (
|
|
574
|
+
if (coupon.isTotalOrderLimitEnabled && coupon.totalOrderLimit) {
|
|
542
575
|
const pipeline = [
|
|
543
576
|
{
|
|
544
577
|
$match: {
|
|
@@ -559,7 +592,7 @@ let CouponService = class CouponService {
|
|
|
559
592
|
},
|
|
560
593
|
{
|
|
561
594
|
$match: {
|
|
562
|
-
'cart.couponCode':
|
|
595
|
+
'cart.couponCode': coupon.code,
|
|
563
596
|
},
|
|
564
597
|
},
|
|
565
598
|
{
|
|
@@ -568,17 +601,17 @@ let CouponService = class CouponService {
|
|
|
568
601
|
];
|
|
569
602
|
const result = await this.orderModel.aggregate(pipeline);
|
|
570
603
|
const orderCount = result[0]?.orderCount ?? 0;
|
|
571
|
-
if (orderCount
|
|
604
|
+
if (orderCount >= coupon.totalOrderLimit) {
|
|
572
605
|
expirationReason = enum_1.CouponExpirationReason.TOTAL_ORDER_LIMIT;
|
|
573
606
|
}
|
|
574
607
|
}
|
|
575
|
-
if (
|
|
576
|
-
const { totalCouponDiscount, totalSecondaryCouponDiscount } = await this.getCouponDiscountTotals(
|
|
577
|
-
if (totalCouponDiscount >=
|
|
608
|
+
if (coupon.isSpendLimitEnabled && coupon.spendLimit) {
|
|
609
|
+
const { totalCouponDiscount, totalSecondaryCouponDiscount } = await this.getCouponDiscountTotals(coupon.code);
|
|
610
|
+
if (totalCouponDiscount >= coupon.spendLimit) {
|
|
578
611
|
expirationReason = enum_1.CouponExpirationReason.SPEND_LIMIT;
|
|
579
612
|
}
|
|
580
613
|
}
|
|
581
|
-
await this.baseCouponModel.findByIdAndUpdate(
|
|
614
|
+
await this.baseCouponModel.findByIdAndUpdate(coupon._id, {
|
|
582
615
|
$set: {
|
|
583
616
|
expirationReason,
|
|
584
617
|
},
|
|
@@ -587,6 +620,20 @@ let CouponService = class CouponService {
|
|
|
587
620
|
runValidators: true,
|
|
588
621
|
});
|
|
589
622
|
}
|
|
623
|
+
async syncCouponExpiry() {
|
|
624
|
+
const coupons = await this.baseCouponModel.find({
|
|
625
|
+
couponType: { $ne: enum_1.CouponType.REFERRAL_CODE },
|
|
626
|
+
expirationReason: null,
|
|
627
|
+
});
|
|
628
|
+
console.log(`Syncing expiry for ${coupons.length} coupons`);
|
|
629
|
+
console.time('syncCouponExpiry');
|
|
630
|
+
for (const coupon of coupons) {
|
|
631
|
+
console.time(`Processing coupon ${coupon.code}`);
|
|
632
|
+
await this.processCouponForExpiry(coupon);
|
|
633
|
+
console.timeEnd(`Processing coupon ${coupon.code}`);
|
|
634
|
+
}
|
|
635
|
+
console.timeEnd('syncCouponExpiry');
|
|
636
|
+
}
|
|
590
637
|
async findCouponByCode(code) {
|
|
591
638
|
const coupon = await this.model.findOne({ code: code, updatedVersion: { $exists: false } });
|
|
592
639
|
if (!coupon) {
|
|
@@ -627,14 +674,14 @@ let CouponService = class CouponService {
|
|
|
627
674
|
totalCouponDiscount: {
|
|
628
675
|
$sum: {
|
|
629
676
|
$toDouble: {
|
|
630
|
-
$ifNull: ['$
|
|
677
|
+
$ifNull: ['$adjustedFinance.pricing.couponDiscount', 0],
|
|
631
678
|
},
|
|
632
679
|
},
|
|
633
680
|
},
|
|
634
681
|
totalSecondaryCouponDiscount: {
|
|
635
682
|
$sum: {
|
|
636
683
|
$toDouble: {
|
|
637
|
-
$ifNull: ['$
|
|
684
|
+
$ifNull: ['$adjustedFinance.pricing.secondaryCouponDiscount', 0],
|
|
638
685
|
},
|
|
639
686
|
},
|
|
640
687
|
},
|
|
@@ -891,9 +938,9 @@ let CouponService = class CouponService {
|
|
|
891
938
|
runValidators: true,
|
|
892
939
|
});
|
|
893
940
|
}
|
|
894
|
-
async
|
|
941
|
+
async getActiveNewUserCoupon() {
|
|
895
942
|
const currentDate = (0, dayjs_1.dayjs)().toDate();
|
|
896
|
-
const
|
|
943
|
+
const activeForNewUserCoupon = await this.baseCouponModel.findOne({
|
|
897
944
|
couponType: enum_1.CouponType.GLOBAL,
|
|
898
945
|
forNewUserOnly: true,
|
|
899
946
|
deletedAt: null,
|
|
@@ -908,11 +955,48 @@ let CouponService = class CouponService {
|
|
|
908
955
|
'duration.end': { $gte: currentDate },
|
|
909
956
|
updatedVersion: { $exists: false },
|
|
910
957
|
});
|
|
958
|
+
return activeForNewUserCoupon;
|
|
959
|
+
}
|
|
960
|
+
async checkExistingNewUserCoupon() {
|
|
961
|
+
const alreadyActiveForNewUserCoupon = await this.getActiveNewUserCoupon();
|
|
911
962
|
if (alreadyActiveForNewUserCoupon) {
|
|
912
963
|
return { exists: true };
|
|
913
964
|
}
|
|
914
965
|
return { exists: false };
|
|
915
966
|
}
|
|
967
|
+
async getAllOrders(userIds) {
|
|
968
|
+
return await this.orderModel.countDocuments({
|
|
969
|
+
user: { $in: userIds },
|
|
970
|
+
status: { $ne: enum_1.RegularOrderStatus.CANCELLED },
|
|
971
|
+
orderType: enum_1.OrderType.REGULAR,
|
|
972
|
+
});
|
|
973
|
+
}
|
|
974
|
+
async handleCouponGiftBox(deviceId, userId) {
|
|
975
|
+
const allUsers = await this.userModel.find({ deviceId }).select('_id');
|
|
976
|
+
const userIds = allUsers.map(user => user._id);
|
|
977
|
+
if (userId) {
|
|
978
|
+
userIds.push(new typegoose_1.mongoose.Types.ObjectId(userId));
|
|
979
|
+
}
|
|
980
|
+
const totalOrders = await this.getAllOrders(userIds);
|
|
981
|
+
const activeNewUserCoupon = await this.getActiveNewUserCoupon();
|
|
982
|
+
if (!activeNewUserCoupon) {
|
|
983
|
+
(0, error_common_1.notFoundError)('No active new user coupon found');
|
|
984
|
+
}
|
|
985
|
+
if (activeNewUserCoupon.isOrderLimitPerUserEnabled &&
|
|
986
|
+
totalOrders < (activeNewUserCoupon.orderLimitPerUser || 0)) {
|
|
987
|
+
return [activeNewUserCoupon];
|
|
988
|
+
}
|
|
989
|
+
(0, error_common_1.notFoundError)('No gift box coupon available');
|
|
990
|
+
return [];
|
|
991
|
+
}
|
|
992
|
+
async updateCouponGiftBoxShown(userId, data) {
|
|
993
|
+
const result = await this.userModel.updateOne({ _id: userId }, {
|
|
994
|
+
$set: {
|
|
995
|
+
isNewUserCouponShowed: data.isNewUserGiftBoxShown,
|
|
996
|
+
},
|
|
997
|
+
});
|
|
998
|
+
return result.modifiedCount;
|
|
999
|
+
}
|
|
916
1000
|
};
|
|
917
1001
|
exports.CouponService = CouponService;
|
|
918
1002
|
exports.CouponService = CouponService = __decorate([
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"coupon.service.js","sourceRoot":"/","sources":["modules/coupon/services/coupon.service.ts"],"names":[],"mappings":"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","sourcesContent":["import Container, { Service } from 'typedi';\nimport { TRPCError } from '@trpc/server';\nimport { DocumentType, mongoose, queryMethod, ReturnModelType } from '@typegoose/typegoose';\nimport {\n\tCart,\n\tCouponModel,\n\tCustomCoupon,\n\tgetCoreUserModel,\n\tGlobalCoupon,\n\tIndividualStoreCoupon,\n\tIndividualUserCoupon,\n\tCoupon as Model,\n\tReferralRewardCoupon,\n\tReferralRewardCouponModel,\n\tRegularOrder,\n\tRegularOrderModel,\n\tShopModel,\n\tShop,\n\tShopsCategoriesCoupon,\n\tUser,\n\tUserModel,\n\tReferralCodeCoupon,\n} from '@lyxa.ai/core/dist/libraries/mongo/models';\nimport {\n\tAllCouponsValidationDTO,\n\tCouponValidationOutputDTO,\n\tValidateCouponDTO,\n\tAllCouponsDTO,\n\tCheckExistingNewUserCouponOutputDTO,\n} from '@modules/coupon/validations';\nimport { SoftDeleteModel } from '@lyxa.ai/core/dist/libraries/mongo/plugins/soft-delete-plugin';\nimport {\n\tFilterDTO,\n\tPaginatedResponse,\n\tDeleteDTO,\n\tShareableLinkDTO,\n} from '@lyxa.ai/core/dist/utilities/validation';\nimport {\n\tcreateRawDocumentPaginatorObject,\n\tpaginateAggregation,\n\tPaginatorOptions,\n} from '@lyxa.ai/core/dist/utilities/pagination';\nimport { ModelType } from '@typegoose/typegoose/lib/types';\nimport {\n\tcustomCouponService,\n\tglobalCouponService,\n\tindividualStoreCouponService,\n\tindividualUserCouponService,\n\treferralCodeCouponService,\n\treferralRewardCouponService,\n} from '.';\nimport {\n\tCouponExpirationReason,\n\tCouponType,\n\tItemType,\n\tOrderType,\n\tRegularOrderStatus,\n\tStatus,\n} from '@lyxa.ai/core/dist/utilities/enum';\nimport { BaseCoupon, BaseCouponModel } from '@lyxa.ai/core/dist/libraries/mongo/models';\nimport {\n\tPunchMarketingHistoryService,\n\tpunchMarketingHistoryService,\n} from '@modules/punch-marketing-history/services';\nimport { getLibraries } from '@lyxa.ai/core';\nimport { NotificationMicroserviceRouter } from '@lyxa.ai/notification';\nimport { CouponRepository } from './patterns/repository/CouponRepository';\nimport {\n\tbadRequestError,\n\tconflictError,\n\tinternalServerError,\n\tnotFoundError,\n\tnotImplementedError,\n} from '@lyxa.ai/core/dist/utilities/error-common';\nimport { shopsCategoriesCouponService } from './shops-categories-coupon.service';\nimport { couponHelperService } from './helper.service';\nimport { dayjs } from '@lyxa.ai/core/dist/utilities/dayjs';\n\n@Service()\nexport class CouponService {\n\tprivate model: typeof CouponModel & SoftDeleteModel<Model>;\n\tprivate baseCouponModel: typeof BaseCouponModel & SoftDeleteModel<BaseCoupon>;\n\tprivate userModel: typeof UserModel & SoftDeleteModel<User>;\n\tprivate orderModel: typeof RegularOrderModel & SoftDeleteModel<RegularOrder>;\n\tprivate shopModel: typeof ShopModel & SoftDeleteModel<Shop>;\n\tprivate referralRewardModel: typeof ReferralRewardCouponModel & SoftDeleteModel<ReferralRewardCoupon>;\n\tprivate punchHistoryService: PunchMarketingHistoryService;\n\tprivate _coreUserModel: ReturnType<typeof getCoreUserModel> | null = null;\n\n\tconstructor() {\n\t\tthis.model = CouponModel as typeof CouponModel & SoftDeleteModel<Model>;\n\t\tthis.baseCouponModel = BaseCouponModel as typeof BaseCouponModel & SoftDeleteModel<BaseCoupon>;\n\t\tthis.userModel = UserModel as typeof UserModel & SoftDeleteModel<User>;\n\t\tthis.orderModel = RegularOrderModel as typeof RegularOrderModel & SoftDeleteModel<RegularOrder>;\n\t\tthis.shopModel = ShopModel as typeof ShopModel & SoftDeleteModel<Shop>;\n\t\tthis.referralRewardModel = ReferralRewardCouponModel as typeof ReferralRewardCouponModel &\n\t\t\tSoftDeleteModel<ReferralRewardCoupon>;\n\t\tthis.punchHistoryService = punchMarketingHistoryService;\n\t}\n\n\tprivate get coreUserModel() {\n\t\tif (!this._coreUserModel) {\n\t\t\tthis._coreUserModel = getCoreUserModel();\n\t\t}\n\t\treturn this._coreUserModel;\n\t}\n\n\t/**\n\t * Create a new record\n\t * @param data Data for the new record\n\t */\n\tpublic async create(data: AllCouponsValidationDTO): Promise<DocumentType<Model>> {\n\t\tlet coupon: DocumentType<Model>;\n\n\t\tconst checkCoupon = await this.model.findOne({\n\t\t\tcode: data.code,\n\t\t\tdeletedAt: null,\n\t\t});\n\n\t\tif (checkCoupon) conflictError('Coupon code already exists');\n\n\t\tswitch (data.couponType) {\n\t\t\tcase CouponType.GLOBAL: {\n\t\t\t\tcoupon = await globalCouponService.create(data);\n\t\t\t\tif (coupon) {\n\t\t\t\t\tconst globalCoupon = coupon as DocumentType<GlobalCoupon>;\n\t\t\t\t\tif (!globalCoupon.forNewUserOnly) {\n\t\t\t\t\t\tawait this.assignCouponToMultipleUser({}, coupon._id);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tawait this.assignCouponToNewUsers(coupon._id);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase CouponType.REFERRAL_CODE: {\n\t\t\t\tcoupon = await referralCodeCouponService.create(data);\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase CouponType.REFERRAL_REWARD: {\n\t\t\t\tcoupon = await referralRewardCouponService.create(data);\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase CouponType.SHOPS_CATEGORIES: {\n\t\t\t\tcoupon = await shopsCategoriesCouponService.create(data);\n\t\t\t\tif (coupon) {\n\t\t\t\t\tconst shopsCategoriesCoupon = coupon as DocumentType<ShopsCategoriesCoupon>;\n\t\t\t\t\tif (!shopsCategoriesCoupon.forNewUserOnly) {\n\t\t\t\t\t\tawait this.assignCouponToMultipleUser({}, coupon._id);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tawait this.assignCouponToNewUsers(coupon._id);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase CouponType.INDIVIDUAL_STORE: {\n\t\t\t\tcoupon = await individualStoreCouponService.create(data);\n\t\t\t\tif (coupon) {\n\t\t\t\t\tconst individualStoreCoupon = coupon as DocumentType<IndividualStoreCoupon>;\n\t\t\t\t\tif (!individualStoreCoupon.forNewUserOnly) {\n\t\t\t\t\t\tawait this.assignCouponToMultipleUser({}, coupon._id);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tawait this.assignCouponToNewUsers(coupon._id);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase CouponType.INDIVIDUAL_USER: {\n\t\t\t\tcoupon = await individualUserCouponService.create(data);\n\t\t\t\tif (coupon) {\n\t\t\t\t\tconst individualUserCoupon = coupon as DocumentType<IndividualUserCoupon>;\n\t\t\t\t\tconst users = individualUserCoupon.users;\n\t\t\t\t\tawait this.assignCouponToMultipleUser({ _id: { $in: users } }, coupon._id);\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase CouponType.CUSTOM_COUPON: {\n\t\t\t\tcoupon = await customCouponService.create(data);\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tdefault: {\n\t\t\t\tbadRequestError('Coupon type is not valid');\n\t\t\t}\n\t\t}\n\n\t\tif (!coupon) internalServerError('Could not create coupon');\n\n\t\t// Send Notification\n\t\tconst dispatcher = getLibraries().getMicroServiceDispatcher();\n\t\tconst notificationRouter =\n\t\t\tawait dispatcher.getMicroService<NotificationMicroserviceRouter>('notification');\n\n\t\tawait notificationRouter.notificationRouter.sendPushNotificationForCoupon.mutate(coupon._id);\n\n\t\treturn coupon;\n\t}\n\n\t/**\n\t * Get record by ID\n\t * @param id ID of the record\n\t */\n\tpublic async findById(id: string | mongoose.Types.ObjectId): Promise<DocumentType<Model>> {\n\t\tconst result = await this.model\n\t\t\t.findOne({\n\t\t\t\t_id: id,\n\t\t\t\tdeletedAt: null,\n\t\t\t})\n\t\t\t.populate([\n\t\t\t\t{\n\t\t\t\t\tpath: 'previousVersions',\n\t\t\t\t},\n\t\t\t]);\n\t\tif (!result) {\n\t\t\tthrow new TRPCError({\n\t\t\t\tcode: 'NOT_FOUND',\n\t\t\t\tmessage: 'Record not found',\n\t\t\t});\n\t\t}\n\t\treturn result;\n\t}\n\n\t/**\n\t * Get records\n\t * @param query Query to find records\n\t */\n\tpublic async find(data?: Partial<FilterDTO>): Promise<PaginatedResponse<DocumentType<ModelType<Model>>>> {\n\t\ttry {\n\t\t\tconst populate = [\n\t\t\t\t...data?.populate,\n\t\t\t\t{\n\t\t\t\t\tpath: 'users',\n\t\t\t\t\tpopulate: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tpath: 'coreUser',\n\t\t\t\t\t\t\tmodel: this.coreUserModel,\n\t\t\t\t\t\t\tselect: 'name profilePhoto -_id',\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t\tselect: 'coreUser phoneNumber',\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tpath: 'influencer',\n\t\t\t\t\tpopulate: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tpath: 'coreUser',\n\t\t\t\t\t\t\tmodel: this.coreUserModel,\n\t\t\t\t\t\t\tselect: 'name profilePhoto -_id',\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t\tselect: 'coreUser phoneNumber',\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tpath: 'referralUser',\n\t\t\t\t\tpopulate: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tpath: 'coreUser',\n\t\t\t\t\t\t\tmodel: this.coreUserModel,\n\t\t\t\t\t\t\tselect: 'name profilePhoto -_id',\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t\tselect: 'coreUser phoneNumber',\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tpath: 'user',\n\t\t\t\t\tpopulate: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tpath: 'coreUser',\n\t\t\t\t\t\t\tmodel: this.coreUserModel,\n\t\t\t\t\t\t\tselect: 'name profilePhoto -_id',\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t\tselect: 'coreUser phoneNumber',\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tpath: 'referralCodeUsedBy',\n\t\t\t\t\tpopulate: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tpath: 'coreUser',\n\t\t\t\t\t\t\tmodel: this.coreUserModel,\n\t\t\t\t\t\t\tselect: 'name profilePhoto -_id',\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t\tselect: 'coreUser phoneNumber',\n\t\t\t\t},\n\t\t\t];\n\n\t\t\tconst paginate = createRawDocumentPaginatorObject(this.model as ReturnModelType<typeof this.model>);\n\t\t\tconst options: PaginatorOptions<typeof Model> = {\n\t\t\t\tpage: data?.page,\n\t\t\t\tsize: data?.size,\n\t\t\t\tsort: data?.sort,\n\t\t\t\tquery: { ...data?.query, updatedVersion: { $exists: false } },\n\t\t\t\tselect: data?.select,\n\t\t\t\tpopulate: populate,\n\t\t\t};\n\t\t\tconst paginatedResult = await paginate(options);\n\t\t\treturn paginatedResult;\n\t\t} catch (err) {\n\t\t\tthrow new TRPCError({\n\t\t\t\tcode: 'INTERNAL_SERVER_ERROR',\n\t\t\t\tmessage: `err: ${err}`,\n\t\t\t});\n\t\t}\n\t}\n\n\t/**\n\t * Update record\n\t * @param id ID of the old coupon\n\t * @param data Data of the updated coupon\n\t */\n\tpublic async update(id: string, data: AllCouponsValidationDTO): Promise<DocumentType<Model>> {\n\t\tlet coupon: DocumentType<BaseCoupon> | null;\n\n\t\tconst [oldCoupon, oldOrders, checkCouponCode] = await Promise.all([\n\t\t\tthis.baseCouponModel.findById(id),\n\t\t\tthis.orderModel\n\t\t\t\t.find({\n\t\t\t\t\t'finance.coupon.coupon': id,\n\t\t\t\t})\n\t\t\t\t.select(['user', 'finance']),\n\t\t\tthis.model.findOne({\n\t\t\t\tcode: data.code,\n\t\t\t\t_id: { $ne: id },\n\t\t\t\tupdatedVersion: { $exists: false },\n\t\t\t}),\n\t\t]);\n\n\t\tif (!oldCoupon) {\n\t\t\tthrow new TRPCError({\n\t\t\t\tcode: 'NOT_FOUND',\n\t\t\t\tmessage: `Coupon not found`,\n\t\t\t});\n\t\t}\n\n\t\tif (checkCouponCode) {\n\t\t\tthrow new TRPCError({\n\t\t\t\tcode: 'CONFLICT',\n\t\t\t\tmessage: `Coupon code already exists`,\n\t\t\t});\n\t\t}\n\n\t\tconst oldCouponUsers = oldOrders.map(order => order.user);\n\n\t\tswitch (data.couponType) {\n\t\t\tcase CouponType.GLOBAL: {\n\t\t\t\tcoupon = await globalCouponService.create(data);\n\t\t\t\tif (coupon) {\n\t\t\t\t\tconst globalCoupon = coupon as DocumentType<GlobalCoupon>;\n\t\t\t\t\tif (!globalCoupon.forNewUserOnly) {\n\t\t\t\t\t\tawait this.exchangeCouponForMultipleUser(\n\t\t\t\t\t\t\t{ _id: { $nin: oldCouponUsers } },\n\t\t\t\t\t\t\toldCoupon._id,\n\t\t\t\t\t\t\tcoupon._id\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase CouponType.SHOPS_CATEGORIES: {\n\t\t\t\tcoupon = await shopsCategoriesCouponService.create(data);\n\t\t\t\tif (coupon) {\n\t\t\t\t\tconst shopsCategoriesCoupon = coupon as DocumentType<ShopsCategoriesCoupon>;\n\t\t\t\t\tif (!shopsCategoriesCoupon.forNewUserOnly) {\n\t\t\t\t\t\tawait this.exchangeCouponForMultipleUser(\n\t\t\t\t\t\t\t{ _id: { $nin: oldCouponUsers } },\n\t\t\t\t\t\t\toldCoupon._id,\n\t\t\t\t\t\t\tshopsCategoriesCoupon._id\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase CouponType.INDIVIDUAL_STORE: {\n\t\t\t\tcoupon = await individualStoreCouponService.create(data);\n\t\t\t\tif (coupon) {\n\t\t\t\t\tconst individualStoreCoupon = coupon as DocumentType<IndividualStoreCoupon>;\n\t\t\t\t\tif (!individualStoreCoupon.forNewUserOnly) {\n\t\t\t\t\t\tawait this.exchangeCouponForMultipleUser(\n\t\t\t\t\t\t\t{ _id: { $nin: oldCouponUsers } },\n\t\t\t\t\t\t\toldCoupon._id,\n\t\t\t\t\t\t\tindividualStoreCoupon._id\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase CouponType.INDIVIDUAL_USER: {\n\t\t\t\tcoupon = await individualUserCouponService.create(data);\n\t\t\t\tif (coupon) {\n\t\t\t\t\tconst individualUserCoupon = coupon as DocumentType<IndividualUserCoupon>;\n\t\t\t\t\tawait this.removeCouponFromMultipleUser({ _id: { $nin: oldCouponUsers } }, oldCoupon._id);\n\t\t\t\t\tawait this.assignCouponToMultipleUser(\n\t\t\t\t\t\t{ _id: { $in: individualUserCoupon.users } },\n\t\t\t\t\t\tindividualUserCoupon._id\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase CouponType.CUSTOM_COUPON: {\n\t\t\t\tcoupon = await customCouponService.create(data);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tdefault: {\n\t\t\t\tthrow new TRPCError({\n\t\t\t\t\tcode: 'BAD_REQUEST',\n\t\t\t\t\tmessage: `Invalid coupon type`,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\tif (!coupon) {\n\t\t\tthrow new TRPCError({\n\t\t\t\tcode: 'BAD_REQUEST',\n\t\t\t\tmessage: `Could create updated coupon`,\n\t\t\t});\n\t\t}\n\n\t\t// add previous version to new coupon\n\t\tconst previousVersions = oldCoupon?.previousVersions || [];\n\t\tpreviousVersions.push(oldCoupon._id);\n\n\t\tconst updatedCoupon = await this.baseCouponModel.findByIdAndUpdate(\n\t\t\tcoupon._id,\n\t\t\t{\n\t\t\t\t$set: {\n\t\t\t\t\tpreviousVersions,\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tnew: true,\n\t\t\t\trunValidators: true,\n\t\t\t}\n\t\t);\n\n\t\tif (!updatedCoupon) {\n\t\t\tthrow new TRPCError({\n\t\t\t\tcode: 'INTERNAL_SERVER_ERROR',\n\t\t\t\tmessage: `Could not set previous versions of coupon`,\n\t\t\t});\n\t\t}\n\t\t// update old coupon\n\t\tconst updatedOldCoupon = await this.baseCouponModel.findByIdAndUpdate(\n\t\t\toldCoupon._id,\n\t\t\t{\n\t\t\t\t$set: {\n\t\t\t\t\tupdatedVersion: coupon._id,\n\t\t\t\t\t'duration.end': coupon.duration.end,\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tnew: true,\n\t\t\t\trunValidators: true,\n\t\t\t}\n\t\t);\n\n\t\treturn updatedCoupon;\n\t}\n\n\tpublic async updateStatus(id: string, status: Status): Promise<DocumentType<Model>> {\n\t\tconst coupon = await this.baseCouponModel.findByIdAndUpdate(\n\t\t\tid,\n\t\t\t{\n\t\t\t\t$set: { status },\n\t\t\t},\n\t\t\t{\n\t\t\t\tnew: true,\n\t\t\t\trunValidators: true,\n\t\t\t}\n\t\t);\n\n\t\tif (!coupon) {\n\t\t\tthrow new TRPCError({\n\t\t\t\tcode: 'NOT_FOUND',\n\t\t\t\tmessage: 'Coupon not found',\n\t\t\t});\n\t\t}\n\n\t\t// also update the status of previous versions of the coupon\n\t\tconst previousVersions = coupon.previousVersions;\n\t\tif (previousVersions && previousVersions.length > 0) {\n\t\t\tawait this.baseCouponModel.updateMany(\n\t\t\t\t{ _id: { $in: previousVersions } },\n\t\t\t\t{\n\t\t\t\t\t$set: { status },\n\t\t\t\t}\n\t\t\t);\n\t\t}\n\n\t\treturn coupon;\n\t}\n\n\t/**\n\t * Delete record\n\t * @param data Data for delete\n\t */\n\tpublic async deleteById(data: DeleteDTO): Promise<string> {\n\t\tconst { _id, softDelete } = data;\n\n\t\tconst coupon = await this.model.findById(_id);\n\n\t\tif (!coupon) {\n\t\t\tnotFoundError('Coupon not found');\n\t\t}\n\n\t\tconst result = await this.model.deleteRecord({ _id, deletedAt: null }, softDelete);\n\t\tif (!result) {\n\t\t\tthrow new TRPCError({\n\t\t\t\tcode: 'NOT_FOUND',\n\t\t\t\tmessage: 'Record not found',\n\t\t\t});\n\t\t}\n\n\t\t// remove coupons from users' coupon lists\n\t\tthis.removeCouponFromMultipleUser({}, _id);\n\n\t\t// also delete previous versions of the coupon\n\t\tconst previousVersions = coupon.previousVersions;\n\t\tif (previousVersions && previousVersions.length > 0) {\n\t\t\tawait this.model.deleteRecord({ _id: { $in: previousVersions }, deletedAt: null }, softDelete);\n\t\t}\n\n\t\treturn 'Record deleted successfully';\n\t}\n\n\t/**\n\t * Get User Coupons\n\t * @param data User and pagination data\n\t */\n\tpublic async getUserCoupons(\n\t\tuser: mongoose.Types.ObjectId | undefined,\n\t\tshop: mongoose.Types.ObjectId | undefined,\n\t\tpage: number = 0,\n\t\tsize: number = 0\n\t): Promise<{\n\t\tavailable: Array<DocumentType<Model>>;\n\t\tused: Array<DocumentType<Model>>;\n\t\texpired: Array<DocumentType<Model>>;\n\t}> {\n\t\tconst couponRepository = new CouponRepository();\n\t\tlet itemType: ItemType | undefined = undefined;\n\t\tif (shop) {\n\t\t\tconst shopDocument = await this.shopModel.findOne({ _id: shop }).select('itemType');\n\t\t\titemType = shopDocument?.itemType;\n\t\t}\n\t\tconst coupons = await couponRepository.getUserCoupons(user, shop, itemType);\n\n\t\tif (shop && user) {\n\t\t\tconst punch = await this.punchHistoryService.getPunchCoupon(user, shop);\n\t\t\tif (punch) {\n\t\t\t\tcoupons.available.unshift(punch);\n\t\t\t}\n\t\t}\n\n\t\treturn couponRepository.addLabelsToAllCoupons(coupons);\n\t}\n\n\tpublic async validateCoupon(data: ValidateCouponDTO): Promise<CouponValidationOutputDTO> {\n\t\tif (data.coupon === 'punch') {\n\t\t\treturn await punchMarketingHistoryService.getPunchDiscount(data);\n\t\t}\n\n\t\tconst user = await this.userModel.findById(data.user);\n\t\tif (!user) notFoundError('User not found');\n\n\t\tlet coupon = await this.model.findOne({\n\t\t\tcode: data.coupon,\n\t\t\t_id: { $in: user.coupons ?? [] },\n\t\t\tstatus: { $in: [Status.ACTIVE, null] },\n\t\t});\n\n\t\tif (!coupon) {\n\t\t\tcoupon = await this.model.findOne({\n\t\t\t\tcode: data.coupon,\n\t\t\t\tstatus: { $in: [Status.ACTIVE, null] },\n\t\t\t\tcouponType: { $in: [CouponType.REFERRAL_CODE, CouponType.CUSTOM_COUPON] },\n\t\t\t\tupdatedVersion: { $exists: false },\n\t\t\t});\n\n\t\t\tif (!coupon) {\n\t\t\t\tnotFoundError('Coupon not found');\n\t\t\t}\n\t\t}\n\n\t\tif (coupon.couponType == CouponType.REFERRAL_CODE) {\n\t\t\treturn await referralCodeCouponService.validateCoupon(data, coupon as DocumentType<ReferralCodeCoupon>);\n\t\t}\n\n\t\tconst baseCoupon = coupon as DocumentType<BaseCoupon>;\n\n\t\tconst { isValid, invalidMessage } = await this.validateBaseCoupon(\n\t\t\tbaseCoupon,\n\t\t\tuser._id,\n\t\t\tdata.amountBeforeCoupon\n\t\t);\n\n\t\tif (!isValid) {\n\t\t\treturn {\n\t\t\t\tisValid,\n\t\t\t\tmessage: invalidMessage,\n\t\t\t};\n\t\t}\n\n\t\tswitch (coupon.couponType) {\n\t\t\tcase CouponType.REFERRAL_REWARD:\n\t\t\t\treturn await referralRewardCouponService.validateCoupon(\n\t\t\t\t\tdata,\n\t\t\t\t\tcoupon as DocumentType<ReferralRewardCoupon>\n\t\t\t\t);\n\t\t\tcase CouponType.GLOBAL:\n\t\t\t\treturn await globalCouponService.validateCoupon(data, coupon as DocumentType<GlobalCoupon>);\n\t\t\tcase CouponType.SHOPS_CATEGORIES:\n\t\t\t\treturn await shopsCategoriesCouponService.validateCoupon(\n\t\t\t\t\tdata,\n\t\t\t\t\tcoupon as DocumentType<ShopsCategoriesCoupon>\n\t\t\t\t);\n\t\t\tcase CouponType.INDIVIDUAL_STORE:\n\t\t\t\treturn await individualStoreCouponService.validateCoupon(\n\t\t\t\t\tdata,\n\t\t\t\t\tcoupon as DocumentType<IndividualStoreCoupon>\n\t\t\t\t);\n\t\t\tcase CouponType.INDIVIDUAL_USER:\n\t\t\t\treturn await individualUserCouponService.validateCoupon(\n\t\t\t\t\tdata,\n\t\t\t\t\tcoupon as DocumentType<IndividualUserCoupon>\n\t\t\t\t);\n\t\t\tcase CouponType.CUSTOM_COUPON:\n\t\t\t\treturn await customCouponService.validateCoupon(data, coupon as DocumentType<CustomCoupon>);\n\t\t\tdefault:\n\t\t\t\tnotImplementedError(`Validation not implemented for ${coupon.couponType} coupons`);\n\t\t}\n\t}\n\n\tprivate isCouponExpired(coupon: DocumentType<BaseCoupon>): Boolean {\n\t\tif (coupon.expirationReason || (coupon?.duration?.end && new Date(coupon?.duration?.end) < new Date())) {\n\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t}\n\n\t/**\n\t *\n\t * @param coupon Base coupon document\n\t * @param user ID of the user trying to user the coupon\n\t * @param orderAmount Order subtotal\n\t * @returns True if coupon is valid\n\t */\n\tprivate async validateBaseCoupon(\n\t\tcoupon: DocumentType<BaseCoupon>,\n\t\tuser: mongoose.Types.ObjectId,\n\t\torderAmount: number\n\t): Promise<{ isValid: boolean; invalidMessage?: string }> {\n\t\tconst invalidConditions = [\n\t\t\tthis.isCouponExpired(coupon), // check coupon expired\n\t\t\tcoupon.duration.start > dayjs().toDate(), // check coupon start\n\t\t\tcoupon.isMinOrderValueEnabled && coupon.minOrderValue && orderAmount < coupon.minOrderValue, // check minimum order value\n\t\t\tcoupon.forNewUserOnly && !(await this.verifyNewUserConditions(coupon, user)), // check if new user\n\t\t\tcoupon.isOrderLimitPerUserEnabled &&\n\t\t\t\tcoupon.orderLimitPerUser &&\n\t\t\t\t(await this.getCouponOrdersForUser(user, coupon.code)) >= coupon.orderLimitPerUser, // check order limit for user\n\t\t];\n\n\t\tconst invalidMessages = [\n\t\t\t'This coupon is expired',\n\t\t\t'This coupon is not available yet',\n\t\t\t'The minimum order amount for this coupon is not met',\n\t\t\t'This coupon is for new users only',\n\t\t\t'You have reached the order limit for this coupon',\n\t\t];\n\n\t\tconst isValid = invalidConditions.every(value => Boolean(value) == false);\n\t\tconst invalidMessage = invalidMessages.filter((_, index) => invalidConditions[index])?.[0];\n\n\t\treturn { isValid, invalidMessage };\n\t}\n\n\t// Returns true if new user conditions are met. False otherwise\n\tprivate async verifyNewUserConditions(\n\t\tcoupon: DocumentType<BaseCoupon>,\n\t\tuser: mongoose.Types.ObjectId\n\t): Promise<boolean> {\n\t\tconst forNewUserOnly = coupon.forNewUserOnly;\n\t\tconst isOrderLimitPerUserEnabled = coupon.isOrderLimitPerUserEnabled;\n\t\tconst orderLimitPerUser = coupon.orderLimitPerUser;\n\n\t\tif (forNewUserOnly) {\n\t\t\tif (isOrderLimitPerUserEnabled && orderLimitPerUser) {\n\t\t\t\tconst orderCount = await couponHelperService.getSameDeviceOrders(user);\n\t\t\t\treturn orderLimitPerUser > orderCount;\n\t\t\t}\n\t\t\treturn await couponHelperService.isNewUser(user);\n\t\t}\n\n\t\treturn true;\n\t}\n\n\tprivate async getCouponOrdersForUser(user: mongoose.Types.ObjectId, couponCode: string): Promise<number> {\n\t\tconst orders = (await this.orderModel\n\t\t\t.find({\n\t\t\t\tuser: user,\n\t\t\t\tstatus: { $ne: RegularOrderStatus.CANCELLED },\n\t\t\t\torderType: OrderType.REGULAR,\n\t\t\t})\n\t\t\t.populate([{ path: 'cart' }])) as Array<DocumentType<RegularOrder> & { cart: DocumentType<Cart> }>;\n\n\t\tconst count = orders.filter(order => order.cart.couponCode == couponCode).length;\n\n\t\treturn count;\n\t}\n\n\tpublic async handleCouponExpiry(couponId: mongoose.Types.ObjectId) {\n\t\tconst coupon = await this.model.findById(couponId);\n\t\tif (!coupon || coupon.couponType == CouponType.REFERRAL_CODE) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst typedCoupon = coupon as DocumentType<BaseCoupon>;\n\n\t\tlet expirationReason: string | null = null;\n\n\t\tif (typedCoupon.isTotalOrderLimitEnabled && typedCoupon.totalOrderLimit) {\n\t\t\t// find the order count by aggregating the order collection,\n\t\t\t// checking orders that have adjustedFinance.pricing.couponDiscount > 0,\n\t\t\t// populating cart collection to match coupon code\n\n\t\t\tconst pipeline = [\n\t\t\t\t{\n\t\t\t\t\t$match: {\n\t\t\t\t\t\tstatus: { $ne: RegularOrderStatus.CANCELLED },\n\t\t\t\t\t\t'adjustedFinance.pricing.couponDiscount': { $gt: 0 },\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t$lookup: {\n\t\t\t\t\t\tfrom: 'carts',\n\t\t\t\t\t\tlocalField: 'cart',\n\t\t\t\t\t\tforeignField: '_id',\n\t\t\t\t\t\tas: 'cart',\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t$unwind: '$cart',\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t$match: {\n\t\t\t\t\t\t'cart.couponCode': typedCoupon.code,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t$count: 'orderCount',\n\t\t\t\t},\n\t\t\t];\n\t\t\tconst result = await this.orderModel.aggregate(pipeline);\n\t\t\tconst orderCount = result[0]?.orderCount ?? 0;\n\n\t\t\tif (orderCount > typedCoupon.totalOrderLimit) {\n\t\t\t\texpirationReason = CouponExpirationReason.TOTAL_ORDER_LIMIT;\n\t\t\t}\n\t\t}\n\t\tif (typedCoupon.isSpendLimitEnabled && typedCoupon.spendLimit) {\n\t\t\t// spend limit\n\n\t\t\tconst { totalCouponDiscount, totalSecondaryCouponDiscount } = await this.getCouponDiscountTotals(\n\t\t\t\ttypedCoupon.code\n\t\t\t);\n\n\t\t\tif (totalCouponDiscount >= typedCoupon.spendLimit) {\n\t\t\t\texpirationReason = CouponExpirationReason.SPEND_LIMIT;\n\t\t\t}\n\t\t}\n\n\t\tawait this.baseCouponModel.findByIdAndUpdate(\n\t\t\ttypedCoupon._id,\n\t\t\t{\n\t\t\t\t$set: {\n\t\t\t\t\texpirationReason,\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tnew: true,\n\t\t\t\trunValidators: true,\n\t\t\t}\n\t\t);\n\t}\n\tprivate async findCouponByCode(code: string): Promise<DocumentType<Model> | null> {\n\t\tconst coupon = await this.model.findOne({ code: code, updatedVersion: { $exists: false } });\n\t\tif (!coupon) {\n\t\t\tthrow new TRPCError({\n\t\t\t\tcode: 'NOT_FOUND',\n\t\t\t\tmessage: 'Coupon not found',\n\t\t\t});\n\t\t}\n\t\treturn coupon;\n\t}\n\n\tprivate async getCouponDiscountTotals(couponCode: string) {\n\t\tconst pipeline = [\n\t\t\t{\n\t\t\t\t$match: {\n\t\t\t\t\tstatus: { $ne: RegularOrderStatus.CANCELLED },\n\t\t\t\t\t'adjustedFinance.pricing.couponDiscount': { $gt: 0 },\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\t$lookup: {\n\t\t\t\t\tfrom: 'carts',\n\t\t\t\t\tlocalField: 'cart',\n\t\t\t\t\tforeignField: '_id',\n\t\t\t\t\tas: 'cart',\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\t$unwind: '$cart',\n\t\t\t},\n\t\t\t{\n\t\t\t\t$match: {\n\t\t\t\t\t'cart.couponCode': couponCode,\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\t$group: {\n\t\t\t\t\t_id: null,\n\t\t\t\t\ttotalCouponDiscount: {\n\t\t\t\t\t\t$sum: {\n\t\t\t\t\t\t\t$toDouble: {\n\t\t\t\t\t\t\t\t$ifNull: ['$finance.pricing.couponDiscount', 0],\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\ttotalSecondaryCouponDiscount: {\n\t\t\t\t\t\t$sum: {\n\t\t\t\t\t\t\t$toDouble: {\n\t\t\t\t\t\t\t\t$ifNull: ['$finance.pricing.secondaryCouponDiscount', 0],\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t];\n\n\t\tconst result = await this.orderModel.aggregate(pipeline);\n\n\t\treturn {\n\t\t\ttotalCouponDiscount: result[0]?.totalCouponDiscount ?? 0,\n\t\t\ttotalSecondaryCouponDiscount: result[0]?.totalSecondaryCouponDiscount ?? 0,\n\t\t};\n\t}\n\n\tprivate async assignCouponToUser(user: mongoose.Types.ObjectId, coupon: mongoose.Types.ObjectId) {\n\t\tconst updatedUser = await this.userModel.findByIdAndUpdate(\n\t\t\tuser,\n\t\t\t{\n\t\t\t\t$push: {\n\t\t\t\t\tcoupons: coupon,\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tnew: true,\n\t\t\t\trunValidators: true,\n\t\t\t}\n\t\t);\n\t}\n\n\tprivate async assignCouponToMultipleUser(\n\t\tquery: mongoose.FilterQuery<User>,\n\t\tcoupon: mongoose.Types.ObjectId\n\t) {\n\t\tconsole.log('Assigning coupon to multiple users with coupon:', coupon);\n\t\tconst updatedUsers = await this.userModel.updateMany(query, {\n\t\t\t$push: {\n\t\t\t\tcoupons: coupon,\n\t\t\t},\n\t\t});\n\t}\n\n\tprivate async assignCouponToNewUsers(coupon: mongoose.Types.ObjectId) {\n\t\tconsole.log('Assigning coupon to new users', coupon);\n\n\t\tconst newUsers = await couponHelperService.getNewUsers();\n\t\tconst updatedUsers = await this.userModel.updateMany(\n\t\t\t{ _id: { $in: newUsers.map(user => user._id) } },\n\t\t\t{\n\t\t\t\t$push: {\n\t\t\t\t\tcoupons: coupon,\n\t\t\t\t},\n\t\t\t}\n\t\t);\n\t}\n\n\tprivate async removeCouponFromUser(user: mongoose.Types.ObjectId, coupon: mongoose.Types.ObjectId) {\n\t\tconst updatedUser = await this.userModel.findByIdAndUpdate(\n\t\t\tuser,\n\t\t\t{\n\t\t\t\t$pull: {\n\t\t\t\t\tcoupons: coupon,\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tnew: true,\n\t\t\t\trunValidators: true,\n\t\t\t}\n\t\t);\n\t}\n\n\tprivate async removeCouponFromMultipleUser(\n\t\tquery: mongoose.FilterQuery<User>,\n\t\tcoupon: mongoose.Types.ObjectId\n\t) {\n\t\tconst updatedUsers = await this.userModel.updateMany(query, {\n\t\t\t$pull: {\n\t\t\t\tcoupons: coupon,\n\t\t\t},\n\t\t});\n\t}\n\n\tprivate throwBadRequest(message: string): never {\n\t\tthrow new TRPCError({\n\t\t\tcode: 'BAD_REQUEST',\n\t\t\tmessage,\n\t\t});\n\t}\n\n\tpublic async addCouponToUser(user: any, couponCode: string): Promise<DocumentType<Model>> {\n\t\tconst coupon = await this.findCouponByCode(couponCode);\n\t\tif (!coupon) {\n\t\t\tthis.throwBadRequest('Coupon not found');\n\t\t}\n\t\tconst isNewUser = await couponHelperService.isNewUser(new mongoose.Types.ObjectId(user));\n\n\t\tif (coupon.couponType == CouponType.REFERRAL_CODE && !isNewUser) {\n\t\t\tthis.throwBadRequest('This coupon is valid for new users only');\n\t\t}\n\n\t\tif (coupon.couponType == CouponType.REFERRAL_CODE) {\n\t\t\tif ((coupon as DocumentType<ReferralCodeCoupon>).referralUser.toString() == user) {\n\t\t\t\tthis.throwBadRequest('You cannot add your own referral code');\n\t\t\t}\n\t\t}\n\n\t\tconst typedCoupon = coupon as DocumentType<BaseCoupon>;\n\n\t\tif (this.isCouponExpired(typedCoupon)) {\n\t\t\tthis.throwBadRequest('This coupon has expired and cannot be added');\n\t\t}\n\n\t\tif (typedCoupon.forNewUserOnly && !isNewUser) {\n\t\t\tthis.throwBadRequest('This coupon is valid for new users only');\n\t\t}\n\n\t\tconst alreadyApplied = await this.hasUserAlreadyAppliedCoupon(user, typedCoupon);\n\t\tif (alreadyApplied) {\n\t\t\tthis.throwBadRequest('Coupon already applied to user');\n\t\t}\n\n\t\tif (typedCoupon.couponType == CouponType.INDIVIDUAL_USER) {\n\t\t\tif (!(typedCoupon as DocumentType<IndividualUserCoupon>).users?.includes(user)) {\n\t\t\t\tthis.throwBadRequest('This coupon is not assigned to this user');\n\t\t\t}\n\t\t}\n\n\t\tawait this.userModel.findByIdAndUpdate(\n\t\t\tuser,\n\t\t\t{ $push: { coupons: typedCoupon._id } },\n\t\t\t{ new: true, runValidators: true }\n\t\t);\n\n\t\treturn coupon;\n\t}\n\n\tprivate async hasUserAlreadyAppliedCoupon(\n\t\tuserId: mongoose.Types.ObjectId,\n\t\tcoupon: DocumentType<BaseCoupon>\n\t): Promise<boolean> {\n\t\tconst couponIds = [coupon._id, ...(coupon.previousVersions ?? []).map(v => v._id)];\n\n\t\tconst user = await this.userModel.exists({\n\t\t\t_id: userId,\n\t\t\tcoupons: { $in: couponIds },\n\t\t});\n\n\t\treturn !!user;\n\t}\n\n\tprivate async exchangeCouponForMultipleUser(\n\t\tquery: mongoose.FilterQuery<User>,\n\t\toldCoupon: mongoose.Types.ObjectId,\n\t\tnewCoupon: mongoose.Types.ObjectId\n\t) {\n\t\tawait this.removeCouponFromMultipleUser(query, oldCoupon);\n\t\tawait this.assignCouponToMultipleUser(query, newCoupon);\n\t}\n\n\tpublic getShareableLink = async (code: string): Promise<ShareableLinkDTO> => {\n\t\tconst secretsService = getLibraries().getSecretsService();\n\t\tconst deepLinkUrl = (await secretsService.getKey('DEEP_LINK_URL')) ?? 'https://link.lyxa.ai';\n\n\t\tconst link = `${deepLinkUrl}/invite/${code}`;\n\n\t\tconst message = `Download Lyxa and explore the wide variety of offerings and benefits! Use my code at checkout to claim a special coupon : ${code}.\n\t\t${link}`;\n\n\t\treturn { link, message };\n\t};\n\n\tpublic async getUserCouponList(data?: Partial<FilterDTO>): Promise<PaginatedResponse<AllCouponsDTO>> {\n\t\ttry {\n\t\t\tlet query = data?.query || {};\n\n\t\t\tif (!query.user) {\n\t\t\t\tbadRequestError('User ID is required in query');\n\t\t\t}\n\n\t\t\tconst select = data?.select || {\n\t\t\t\t_id: 1,\n\t\t\t\t'createdBy.name': 1,\n\t\t\t\t'duration.start': 1,\n\t\t\t\t'duration.end': 1,\n\t\t\t\tcode: 1,\n\t\t\t\tstatus: 1,\n\t\t\t\tcreatedAt: 1,\n\t\t\t\tcouponType: 1,\n\t\t\t};\n\n\t\t\tlet isExpiredField = null;\n\n\t\t\tif (query.status) {\n\t\t\t\tif (query.status === 'expired') {\n\t\t\t\t\tisExpiredField = true;\n\t\t\t\t\tdelete query.status;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (query.createdAt) {\n\t\t\t\t// convert to date range\n\t\t\t\tif ('$gte' in query.createdAt) {\n\t\t\t\t\tquery.createdAt.$gte = new Date(query.createdAt.$gte);\n\t\t\t\t}\n\t\t\t\tif ('$lte' in query.createdAt) {\n\t\t\t\t\tquery.createdAt.$lte = new Date(query.createdAt.$lte);\n\t\t\t\t}\n\t\t\t\tif ('$gt' in query.createdAt) {\n\t\t\t\t\tquery.createdAt.$gt = new Date(query.createdAt.$gt);\n\t\t\t\t}\n\t\t\t\tif ('$lt' in query.createdAt) {\n\t\t\t\t\tquery.createdAt.$lt = new Date(query.createdAt.$lt);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst user = await this.userModel.findById(query.user).select('coupons');\n\t\t\tquery._id = { $in: user?.coupons ?? [] };\n\t\t\tdelete query.user; // remove user from query to avoid issues in aggregation match stage\n\n\t\t\tconst pipeline: any[] = [\n\t\t\t\t{ $match: { ...query, deletedAt: null } }, // Filter by search query\n\t\t\t\t{\n\t\t\t\t\t$lookup: {\n\t\t\t\t\t\t// INNER JOIN on categories\n\t\t\t\t\t\tfrom: 'admins', // Mongoose auto-pluralizes collection names\n\t\t\t\t\t\tlocalField: 'createdBy',\n\t\t\t\t\t\tforeignField: '_id',\n\t\t\t\t\t\tas: 'createdBy',\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{ $unwind: { path: '$createdBy', preserveNullAndEmptyArrays: true } }, // Flatten the array\n\t\t\t\t{\n\t\t\t\t\t$addFields: {\n\t\t\t\t\t\tisExpired: {\n\t\t\t\t\t\t\t$cond: {\n\t\t\t\t\t\t\t\tif: {\n\t\t\t\t\t\t\t\t\t$or: [\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t$and: [\n\t\t\t\t\t\t\t\t\t\t\t\t{ $ifNull: ['$duration.end', false] },\n\t\t\t\t\t\t\t\t\t\t\t\t{ $lt: ['$duration.end', dayjs().toDate()] },\n\t\t\t\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{ $ifNull: ['$expirationReason', false] },\n\t\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tthen: true,\n\t\t\t\t\t\t\t\telse: false,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t$match: isExpiredField\n\t\t\t\t\t\t? { isExpired: true }\n\t\t\t\t\t\t: query.status === 'active'\n\t\t\t\t\t\t\t? { isExpired: false }\n\t\t\t\t\t\t\t: {},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t$addFields: {\n\t\t\t\t\t\tstatus: {\n\t\t\t\t\t\t\t$cond: {\n\t\t\t\t\t\t\t\tif: { $eq: ['$isExpired', true] },\n\t\t\t\t\t\t\t\tthen: 'expired',\n\t\t\t\t\t\t\t\telse: '$status',\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t$project: select,\n\t\t\t\t},\n\t\t\t];\n\n\t\t\tif (data?.search?.searchKey) {\n\t\t\t\tconst searchKey = data.search.searchKey;\n\t\t\t\tconst regex = new RegExp(searchKey, 'i'); // case-insensitive search\n\t\t\t\tconst fields = data.search.searchFields?.length ? data.search.searchFields : ['code']; // default field(s) to search in\n\n\t\t\t\tpipeline.push({\n\t\t\t\t\t$match: {\n\t\t\t\t\t\t$or: fields.map(field => ({ [field]: { $regex: regex } })),\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t}\n\n\t\t\t// Execute the aggregation with pagination and sorting\n\t\t\tconst results = await paginateAggregation(this.model, pipeline, data?.page, data?.size, data?.sort);\n\n\t\t\treturn results as unknown as PaginatedResponse<AllCouponsDTO>;\n\t\t} catch (err) {\n\t\t\tthrow new TRPCError({\n\t\t\t\tcode: 'INTERNAL_SERVER_ERROR',\n\t\t\t\tmessage: `err: ${err}`,\n\t\t\t});\n\t\t}\n\t}\n\n\tpublic async addExistingCouponsToNewUser(userId: mongoose.Types.ObjectId) {\n\t\tconst isNewUser = await couponHelperService.isNewUser(userId);\n\n\t\tconst query: any = {\n\t\t\tcouponType: { $in: [CouponType.GLOBAL, CouponType.INDIVIDUAL_STORE, CouponType.SHOPS_CATEGORIES] },\n\t\t\tdeletedAt: null,\n\t\t\texpirationReason: null,\n\t\t\t$or: [\n\t\t\t\t{ 'duration.end': { $gt: dayjs().toDate() } },\n\t\t\t\t{ 'duration.end': { $exists: false } },\n\t\t\t\t{ 'duration.end': null },\n\t\t\t],\n\t\t\tupdatedVersion: { $exists: false },\n\t\t};\n\n\t\tif (!isNewUser) {\n\t\t\tquery.forNewUserOnly = { $ne: true };\n\t\t}\n\n\t\t// assign all coupons that are not expired\n\t\tconst coupons = await this.baseCouponModel.find(query);\n\n\t\tconst couponIds = coupons.map(coupon => coupon._id);\n\n\t\tawait this.userModel.findByIdAndUpdate(\n\t\t\tuserId,\n\t\t\t{\n\t\t\t\t$addToSet: {\n\t\t\t\t\tcoupons: { $each: couponIds },\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tnew: true,\n\t\t\t\trunValidators: true,\n\t\t\t}\n\t\t);\n\t}\n\n\tpublic async checkExistingNewUserCoupon(): Promise<CheckExistingNewUserCouponOutputDTO> {\n\t\tconst currentDate = dayjs().toDate();\n\t\tconst alreadyActiveForNewUserCoupon = await this.baseCouponModel.findOne({\n\t\t\tcouponType: CouponType.GLOBAL,\n\t\t\tforNewUserOnly: true,\n\t\t\tdeletedAt: null,\n\t\t\t$or: [\n\t\t\t\t{\n\t\t\t\t\texpirationReason: { $exists: false },\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\texpirationReason: null,\n\t\t\t\t},\n\t\t\t],\n\t\t\t'duration.end': { $gte: currentDate },\n\t\t\tupdatedVersion: { $exists: false },\n\t\t});\n\n\t\tif (alreadyActiveForNewUserCoupon) {\n\t\t\treturn { exists: true };\n\t\t}\n\t\treturn { exists: false };\n\t}\n}\n\nexport const couponService = Container.get(CouponService);\n"]}
|
|
1
|
+
{"version":3,"file":"coupon.service.js","sourceRoot":"/","sources":["modules/coupon/services/coupon.service.ts"],"names":[],"mappings":"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","sourcesContent":["import Container, { Service } from 'typedi';\nimport { TRPCError } from '@trpc/server';\nimport { DocumentType, mongoose, queryMethod, ReturnModelType } from '@typegoose/typegoose';\nimport {\n\tCart,\n\tCouponModel,\n\tCustomCoupon,\n\tgetCoreUserModel,\n\tGlobalCoupon,\n\tIndividualStoreCoupon,\n\tIndividualUserCoupon,\n\tCoupon as Model,\n\tReferralRewardCoupon,\n\tReferralRewardCouponModel,\n\tRegularOrder,\n\tRegularOrderModel,\n\tShopModel,\n\tShop,\n\tShopsCategoriesCoupon,\n\tUser,\n\tUserModel,\n\tReferralCodeCoupon,\n} from '@lyxa.ai/core/dist/libraries/mongo/models';\nimport {\n\tAllCouponsValidationDTO,\n\tCouponValidationOutputDTO,\n\tValidateCouponDTO,\n\tAllCouponsDTO,\n\tCheckExistingNewUserCouponOutputDTO,\n} from '@modules/coupon/validations';\nimport { SoftDeleteModel } from '@lyxa.ai/core/dist/libraries/mongo/plugins/soft-delete-plugin';\nimport {\n\tFilterDTO,\n\tPaginatedResponse,\n\tDeleteDTO,\n\tShareableLinkDTO,\n} from '@lyxa.ai/core/dist/utilities/validation';\nimport {\n\tcreateRawDocumentPaginatorObject,\n\tpaginateAggregation,\n\tPaginatorOptions,\n} from '@lyxa.ai/core/dist/utilities/pagination';\nimport { ModelType } from '@typegoose/typegoose/lib/types';\nimport {\n\tcustomCouponService,\n\tglobalCouponService,\n\tindividualStoreCouponService,\n\tindividualUserCouponService,\n\treferralCodeCouponService,\n\treferralRewardCouponService,\n} from '.';\nimport {\n\tCouponExpirationReason,\n\tCouponType,\n\tItemType,\n\tOrderType,\n\tRegularOrderStatus,\n\tStatus,\n} from '@lyxa.ai/core/dist/utilities/enum';\nimport { BaseCoupon, BaseCouponModel } from '@lyxa.ai/core/dist/libraries/mongo/models';\nimport {\n\tPunchMarketingHistoryService,\n\tpunchMarketingHistoryService,\n} from '@modules/punch-marketing-history/services';\nimport { getLibraries } from '@lyxa.ai/core';\nimport { NotificationMicroserviceRouter } from '@lyxa.ai/notification';\nimport { CouponRepository } from './patterns/repository/CouponRepository';\nimport {\n\tbadRequestError,\n\tconflictError,\n\tinternalServerError,\n\tnotFoundError,\n\tnotImplementedError,\n} from '@lyxa.ai/core/dist/utilities/error-common';\nimport { shopsCategoriesCouponService } from './shops-categories-coupon.service';\nimport { CouponHelperService, couponHelperService } from './helper.service';\nimport { Dayjs, dayjs } from '@lyxa.ai/core/dist/utilities/dayjs';\n\n@Service()\nexport class CouponService {\n\tprivate model: typeof CouponModel & SoftDeleteModel<Model>;\n\tprivate baseCouponModel: typeof BaseCouponModel & SoftDeleteModel<BaseCoupon>;\n\tprivate userModel: typeof UserModel & SoftDeleteModel<User>;\n\tprivate orderModel: typeof RegularOrderModel & SoftDeleteModel<RegularOrder>;\n\tprivate shopModel: typeof ShopModel & SoftDeleteModel<Shop>;\n\tprivate referralRewardModel: typeof ReferralRewardCouponModel & SoftDeleteModel<ReferralRewardCoupon>;\n\tprivate punchHistoryService: PunchMarketingHistoryService;\n\tprivate _coreUserModel: ReturnType<typeof getCoreUserModel> | null = null;\n\tprivate couponHelper: CouponHelperService;\n\n\tconstructor() {\n\t\tthis.model = CouponModel as typeof CouponModel & SoftDeleteModel<Model>;\n\t\tthis.baseCouponModel = BaseCouponModel as typeof BaseCouponModel & SoftDeleteModel<BaseCoupon>;\n\t\tthis.userModel = UserModel as typeof UserModel & SoftDeleteModel<User>;\n\t\tthis.orderModel = RegularOrderModel as typeof RegularOrderModel & SoftDeleteModel<RegularOrder>;\n\t\tthis.shopModel = ShopModel as typeof ShopModel & SoftDeleteModel<Shop>;\n\t\tthis.referralRewardModel = ReferralRewardCouponModel as typeof ReferralRewardCouponModel &\n\t\t\tSoftDeleteModel<ReferralRewardCoupon>;\n\t\tthis.punchHistoryService = punchMarketingHistoryService;\n\t\tthis.couponHelper = couponHelperService;\n\t}\n\n\tprivate get coreUserModel() {\n\t\tif (!this._coreUserModel) {\n\t\t\tthis._coreUserModel = getCoreUserModel();\n\t\t}\n\t\treturn this._coreUserModel;\n\t}\n\n\t/**\n\t * Create a new record\n\t * @param data Data for the new record\n\t */\n\tpublic async create(data: AllCouponsValidationDTO): Promise<DocumentType<Model>> {\n\t\tlet coupon: DocumentType<Model>;\n\n\t\tif (\n\t\t\tdata.couponType != CouponType.REFERRAL_CODE &&\n\t\t\tdata?.duration &&\n\t\t\t!this.couponHelper.isDurationValid(dayjs(data?.duration?.start), dayjs(data?.duration?.end))\n\t\t) {\n\t\t\tconflictError(`Start date/time cannot be in the past `);\n\t\t}\n\n\t\tconst checkCoupon = await this.model.findOne({\n\t\t\tcode: data.code,\n\t\t\tdeletedAt: null,\n\t\t});\n\n\t\tif (checkCoupon) conflictError('Coupon code already exists');\n\n\t\tswitch (data.couponType) {\n\t\t\tcase CouponType.GLOBAL: {\n\t\t\t\tcoupon = await globalCouponService.create(data);\n\t\t\t\tif (coupon) {\n\t\t\t\t\tconst globalCoupon = coupon as DocumentType<GlobalCoupon>;\n\t\t\t\t\tif (!globalCoupon.forNewUserOnly) {\n\t\t\t\t\t\tawait this.assignCouponToMultipleUser({}, coupon._id);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tawait this.assignCouponToNewUsers(coupon._id);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase CouponType.REFERRAL_CODE: {\n\t\t\t\tcoupon = await referralCodeCouponService.create(data);\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase CouponType.REFERRAL_REWARD: {\n\t\t\t\tcoupon = await referralRewardCouponService.create(data);\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase CouponType.SHOPS_CATEGORIES: {\n\t\t\t\tcoupon = await shopsCategoriesCouponService.create(data);\n\t\t\t\tif (coupon) {\n\t\t\t\t\tconst shopsCategoriesCoupon = coupon as DocumentType<ShopsCategoriesCoupon>;\n\t\t\t\t\tif (!shopsCategoriesCoupon.forNewUserOnly) {\n\t\t\t\t\t\tawait this.assignCouponToMultipleUser({}, coupon._id);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tawait this.assignCouponToNewUsers(coupon._id);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase CouponType.INDIVIDUAL_STORE: {\n\t\t\t\tcoupon = await individualStoreCouponService.create(data);\n\t\t\t\tif (coupon) {\n\t\t\t\t\tconst individualStoreCoupon = coupon as DocumentType<IndividualStoreCoupon>;\n\t\t\t\t\tif (!individualStoreCoupon.forNewUserOnly) {\n\t\t\t\t\t\tawait this.assignCouponToMultipleUser({}, coupon._id);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tawait this.assignCouponToNewUsers(coupon._id);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase CouponType.INDIVIDUAL_USER: {\n\t\t\t\tcoupon = await individualUserCouponService.create(data);\n\t\t\t\tif (coupon) {\n\t\t\t\t\tconst individualUserCoupon = coupon as DocumentType<IndividualUserCoupon>;\n\t\t\t\t\tconst users = individualUserCoupon.users;\n\t\t\t\t\tawait this.assignCouponToMultipleUser({ _id: { $in: users } }, coupon._id);\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcase CouponType.CUSTOM_COUPON: {\n\t\t\t\tcoupon = await customCouponService.create(data);\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tdefault: {\n\t\t\t\tbadRequestError('Coupon type is not valid');\n\t\t\t}\n\t\t}\n\n\t\tif (!coupon) internalServerError('Could not create coupon');\n\n\t\t// Send Notification\n\t\tconst dispatcher = getLibraries().getMicroServiceDispatcher();\n\t\tconst notificationRouter =\n\t\t\tawait dispatcher.getMicroService<NotificationMicroserviceRouter>('notification');\n\n\t\tawait notificationRouter.notificationRouter.sendPushNotificationForCoupon.mutate(coupon._id);\n\n\t\treturn coupon;\n\t}\n\n\t/**\n\t * Get record by ID\n\t * @param id ID of the record\n\t */\n\tpublic async findById(id: string | mongoose.Types.ObjectId): Promise<DocumentType<Model>> {\n\t\tconst result = await this.model\n\t\t\t.findOne({\n\t\t\t\t_id: id,\n\t\t\t\tdeletedAt: null,\n\t\t\t})\n\t\t\t.populate([\n\t\t\t\t{\n\t\t\t\t\tpath: 'previousVersions',\n\t\t\t\t},\n\t\t\t]);\n\t\tif (!result) {\n\t\t\tthrow new TRPCError({\n\t\t\t\tcode: 'NOT_FOUND',\n\t\t\t\tmessage: 'Record not found',\n\t\t\t});\n\t\t}\n\t\treturn result;\n\t}\n\n\t/**\n\t * Get records\n\t * @param query Query to find records\n\t */\n\tpublic async find(data?: Partial<FilterDTO>): Promise<PaginatedResponse<DocumentType<ModelType<Model>>>> {\n\t\ttry {\n\t\t\tconst populate = [\n\t\t\t\t...data?.populate,\n\t\t\t\t{\n\t\t\t\t\tpath: 'users',\n\t\t\t\t\tpopulate: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tpath: 'coreUser',\n\t\t\t\t\t\t\tmodel: this.coreUserModel,\n\t\t\t\t\t\t\tselect: 'name profilePhoto -_id',\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t\tselect: 'coreUser phoneNumber',\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tpath: 'influencer',\n\t\t\t\t\tpopulate: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tpath: 'coreUser',\n\t\t\t\t\t\t\tmodel: this.coreUserModel,\n\t\t\t\t\t\t\tselect: 'name profilePhoto -_id',\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t\tselect: 'coreUser phoneNumber',\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tpath: 'referralUser',\n\t\t\t\t\tpopulate: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tpath: 'coreUser',\n\t\t\t\t\t\t\tmodel: this.coreUserModel,\n\t\t\t\t\t\t\tselect: 'name profilePhoto -_id',\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t\tselect: 'coreUser phoneNumber',\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tpath: 'user',\n\t\t\t\t\tpopulate: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tpath: 'coreUser',\n\t\t\t\t\t\t\tmodel: this.coreUserModel,\n\t\t\t\t\t\t\tselect: 'name profilePhoto -_id',\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t\tselect: 'coreUser phoneNumber',\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tpath: 'referralCodeUsedBy',\n\t\t\t\t\tpopulate: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tpath: 'coreUser',\n\t\t\t\t\t\t\tmodel: this.coreUserModel,\n\t\t\t\t\t\t\tselect: 'name profilePhoto -_id',\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t\tselect: 'coreUser phoneNumber',\n\t\t\t\t},\n\t\t\t];\n\n\t\t\tconst paginate = createRawDocumentPaginatorObject(this.model as ReturnModelType<typeof this.model>);\n\t\t\tconst options: PaginatorOptions<typeof Model> = {\n\t\t\t\tpage: data?.page,\n\t\t\t\tsize: data?.size,\n\t\t\t\tsort: data?.sort,\n\t\t\t\tquery: { ...data?.query, updatedVersion: { $exists: false } },\n\t\t\t\tselect: data?.select,\n\t\t\t\tpopulate: populate,\n\t\t\t};\n\t\t\tconst paginatedResult = await paginate(options);\n\t\t\treturn paginatedResult;\n\t\t} catch (err) {\n\t\t\tthrow new TRPCError({\n\t\t\t\tcode: 'INTERNAL_SERVER_ERROR',\n\t\t\t\tmessage: `err: ${err}`,\n\t\t\t});\n\t\t}\n\t}\n\n\t/**\n\t * Update record\n\t * @param id ID of the old coupon\n\t * @param data Data of the updated coupon\n\t */\n\tpublic async update(id: string, data: AllCouponsValidationDTO): Promise<DocumentType<Model>> {\n\t\tlet coupon: DocumentType<BaseCoupon> | null;\n\n\t\tconst [oldCoupon, checkCouponCode, usersWithOldCoupon] = await Promise.all([\n\t\t\tthis.baseCouponModel.findById(id),\n\t\t\tthis.model.findOne({\n\t\t\t\tcode: data.code,\n\t\t\t\t_id: { $ne: id },\n\t\t\t\tupdatedVersion: { $exists: false },\n\t\t\t}),\n\t\t\tthis.userModel\n\t\t\t\t.find({\n\t\t\t\t\tcoupons: new mongoose.Types.ObjectId(id),\n\t\t\t\t})\n\t\t\t\t.select(['_id', 'coupons']),\n\t\t]);\n\n\t\tif (!oldCoupon) {\n\t\t\tthrow new TRPCError({\n\t\t\t\tcode: 'NOT_FOUND',\n\t\t\t\tmessage: `Coupon not found`,\n\t\t\t});\n\t\t}\n\n\t\tif (\n\t\t\tdata.couponType != CouponType.REFERRAL_CODE &&\n\t\t\toldCoupon?.duration &&\n\t\t\tdayjs(oldCoupon?.duration?.start) > dayjs(data?.duration.start)\n\t\t) {\n\t\t\tthrow new TRPCError({\n\t\t\t\tcode: 'BAD_REQUEST',\n\t\t\t\tmessage: `Don't allow updating coupon to have earlier start date/time than the original coupon`,\n\t\t\t});\n\t\t}\n\n\t\tif (\n\t\t\tdata.couponType != CouponType.REFERRAL_CODE &&\n\t\t\tdata?.duration &&\n\t\t\tdayjs(data?.duration?.start) > dayjs(data?.duration.end)\n\t\t) {\n\t\t\tthrow new TRPCError({\n\t\t\t\tcode: 'BAD_REQUEST',\n\t\t\t\tmessage: `End date/time must be after start date/time`,\n\t\t\t});\n\t\t}\n\n\t\tif (checkCouponCode) {\n\t\t\tthrow new TRPCError({\n\t\t\t\tcode: 'CONFLICT',\n\t\t\t\tmessage: `Coupon code already exists`,\n\t\t\t});\n\t\t}\n\n\t\tswitch (data.couponType) {\n\t\t\tcase CouponType.GLOBAL: {\n\t\t\t\tcoupon = await globalCouponService.create(data);\n\t\t\t\tif (coupon) {\n\t\t\t\t\tconst globalCoupon = coupon as DocumentType<GlobalCoupon>;\n\t\t\t\t\tif (!globalCoupon.forNewUserOnly) {\n\t\t\t\t\t\tawait this.exchangeCouponForMultipleUser(\n\t\t\t\t\t\t\t{ _id: { $in: usersWithOldCoupon?.map(u => u._id) } },\n\t\t\t\t\t\t\toldCoupon._id,\n\t\t\t\t\t\t\tcoupon._id\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase CouponType.SHOPS_CATEGORIES: {\n\t\t\t\tcoupon = await shopsCategoriesCouponService.create(data);\n\t\t\t\tif (coupon) {\n\t\t\t\t\tconst shopsCategoriesCoupon = coupon as DocumentType<ShopsCategoriesCoupon>;\n\t\t\t\t\tif (!shopsCategoriesCoupon.forNewUserOnly) {\n\t\t\t\t\t\tawait this.exchangeCouponForMultipleUser(\n\t\t\t\t\t\t\t{ _id: { $in: usersWithOldCoupon?.map(u => u._id) } },\n\t\t\t\t\t\t\toldCoupon._id,\n\t\t\t\t\t\t\tshopsCategoriesCoupon._id\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase CouponType.INDIVIDUAL_STORE: {\n\t\t\t\tcoupon = await individualStoreCouponService.create(data);\n\t\t\t\tif (coupon) {\n\t\t\t\t\tconst individualStoreCoupon = coupon as DocumentType<IndividualStoreCoupon>;\n\t\t\t\t\tif (!individualStoreCoupon.forNewUserOnly) {\n\t\t\t\t\t\tawait this.exchangeCouponForMultipleUser(\n\t\t\t\t\t\t\t{ _id: { $in: usersWithOldCoupon?.map(u => u._id) } },\n\t\t\t\t\t\t\toldCoupon._id,\n\t\t\t\t\t\t\tindividualStoreCoupon._id\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase CouponType.INDIVIDUAL_USER: {\n\t\t\t\tcoupon = await individualUserCouponService.create(data);\n\t\t\t\tif (coupon) {\n\t\t\t\t\tconst individualUserCoupon = coupon as DocumentType<IndividualUserCoupon>;\n\t\t\t\t\tawait this.removeCouponFromMultipleUser(\n\t\t\t\t\t\t{ _id: { $in: usersWithOldCoupon?.map(u => u._id) } },\n\t\t\t\t\t\toldCoupon._id\n\t\t\t\t\t);\n\t\t\t\t\tawait this.assignCouponToMultipleUser(\n\t\t\t\t\t\t{ _id: { $in: individualUserCoupon.users } },\n\t\t\t\t\t\tindividualUserCoupon._id\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase CouponType.CUSTOM_COUPON: {\n\t\t\t\tcoupon = await customCouponService.create(data);\n\t\t\t\tif (coupon) {\n\t\t\t\t\tconst customCoupon = coupon as DocumentType<CustomCoupon>;\n\t\t\t\t\tif (!customCoupon.forNewUserOnly) {\n\t\t\t\t\t\tawait this.exchangeCouponForMultipleUser(\n\t\t\t\t\t\t\t{ _id: { $in: usersWithOldCoupon?.map(u => u._id) } },\n\t\t\t\t\t\t\toldCoupon._id,\n\t\t\t\t\t\t\tcoupon._id\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tdefault: {\n\t\t\t\tthrow new TRPCError({\n\t\t\t\t\tcode: 'BAD_REQUEST',\n\t\t\t\t\tmessage: `Invalid coupon type`,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\tif (!coupon) {\n\t\t\tthrow new TRPCError({\n\t\t\t\tcode: 'BAD_REQUEST',\n\t\t\t\tmessage: `Could create updated coupon`,\n\t\t\t});\n\t\t}\n\n\t\t// add previous version to new coupon\n\t\tconst previousVersions = oldCoupon?.previousVersions || [];\n\t\tpreviousVersions.push(oldCoupon._id);\n\n\t\tconst updatedCoupon = await this.baseCouponModel.findByIdAndUpdate(\n\t\t\tcoupon._id,\n\t\t\t{\n\t\t\t\t$set: {\n\t\t\t\t\tpreviousVersions,\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tnew: true,\n\t\t\t\trunValidators: true,\n\t\t\t}\n\t\t);\n\n\t\tif (!updatedCoupon) {\n\t\t\tthrow new TRPCError({\n\t\t\t\tcode: 'INTERNAL_SERVER_ERROR',\n\t\t\t\tmessage: `Could not set previous versions of coupon`,\n\t\t\t});\n\t\t}\n\t\t// update old coupon\n\t\tconst updatedOldCoupon = await this.baseCouponModel.findByIdAndUpdate(\n\t\t\toldCoupon._id,\n\t\t\t{\n\t\t\t\t$set: {\n\t\t\t\t\tupdatedVersion: coupon._id,\n\t\t\t\t\t'duration.end': coupon.duration.end,\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tnew: true,\n\t\t\t\trunValidators: true,\n\t\t\t}\n\t\t);\n\n\t\treturn updatedCoupon;\n\t}\n\n\tpublic async updateStatus(id: string, status: Status): Promise<DocumentType<Model>> {\n\t\tconst coupon = await this.baseCouponModel.findByIdAndUpdate(\n\t\t\tid,\n\t\t\t{\n\t\t\t\t$set: { status },\n\t\t\t},\n\t\t\t{\n\t\t\t\tnew: true,\n\t\t\t\trunValidators: true,\n\t\t\t}\n\t\t);\n\n\t\tif (!coupon) {\n\t\t\tthrow new TRPCError({\n\t\t\t\tcode: 'NOT_FOUND',\n\t\t\t\tmessage: 'Coupon not found',\n\t\t\t});\n\t\t}\n\n\t\t// also update the status of previous versions of the coupon\n\t\tconst previousVersions = coupon.previousVersions;\n\t\tif (previousVersions && previousVersions.length > 0) {\n\t\t\tawait this.baseCouponModel.updateMany(\n\t\t\t\t{ _id: { $in: previousVersions } },\n\t\t\t\t{\n\t\t\t\t\t$set: { status },\n\t\t\t\t}\n\t\t\t);\n\t\t}\n\n\t\treturn coupon;\n\t}\n\n\t/**\n\t * Delete record\n\t * @param data Data for delete\n\t */\n\tpublic async deleteById(data: DeleteDTO): Promise<string> {\n\t\tconst { _id, softDelete } = data;\n\n\t\tconst coupon = await this.model.findById(_id);\n\n\t\tif (!coupon) {\n\t\t\tnotFoundError('Coupon not found');\n\t\t}\n\n\t\tconst result = await this.model.deleteRecord({ _id, deletedAt: null }, softDelete);\n\t\tif (!result) {\n\t\t\tthrow new TRPCError({\n\t\t\t\tcode: 'NOT_FOUND',\n\t\t\t\tmessage: 'Record not found',\n\t\t\t});\n\t\t}\n\n\t\t// remove coupons from users' coupon lists\n\t\tthis.removeCouponFromMultipleUser({}, _id);\n\n\t\t// also delete previous versions of the coupon\n\t\tconst previousVersions = coupon.previousVersions;\n\t\tif (previousVersions && previousVersions.length > 0) {\n\t\t\tawait this.model.deleteRecord({ _id: { $in: previousVersions }, deletedAt: null }, softDelete);\n\t\t}\n\n\t\treturn 'Record deleted successfully';\n\t}\n\n\t/**\n\t * Get User Coupons\n\t * @param data User and pagination data\n\t */\n\tpublic async getUserCoupons(\n\t\tuser: mongoose.Types.ObjectId | undefined,\n\t\tshop: mongoose.Types.ObjectId | undefined,\n\t\tpage: number = 0,\n\t\tsize: number = 0\n\t): Promise<{\n\t\tavailable: Array<DocumentType<Model>>;\n\t\tused: Array<DocumentType<Model>>;\n\t\texpired: Array<DocumentType<Model>>;\n\t}> {\n\t\tconst couponRepository = new CouponRepository();\n\t\tlet itemType: ItemType | undefined = undefined;\n\t\tif (shop) {\n\t\t\tconst shopDocument = await this.shopModel.findOne({ _id: shop }).select('itemType');\n\t\t\titemType = shopDocument?.itemType;\n\t\t}\n\t\tconst coupons = await couponRepository.getUserCoupons(user, shop, itemType);\n\n\t\tif (shop && user) {\n\t\t\tconst punch = await this.punchHistoryService.getPunchCoupon(user, shop);\n\t\t\tif (punch) {\n\t\t\t\tcoupons.available.push(punch);\n\t\t\t}\n\t\t}\n\n\t\treturn couponRepository.addLabelsToAllCoupons(coupons);\n\t}\n\n\tpublic async validateCoupon(data: ValidateCouponDTO): Promise<CouponValidationOutputDTO> {\n\t\tif (data.coupon === 'punch') {\n\t\t\treturn await punchMarketingHistoryService.getPunchDiscount(data);\n\t\t}\n\n\t\tconst user = await this.userModel.findById(data.user);\n\t\tif (!user) notFoundError('User not found');\n\n\t\tlet coupon = await this.model.findOne({\n\t\t\tcode: data.coupon,\n\t\t\t_id: { $in: user.coupons ?? [] },\n\t\t\tstatus: { $in: [Status.ACTIVE, null] },\n\t\t});\n\n\t\tif (!coupon) {\n\t\t\tcoupon = await this.model.findOne({\n\t\t\t\tcode: data.coupon,\n\t\t\t\tstatus: { $in: [Status.ACTIVE, null] },\n\t\t\t\tcouponType: { $in: [CouponType.REFERRAL_CODE, CouponType.CUSTOM_COUPON] },\n\t\t\t\tupdatedVersion: { $exists: false },\n\t\t\t});\n\n\t\t\tif (!coupon) {\n\t\t\t\tnotFoundError('Coupon not found');\n\t\t\t}\n\t\t}\n\n\t\tif (coupon.couponType == CouponType.REFERRAL_CODE) {\n\t\t\treturn await referralCodeCouponService.validateCoupon(data, coupon as DocumentType<ReferralCodeCoupon>);\n\t\t}\n\n\t\tconst baseCoupon = coupon as DocumentType<BaseCoupon>;\n\n\t\tconst { isValid, invalidMessage } = await this.validateBaseCoupon(\n\t\t\tbaseCoupon,\n\t\t\tuser._id,\n\t\t\tdata.amountBeforeCoupon,\n\t\t\tBoolean(data.scheduledAt) ? dayjs(data.scheduledAt) : undefined\n\t\t);\n\n\t\tif (!isValid) {\n\t\t\treturn {\n\t\t\t\tisValid,\n\t\t\t\tmessage: invalidMessage,\n\t\t\t};\n\t\t}\n\n\t\tswitch (coupon.couponType) {\n\t\t\tcase CouponType.REFERRAL_REWARD:\n\t\t\t\treturn await referralRewardCouponService.validateCoupon(\n\t\t\t\t\tdata,\n\t\t\t\t\tcoupon as DocumentType<ReferralRewardCoupon>\n\t\t\t\t);\n\t\t\tcase CouponType.GLOBAL:\n\t\t\t\treturn await globalCouponService.validateCoupon(data, coupon as DocumentType<GlobalCoupon>);\n\t\t\tcase CouponType.SHOPS_CATEGORIES:\n\t\t\t\treturn await shopsCategoriesCouponService.validateCoupon(\n\t\t\t\t\tdata,\n\t\t\t\t\tcoupon as DocumentType<ShopsCategoriesCoupon>\n\t\t\t\t);\n\t\t\tcase CouponType.INDIVIDUAL_STORE:\n\t\t\t\treturn await individualStoreCouponService.validateCoupon(\n\t\t\t\t\tdata,\n\t\t\t\t\tcoupon as DocumentType<IndividualStoreCoupon>\n\t\t\t\t);\n\t\t\tcase CouponType.INDIVIDUAL_USER:\n\t\t\t\treturn await individualUserCouponService.validateCoupon(\n\t\t\t\t\tdata,\n\t\t\t\t\tcoupon as DocumentType<IndividualUserCoupon>\n\t\t\t\t);\n\t\t\tcase CouponType.CUSTOM_COUPON:\n\t\t\t\treturn await customCouponService.validateCoupon(data, coupon as DocumentType<CustomCoupon>);\n\t\t\tdefault:\n\t\t\t\tnotImplementedError(`Validation not implemented for ${coupon.couponType} coupons`);\n\t\t}\n\t}\n\n\tprivate isCouponExpired(coupon: DocumentType<BaseCoupon>): Boolean {\n\t\tif (coupon.expirationReason || (coupon?.duration?.end && new Date(coupon?.duration?.end) < new Date())) {\n\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t}\n\n\t/**\n\t *\n\t * @param coupon Base coupon document\n\t * @param user ID of the user trying to user the coupon\n\t * @param orderAmount Order subtotal\n\t * @returns True if coupon is valid\n\t */\n\tprivate async validateBaseCoupon(\n\t\tcoupon: DocumentType<BaseCoupon>,\n\t\tuser: mongoose.Types.ObjectId,\n\t\torderAmount: number,\n\t\tscheduledAt: Dayjs | undefined = undefined\n\t): Promise<{ isValid: boolean; invalidMessage?: string }> {\n\t\tconst invalidConditions = [\n\t\t\tthis.isCouponExpired(coupon), // check coupon expired\n\t\t\tcoupon.duration.start > dayjs().toDate(), // check coupon start\n\t\t\tcoupon.isMinOrderValueEnabled && coupon.minOrderValue && orderAmount < coupon.minOrderValue, // check minimum order value\n\t\t\tcoupon.forNewUserOnly && !(await this.verifyNewUserConditions(coupon, user)), // check if new user\n\t\t\tcoupon.isOrderLimitPerUserEnabled &&\n\t\t\t\tcoupon.orderLimitPerUser &&\n\t\t\t\t(await this.getCouponOrdersForUser(user, coupon.code)) >= coupon.orderLimitPerUser, // check order limit for user\n\t\t\tscheduledAt && Boolean(coupon.duration.end) && dayjs(coupon.duration.end).isBefore(scheduledAt), // check scheduledAt is before coupon end date\n\t\t];\n\n\t\tconst invalidMessages = [\n\t\t\t'This coupon is expired',\n\t\t\t'This coupon is not available yet',\n\t\t\t'The minimum order amount for this coupon is not met',\n\t\t\t'This coupon is for new users only',\n\t\t\t'You have reached the order limit for this coupon',\n\t\t\t'This coupon is not valid for this scheduled orders',\n\t\t];\n\n\t\tconst isValid = invalidConditions.every(value => Boolean(value) == false);\n\t\tconst invalidMessage = invalidMessages.filter((_, index) => invalidConditions[index])?.[0];\n\n\t\treturn { isValid, invalidMessage };\n\t}\n\n\t// Returns true if new user conditions are met. False otherwise\n\tprivate async verifyNewUserConditions(\n\t\tcoupon: DocumentType<BaseCoupon>,\n\t\tuser: mongoose.Types.ObjectId\n\t): Promise<boolean> {\n\t\tconst forNewUserOnly = coupon.forNewUserOnly;\n\t\tconst isOrderLimitPerUserEnabled = coupon.isOrderLimitPerUserEnabled;\n\t\tconst orderLimitPerUser = coupon.orderLimitPerUser;\n\n\t\tif (forNewUserOnly) {\n\t\t\tif (isOrderLimitPerUserEnabled && orderLimitPerUser) {\n\t\t\t\tconst orderCount = await couponHelperService.getSameDeviceOrders(user);\n\t\t\t\treturn orderLimitPerUser > orderCount;\n\t\t\t}\n\t\t\treturn await couponHelperService.isNewUser(user);\n\t\t}\n\n\t\treturn true;\n\t}\n\n\tprivate async getCouponOrdersForUser(user: mongoose.Types.ObjectId, couponCode: string): Promise<number> {\n\t\tconst orders = (await this.orderModel\n\t\t\t.find({\n\t\t\t\tuser: user,\n\t\t\t\tstatus: { $ne: RegularOrderStatus.CANCELLED },\n\t\t\t\torderType: OrderType.REGULAR,\n\t\t\t})\n\t\t\t.populate([{ path: 'cart' }])) as Array<DocumentType<RegularOrder> & { cart: DocumentType<Cart> }>;\n\n\t\tconst count = orders.filter(order => order.cart.couponCode == couponCode).length;\n\n\t\treturn count;\n\t}\n\n\tpublic async handleCouponExpiry(couponId: mongoose.Types.ObjectId) {\n\t\tconst coupon = await this.model.findById(couponId);\n\t\tif (!coupon || coupon.couponType == CouponType.REFERRAL_CODE) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst typedCoupon = coupon as DocumentType<BaseCoupon>;\n\t\tawait this.processCouponForExpiry(typedCoupon);\n\t}\n\n\tprivate async processCouponForExpiry(coupon: DocumentType<BaseCoupon>) {\n\t\tlet expirationReason: string | null = null;\n\n\t\tif (coupon.isTotalOrderLimitEnabled && coupon.totalOrderLimit) {\n\t\t\t// find the order count by aggregating the order collection,\n\t\t\t// checking orders that have adjustedFinance.pricing.couponDiscount > 0,\n\t\t\t// populating cart collection to match coupon code\n\n\t\t\tconst pipeline = [\n\t\t\t\t{\n\t\t\t\t\t$match: {\n\t\t\t\t\t\tstatus: { $ne: RegularOrderStatus.CANCELLED },\n\t\t\t\t\t\t'adjustedFinance.pricing.couponDiscount': { $gt: 0 },\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t$lookup: {\n\t\t\t\t\t\tfrom: 'carts',\n\t\t\t\t\t\tlocalField: 'cart',\n\t\t\t\t\t\tforeignField: '_id',\n\t\t\t\t\t\tas: 'cart',\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t$unwind: '$cart',\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t$match: {\n\t\t\t\t\t\t'cart.couponCode': coupon.code,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t$count: 'orderCount',\n\t\t\t\t},\n\t\t\t];\n\t\t\tconst result = await this.orderModel.aggregate(pipeline);\n\t\t\tconst orderCount = result[0]?.orderCount ?? 0;\n\n\t\t\tif (orderCount >= coupon.totalOrderLimit) {\n\t\t\t\texpirationReason = CouponExpirationReason.TOTAL_ORDER_LIMIT;\n\t\t\t}\n\t\t}\n\t\tif (coupon.isSpendLimitEnabled && coupon.spendLimit) {\n\t\t\t// spend limit\n\n\t\t\tconst { totalCouponDiscount, totalSecondaryCouponDiscount } = await this.getCouponDiscountTotals(\n\t\t\t\tcoupon.code\n\t\t\t);\n\n\t\t\tif (totalCouponDiscount >= coupon.spendLimit) {\n\t\t\t\texpirationReason = CouponExpirationReason.SPEND_LIMIT;\n\t\t\t}\n\t\t}\n\n\t\tawait this.baseCouponModel.findByIdAndUpdate(\n\t\t\tcoupon._id,\n\t\t\t{\n\t\t\t\t$set: {\n\t\t\t\t\texpirationReason,\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tnew: true,\n\t\t\t\trunValidators: true,\n\t\t\t}\n\t\t);\n\t}\n\n\tpublic async syncCouponExpiry() {\n\t\tconst coupons = await this.baseCouponModel.find({\n\t\t\tcouponType: { $ne: CouponType.REFERRAL_CODE },\n\t\t\texpirationReason: null,\n\t\t});\n\n\t\tconsole.log(`Syncing expiry for ${coupons.length} coupons`);\n\n\t\tconsole.time('syncCouponExpiry');\n\t\tfor (const coupon of coupons) {\n\t\t\tconsole.time(`Processing coupon ${coupon.code}`);\n\t\t\tawait this.processCouponForExpiry(coupon);\n\t\t\tconsole.timeEnd(`Processing coupon ${coupon.code}`);\n\t\t}\n\t\tconsole.timeEnd('syncCouponExpiry');\n\t}\n\n\tprivate async findCouponByCode(code: string): Promise<DocumentType<Model> | null> {\n\t\tconst coupon = await this.model.findOne({ code: code, updatedVersion: { $exists: false } });\n\t\tif (!coupon) {\n\t\t\tthrow new TRPCError({\n\t\t\t\tcode: 'NOT_FOUND',\n\t\t\t\tmessage: 'Coupon not found',\n\t\t\t});\n\t\t}\n\t\treturn coupon;\n\t}\n\n\tprivate async getCouponDiscountTotals(couponCode: string) {\n\t\tconst pipeline = [\n\t\t\t{\n\t\t\t\t$match: {\n\t\t\t\t\tstatus: { $ne: RegularOrderStatus.CANCELLED },\n\t\t\t\t\t'adjustedFinance.pricing.couponDiscount': { $gt: 0 },\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\t$lookup: {\n\t\t\t\t\tfrom: 'carts',\n\t\t\t\t\tlocalField: 'cart',\n\t\t\t\t\tforeignField: '_id',\n\t\t\t\t\tas: 'cart',\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\t$unwind: '$cart',\n\t\t\t},\n\t\t\t{\n\t\t\t\t$match: {\n\t\t\t\t\t'cart.couponCode': couponCode,\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\t$group: {\n\t\t\t\t\t_id: null,\n\t\t\t\t\ttotalCouponDiscount: {\n\t\t\t\t\t\t$sum: {\n\t\t\t\t\t\t\t$toDouble: {\n\t\t\t\t\t\t\t\t$ifNull: ['$adjustedFinance.pricing.couponDiscount', 0],\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\ttotalSecondaryCouponDiscount: {\n\t\t\t\t\t\t$sum: {\n\t\t\t\t\t\t\t$toDouble: {\n\t\t\t\t\t\t\t\t$ifNull: ['$adjustedFinance.pricing.secondaryCouponDiscount', 0],\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t];\n\n\t\tconst result = await this.orderModel.aggregate(pipeline);\n\n\t\treturn {\n\t\t\ttotalCouponDiscount: result[0]?.totalCouponDiscount ?? 0,\n\t\t\ttotalSecondaryCouponDiscount: result[0]?.totalSecondaryCouponDiscount ?? 0,\n\t\t};\n\t}\n\n\tprivate async assignCouponToUser(user: mongoose.Types.ObjectId, coupon: mongoose.Types.ObjectId) {\n\t\tconst updatedUser = await this.userModel.findByIdAndUpdate(\n\t\t\tuser,\n\t\t\t{\n\t\t\t\t$push: {\n\t\t\t\t\tcoupons: coupon,\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tnew: true,\n\t\t\t\trunValidators: true,\n\t\t\t}\n\t\t);\n\t}\n\n\tprivate async assignCouponToMultipleUser(\n\t\tquery: mongoose.FilterQuery<User>,\n\t\tcoupon: mongoose.Types.ObjectId\n\t) {\n\t\tconsole.log('Assigning coupon to multiple users with coupon:', coupon);\n\t\tconst updatedUsers = await this.userModel.updateMany(query, {\n\t\t\t$push: {\n\t\t\t\tcoupons: coupon,\n\t\t\t},\n\t\t});\n\t}\n\n\tprivate async assignCouponToNewUsers(coupon: mongoose.Types.ObjectId) {\n\t\tconsole.log('Assigning coupon to new users', coupon);\n\n\t\tconst newUsers = await couponHelperService.getNewUsers();\n\t\tconst updatedUsers = await this.userModel.updateMany(\n\t\t\t{ _id: { $in: newUsers.map(user => user._id) } },\n\t\t\t{\n\t\t\t\t$push: {\n\t\t\t\t\tcoupons: coupon,\n\t\t\t\t},\n\t\t\t}\n\t\t);\n\t}\n\n\tprivate async removeCouponFromUser(user: mongoose.Types.ObjectId, coupon: mongoose.Types.ObjectId) {\n\t\tconst updatedUser = await this.userModel.findByIdAndUpdate(\n\t\t\tuser,\n\t\t\t{\n\t\t\t\t$pull: {\n\t\t\t\t\tcoupons: coupon,\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tnew: true,\n\t\t\t\trunValidators: true,\n\t\t\t}\n\t\t);\n\t}\n\n\tprivate async removeCouponFromMultipleUser(\n\t\tquery: mongoose.FilterQuery<User>,\n\t\tcoupon: mongoose.Types.ObjectId\n\t) {\n\t\tconst updatedUsers = await this.userModel.updateMany(query, {\n\t\t\t$pull: {\n\t\t\t\tcoupons: coupon,\n\t\t\t},\n\t\t});\n\t}\n\n\tprivate throwBadRequest(message: string): never {\n\t\tthrow new TRPCError({\n\t\t\tcode: 'BAD_REQUEST',\n\t\t\tmessage,\n\t\t});\n\t}\n\n\tpublic async addCouponToUser(user: any, couponCode: string): Promise<DocumentType<Model>> {\n\t\tconst coupon = await this.findCouponByCode(couponCode);\n\t\tif (!coupon) {\n\t\t\tthis.throwBadRequest('Coupon not found');\n\t\t}\n\t\tconst isNewUser = await couponHelperService.isNewUser(new mongoose.Types.ObjectId(user));\n\n\t\tif (coupon.couponType == CouponType.REFERRAL_CODE && !isNewUser) {\n\t\t\tthis.throwBadRequest('This coupon is valid for new users only');\n\t\t}\n\n\t\tif (coupon.couponType == CouponType.REFERRAL_CODE) {\n\t\t\tif ((coupon as DocumentType<ReferralCodeCoupon>).referralUser.toString() == user) {\n\t\t\t\tthis.throwBadRequest('You cannot add your own referral code');\n\t\t\t}\n\t\t}\n\n\t\tconst typedCoupon = coupon as DocumentType<BaseCoupon>;\n\n\t\tif (this.isCouponExpired(typedCoupon)) {\n\t\t\tthis.throwBadRequest('This coupon has expired and cannot be added');\n\t\t}\n\n\t\tif (typedCoupon.forNewUserOnly && !isNewUser) {\n\t\t\tthis.throwBadRequest('This coupon is valid for new users only');\n\t\t}\n\n\t\tconst alreadyApplied = await this.hasUserAlreadyAppliedCoupon(user, typedCoupon);\n\t\tif (alreadyApplied) {\n\t\t\tthis.throwBadRequest('Coupon already applied to user');\n\t\t}\n\n\t\tif (typedCoupon.couponType == CouponType.INDIVIDUAL_USER) {\n\t\t\tif (!(typedCoupon as DocumentType<IndividualUserCoupon>).users?.includes(user)) {\n\t\t\t\tthis.throwBadRequest('This coupon is not assigned to this user');\n\t\t\t}\n\t\t}\n\n\t\tawait this.userModel.findByIdAndUpdate(\n\t\t\tuser,\n\t\t\t{ $push: { coupons: typedCoupon._id } },\n\t\t\t{ new: true, runValidators: true }\n\t\t);\n\n\t\treturn coupon;\n\t}\n\n\tprivate async hasUserAlreadyAppliedCoupon(\n\t\tuserId: mongoose.Types.ObjectId,\n\t\tcoupon: DocumentType<BaseCoupon>\n\t): Promise<boolean> {\n\t\tconst couponIds = [coupon._id, ...(coupon.previousVersions ?? []).map(v => v._id)];\n\n\t\tconst user = await this.userModel.exists({\n\t\t\t_id: userId,\n\t\t\tcoupons: { $in: couponIds },\n\t\t});\n\n\t\treturn !!user;\n\t}\n\n\tprivate async exchangeCouponForMultipleUser(\n\t\tquery: mongoose.FilterQuery<User>,\n\t\toldCoupon: mongoose.Types.ObjectId,\n\t\tnewCoupon: mongoose.Types.ObjectId\n\t) {\n\t\tawait this.removeCouponFromMultipleUser(query, oldCoupon);\n\t\tawait this.assignCouponToMultipleUser(query, newCoupon);\n\t}\n\n\tpublic getShareableLink = async (code: string): Promise<ShareableLinkDTO> => {\n\t\tconst secretsService = getLibraries().getSecretsService();\n\t\tconst deepLinkUrl = (await secretsService.getKey('DEEP_LINK_URL')) ?? 'https://link.lyxa.ai';\n\n\t\tconst link = `${deepLinkUrl}/invite/${code}`;\n\n\t\tconst message = `Download Lyxa and explore the wide variety of offerings and benefits! Use my code at checkout to claim a special coupon : ${code}.\n\t\t${link}`;\n\n\t\treturn { link, message };\n\t};\n\n\tpublic async getUserCouponList(data?: Partial<FilterDTO>): Promise<PaginatedResponse<AllCouponsDTO>> {\n\t\ttry {\n\t\t\tlet query = data?.query || {};\n\n\t\t\tif (!query.user) {\n\t\t\t\tbadRequestError('User ID is required in query');\n\t\t\t}\n\n\t\t\tconst select = data?.select || {\n\t\t\t\t_id: 1,\n\t\t\t\t'createdBy.name': 1,\n\t\t\t\t'duration.start': 1,\n\t\t\t\t'duration.end': 1,\n\t\t\t\tcode: 1,\n\t\t\t\tstatus: 1,\n\t\t\t\tcreatedAt: 1,\n\t\t\t\tcouponType: 1,\n\t\t\t};\n\n\t\t\tlet isExpiredField = null;\n\n\t\t\tif (query.status) {\n\t\t\t\tif (query.status === 'expired') {\n\t\t\t\t\tisExpiredField = true;\n\t\t\t\t\tdelete query.status;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (query.createdAt) {\n\t\t\t\t// convert to date range\n\t\t\t\tif ('$gte' in query.createdAt) {\n\t\t\t\t\tquery.createdAt.$gte = new Date(query.createdAt.$gte);\n\t\t\t\t}\n\t\t\t\tif ('$lte' in query.createdAt) {\n\t\t\t\t\tquery.createdAt.$lte = new Date(query.createdAt.$lte);\n\t\t\t\t}\n\t\t\t\tif ('$gt' in query.createdAt) {\n\t\t\t\t\tquery.createdAt.$gt = new Date(query.createdAt.$gt);\n\t\t\t\t}\n\t\t\t\tif ('$lt' in query.createdAt) {\n\t\t\t\t\tquery.createdAt.$lt = new Date(query.createdAt.$lt);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst user = await this.userModel.findById(query.user).select('coupons');\n\t\t\tquery._id = { $in: user?.coupons ?? [] };\n\t\t\tdelete query.user; // remove user from query to avoid issues in aggregation match stage\n\n\t\t\tconst pipeline: any[] = [\n\t\t\t\t{ $match: { ...query, deletedAt: null } }, // Filter by search query\n\t\t\t\t{\n\t\t\t\t\t$lookup: {\n\t\t\t\t\t\t// INNER JOIN on categories\n\t\t\t\t\t\tfrom: 'admins', // Mongoose auto-pluralizes collection names\n\t\t\t\t\t\tlocalField: 'createdBy',\n\t\t\t\t\t\tforeignField: '_id',\n\t\t\t\t\t\tas: 'createdBy',\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{ $unwind: { path: '$createdBy', preserveNullAndEmptyArrays: true } }, // Flatten the array\n\t\t\t\t{\n\t\t\t\t\t$addFields: {\n\t\t\t\t\t\tisExpired: {\n\t\t\t\t\t\t\t$cond: {\n\t\t\t\t\t\t\t\tif: {\n\t\t\t\t\t\t\t\t\t$or: [\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t$and: [\n\t\t\t\t\t\t\t\t\t\t\t\t{ $ifNull: ['$duration.end', false] },\n\t\t\t\t\t\t\t\t\t\t\t\t{ $lt: ['$duration.end', dayjs().toDate()] },\n\t\t\t\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{ $ifNull: ['$expirationReason', false] },\n\t\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tthen: true,\n\t\t\t\t\t\t\t\telse: false,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t$match: isExpiredField\n\t\t\t\t\t\t? { isExpired: true }\n\t\t\t\t\t\t: query.status === 'active'\n\t\t\t\t\t\t\t? { isExpired: false }\n\t\t\t\t\t\t\t: {},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t$addFields: {\n\t\t\t\t\t\tstatus: {\n\t\t\t\t\t\t\t$cond: {\n\t\t\t\t\t\t\t\tif: { $eq: ['$isExpired', true] },\n\t\t\t\t\t\t\t\tthen: 'expired',\n\t\t\t\t\t\t\t\telse: '$status',\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t$project: select,\n\t\t\t\t},\n\t\t\t];\n\n\t\t\tif (data?.search?.searchKey) {\n\t\t\t\tconst searchKey = data.search.searchKey;\n\t\t\t\tconst regex = new RegExp(searchKey, 'i'); // case-insensitive search\n\t\t\t\tconst fields = data.search.searchFields?.length ? data.search.searchFields : ['code']; // default field(s) to search in\n\n\t\t\t\tpipeline.push({\n\t\t\t\t\t$match: {\n\t\t\t\t\t\t$or: fields.map(field => ({ [field]: { $regex: regex } })),\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t}\n\n\t\t\t// Execute the aggregation with pagination and sorting\n\t\t\tconst results = await paginateAggregation(this.model, pipeline, data?.page, data?.size, data?.sort);\n\n\t\t\treturn results as unknown as PaginatedResponse<AllCouponsDTO>;\n\t\t} catch (err) {\n\t\t\tthrow new TRPCError({\n\t\t\t\tcode: 'INTERNAL_SERVER_ERROR',\n\t\t\t\tmessage: `err: ${err}`,\n\t\t\t});\n\t\t}\n\t}\n\n\tpublic async addExistingCouponsToNewUser(userId: mongoose.Types.ObjectId) {\n\t\tconst isNewUser = await couponHelperService.isNewUser(userId);\n\n\t\tconst query: any = {\n\t\t\tcouponType: { $in: [CouponType.GLOBAL, CouponType.INDIVIDUAL_STORE, CouponType.SHOPS_CATEGORIES] },\n\t\t\tdeletedAt: null,\n\t\t\texpirationReason: null,\n\t\t\t$or: [\n\t\t\t\t{ 'duration.end': { $gt: dayjs().toDate() } },\n\t\t\t\t{ 'duration.end': { $exists: false } },\n\t\t\t\t{ 'duration.end': null },\n\t\t\t],\n\t\t\tupdatedVersion: { $exists: false },\n\t\t};\n\n\t\tif (!isNewUser) {\n\t\t\tquery.forNewUserOnly = { $ne: true };\n\t\t}\n\n\t\t// assign all coupons that are not expired\n\t\tconst coupons = await this.baseCouponModel.find(query);\n\n\t\tconst couponIds = coupons.map(coupon => coupon._id);\n\n\t\tawait this.userModel.findByIdAndUpdate(\n\t\t\tuserId,\n\t\t\t{\n\t\t\t\t$addToSet: {\n\t\t\t\t\tcoupons: { $each: couponIds },\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tnew: true,\n\t\t\t\trunValidators: true,\n\t\t\t}\n\t\t);\n\t}\n\n\tpublic async getActiveNewUserCoupon(): Promise<DocumentType<BaseCoupon> | null> {\n\t\tconst currentDate = dayjs().toDate();\n\t\tconst activeForNewUserCoupon = await this.baseCouponModel.findOne({\n\t\t\tcouponType: CouponType.GLOBAL,\n\t\t\tforNewUserOnly: true,\n\t\t\tdeletedAt: null,\n\t\t\t$or: [\n\t\t\t\t{\n\t\t\t\t\texpirationReason: { $exists: false },\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\texpirationReason: null,\n\t\t\t\t},\n\t\t\t],\n\t\t\t'duration.end': { $gte: currentDate },\n\t\t\tupdatedVersion: { $exists: false },\n\t\t});\n\n\t\treturn activeForNewUserCoupon;\n\t}\n\n\tpublic async checkExistingNewUserCoupon(): Promise<CheckExistingNewUserCouponOutputDTO> {\n\t\tconst alreadyActiveForNewUserCoupon = await this.getActiveNewUserCoupon();\n\n\t\tif (alreadyActiveForNewUserCoupon) {\n\t\t\treturn { exists: true };\n\t\t}\n\n\t\treturn { exists: false };\n\t}\n\n\tprivate async getAllOrders(userIds: mongoose.Types.ObjectId[]): Promise<number> {\n\t\treturn await this.orderModel.countDocuments({\n\t\t\tuser: { $in: userIds },\n\t\t\tstatus: { $ne: RegularOrderStatus.CANCELLED },\n\t\t\torderType: OrderType.REGULAR,\n\t\t});\n\t}\n\n\tpublic async handleCouponGiftBox(\n\t\tdeviceId: string,\n\t\tuserId: mongoose.Types.ObjectId | null\n\t): Promise<DocumentType<GlobalCoupon>[]> {\n\t\t// 1. Get all the user id using device id\n\t\tconst allUsers = await this.userModel.find({ deviceId }).select('_id');\n\n\t\t// 2. Make an array using all the user ids\n\t\tconst userIds = allUsers.map(user => user._id);\n\n\t\t// 3. Append the current user id to the array\n\t\tif (userId) {\n\t\t\tuserIds.push(new mongoose.Types.ObjectId(userId));\n\t\t}\n\n\t\t// 4. Find how many orders placed by these user ids\n\t\tconst totalOrders = await this.getAllOrders(userIds);\n\n\t\t// 5. Get coupon details\n\t\tconst activeNewUserCoupon = await this.getActiveNewUserCoupon();\n\t\tif (!activeNewUserCoupon) {\n\t\t\tnotFoundError('No active new user coupon found');\n\t\t}\n\n\t\t// 6. Check the total order quantity less than to order limit per user\n\t\tif (\n\t\t\tactiveNewUserCoupon.isOrderLimitPerUserEnabled &&\n\t\t\ttotalOrders < (activeNewUserCoupon.orderLimitPerUser || 0)\n\t\t) {\n\t\t\treturn [activeNewUserCoupon as DocumentType<GlobalCoupon>];\n\t\t}\n\n\t\tnotFoundError('No gift box coupon available');\n\n\t\treturn [];\n\t}\n\n\tpublic async updateCouponGiftBoxShown(userId: mongoose.Types.ObjectId, data: any): Promise<number> {\n\t\tconst result = await this.userModel.updateOne(\n\t\t\t{ _id: userId },\n\t\t\t{\n\t\t\t\t$set: {\n\t\t\t\t\tisNewUserCouponShowed: data.isNewUserGiftBoxShown,\n\t\t\t\t},\n\t\t\t}\n\t\t);\n\n\t\treturn result.modifiedCount;\n\t}\n}\n\nexport const couponService = Container.get(CouponService);\n"]}
|