@lyxa.ai/marketing 1.0.40 → 1.0.41
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 +9 -0
- package/dist/lib/index.d.ts.map +1 -1
- package/dist/lib/modules/coupon/routers/coupon.router.d.ts +4 -0
- package/dist/lib/modules/coupon/routers/coupon.router.d.ts.map +1 -1
- package/dist/lib/modules/coupon/services/coupon.service.d.ts.map +1 -1
- package/dist/lib/modules/coupon/services/coupon.service.js +13 -25
- package/dist/lib/modules/coupon/services/coupon.service.js.map +1 -1
- package/dist/lib/modules/coupon/services/custom-coupon.service.d.ts +28 -2
- package/dist/lib/modules/coupon/services/custom-coupon.service.d.ts.map +1 -1
- package/dist/lib/modules/coupon/services/custom-coupon.service.js +13 -33
- package/dist/lib/modules/coupon/services/custom-coupon.service.js.map +1 -1
- package/dist/lib/modules/coupon/services/helper.service.d.ts +30 -2
- package/dist/lib/modules/coupon/services/helper.service.d.ts.map +1 -1
- package/dist/lib/modules/coupon/services/helper.service.js +112 -4
- package/dist/lib/modules/coupon/services/helper.service.js.map +1 -1
- package/dist/lib/modules/coupon/services/individual-store-coupon.service.d.ts +29 -3
- package/dist/lib/modules/coupon/services/individual-store-coupon.service.d.ts.map +1 -1
- package/dist/lib/modules/coupon/services/individual-store-coupon.service.js +10 -62
- package/dist/lib/modules/coupon/services/individual-store-coupon.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 -6
- package/dist/lib/modules/coupon/services/patterns/repository/CouponRepository.js.map +1 -1
- package/dist/lib/modules/coupon/services/referral-code-coupon.service.d.ts +9 -0
- package/dist/lib/modules/coupon/services/referral-code-coupon.service.d.ts.map +1 -1
- package/dist/lib/modules/coupon/services/referral-code-coupon.service.js +96 -29
- package/dist/lib/modules/coupon/services/referral-code-coupon.service.js.map +1 -1
- package/dist/lib/modules/coupon/services/shops-categories-coupon.service.d.ts +29 -3
- package/dist/lib/modules/coupon/services/shops-categories-coupon.service.d.ts.map +1 -1
- package/dist/lib/modules/coupon/services/shops-categories-coupon.service.js +10 -63
- package/dist/lib/modules/coupon/services/shops-categories-coupon.service.js.map +1 -1
- package/dist/lib/modules/coupon/validations/coupon.validation.d.ts +13 -0
- package/dist/lib/modules/coupon/validations/coupon.validation.d.ts.map +1 -1
- package/dist/lib/modules/coupon/validations/coupon.validation.js +3 -2
- package/dist/lib/modules/coupon/validations/coupon.validation.js.map +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 +4 -4
- package/dist/lib/modules/deal-setting/services/deal-setting.service.js.map +1 -1
- package/dist/lib/modules/marketing/patterns/repository/MarketingMetricsRepository.d.ts.map +1 -1
- package/dist/lib/modules/marketing/patterns/repository/MarketingMetricsRepository.js.map +1 -1
- package/dist/lib/modules/marketing/routers/marketing.router.d.ts +5 -0
- package/dist/lib/modules/marketing/routers/marketing.router.d.ts.map +1 -1
- package/dist/lib/modules/marketing/routers/marketing.router.js +3 -0
- package/dist/lib/modules/marketing/routers/marketing.router.js.map +1 -1
- package/dist/lib/modules/marketing/services/synchronize-product-marketing.service.d.ts.map +1 -1
- package/dist/lib/modules/marketing/services/synchronize-product-marketing.service.js +28 -7
- package/dist/lib/modules/marketing/services/synchronize-product-marketing.service.js.map +1 -1
- package/dist/lib/modules/marketing/validations/buy1-get1-marketing.validation.d.ts +12 -12
- package/dist/lib/modules/marketing/validations/discount-marketing.validation.d.ts +12 -12
- package/dist/types/index.d.ts +9 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/modules/coupon/routers/coupon.router.d.ts +4 -0
- package/dist/types/modules/coupon/routers/coupon.router.d.ts.map +1 -1
- package/dist/types/modules/coupon/services/coupon.service.d.ts.map +1 -1
- package/dist/types/modules/coupon/services/custom-coupon.service.d.ts +28 -2
- package/dist/types/modules/coupon/services/custom-coupon.service.d.ts.map +1 -1
- package/dist/types/modules/coupon/services/helper.service.d.ts +30 -2
- package/dist/types/modules/coupon/services/helper.service.d.ts.map +1 -1
- package/dist/types/modules/coupon/services/individual-store-coupon.service.d.ts +29 -3
- package/dist/types/modules/coupon/services/individual-store-coupon.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/services/referral-code-coupon.service.d.ts +57 -0
- package/dist/types/modules/coupon/services/referral-code-coupon.service.d.ts.map +1 -1
- package/dist/types/modules/coupon/services/shops-categories-coupon.service.d.ts +29 -3
- package/dist/types/modules/coupon/services/shops-categories-coupon.service.d.ts.map +1 -1
- package/dist/types/modules/coupon/validations/coupon.validation.d.ts +13 -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.map +1 -1
- package/dist/types/modules/marketing/patterns/repository/MarketingMetricsRepository.d.ts.map +1 -1
- package/dist/types/modules/marketing/routers/marketing.router.d.ts +5 -0
- package/dist/types/modules/marketing/routers/marketing.router.d.ts.map +1 -1
- package/dist/types/modules/marketing/services/synchronize-product-marketing.service.d.ts.map +1 -1
- package/dist/types/modules/marketing/validations/buy1-get1-marketing.validation.d.ts +12 -12
- package/dist/types/modules/marketing/validations/discount-marketing.validation.d.ts +12 -12
- package/package.json +2 -2
|
@@ -47,16 +47,21 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
47
47
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
48
48
|
exports.couponHelperService = exports.CouponHelperService = void 0;
|
|
49
49
|
const typedi_1 = __importStar(require("typedi"));
|
|
50
|
+
const typegoose_1 = require("@typegoose/typegoose");
|
|
50
51
|
const models_1 = require("@lyxa.ai/core/dist/libraries/mongo/models");
|
|
51
52
|
const enum_1 = require("@lyxa.ai/core/dist/utilities/enum");
|
|
52
53
|
const dayjs_1 = __importDefault(require("@lyxa.ai/core/dist/utilities/dayjs/dayjs"));
|
|
54
|
+
const currency_1 = require("@lyxa.ai/core/dist/utilities/currency");
|
|
55
|
+
const shared_1 = require("@lyxa.ai/core/dist/utilities/shared");
|
|
53
56
|
let CouponHelperService = class CouponHelperService {
|
|
54
57
|
userModel;
|
|
55
58
|
orderModel;
|
|
59
|
+
shopModel;
|
|
56
60
|
_coreUserModel = null;
|
|
57
61
|
constructor() {
|
|
58
62
|
this.userModel = models_1.UserModel;
|
|
59
63
|
this.orderModel = models_1.RegularOrderModel;
|
|
64
|
+
this.shopModel = models_1.ShopModel;
|
|
60
65
|
}
|
|
61
66
|
get coreUserModel() {
|
|
62
67
|
if (!this._coreUserModel) {
|
|
@@ -83,7 +88,7 @@ let CouponHelperService = class CouponHelperService {
|
|
|
83
88
|
});
|
|
84
89
|
return orderCount < 1;
|
|
85
90
|
}
|
|
86
|
-
async
|
|
91
|
+
async getSameDeviceOrdersWithCoupon(user, coupon) {
|
|
87
92
|
let users = [user._id.toString()];
|
|
88
93
|
const existingUser = await this.userModel.findOne({
|
|
89
94
|
_id: user,
|
|
@@ -99,6 +104,7 @@ let CouponHelperService = class CouponHelperService {
|
|
|
99
104
|
const orderCount = await this.orderModel.countDocuments({
|
|
100
105
|
user: { $in: users },
|
|
101
106
|
status: { $ne: enum_1.RegularOrderStatus.CANCELLED },
|
|
107
|
+
'adjustedFinance.coupon.coupon': coupon._id,
|
|
102
108
|
});
|
|
103
109
|
return orderCount;
|
|
104
110
|
}
|
|
@@ -162,13 +168,115 @@ let CouponHelperService = class CouponHelperService {
|
|
|
162
168
|
}
|
|
163
169
|
isDurationValid(start, end) {
|
|
164
170
|
const getRoundedHourBack = (hoursBack = 0) => {
|
|
165
|
-
return (0, dayjs_1.default)()
|
|
166
|
-
.subtract(hoursBack, 'hour')
|
|
167
|
-
.startOf('hour');
|
|
171
|
+
return (0, dayjs_1.default)().subtract(hoursBack, 'hour').startOf('hour');
|
|
168
172
|
};
|
|
169
173
|
const cutoffTime = getRoundedHourBack();
|
|
170
174
|
return start >= cutoffTime && end >= cutoffTime;
|
|
171
175
|
}
|
|
176
|
+
async calculateCouponDiscount(data, coupon) {
|
|
177
|
+
let discountAmount = coupon.valueType === enum_1.ValueType.FIXED
|
|
178
|
+
? coupon.value
|
|
179
|
+
: (0, shared_1.roundBaseCurrency)((data.amountBeforeCoupon * coupon.value) / 100);
|
|
180
|
+
let secondaryDiscountAmount = coupon.valueType === enum_1.ValueType.FIXED
|
|
181
|
+
? await (0, currency_1.convertToSecondary)(coupon.value)
|
|
182
|
+
: (0, shared_1.roundSecondaryCurrency)((data.secondaryAmountBeforeCoupon * coupon.value) / 100);
|
|
183
|
+
if (coupon.isMaxDiscountLimitEnabled && coupon.maxDiscountLimit) {
|
|
184
|
+
const secondaryMax = await (0, currency_1.convertToSecondary)(coupon.maxDiscountLimit);
|
|
185
|
+
discountAmount = Math.min(discountAmount, coupon.maxDiscountLimit);
|
|
186
|
+
secondaryDiscountAmount = Math.min(secondaryDiscountAmount, secondaryMax);
|
|
187
|
+
}
|
|
188
|
+
discountAmount = Math.min(discountAmount, data.amountBeforeCoupon);
|
|
189
|
+
secondaryDiscountAmount = Math.min(secondaryDiscountAmount, data.secondaryAmountBeforeCoupon);
|
|
190
|
+
return { discountAmount, secondaryDiscountAmount };
|
|
191
|
+
}
|
|
192
|
+
buildCouponResponse(data, discountAmount, secondaryDiscountAmount, isShopCoverExpenses, couponDetails) {
|
|
193
|
+
return {
|
|
194
|
+
isValid: true,
|
|
195
|
+
discountAmount,
|
|
196
|
+
secondaryDiscountAmount,
|
|
197
|
+
amountAfterCoupon: (0, shared_1.roundBaseCurrency)(data.amountBeforeCoupon - discountAmount),
|
|
198
|
+
secondaryAmountAfterCoupon: (0, shared_1.roundSecondaryCurrency)(data.secondaryAmountBeforeCoupon - secondaryDiscountAmount),
|
|
199
|
+
discountCut: {
|
|
200
|
+
companyCut: isShopCoverExpenses ? 0 : discountAmount,
|
|
201
|
+
secondaryCompanyCut: isShopCoverExpenses ? 0 : secondaryDiscountAmount,
|
|
202
|
+
shopCut: isShopCoverExpenses ? discountAmount : 0,
|
|
203
|
+
secondaryShopCut: isShopCoverExpenses ? secondaryDiscountAmount : 0,
|
|
204
|
+
},
|
|
205
|
+
couponDetails,
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
async validateShopEligibility({ data, coupon }) {
|
|
209
|
+
const shop = await this.shopModel.findOne({
|
|
210
|
+
_id: new typegoose_1.mongoose.Types.ObjectId(data.shop),
|
|
211
|
+
deletedAt: null,
|
|
212
|
+
});
|
|
213
|
+
if (!shop)
|
|
214
|
+
return { isValid: false, message: 'Shop not found' };
|
|
215
|
+
const singleShopError = await this.validateSingleShopRestriction(shop, coupon);
|
|
216
|
+
if (singleShopError)
|
|
217
|
+
return singleShopError;
|
|
218
|
+
const restrictionError = this.validateMultiRestrictions(shop, coupon);
|
|
219
|
+
if (restrictionError)
|
|
220
|
+
return restrictionError;
|
|
221
|
+
const firstOrderError = await this.validateFirstOrderOnly(data, shop, coupon);
|
|
222
|
+
if (firstOrderError)
|
|
223
|
+
return firstOrderError;
|
|
224
|
+
return { isValid: true, shop };
|
|
225
|
+
}
|
|
226
|
+
async validateSingleShopRestriction(shop, coupon) {
|
|
227
|
+
if (!coupon.shop)
|
|
228
|
+
return null;
|
|
229
|
+
const couponShopId = coupon.shop.toString();
|
|
230
|
+
const currentShopId = shop._id.toString();
|
|
231
|
+
if (couponShopId === currentShopId)
|
|
232
|
+
return null;
|
|
233
|
+
const validShop = await this.shopModel.findOne({ _id: coupon.shop, deletedAt: null }).select('name');
|
|
234
|
+
if (!validShop) {
|
|
235
|
+
return {
|
|
236
|
+
isValid: false,
|
|
237
|
+
message: 'Coupon is associated with an invalid shop',
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
return {
|
|
241
|
+
isValid: false,
|
|
242
|
+
message: `This coupon can be used at ${validShop.name} only`,
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
validateMultiRestrictions(shop, coupon) {
|
|
246
|
+
const hasShopRestriction = Array.isArray(coupon.shops) && coupon.shops.length > 0;
|
|
247
|
+
const hasItemTypeRestriction = Array.isArray(coupon.itemTypes) && coupon.itemTypes.length > 0;
|
|
248
|
+
if (!hasShopRestriction && !hasItemTypeRestriction)
|
|
249
|
+
return null;
|
|
250
|
+
const shopMatches = hasShopRestriction && coupon.shops.some((s) => s.toString() === shop._id.toString());
|
|
251
|
+
const itemTypeMatches = hasItemTypeRestriction && coupon.itemTypes.includes(shop.itemType);
|
|
252
|
+
if (!shopMatches && !itemTypeMatches) {
|
|
253
|
+
return { isValid: false, message: 'Coupon is not valid for this shop' };
|
|
254
|
+
}
|
|
255
|
+
return null;
|
|
256
|
+
}
|
|
257
|
+
async validateFirstOrderOnly(data, shop, coupon) {
|
|
258
|
+
if (!coupon.firstOrderOnly)
|
|
259
|
+
return null;
|
|
260
|
+
const existingOrder = await this.orderModel.exists({
|
|
261
|
+
user: new typegoose_1.mongoose.Types.ObjectId(data.user),
|
|
262
|
+
shop: shop._id,
|
|
263
|
+
status: { $ne: enum_1.RegularOrderStatus.CANCELLED },
|
|
264
|
+
});
|
|
265
|
+
if (existingOrder) {
|
|
266
|
+
return {
|
|
267
|
+
isValid: false,
|
|
268
|
+
message: 'This coupon is only valid for the first order in the shop',
|
|
269
|
+
};
|
|
270
|
+
}
|
|
271
|
+
return null;
|
|
272
|
+
}
|
|
273
|
+
async fetchUserName(userId) {
|
|
274
|
+
const user = await this.userModel.findById(userId).select('coreUser').lean();
|
|
275
|
+
if (!user)
|
|
276
|
+
return 'Unknown User';
|
|
277
|
+
const coreUser = await this.coreUserModel.findById(user.coreUser).select('name').lean();
|
|
278
|
+
return coreUser ? coreUser.name : 'Unknown User';
|
|
279
|
+
}
|
|
172
280
|
};
|
|
173
281
|
exports.CouponHelperService = CouponHelperService;
|
|
174
282
|
exports.CouponHelperService = CouponHelperService = __decorate([
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"helper.service.js","sourceRoot":"/","sources":["modules/coupon/services/helper.service.ts"],"names":[],"mappings":"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","sourcesContent":["import Container, { Service } from 'typedi';\nimport { mongoose } from '@typegoose/typegoose';\nimport {\n\tgetCoreUserModel,\n\tRegularOrder,\n\tRegularOrderModel,\n\tUser,\n\tUserModel,\n} from '@lyxa.ai/core/dist/libraries/mongo/models';\nimport { SoftDeleteModel } from '@lyxa.ai/core/dist/libraries/mongo/plugins/soft-delete-plugin';\nimport { RegularOrderStatus } from '@lyxa.ai/core/dist/utilities/enum';\nimport dayjs, { Dayjs } from '@lyxa.ai/core/dist/utilities/dayjs/dayjs';\n\n@Service()\nexport class CouponHelperService {\n\tprivate userModel: typeof UserModel & SoftDeleteModel<User>;\n\tprivate orderModel: typeof RegularOrderModel & SoftDeleteModel<RegularOrder>;\n\tprivate _coreUserModel: ReturnType<typeof getCoreUserModel> | null = null;\n\n\tconstructor() {\n\t\tthis.userModel = UserModel as typeof UserModel & SoftDeleteModel<User>;\n\t\tthis.orderModel = RegularOrderModel as typeof RegularOrderModel & SoftDeleteModel<RegularOrder>;\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\tpublic async isNewUser(user: mongoose.Types.ObjectId): Promise<boolean> {\n\t\tlet users = [user._id.toString()];\n\n\t\tconst existingUser = await this.userModel.findOne({\n\t\t\t_id: user,\n\t\t});\n\n\t\tconst sameDeviceUsers = await this.userModel.find({\n\t\t\tdeviceId: existingUser?.deviceId,\n\t\t});\n\n\t\tsameDeviceUsers.forEach(u => {\n\t\t\tif (!users.includes(u._id.toString())) {\n\t\t\t\tusers.push(u._id.toString());\n\t\t\t}\n\t\t});\n\n\t\tconst orderCount = await this.orderModel.countDocuments({\n\t\t\tuser: { $in: users },\n\t\t\tstatus: { $ne: RegularOrderStatus.CANCELLED },\n\t\t});\n\n\t\treturn orderCount < 1;\n\t}\n\n\tpublic async getSameDeviceOrders(user: mongoose.Types.ObjectId): Promise<number> {\n\t\tlet users = [user._id.toString()];\n\n\t\tconst existingUser = await this.userModel.findOne({\n\t\t\t_id: user,\n\t\t});\n\n\t\tconst sameDeviceUsers = await this.userModel.find({\n\t\t\tdeviceId: existingUser?.deviceId,\n\t\t});\n\n\t\tsameDeviceUsers.forEach(u => {\n\t\t\tif (!users.includes(u._id.toString())) {\n\t\t\t\tusers.push(u._id.toString());\n\t\t\t}\n\t\t});\n\n\t\tconst orderCount = await this.orderModel.countDocuments({\n\t\t\tuser: { $in: users },\n\t\t\tstatus: { $ne: RegularOrderStatus.CANCELLED },\n\t\t});\n\n\t\treturn orderCount;\n\t}\n\n\tpublic async getNewUsers(): Promise<mongoose.Types.ObjectId[]> {\n\t\tconst pipeline: mongoose.PipelineStage[] = [\n\t\t\t// Step 1: Lookup all users who share the same deviceId\n\t\t\t{\n\t\t\t\t$lookup: {\n\t\t\t\t\tfrom: 'users',\n\t\t\t\t\tlocalField: 'deviceId',\n\t\t\t\t\tforeignField: 'deviceId',\n\t\t\t\t\tas: 'sameDeviceUsers',\n\t\t\t\t},\n\t\t\t},\n\n\t\t\t// Step 2: Collect the list of userIds belonging to this device\n\t\t\t{\n\t\t\t\t$set: {\n\t\t\t\t\tallUserIds: {\n\t\t\t\t\t\t$map: {\n\t\t\t\t\t\t\tinput: '$sameDeviceUsers',\n\t\t\t\t\t\t\tas: 'u',\n\t\t\t\t\t\t\tin: '$$u._id',\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\n\t\t\t// Step 3: Lookup orders attached to any of these users\n\t\t\t{\n\t\t\t\t$lookup: {\n\t\t\t\t\tfrom: 'orders',\n\t\t\t\t\tlet: { ids: '$allUserIds' },\n\t\t\t\t\tpipeline: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t$match: {\n\t\t\t\t\t\t\t\t$expr: {\n\t\t\t\t\t\t\t\t\t$and: [{ $in: ['$user', '$$ids'] }, { $ne: ['$status', 'CANCELLED'] }],\n\t\t\t\t\t\t\t\t},\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\tas: 'orders',\n\t\t\t\t},\n\t\t\t},\n\n\t\t\t// Step 4: Count orders\n\t\t\t{\n\t\t\t\t$set: {\n\t\t\t\t\torderCount: { $size: '$orders' },\n\t\t\t\t},\n\t\t\t},\n\n\t\t\t// Step 5: New user = zero or one non-cancelled order\n\t\t\t{\n\t\t\t\t$match: {\n\t\t\t\t\torderCount: { $lte: 1 },\n\t\t\t\t},\n\t\t\t},\n\n\t\t\t// Optional: Remove temporary fields\n\t\t\t{\n\t\t\t\t$project: {\n\t\t\t\t\tsameDeviceUsers: 0,\n\t\t\t\t\tallUserIds: 0,\n\t\t\t\t\torders: 0,\n\t\t\t\t},\n\t\t\t},\n\t\t];\n\n\t\tconst newUsers = await this.userModel.aggregate(pipeline).exec();\n\n\t\treturn newUsers.map(u => u._id);\n\t}\n\n\tpublic isDurationValid(start: Dayjs, end: Dayjs): boolean {\n\t\tconst getRoundedHourBack = (hoursBack = 0) => {\n\t\t\treturn dayjs()\n\t\t.subtract(hoursBack, 'hour')\n\t\t.startOf('hour');\n\t\t};\n\n\t\tconst cutoffTime = getRoundedHourBack();\n\t\t\n\t\treturn start >= cutoffTime && end >= cutoffTime;\n\t}\n}\n\nexport const couponHelperService = Container.get(CouponHelperService);\n"]}
|
|
1
|
+
{"version":3,"file":"helper.service.js","sourceRoot":"/","sources":["modules/coupon/services/helper.service.ts"],"names":[],"mappings":"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","sourcesContent":["import Container, { Service } from 'typedi';\nimport { DocumentType, mongoose } from '@typegoose/typegoose';\nimport {\n\tBaseCoupon,\n\tgetCoreUserModel,\n\tRegularOrder,\n\tRegularOrderModel,\n\tShop,\n\tShopModel,\n\tUser,\n\tUserModel,\n} from '@lyxa.ai/core/dist/libraries/mongo/models';\nimport { SoftDeleteModel } from '@lyxa.ai/core/dist/libraries/mongo/plugins/soft-delete-plugin';\nimport { RegularOrderStatus, ValueType } from '@lyxa.ai/core/dist/utilities/enum';\nimport dayjs, { Dayjs } from '@lyxa.ai/core/dist/utilities/dayjs/dayjs';\nimport { CouponValidationOutputDTO, ValidateCouponDTO } from '../validations';\nimport { convertToSecondary } from '@lyxa.ai/core/dist/utilities/currency';\nimport { roundBaseCurrency, roundSecondaryCurrency } from '@lyxa.ai/core/dist/utilities/shared';\n\n@Service()\nexport class CouponHelperService {\n\tprivate userModel: typeof UserModel & SoftDeleteModel<User>;\n\tprivate orderModel: typeof RegularOrderModel & SoftDeleteModel<RegularOrder>;\n\tprivate shopModel: typeof ShopModel & SoftDeleteModel<Shop>;\n\tprivate _coreUserModel: ReturnType<typeof getCoreUserModel> | null = null;\n\n\tconstructor() {\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}\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\tpublic async isNewUser(user: mongoose.Types.ObjectId): Promise<boolean> {\n\t\tlet users = [user._id.toString()];\n\n\t\tconst existingUser = await this.userModel.findOne({\n\t\t\t_id: user,\n\t\t});\n\n\t\tconst sameDeviceUsers = await this.userModel.find({\n\t\t\tdeviceId: existingUser?.deviceId,\n\t\t});\n\n\t\tsameDeviceUsers.forEach(u => {\n\t\t\tif (!users.includes(u._id.toString())) {\n\t\t\t\tusers.push(u._id.toString());\n\t\t\t}\n\t\t});\n\n\t\tconst orderCount = await this.orderModel.countDocuments({\n\t\t\tuser: { $in: users },\n\t\t\tstatus: { $ne: RegularOrderStatus.CANCELLED },\n\t\t});\n\n\t\treturn orderCount < 1;\n\t}\n\n\tpublic async getSameDeviceOrdersWithCoupon(\n\t\tuser: mongoose.Types.ObjectId,\n\t\tcoupon: DocumentType<BaseCoupon>\n\t): Promise<number> {\n\t\tlet users = [user._id.toString()];\n\n\t\tconst existingUser = await this.userModel.findOne({\n\t\t\t_id: user,\n\t\t});\n\n\t\tconst sameDeviceUsers = await this.userModel.find({\n\t\t\tdeviceId: existingUser?.deviceId,\n\t\t});\n\n\t\tsameDeviceUsers.forEach(u => {\n\t\t\tif (!users.includes(u._id.toString())) {\n\t\t\t\tusers.push(u._id.toString());\n\t\t\t}\n\t\t});\n\n\t\tconst orderCount = await this.orderModel.countDocuments({\n\t\t\tuser: { $in: users },\n\t\t\tstatus: { $ne: RegularOrderStatus.CANCELLED },\n\t\t\t'adjustedFinance.coupon.coupon': coupon._id,\n\t\t});\n\n\t\treturn orderCount;\n\t}\n\n\tpublic async getNewUsers(): Promise<mongoose.Types.ObjectId[]> {\n\t\tconst pipeline: mongoose.PipelineStage[] = [\n\t\t\t// Step 1: Lookup all users who share the same deviceId\n\t\t\t{\n\t\t\t\t$lookup: {\n\t\t\t\t\tfrom: 'users',\n\t\t\t\t\tlocalField: 'deviceId',\n\t\t\t\t\tforeignField: 'deviceId',\n\t\t\t\t\tas: 'sameDeviceUsers',\n\t\t\t\t},\n\t\t\t},\n\n\t\t\t// Step 2: Collect the list of userIds belonging to this device\n\t\t\t{\n\t\t\t\t$set: {\n\t\t\t\t\tallUserIds: {\n\t\t\t\t\t\t$map: {\n\t\t\t\t\t\t\tinput: '$sameDeviceUsers',\n\t\t\t\t\t\t\tas: 'u',\n\t\t\t\t\t\t\tin: '$$u._id',\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\n\t\t\t// Step 3: Lookup orders attached to any of these users\n\t\t\t{\n\t\t\t\t$lookup: {\n\t\t\t\t\tfrom: 'orders',\n\t\t\t\t\tlet: { ids: '$allUserIds' },\n\t\t\t\t\tpipeline: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t$match: {\n\t\t\t\t\t\t\t\t$expr: {\n\t\t\t\t\t\t\t\t\t$and: [{ $in: ['$user', '$$ids'] }, { $ne: ['$status', 'CANCELLED'] }],\n\t\t\t\t\t\t\t\t},\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\tas: 'orders',\n\t\t\t\t},\n\t\t\t},\n\n\t\t\t// Step 4: Count orders\n\t\t\t{\n\t\t\t\t$set: {\n\t\t\t\t\torderCount: { $size: '$orders' },\n\t\t\t\t},\n\t\t\t},\n\n\t\t\t// Step 5: New user = zero or one non-cancelled order\n\t\t\t{\n\t\t\t\t$match: {\n\t\t\t\t\torderCount: { $lte: 1 },\n\t\t\t\t},\n\t\t\t},\n\n\t\t\t// Optional: Remove temporary fields\n\t\t\t{\n\t\t\t\t$project: {\n\t\t\t\t\tsameDeviceUsers: 0,\n\t\t\t\t\tallUserIds: 0,\n\t\t\t\t\torders: 0,\n\t\t\t\t},\n\t\t\t},\n\t\t];\n\n\t\tconst newUsers = await this.userModel.aggregate(pipeline).exec();\n\n\t\treturn newUsers.map(u => u._id);\n\t}\n\n\tpublic isDurationValid(start: Dayjs, end: Dayjs): boolean {\n\t\tconst getRoundedHourBack = (hoursBack = 0) => {\n\t\t\treturn dayjs().subtract(hoursBack, 'hour').startOf('hour');\n\t\t};\n\n\t\tconst cutoffTime = getRoundedHourBack();\n\n\t\treturn start >= cutoffTime && end >= cutoffTime;\n\t}\n\n\tpublic async calculateCouponDiscount(data: ValidateCouponDTO, coupon: DocumentType<BaseCoupon>) {\n\t\tlet discountAmount =\n\t\t\tcoupon.valueType === ValueType.FIXED\n\t\t\t\t? coupon.value\n\t\t\t\t: roundBaseCurrency((data.amountBeforeCoupon * coupon.value) / 100);\n\n\t\tlet secondaryDiscountAmount =\n\t\t\tcoupon.valueType === ValueType.FIXED\n\t\t\t\t? await convertToSecondary(coupon.value)\n\t\t\t\t: roundSecondaryCurrency((data.secondaryAmountBeforeCoupon * coupon.value) / 100);\n\n\t\tif (coupon.isMaxDiscountLimitEnabled && coupon.maxDiscountLimit) {\n\t\t\tconst secondaryMax = await convertToSecondary(coupon.maxDiscountLimit);\n\n\t\t\tdiscountAmount = Math.min(discountAmount, coupon.maxDiscountLimit);\n\t\t\tsecondaryDiscountAmount = Math.min(secondaryDiscountAmount, secondaryMax);\n\t\t}\n\n\t\t// Prevent negative totals\n\t\tdiscountAmount = Math.min(discountAmount, data.amountBeforeCoupon);\n\t\tsecondaryDiscountAmount = Math.min(secondaryDiscountAmount, data.secondaryAmountBeforeCoupon);\n\n\t\treturn { discountAmount, secondaryDiscountAmount };\n\t}\n\n\tpublic buildCouponResponse(\n\t\tdata: ValidateCouponDTO,\n\t\tdiscountAmount: number,\n\t\tsecondaryDiscountAmount: number,\n\t\tisShopCoverExpenses: boolean,\n\t\tcouponDetails?: Record<string, any>\n\t): CouponValidationOutputDTO {\n\t\treturn {\n\t\t\tisValid: true,\n\t\t\tdiscountAmount,\n\t\t\tsecondaryDiscountAmount,\n\t\t\tamountAfterCoupon: roundBaseCurrency(data.amountBeforeCoupon - discountAmount),\n\t\t\tsecondaryAmountAfterCoupon: roundSecondaryCurrency(\n\t\t\t\tdata.secondaryAmountBeforeCoupon - secondaryDiscountAmount\n\t\t\t),\n\t\t\tdiscountCut: {\n\t\t\t\tcompanyCut: isShopCoverExpenses ? 0 : discountAmount,\n\t\t\t\tsecondaryCompanyCut: isShopCoverExpenses ? 0 : secondaryDiscountAmount,\n\t\t\t\tshopCut: isShopCoverExpenses ? discountAmount : 0,\n\t\t\t\tsecondaryShopCut: isShopCoverExpenses ? secondaryDiscountAmount : 0,\n\t\t\t},\n\t\t\tcouponDetails,\n\t\t};\n\t}\n\n\tpublic async validateShopEligibility({ data, coupon }: { data: ValidateCouponDTO; coupon: any }) {\n\t\tconst shop = await this.shopModel.findOne({\n\t\t\t_id: new mongoose.Types.ObjectId(data.shop),\n\t\t\tdeletedAt: null,\n\t\t});\n\n\t\tif (!shop) return { isValid: false, message: 'Shop not found' };\n\n\t\tconst singleShopError = await this.validateSingleShopRestriction(shop, coupon);\n\t\tif (singleShopError) return singleShopError;\n\n\t\tconst restrictionError = this.validateMultiRestrictions(shop, coupon);\n\t\tif (restrictionError) return restrictionError;\n\n\t\tconst firstOrderError = await this.validateFirstOrderOnly(data, shop, coupon);\n\t\tif (firstOrderError) return firstOrderError;\n\n\t\treturn { isValid: true, shop };\n\t}\n\n\tprivate async validateSingleShopRestriction(shop: any, coupon: any) {\n\t\tif (!coupon.shop) return null;\n\n\t\tconst couponShopId = coupon.shop.toString();\n\t\tconst currentShopId = shop._id.toString();\n\n\t\tif (couponShopId === currentShopId) return null;\n\n\t\tconst validShop = await this.shopModel.findOne({ _id: coupon.shop, deletedAt: null }).select('name');\n\n\t\tif (!validShop) {\n\t\t\treturn {\n\t\t\t\tisValid: false,\n\t\t\t\tmessage: 'Coupon is associated with an invalid shop',\n\t\t\t};\n\t\t}\n\n\t\treturn {\n\t\t\tisValid: false,\n\t\t\tmessage: `This coupon can be used at ${validShop.name} only`,\n\t\t};\n\t}\n\n\tprivate validateMultiRestrictions(shop: any, coupon: any) {\n\t\tconst hasShopRestriction = Array.isArray(coupon.shops) && coupon.shops.length > 0;\n\t\tconst hasItemTypeRestriction = Array.isArray(coupon.itemTypes) && coupon.itemTypes.length > 0;\n\n\t\tif (!hasShopRestriction && !hasItemTypeRestriction) return null;\n\n\t\tconst shopMatches =\n\t\t\thasShopRestriction && coupon.shops.some((s: any) => s.toString() === shop._id.toString());\n\n\t\tconst itemTypeMatches = hasItemTypeRestriction && coupon.itemTypes.includes(shop.itemType);\n\n\t\tif (!shopMatches && !itemTypeMatches) {\n\t\t\treturn { isValid: false, message: 'Coupon is not valid for this shop' };\n\t\t}\n\n\t\treturn null;\n\t}\n\n\tprivate async validateFirstOrderOnly(data: ValidateCouponDTO, shop: any, coupon: any) {\n\t\tif (!coupon.firstOrderOnly) return null;\n\n\t\tconst existingOrder = await this.orderModel.exists({\n\t\t\tuser: new mongoose.Types.ObjectId(data.user),\n\t\t\tshop: shop._id,\n\t\t\tstatus: { $ne: RegularOrderStatus.CANCELLED },\n\t\t});\n\n\t\tif (existingOrder) {\n\t\t\treturn {\n\t\t\t\tisValid: false,\n\t\t\t\tmessage: 'This coupon is only valid for the first order in the shop',\n\t\t\t};\n\t\t}\n\n\t\treturn null;\n\t}\n\n\tpublic async fetchUserName(userId: mongoose.Types.ObjectId): Promise<string> {\n\t\tconst user = await this.userModel.findById(userId).select('coreUser').lean();\n\t\t\n\t\tif (!user) return 'Unknown User';\n\n\t\tconst coreUser = await this.coreUserModel.findById(user.coreUser).select('name').lean();\n\n\t\treturn coreUser ? coreUser.name : 'Unknown User';\n\t}\n}\n\nexport const couponHelperService = Container.get(CouponHelperService);\n"]}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { DocumentType } from '@typegoose/typegoose';
|
|
1
|
+
import { DocumentType, mongoose } from '@typegoose/typegoose';
|
|
2
2
|
import { IndividualStoreCoupon as Model } from '@lyxa.ai/core/dist/libraries/mongo/models/';
|
|
3
|
-
import {
|
|
3
|
+
import { CreateIndividualStoreCouponDTO as CreateDTO, UpdateIndividualStoreCouponDTO as UpdateDTO, ValidateCouponDTO } from '../../coupon/validations';
|
|
4
4
|
export declare class IndividualStoreCouponService {
|
|
5
5
|
private model;
|
|
6
6
|
private readonly shopModelForCoupon;
|
|
@@ -8,7 +8,33 @@ export declare class IndividualStoreCouponService {
|
|
|
8
8
|
constructor();
|
|
9
9
|
create(data: CreateDTO): Promise<DocumentType<Model>>;
|
|
10
10
|
update(id: string, data: UpdateDTO): Promise<DocumentType<Model>>;
|
|
11
|
-
validateCoupon(data: ValidateCouponDTO,
|
|
11
|
+
validateCoupon(data: ValidateCouponDTO, coupon: DocumentType<Model>): Promise<{
|
|
12
|
+
isValid: boolean;
|
|
13
|
+
message?: string | undefined;
|
|
14
|
+
amountAfterCoupon?: number | undefined;
|
|
15
|
+
secondaryAmountAfterCoupon?: number | undefined;
|
|
16
|
+
discountAmount?: number | undefined;
|
|
17
|
+
secondaryDiscountAmount?: number | undefined;
|
|
18
|
+
discountCut?: {
|
|
19
|
+
companyCut?: number | undefined;
|
|
20
|
+
secondaryCompanyCut?: number | undefined;
|
|
21
|
+
shopCut?: number | undefined;
|
|
22
|
+
secondaryShopCut?: number | undefined;
|
|
23
|
+
} | undefined;
|
|
24
|
+
couponDetails?: Record<string, unknown> | undefined;
|
|
25
|
+
} | {
|
|
26
|
+
isValid: boolean;
|
|
27
|
+
message: string;
|
|
28
|
+
shop?: undefined;
|
|
29
|
+
} | {
|
|
30
|
+
isValid: boolean;
|
|
31
|
+
shop: mongoose.Document<unknown, import("@typegoose/typegoose/lib/types").BeAnObject, import("@lyxa.ai/core/dist/libraries/mongo/models/shop.model").Shop, import("@typegoose/typegoose/lib/types").BeAnyObject, {}> & Omit<import("@lyxa.ai/core/dist/libraries/mongo/models/shop.model").Shop & {
|
|
32
|
+
_id: mongoose.Types.ObjectId;
|
|
33
|
+
} & {
|
|
34
|
+
__v: number;
|
|
35
|
+
}, "typegooseName"> & import("@typegoose/typegoose/lib/types").IObjectWithTypegooseFunction;
|
|
36
|
+
message?: undefined;
|
|
37
|
+
}>;
|
|
12
38
|
}
|
|
13
39
|
export declare const individualStoreCouponService: IndividualStoreCouponService;
|
|
14
40
|
//# sourceMappingURL=individual-store-coupon.service.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"individual-store-coupon.service.d.ts","sourceRoot":"/","sources":["modules/coupon/services/individual-store-coupon.service.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,YAAY,
|
|
1
|
+
{"version":3,"file":"individual-store-coupon.service.d.ts","sourceRoot":"/","sources":["modules/coupon/services/individual-store-coupon.service.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAEN,qBAAqB,IAAI,KAAK,EAI9B,MAAM,4CAA4C,CAAC;AACpD,OAAO,EACN,8BAA8B,IAAI,SAAS,EAC3C,8BAA8B,IAAI,SAAS,EAC3C,iBAAiB,EACjB,MAAM,6BAA6B,CAAC;AAIrC,qBACa,4BAA4B;IACxC,OAAO,CAAC,KAAK,CAAC;IACd,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAmB;IACtD,OAAO,CAAC,UAAU,CAA2D;;IAYhE,MAAM,CAAC,IAAI,EAAE,SAAS,GAAG,OAAO,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC;IAWrD,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,GAAG,OAAO,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC;IAuBjE,cAAc,CAAC,IAAI,EAAE,iBAAiB,EAAE,MAAM,EAAE,YAAY,CAAC,KAAK,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;CAYhF;AAED,eAAO,MAAM,4BAA4B,8BAA8C,CAAC"}
|
|
@@ -45,11 +45,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
45
45
|
exports.individualStoreCouponService = exports.IndividualStoreCouponService = void 0;
|
|
46
46
|
const typedi_1 = __importStar(require("typedi"));
|
|
47
47
|
const server_1 = require("@trpc/server");
|
|
48
|
-
const typegoose_1 = require("@typegoose/typegoose");
|
|
49
48
|
const models_1 = require("@lyxa.ai/core/dist/libraries/mongo/models/");
|
|
50
|
-
const
|
|
51
|
-
const shared_1 = require("@lyxa.ai/core/dist/utilities/shared");
|
|
52
|
-
const enum_1 = require("@lyxa.ai/core/dist/utilities/enum");
|
|
49
|
+
const helper_service_1 = require("./helper.service");
|
|
53
50
|
let IndividualStoreCouponService = class IndividualStoreCouponService {
|
|
54
51
|
model;
|
|
55
52
|
shopModelForCoupon;
|
|
@@ -79,64 +76,15 @@ let IndividualStoreCouponService = class IndividualStoreCouponService {
|
|
|
79
76
|
}
|
|
80
77
|
return record;
|
|
81
78
|
}
|
|
82
|
-
async validateCoupon(data,
|
|
83
|
-
const
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
if (couponDocument?.shop?.toString() !== shopId.toString()) {
|
|
92
|
-
return {
|
|
93
|
-
isValid: false,
|
|
94
|
-
message: 'Coupon is not valid for this shop',
|
|
95
|
-
};
|
|
96
|
-
}
|
|
97
|
-
if (couponDocument.firstOrderOnly) {
|
|
98
|
-
const order = await this.orderModel.findOne({
|
|
99
|
-
user: new typegoose_1.mongoose.Types.ObjectId(data.user),
|
|
100
|
-
shop: new typegoose_1.mongoose.Types.ObjectId(data.shop),
|
|
101
|
-
status: { $ne: enum_1.RegularOrderStatus.CANCELLED },
|
|
102
|
-
});
|
|
103
|
-
if (order) {
|
|
104
|
-
return {
|
|
105
|
-
isValid: false,
|
|
106
|
-
message: 'This coupon is only valid for the first order in the shop',
|
|
107
|
-
};
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
let discountAmount = couponDocument.valueType == enum_1.ValueType.FIXED
|
|
111
|
-
? couponDocument.value
|
|
112
|
-
: (0, shared_1.roundBaseCurrency)((data.amountBeforeCoupon * couponDocument.value) / 100);
|
|
113
|
-
let secondaryDiscountAmount = couponDocument.valueType == enum_1.ValueType.FIXED
|
|
114
|
-
? await (0, currency_1.convertToSecondary)(couponDocument.value)
|
|
115
|
-
: (0, shared_1.roundSecondaryCurrency)((data.secondaryAmountBeforeCoupon * couponDocument.value) / 100);
|
|
116
|
-
if (couponDocument.isMaxDiscountLimitEnabled && couponDocument.maxDiscountLimit) {
|
|
117
|
-
discountAmount = Math.min(discountAmount, couponDocument.maxDiscountLimit);
|
|
118
|
-
secondaryDiscountAmount = Math.min(secondaryDiscountAmount, await (0, currency_1.convertToSecondary)(couponDocument.maxDiscountLimit));
|
|
119
|
-
}
|
|
120
|
-
if (discountAmount > data.amountBeforeCoupon) {
|
|
121
|
-
discountAmount = data.amountBeforeCoupon;
|
|
122
|
-
}
|
|
123
|
-
if (secondaryDiscountAmount > data.secondaryAmountBeforeCoupon) {
|
|
124
|
-
secondaryDiscountAmount = data.secondaryAmountBeforeCoupon;
|
|
125
|
-
}
|
|
126
|
-
const isShopCoverExpenses = couponDocument.isShopCoverExpenses;
|
|
127
|
-
return {
|
|
128
|
-
isValid: true,
|
|
129
|
-
discountAmount,
|
|
130
|
-
secondaryDiscountAmount,
|
|
131
|
-
amountAfterCoupon: (0, shared_1.roundBaseCurrency)(data.amountBeforeCoupon - discountAmount),
|
|
132
|
-
secondaryAmountAfterCoupon: (0, shared_1.roundSecondaryCurrency)(data.secondaryAmountBeforeCoupon - secondaryDiscountAmount),
|
|
133
|
-
discountCut: {
|
|
134
|
-
companyCut: isShopCoverExpenses ? 0 : discountAmount,
|
|
135
|
-
secondaryCompanyCut: isShopCoverExpenses ? 0 : secondaryDiscountAmount,
|
|
136
|
-
shopCut: isShopCoverExpenses ? discountAmount : 0,
|
|
137
|
-
secondaryShopCut: isShopCoverExpenses ? secondaryDiscountAmount : 0,
|
|
138
|
-
},
|
|
139
|
-
};
|
|
79
|
+
async validateCoupon(data, coupon) {
|
|
80
|
+
const validation = await helper_service_1.couponHelperService.validateShopEligibility({
|
|
81
|
+
data,
|
|
82
|
+
coupon
|
|
83
|
+
});
|
|
84
|
+
if (!validation.isValid)
|
|
85
|
+
return validation;
|
|
86
|
+
const { discountAmount, secondaryDiscountAmount } = await helper_service_1.couponHelperService.calculateCouponDiscount(data, coupon);
|
|
87
|
+
return helper_service_1.couponHelperService.buildCouponResponse(data, discountAmount, secondaryDiscountAmount, coupon.isShopCoverExpenses ?? false);
|
|
140
88
|
}
|
|
141
89
|
};
|
|
142
90
|
exports.IndividualStoreCouponService = IndividualStoreCouponService;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"individual-store-coupon.service.js","sourceRoot":"/","sources":["modules/coupon/services/individual-store-coupon.service.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,iDAA4C;AAC5C,yCAAyC;
|
|
1
|
+
{"version":3,"file":"individual-store-coupon.service.js","sourceRoot":"/","sources":["modules/coupon/services/individual-store-coupon.service.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,iDAA4C;AAC5C,yCAAyC;AAEzC,uEAMoD;AAOpD,qDAAuD;AAGhD,IAAM,4BAA4B,GAAlC,MAAM,4BAA4B;IAChC,KAAK,CAAC;IACG,kBAAkB,CAAmB;IAC9C,UAAU,CAA2D;IAE7E;QACC,IAAI,CAAC,KAAK,GAAG,mCAA0B,CAAC;QACxC,IAAI,CAAC,kBAAkB,GAAG,kBAA6B,CAAC;QACxD,IAAI,CAAC,UAAU,GAAG,0BAA6E,CAAC;IACjG,CAAC;IAMM,KAAK,CAAC,MAAM,CAAC,IAAe;QAClC,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QAEvC,OAAO,MAAM,CAAC;IACf,CAAC;IAOM,KAAK,CAAC,MAAM,CAAC,EAAU,EAAE,IAAe;QAC9C,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,gBAAgB,CAC/C;YACC,GAAG,EAAE,EAAE;YACP,SAAS,EAAE,IAAI;SACf,EACD,IAAI,EACJ;YACC,GAAG,EAAE,IAAI;YACT,aAAa,EAAE,IAAI;SACnB,CACD,CAAC;QAEF,IAAI,CAAC,MAAM,EAAE,CAAC;YACb,MAAM,IAAI,kBAAS,CAAC;gBACnB,IAAI,EAAE,WAAW;gBACjB,OAAO,EAAE,kBAAkB;aAC3B,CAAC,CAAC;QACJ,CAAC;QAED,OAAO,MAAM,CAAC;IACf,CAAC;IAEM,KAAK,CAAC,cAAc,CAAC,IAAuB,EAAE,MAA2B;QAC/E,MAAM,UAAU,GAAG,MAAM,oCAAmB,CAAC,uBAAuB,CAAC;YACpE,IAAI;YACJ,MAAM;SACN,CAAC,CAAC;QAEH,IAAI,CAAC,UAAU,CAAC,OAAO;YAAE,OAAO,UAAU,CAAC;QAE3C,MAAM,EAAE,cAAc,EAAE,uBAAuB,EAAE,GAAG,MAAM,oCAAmB,CAAC,uBAAuB,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QAEpH,OAAO,oCAAmB,CAAC,mBAAmB,CAAC,IAAI,EAAE,cAAc,EAAE,uBAAuB,EAAE,MAAM,CAAC,mBAAmB,IAAI,KAAK,CAAC,CAAC;IACpI,CAAC;CACD,CAAA;AA7DY,oEAA4B;uCAA5B,4BAA4B;IADxC,IAAA,gBAAO,GAAE;;GACG,4BAA4B,CA6DxC;AAEY,QAAA,4BAA4B,GAAG,gBAAS,CAAC,GAAG,CAAC,4BAA4B,CAAC,CAAC","sourcesContent":["import Container, { Service } from 'typedi';\nimport { TRPCError } from '@trpc/server';\nimport { DocumentType, mongoose } from '@typegoose/typegoose';\nimport {\n\tIndividualStoreCouponModel,\n\tIndividualStoreCoupon as Model,\n\tRegularOrder,\n\tRegularOrderModel,\n\tShopModel,\n} from '@lyxa.ai/core/dist/libraries/mongo/models/';\nimport {\n\tCreateIndividualStoreCouponDTO as CreateDTO,\n\tUpdateIndividualStoreCouponDTO as UpdateDTO,\n\tValidateCouponDTO,\n} from '@modules/coupon/validations';\nimport { SoftDeleteModel } from '@lyxa.ai/core/dist/libraries/mongo/plugins/soft-delete-plugin';\nimport { couponHelperService } from './helper.service';\n\n@Service()\nexport class IndividualStoreCouponService {\n\tprivate model;\n\tprivate readonly shopModelForCoupon: typeof ShopModel;\n\tprivate orderModel: typeof RegularOrderModel & SoftDeleteModel<RegularOrder>;\n\n\tconstructor() {\n\t\tthis.model = IndividualStoreCouponModel;\n\t\tthis.shopModelForCoupon = ShopModel as typeof ShopModel;\n\t\tthis.orderModel = RegularOrderModel as typeof RegularOrderModel & SoftDeleteModel<RegularOrder>;\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: CreateDTO): Promise<DocumentType<Model>> {\n\t\tconst coupon = this.model.create(data);\n\n\t\treturn coupon;\n\t}\n\n\t/**\n\t * Update record\n\t * @param id ID of the record\n\t * @param data Data to update\n\t */\n\tpublic async update(id: string, data: UpdateDTO): Promise<DocumentType<Model>> {\n\t\tconst record = await this.model.findOneAndUpdate(\n\t\t\t{\n\t\t\t\t_id: id,\n\t\t\t\tdeletedAt: null,\n\t\t\t},\n\t\t\tdata,\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 (!record) {\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\treturn record;\n\t}\n\n\tpublic async validateCoupon(data: ValidateCouponDTO, coupon: DocumentType<Model>) {\n\t\tconst validation = await couponHelperService.validateShopEligibility({\n\t\t\tdata,\n\t\t\tcoupon\n\t\t});\n\n\t\tif (!validation.isValid) return validation;\n\n\t\tconst { discountAmount, secondaryDiscountAmount } = await couponHelperService.calculateCouponDiscount(data, coupon);\n\n\t\treturn couponHelperService.buildCouponResponse(data, discountAmount, secondaryDiscountAmount, coupon.isShopCoverExpenses ?? false);\n\t}\n}\n\nexport const individualStoreCouponService = Container.get(IndividualStoreCouponService);\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CouponRepository.d.ts","sourceRoot":"/","sources":["modules/coupon/services/patterns/repository/CouponRepository.ts"],"names":[],"mappings":"AAUA,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAEhD,OAAO,EAEN,QAAQ,EAIR,MAAM,mCAAmC,CAAC;AAK3C,qBAAa,gBAAgB;IAC5B,OAAO,CAAC,QAAQ,CAAC,KAAK,CAA+C;IACrE,OAAO,CAAC,QAAQ,CAAC,SAAS,CAA2C;IACrE,OAAO,CAAC,QAAQ,CAAC,qBAAqB,CAAiE;IACvG,OAAO,CAAC,cAAc,CAAoD;;IAS1E,OAAO,KAAK,aAAa,GAKxB;IAEY,cAAc,CAC1B,IAAI,EAAE,QAAQ,CAAC,KAAK,CAAC,QAAQ,GAAG,SAAS,EACzC,IAAI,EAAE,QAAQ,CAAC,KAAK,CAAC,QAAQ,GAAG,SAAS,EACzC,QAAQ,EAAE,QAAQ,GAAG,SAAS,GAC5B,OAAO,CAAC,GAAG,CAAC;IAoVR,qBAAqB,CAAC,OAAO,EAAE,GAAG,GAAG,GAAG;IAQxC,kBAAkB,CAAC,OAAO,EAAE,GAAG,EAAE,GAAG,GAAG,EAAE;IA6ChD,OAAO,CAAC,cAAc;
|
|
1
|
+
{"version":3,"file":"CouponRepository.d.ts","sourceRoot":"/","sources":["modules/coupon/services/patterns/repository/CouponRepository.ts"],"names":[],"mappings":"AAUA,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAEhD,OAAO,EAEN,QAAQ,EAIR,MAAM,mCAAmC,CAAC;AAK3C,qBAAa,gBAAgB;IAC5B,OAAO,CAAC,QAAQ,CAAC,KAAK,CAA+C;IACrE,OAAO,CAAC,QAAQ,CAAC,SAAS,CAA2C;IACrE,OAAO,CAAC,QAAQ,CAAC,qBAAqB,CAAiE;IACvG,OAAO,CAAC,cAAc,CAAoD;;IAS1E,OAAO,KAAK,aAAa,GAKxB;IAEY,cAAc,CAC1B,IAAI,EAAE,QAAQ,CAAC,KAAK,CAAC,QAAQ,GAAG,SAAS,EACzC,IAAI,EAAE,QAAQ,CAAC,KAAK,CAAC,QAAQ,GAAG,SAAS,EACzC,QAAQ,EAAE,QAAQ,GAAG,SAAS,GAC5B,OAAO,CAAC,GAAG,CAAC;IAoVR,qBAAqB,CAAC,OAAO,EAAE,GAAG,GAAG,GAAG;IAQxC,kBAAkB,CAAC,OAAO,EAAE,GAAG,EAAE,GAAG,GAAG,EAAE;IA6ChD,OAAO,CAAC,cAAc;IAkBtB,OAAO,CAAC,iBAAiB;IA0DzB,OAAO,CAAC,2BAA2B;CAyGnC"}
|
|
@@ -345,20 +345,23 @@ class CouponRepository {
|
|
|
345
345
|
if (coupon.isOrderLimitPerUserEnabled && coupon.orderLimitPerUser > 0) {
|
|
346
346
|
validityParts.push(`applied on ${coupon.orderLimitPerUser} order`);
|
|
347
347
|
}
|
|
348
|
-
if (coupon.couponType === enum_1.CouponType.REFERRAL_CODE || coupon.couponType === enum_1.CouponType.REFERRAL_REWARD) {
|
|
349
|
-
validityParts = [];
|
|
350
|
-
validityParts.push(`Applied on 1 Order`);
|
|
351
|
-
}
|
|
352
348
|
coupon.couponValidityLabel = validityParts.join('. ');
|
|
353
349
|
return coupon;
|
|
354
350
|
});
|
|
355
351
|
return resultsWithLabels;
|
|
356
352
|
}
|
|
357
353
|
formatCurrency(value, secondaryCurrencyValue) {
|
|
354
|
+
const formatterUSD = new Intl.NumberFormat('en-US', {
|
|
355
|
+
minimumFractionDigits: 0,
|
|
356
|
+
maximumFractionDigits: 2,
|
|
357
|
+
});
|
|
358
|
+
const formatterLBP = new Intl.NumberFormat('en-US', {
|
|
359
|
+
minimumFractionDigits: 0,
|
|
360
|
+
});
|
|
358
361
|
if (secondaryCurrencyValue !== null && secondaryCurrencyValue !== undefined) {
|
|
359
|
-
return 'LBP ' +
|
|
362
|
+
return 'LBP ' + formatterLBP.format(Number(secondaryCurrencyValue));
|
|
360
363
|
}
|
|
361
|
-
return '$' +
|
|
364
|
+
return '$' + formatterUSD.format(Number(value ?? 0));
|
|
362
365
|
}
|
|
363
366
|
filterShopCoupons(shop, itemType) {
|
|
364
367
|
return {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CouponRepository.js","sourceRoot":"/","sources":["modules/coupon/services/patterns/repository/CouponRepository.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n\tCoupon,\n\tCouponModel,\n\tgetCoreUserModel,\n\tReferralSetting,\n\tReferralSettingModel,\n\tUser,\n\tUserModel,\n} from '@lyxa.ai/core/dist/libraries/mongo/models';\nimport { SoftDeleteModel } from '@lyxa.ai/core/dist/libraries/mongo/plugins/soft-delete-plugin';\nimport { mongoose } from '@typegoose/typegoose';\nimport { getRoundSecondaryCurrencyStage } from '@lyxa.ai/core/dist/utilities/pipelines/common-pipeline-functions';\nimport {\n\tCouponType,\n\tItemType,\n\tRegularOrderStatus,\n\tStatus,\n\tValueType,\n} from '@lyxa.ai/core/dist/utilities/enum';\nimport { getExchangeRate } from '@lyxa.ai/core/dist/utilities/currency';\nimport { roundSecondaryCurrency } from '@lyxa.ai/core/dist/utilities/shared';\nimport { dayjs } from '@lyxa.ai/core/dist/utilities/dayjs';\n\nexport class CouponRepository {\n\tprivate readonly model: typeof CouponModel & SoftDeleteModel<Coupon>;\n\tprivate readonly userModel: typeof UserModel & SoftDeleteModel<User>;\n\tprivate readonly referralSettingsModel: typeof ReferralSettingModel & SoftDeleteModel<ReferralSetting>;\n\tprivate _coreUserModel: ReturnType<typeof getCoreUserModel> | null = null;\n\n\tconstructor() {\n\t\tthis.model = CouponModel as typeof CouponModel & SoftDeleteModel<Coupon>;\n\t\tthis.userModel = UserModel as typeof UserModel & SoftDeleteModel<User>;\n\t\tthis.referralSettingsModel = ReferralSettingModel as typeof ReferralSettingModel &\n\t\t\tSoftDeleteModel<ReferralSetting>;\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\tpublic async getUserCoupons(\n\t\tuser: mongoose.Types.ObjectId | undefined,\n\t\tshop: mongoose.Types.ObjectId | undefined,\n\t\titemType: ItemType | undefined\n\t): Promise<any> {\n\t\tconst exchangeRate = await getExchangeRate();\n\n\t\tconst referralSettings = await this.referralSettingsModel.findOne();\n\n\t\tconst secondaryReferralReceiverValue =\n\t\t\treferralSettings?.receiver?.valueType == ValueType.PERCENTAGE\n\t\t\t\t? null\n\t\t\t\t: roundSecondaryCurrency((referralSettings?.receiver?.value ?? 0) * exchangeRate);\n\n\t\tconst secondaryReferralReceiverMinOrderAmount = roundSecondaryCurrency(\n\t\t\t(referralSettings?.receiver?.minimumOrderValue ?? 0) * exchangeRate\n\t\t);\n\n\t\tconst pipeline: mongoose.PipelineStage[] = [\n\t\t\t// Match the user\n\t\t\t{\n\t\t\t\t$match: { _id: user },\n\t\t\t},\n\n\t\t\t// Lookup coupon documents\n\t\t\t{\n\t\t\t\t$lookup: {\n\t\t\t\t\tfrom: 'coupons',\n\t\t\t\t\tlocalField: 'coupons',\n\t\t\t\t\tforeignField: '_id',\n\t\t\t\t\tas: 'couponDocs',\n\t\t\t\t\tpipeline: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t$match: {\n\t\t\t\t\t\t\t\t$expr: {\n\t\t\t\t\t\t\t\t\t$and: [\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t$eq: [{ $ifNull: ['$status', Status.ACTIVE] }, Status.ACTIVE],\n\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\t$lte: [{ $ifNull: ['$duration.start', dayjs().toDate()] }, dayjs().toDate()],\n\t\t\t\t\t\t\t\t\t\t},\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},\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t$lookup: {\n\t\t\t\t\t\t\t\tfrom: 'users',\n\t\t\t\t\t\t\t\tlocalField: 'referralUser',\n\t\t\t\t\t\t\t\tforeignField: '_id',\n\t\t\t\t\t\t\t\tas: 'referralUser',\n\t\t\t\t\t\t\t\tpipeline: [{ $project: { coreUser: 1 } }],\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t$lookup: {\n\t\t\t\t\t\t\t\tfrom: 'users',\n\t\t\t\t\t\t\t\tlocalField: 'influencer',\n\t\t\t\t\t\t\t\tforeignField: '_id',\n\t\t\t\t\t\t\t\tas: 'influencer',\n\t\t\t\t\t\t\t\tpipeline: [{ $project: { coreUser: 1 } }],\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t$lookup: {\n\t\t\t\t\t\t\t\tfrom: 'shops',\n\t\t\t\t\t\t\t\tlocalField: 'shop',\n\t\t\t\t\t\t\t\tforeignField: '_id',\n\t\t\t\t\t\t\t\tas: 'shop',\n\t\t\t\t\t\t\t\tpipeline: [{ $project: { name: 1 } }],\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t$unwind: { path: '$shop', preserveNullAndEmptyArrays: true },\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t$unwind: { path: '$referralUser', preserveNullAndEmptyArrays: true },\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t$unwind: { path: '$influencer', preserveNullAndEmptyArrays: true },\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t$addFields: {\n\t\t\t\t\t\t\t\treferringUser: {\n\t\t\t\t\t\t\t\t\t$ifNull: ['$referralUser.coreUser', '$influencer.coreUser'],\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t$project: { referralUser: 0, influencer: 0 },\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t},\n\t\t\t},\n\n\t\t\t// Lookup orders containing coupons for this user\n\t\t\t{\n\t\t\t\t$lookup: {\n\t\t\t\t\tfrom: 'orders',\n\t\t\t\t\tlet: { userId: '$_id' },\n\t\t\t\t\tpipeline: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t$match: {\n\t\t\t\t\t\t\t\t$expr: { $eq: ['$user', '$$userId'] },\n\t\t\t\t\t\t\t\t'adjustedFinance.coupon': { $exists: true },\n\t\t\t\t\t\t\t\tstatus: { $ne: RegularOrderStatus.CANCELLED },\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t$lookup: {\n\t\t\t\t\t\t\t\tfrom: 'coupons',\n\t\t\t\t\t\t\t\tlocalField: 'adjustedFinance.coupon.coupon',\n\t\t\t\t\t\t\t\tforeignField: '_id',\n\t\t\t\t\t\t\t\tas: 'couponInfo',\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t$unwind: '$couponInfo',\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t$group: {\n\t\t\t\t\t\t\t\t_id: '$adjustedFinance.coupon.coupon',\n\t\t\t\t\t\t\t\tsnap: { $first: '$couponInfo' },\n\t\t\t\t\t\t\t\tcount: { $sum: 1 },\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\tas: 'couponUsage',\n\t\t\t\t},\n\t\t\t},\n\n\t\t\t// Unwind coupons to classify individually\n\t\t\t{\n\t\t\t\t$unwind: '$couponDocs',\n\t\t\t},\n\n\t\t\t// Filter individual shop and shops categories coupons\n\t\t\tthis.filterShopCoupons(shop, itemType),\n\n\t\t\t// Filter first order only coupons\n\t\t\t...this.filterFirstOrderOnlyCoupons(shop),\n\n\t\t\t// Join usage count for this coupon\n\t\t\t{\n\t\t\t\t$addFields: {\n\t\t\t\t\tusageData: {\n\t\t\t\t\t\t$arrayElemAt: [\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t$filter: {\n\t\t\t\t\t\t\t\t\tinput: '$couponUsage',\n\t\t\t\t\t\t\t\t\tas: 'cu',\n\t\t\t\t\t\t\t\t\tcond: { $eq: ['$$cu._id', '$couponDocs._id'] },\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t0,\n\t\t\t\t\t\t],\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\n\t\t\t// Classify expiration exactly like isCouponExpired()\n\t\t\t{\n\t\t\t\t$addFields: {\n\t\t\t\t\tisExpired: {\n\t\t\t\t\t\t$or: [\n\t\t\t\t\t\t\t// true only if expirationReason is a non-empty string\n\t\t\t\t\t\t\t{ $gt: [{ $strLenCP: { $ifNull: ['$couponDocs.expirationReason', ''] } }, 0] },\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t$and: [\n\t\t\t\t\t\t\t\t\t{ $ifNull: ['$couponDocs.duration.end', false] },\n\t\t\t\t\t\t\t\t\t{ $lt: ['$couponDocs.duration.end', '$$NOW'] }, // consistent “now”\n\t\t\t\t\t\t\t\t],\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\tusedCount: { $ifNull: ['$usageData.count', 0] },\n\t\t\t\t},\n\t\t\t},\n\n\t\t\t// Add exchange rate and secondary currency rounding factor\n\t\t\t{\n\t\t\t\t$addFields: {\n\t\t\t\t\texchangeRate: exchangeRate,\n\t\t\t\t},\n\t\t\t},\n\n\t\t\t// Compute and add secondary currency values to coupon documents\n\t\t\t{\n\t\t\t\t$addFields: {\n\t\t\t\t\t// base value\n\t\t\t\t\t'couponDocs.value': {\n\t\t\t\t\t\t$switch: {\n\t\t\t\t\t\t\tbranches: [\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tcase: { $eq: ['$couponDocs.couponType', CouponType.REFERRAL_CODE] },\n\t\t\t\t\t\t\t\t\tthen: referralSettings?.receiver?.value ?? 0,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\tdefault: '$couponDocs.value',\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\n\t\t\t\t\t// value type\n\t\t\t\t\t'couponDocs.valueType': {\n\t\t\t\t\t\t$switch: {\n\t\t\t\t\t\t\tbranches: [\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tcase: { $eq: ['$couponDocs.couponType', CouponType.REFERRAL_CODE] },\n\t\t\t\t\t\t\t\t\tthen: referralSettings?.receiver?.valueType ?? 0,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\tdefault: '$couponDocs.valueType',\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\n\t\t\t\t\t'couponDocs.secondaryCurrencyValue': {\n\t\t\t\t\t\t$cond: [\n\t\t\t\t\t\t\t// If valueType is percentage => null always\n\t\t\t\t\t\t\t{ $eq: ['$couponDocs.valueType', ValueType.PERCENTAGE] },\n\t\t\t\t\t\t\tnull,\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t$switch: {\n\t\t\t\t\t\t\t\t\tbranches: [\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\tcase: { $eq: ['$couponDocs.couponType', CouponType.REFERRAL_CODE] },\n\t\t\t\t\t\t\t\t\t\t\tthen: secondaryReferralReceiverValue,\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\t\tdefault: getRoundSecondaryCurrencyStage({\n\t\t\t\t\t\t\t\t\t\t$multiply: ['$couponDocs.value', exchangeRate],\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},\n\t\t\t\t\t\t],\n\t\t\t\t\t},\n\n\t\t\t\t\t'couponDocs.secondaryCurrencyMaxDiscountLimit': {\n\t\t\t\t\t\t$switch: {\n\t\t\t\t\t\t\tbranches: [\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tcase: { $eq: ['$couponDocs.couponType', CouponType.REFERRAL_CODE] },\n\t\t\t\t\t\t\t\t\tthen: null,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\tdefault: getRoundSecondaryCurrencyStage({\n\t\t\t\t\t\t\t\t$multiply: ['$couponDocs.maxDiscountLimit', exchangeRate],\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\t'couponDocs.secondaryCurrencyMinOrderValue': {\n\t\t\t\t\t\t$switch: {\n\t\t\t\t\t\t\tbranches: [\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tcase: { $eq: ['$couponDocs.couponType', CouponType.REFERRAL_CODE] },\n\t\t\t\t\t\t\t\t\tthen: secondaryReferralReceiverMinOrderAmount,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\tdefault: getRoundSecondaryCurrencyStage({\n\t\t\t\t\t\t\t\t$multiply: ['$couponDocs.minOrderValue', exchangeRate],\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\n\t\t\t// Category logic\n\t\t\t{\n\t\t\t\t$addFields: {\n\t\t\t\t\tcategory: {\n\t\t\t\t\t\t$cond: [\n\t\t\t\t\t\t\t'$isExpired',\n\t\t\t\t\t\t\t'expired',\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t$cond: [\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t$and: [\n\t\t\t\t\t\t\t\t\t\t\t{ $gt: ['$usedCount', 0] },\n\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t$or: [\n\t\t\t\t\t\t\t\t\t\t\t\t\t{ $not: ['$couponDocs.orderLimitPerUser'] },\n\t\t\t\t\t\t\t\t\t\t\t\t\t{ $lt: ['$usedCount', '$couponDocs.orderLimitPerUser'] },\n\t\t\t\t\t\t\t\t\t\t\t\t],\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},\n\t\t\t\t\t\t\t\t\t'available',\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t$cond: [{ $gt: ['$usedCount', 0] }, 'used', 'available'],\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},\n\t\t\t\t\t\t],\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\n\t\t\t// Group into arrays\n\t\t\t{\n\t\t\t\t$group: {\n\t\t\t\t\t_id: '$_id',\n\t\t\t\t\tavailable: {\n\t\t\t\t\t\t$push: {\n\t\t\t\t\t\t\t$cond: [{ $eq: ['$category', 'available'] }, '$couponDocs', '$$REMOVE'],\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tused: {\n\t\t\t\t\t\t$push: {\n\t\t\t\t\t\t\t$cond: [{ $eq: ['$category', 'used'] }, '$usageData.snap', '$$REMOVE'],\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\texpired: {\n\t\t\t\t\t\t$push: {\n\t\t\t\t\t\t\t$cond: [{ $eq: ['$category', 'expired'] }, '$couponDocs', '$$REMOVE'],\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\t{\n\t\t\t\t$project: {\n\t\t\t\t\t_id: 0,\n\t\t\t\t},\n\t\t\t},\n\t\t];\n\n\t\tconst [results] = await this.userModel.aggregate(pipeline);\n\n\t\tif (!results) {\n\t\t\treturn {\n\t\t\t\tavailable: [],\t\n\t\t\t\tused: [],\n\t\t\t\texpired: [],\n\t\t\t};\n\t\t}\n\n\t\tconst populatedResults = await this.userModel.populate(results, {\n\t\t\tpath: 'available.referringUser',\n\t\t\tmodel: this.coreUserModel,\n\t\t\tselect: { _id: 0, name: 1 },\n\t\t});\n\n\t\treturn populatedResults;\n\t}\n\n\tpublic addLabelsToAllCoupons(coupons: any): any {\n\t\treturn {\n\t\t\tavailable: this.addLabelsToCoupons(coupons.available).reverse(), // Just to make newly added coupon at the top\n\t\t\tused: this.addLabelsToCoupons(coupons.used).reverse(), // Just to make newly added coupon at the top\n\t\t\texpired: this.addLabelsToCoupons(coupons.expired).reverse(), // Just to make newly added coupon at the top\n\t\t};\n\t}\n\n\tpublic addLabelsToCoupons(coupons: any[]): any[] {\n\t\tconst resultsWithLabels = coupons.map(coupon => {\n\t\t\t// couponOfferLabel\n\t\t\tconst valuePart =\n\t\t\t\tcoupon.valueType === 'fixed'\n\t\t\t\t\t? this.formatCurrency(coupon.value, coupon.secondaryCurrencyValue)\n\t\t\t\t\t: `${coupon.value}%`;\n\n\t\t\tconst maxDiscountPart =\n\t\t\t\tcoupon.isMaxDiscountLimitEnabled && coupon.maxDiscountLimit > 0\n\t\t\t\t\t? ` up to ${this.formatCurrency(coupon.maxDiscountLimit, coupon.secondaryCurrencyMaxDiscountLimit)}`\n\t\t\t\t\t: '';\n\n\t\t\tconst influencerPart = coupon.referringUser ? ` (Referred by ${coupon.referringUser.name})` : '';\n\n\t\t\tcoupon.couponOfferLabel = `Save ${valuePart}${maxDiscountPart}${influencerPart}`;\n\n\t\t\t// couponValidityLabel\n\t\t\tlet validityParts: string[] = [];\n\n\t\t\t// 1. Minimum Order\n\t\t\tif (coupon.isMinOrderValueEnabled && coupon.minOrderValue > 0) {\n\t\t\t\tvalidityParts.push(\n\t\t\t\t\t`Minimum order ${this.formatCurrency(coupon.minOrderValue, coupon.secondaryCurrencyMinOrderValue)}`\n\t\t\t\t);\n\t\t\t}\n\n\t\t\t// 2. Order Limit\n\t\t\tif (coupon.isOrderLimitPerUserEnabled && coupon.orderLimitPerUser > 0) {\n\t\t\t\tvalidityParts.push(`applied on ${coupon.orderLimitPerUser} order`);\n\t\t\t}\n\n\t\t\tif(coupon.couponType === CouponType.REFERRAL_CODE || coupon.couponType === CouponType.REFERRAL_REWARD){\n\t\t\t\tvalidityParts = [];\n\t\t\t\tvalidityParts.push(`Applied on 1 Order`);\n\t\t\t}\n\n\t\t\tcoupon.couponValidityLabel = validityParts.join('. ');\n\n\t\t\treturn coupon;\n\t\t});\n\n\t\treturn resultsWithLabels;\n\t}\n\n\tprivate formatCurrency(value: any, secondaryCurrencyValue: any) {\n\t\tif (secondaryCurrencyValue !== null && secondaryCurrencyValue !== undefined) {\n\t\t\treturn 'LBP ' + String(secondaryCurrencyValue);\n\t\t}\n\t\treturn '$' + String(value ?? 0);\n\t}\n\n\tprivate filterShopCoupons(\n\t\tshop: mongoose.Types.ObjectId | undefined,\n\t\titemType: ItemType | undefined\n\t): mongoose.PipelineStage {\n\t\treturn {\n\t\t\t$match: {\n\t\t\t\t$expr: {\n\t\t\t\t\t// If shopId is undefined → skip filtering (always true)\n\t\t\t\t\t$cond: [\n\t\t\t\t\t\t{ $not: [shop] }, // means shopId is null/undefined\n\t\t\t\t\t\ttrue, // skip filtering\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t$or: [\n\t\t\t\t\t\t\t\t// Case 1: INDIVIDUAL_STORE → shop must match\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t$and: [\n\t\t\t\t\t\t\t\t\t\t{ $eq: ['$couponDocs.couponType', CouponType.INDIVIDUAL_STORE] },\n\t\t\t\t\t\t\t\t\t\t{ $eq: ['$couponDocs.shop._id', shop] },\n\t\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\t},\n\n\t\t\t\t\t\t\t\t// Case 2: SHOP_CATEGORY\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t$and: [\n\t\t\t\t\t\t\t\t\t\t{ $eq: ['$couponDocs.couponType', CouponType.SHOPS_CATEGORIES] },\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t$or: [\n\t\t\t\t\t\t\t\t\t\t\t\t// itemType matches\n\t\t\t\t\t\t\t\t\t\t\t\t{ $eq: ['$couponDocs.itemType', itemType] },\n\n\t\t\t\t\t\t\t\t\t\t\t\t// or shopId is inside couponDocs.shops[]\n\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t$in: [shop, { $ifNull: ['$couponDocs.shops', []] }],\n\t\t\t\t\t\t\t\t\t\t\t\t},\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],\n\t\t\t\t\t\t\t\t},\n\n\t\t\t\t\t\t\t\t// Case 3: All other coupon types → keep\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t$not: [\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t$in: [\n\t\t\t\t\t\t\t\t\t\t\t\t'$couponDocs.couponType',\n\t\t\t\t\t\t\t\t\t\t\t\t[CouponType.INDIVIDUAL_STORE, CouponType.SHOPS_CATEGORIES],\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],\n\t\t\t\t\t\t\t\t},\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\t}\n\n\tprivate filterFirstOrderOnlyCoupons(shop?: mongoose.Types.ObjectId): mongoose.PipelineStage[] {\n\t\treturn [\n\t\t\t{\n\t\t\t\t$lookup: {\n\t\t\t\t\tfrom: 'orders',\n\t\t\t\t\tlet: {\n\t\t\t\t\t\tuserId: '$_id',\n\t\t\t\t\t\tshopId: shop ?? '$couponDocs.shop._id',\n\t\t\t\t\t\tcouponShops: { $ifNull: ['$couponDocs.shops', []] },\n\t\t\t\t\t},\n\t\t\t\t\tpipeline: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t$match: {\n\t\t\t\t\t\t\t\t$expr: {\n\t\t\t\t\t\t\t\t\t$and: [\n\t\t\t\t\t\t\t\t\t\t{ $eq: ['$user', '$$userId'] },\n\n\t\t\t\t\t\t\t\t\t\t{ $ne: ['$status', RegularOrderStatus.CANCELLED] },\n\n\t\t\t\t\t\t\t\t\t\t// If shop is provided → only that shop\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t$cond: [\n\t\t\t\t\t\t\t\t\t\t\t\t{ $ne: ['$$shopId', null] },\n\t\t\t\t\t\t\t\t\t\t\t\t{ $eq: ['$shop', '$$shopId'] },\n\n\t\t\t\t\t\t\t\t\t\t\t\t// Else → any shop in coupon.shops\n\t\t\t\t\t\t\t\t\t\t\t\t{ $in: ['$shop', '$$couponShops'] },\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],\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t$group: {\n\t\t\t\t\t\t\t\t_id: null,\n\t\t\t\t\t\t\t\torderedShops: { $addToSet: '$shop' },\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\tas: 'orderStats',\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\t$addFields: {\n\t\t\t\t\torderedShops: {\n\t\t\t\t\t\t$ifNull: [{ $arrayElemAt: ['$orderStats.orderedShops', 0] }, []],\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\t$addFields: {\n\t\t\t\t\t// Individual store logic\n\t\t\t\t\thasOrderedFromStore: {\n\t\t\t\t\t\t$cond: [\n\t\t\t\t\t\t\t{ $eq: ['$couponDocs.couponType', CouponType.INDIVIDUAL_STORE] },\n\t\t\t\t\t\t\t{ $in: [shop ?? '$couponDocs.shop._id', '$orderedShops'] },\n\t\t\t\t\t\t\tfalse,\n\t\t\t\t\t\t],\n\t\t\t\t\t},\n\n\t\t\t\t\t// Multiple store logic\n\t\t\t\t\thasUnusedShopInCategory: {\n\t\t\t\t\t\t$cond: [\n\t\t\t\t\t\t\t{ $eq: ['$couponDocs.couponType', CouponType.SHOPS_CATEGORIES] },\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t$cond: [\n\t\t\t\t\t\t\t\t\t{ $ifNull: [shop, false] },\n\t\t\t\t\t\t\t\t\t// shop provided → hide if user has ordered from this shop\n\t\t\t\t\t\t\t\t\t{ $in: [shop, '$orderedShops'] },\n\t\t\t\t\t\t\t\t\t// no shop provided → hide if no unused shops\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t$eq: [\n\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t$size: { $setDifference: [{ $ifNull: ['$couponDocs.shops', []] }, '$orderedShops'] },\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t0,\n\t\t\t\t\t\t\t\t\t\t],\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},\n\t\t\t\t\t\t\tfalse,\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\t{\n\t\t\t\t$match: {\n\t\t\t\t\t$expr: {\n\t\t\t\t\t\t$not: {\n\t\t\t\t\t\t\t$and: [\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t$in: ['$couponDocs.couponType', [CouponType.INDIVIDUAL_STORE, CouponType.SHOPS_CATEGORIES]],\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{ $eq: ['$couponDocs.firstOrderOnly', true] },\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t$or: ['$hasOrderedFromStore', '$hasUnusedShopInCategory'],\n\t\t\t\t\t\t\t\t},\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\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"CouponRepository.js","sourceRoot":"/","sources":["modules/coupon/services/patterns/repository/CouponRepository.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n\tCoupon,\n\tCouponModel,\n\tgetCoreUserModel,\n\tReferralSetting,\n\tReferralSettingModel,\n\tUser,\n\tUserModel,\n} from '@lyxa.ai/core/dist/libraries/mongo/models';\nimport { SoftDeleteModel } from '@lyxa.ai/core/dist/libraries/mongo/plugins/soft-delete-plugin';\nimport { mongoose } from '@typegoose/typegoose';\nimport { getRoundSecondaryCurrencyStage } from '@lyxa.ai/core/dist/utilities/pipelines/common-pipeline-functions';\nimport {\n\tCouponType,\n\tItemType,\n\tRegularOrderStatus,\n\tStatus,\n\tValueType,\n} from '@lyxa.ai/core/dist/utilities/enum';\nimport { getExchangeRate } from '@lyxa.ai/core/dist/utilities/currency';\nimport { roundSecondaryCurrency } from '@lyxa.ai/core/dist/utilities/shared';\nimport { dayjs } from '@lyxa.ai/core/dist/utilities/dayjs';\n\nexport class CouponRepository {\n\tprivate readonly model: typeof CouponModel & SoftDeleteModel<Coupon>;\n\tprivate readonly userModel: typeof UserModel & SoftDeleteModel<User>;\n\tprivate readonly referralSettingsModel: typeof ReferralSettingModel & SoftDeleteModel<ReferralSetting>;\n\tprivate _coreUserModel: ReturnType<typeof getCoreUserModel> | null = null;\n\n\tconstructor() {\n\t\tthis.model = CouponModel as typeof CouponModel & SoftDeleteModel<Coupon>;\n\t\tthis.userModel = UserModel as typeof UserModel & SoftDeleteModel<User>;\n\t\tthis.referralSettingsModel = ReferralSettingModel as typeof ReferralSettingModel &\n\t\t\tSoftDeleteModel<ReferralSetting>;\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\tpublic async getUserCoupons(\n\t\tuser: mongoose.Types.ObjectId | undefined,\n\t\tshop: mongoose.Types.ObjectId | undefined,\n\t\titemType: ItemType | undefined\n\t): Promise<any> {\n\t\tconst exchangeRate = await getExchangeRate();\n\n\t\tconst referralSettings = await this.referralSettingsModel.findOne();\n\n\t\tconst secondaryReferralReceiverValue =\n\t\t\treferralSettings?.receiver?.valueType == ValueType.PERCENTAGE\n\t\t\t\t? null\n\t\t\t\t: roundSecondaryCurrency((referralSettings?.receiver?.value ?? 0) * exchangeRate);\n\n\t\tconst secondaryReferralReceiverMinOrderAmount = roundSecondaryCurrency(\n\t\t\t(referralSettings?.receiver?.minimumOrderValue ?? 0) * exchangeRate\n\t\t);\n\n\t\tconst pipeline: mongoose.PipelineStage[] = [\n\t\t\t// Match the user\n\t\t\t{\n\t\t\t\t$match: { _id: user },\n\t\t\t},\n\n\t\t\t// Lookup coupon documents\n\t\t\t{\n\t\t\t\t$lookup: {\n\t\t\t\t\tfrom: 'coupons',\n\t\t\t\t\tlocalField: 'coupons',\n\t\t\t\t\tforeignField: '_id',\n\t\t\t\t\tas: 'couponDocs',\n\t\t\t\t\tpipeline: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t$match: {\n\t\t\t\t\t\t\t\t$expr: {\n\t\t\t\t\t\t\t\t\t$and: [\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t$eq: [{ $ifNull: ['$status', Status.ACTIVE] }, Status.ACTIVE],\n\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\t$lte: [{ $ifNull: ['$duration.start', dayjs().toDate()] }, dayjs().toDate()],\n\t\t\t\t\t\t\t\t\t\t},\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},\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t$lookup: {\n\t\t\t\t\t\t\t\tfrom: 'users',\n\t\t\t\t\t\t\t\tlocalField: 'referralUser',\n\t\t\t\t\t\t\t\tforeignField: '_id',\n\t\t\t\t\t\t\t\tas: 'referralUser',\n\t\t\t\t\t\t\t\tpipeline: [{ $project: { coreUser: 1 } }],\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t$lookup: {\n\t\t\t\t\t\t\t\tfrom: 'users',\n\t\t\t\t\t\t\t\tlocalField: 'influencer',\n\t\t\t\t\t\t\t\tforeignField: '_id',\n\t\t\t\t\t\t\t\tas: 'influencer',\n\t\t\t\t\t\t\t\tpipeline: [{ $project: { coreUser: 1 } }],\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t$lookup: {\n\t\t\t\t\t\t\t\tfrom: 'shops',\n\t\t\t\t\t\t\t\tlocalField: 'shop',\n\t\t\t\t\t\t\t\tforeignField: '_id',\n\t\t\t\t\t\t\t\tas: 'shop',\n\t\t\t\t\t\t\t\tpipeline: [{ $project: { name: 1 } }],\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t$unwind: { path: '$shop', preserveNullAndEmptyArrays: true },\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t$unwind: { path: '$referralUser', preserveNullAndEmptyArrays: true },\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t$unwind: { path: '$influencer', preserveNullAndEmptyArrays: true },\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t$addFields: {\n\t\t\t\t\t\t\t\treferringUser: {\n\t\t\t\t\t\t\t\t\t$ifNull: ['$referralUser.coreUser', '$influencer.coreUser'],\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t$project: { referralUser: 0, influencer: 0 },\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t},\n\t\t\t},\n\n\t\t\t// Lookup orders containing coupons for this user\n\t\t\t{\n\t\t\t\t$lookup: {\n\t\t\t\t\tfrom: 'orders',\n\t\t\t\t\tlet: { userId: '$_id' },\n\t\t\t\t\tpipeline: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t$match: {\n\t\t\t\t\t\t\t\t$expr: { $eq: ['$user', '$$userId'] },\n\t\t\t\t\t\t\t\t'adjustedFinance.coupon': { $exists: true },\n\t\t\t\t\t\t\t\tstatus: { $ne: RegularOrderStatus.CANCELLED },\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t$lookup: {\n\t\t\t\t\t\t\t\tfrom: 'coupons',\n\t\t\t\t\t\t\t\tlocalField: 'adjustedFinance.coupon.coupon',\n\t\t\t\t\t\t\t\tforeignField: '_id',\n\t\t\t\t\t\t\t\tas: 'couponInfo',\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t$unwind: '$couponInfo',\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t$group: {\n\t\t\t\t\t\t\t\t_id: '$adjustedFinance.coupon.coupon',\n\t\t\t\t\t\t\t\tsnap: { $first: '$couponInfo' },\n\t\t\t\t\t\t\t\tcount: { $sum: 1 },\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\tas: 'couponUsage',\n\t\t\t\t},\n\t\t\t},\n\n\t\t\t// Unwind coupons to classify individually\n\t\t\t{\n\t\t\t\t$unwind: '$couponDocs',\n\t\t\t},\n\n\t\t\t// Filter individual shop and shops categories coupons\n\t\t\tthis.filterShopCoupons(shop, itemType),\n\n\t\t\t// Filter first order only coupons\n\t\t\t...this.filterFirstOrderOnlyCoupons(shop),\n\n\t\t\t// Join usage count for this coupon\n\t\t\t{\n\t\t\t\t$addFields: {\n\t\t\t\t\tusageData: {\n\t\t\t\t\t\t$arrayElemAt: [\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t$filter: {\n\t\t\t\t\t\t\t\t\tinput: '$couponUsage',\n\t\t\t\t\t\t\t\t\tas: 'cu',\n\t\t\t\t\t\t\t\t\tcond: { $eq: ['$$cu._id', '$couponDocs._id'] },\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t0,\n\t\t\t\t\t\t],\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\n\t\t\t// Classify expiration exactly like isCouponExpired()\n\t\t\t{\n\t\t\t\t$addFields: {\n\t\t\t\t\tisExpired: {\n\t\t\t\t\t\t$or: [\n\t\t\t\t\t\t\t// true only if expirationReason is a non-empty string\n\t\t\t\t\t\t\t{ $gt: [{ $strLenCP: { $ifNull: ['$couponDocs.expirationReason', ''] } }, 0] },\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t$and: [\n\t\t\t\t\t\t\t\t\t{ $ifNull: ['$couponDocs.duration.end', false] },\n\t\t\t\t\t\t\t\t\t{ $lt: ['$couponDocs.duration.end', '$$NOW'] }, // consistent “now”\n\t\t\t\t\t\t\t\t],\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\tusedCount: { $ifNull: ['$usageData.count', 0] },\n\t\t\t\t},\n\t\t\t},\n\n\t\t\t// Add exchange rate and secondary currency rounding factor\n\t\t\t{\n\t\t\t\t$addFields: {\n\t\t\t\t\texchangeRate: exchangeRate,\n\t\t\t\t},\n\t\t\t},\n\n\t\t\t// Compute and add secondary currency values to coupon documents\n\t\t\t{\n\t\t\t\t$addFields: {\n\t\t\t\t\t// base value\n\t\t\t\t\t'couponDocs.value': {\n\t\t\t\t\t\t$switch: {\n\t\t\t\t\t\t\tbranches: [\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tcase: { $eq: ['$couponDocs.couponType', CouponType.REFERRAL_CODE] },\n\t\t\t\t\t\t\t\t\tthen: referralSettings?.receiver?.value ?? 0,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\tdefault: '$couponDocs.value',\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\n\t\t\t\t\t// value type\n\t\t\t\t\t'couponDocs.valueType': {\n\t\t\t\t\t\t$switch: {\n\t\t\t\t\t\t\tbranches: [\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tcase: { $eq: ['$couponDocs.couponType', CouponType.REFERRAL_CODE] },\n\t\t\t\t\t\t\t\t\tthen: referralSettings?.receiver?.valueType ?? 0,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\tdefault: '$couponDocs.valueType',\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\n\t\t\t\t\t'couponDocs.secondaryCurrencyValue': {\n\t\t\t\t\t\t$cond: [\n\t\t\t\t\t\t\t// If valueType is percentage => null always\n\t\t\t\t\t\t\t{ $eq: ['$couponDocs.valueType', ValueType.PERCENTAGE] },\n\t\t\t\t\t\t\tnull,\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t$switch: {\n\t\t\t\t\t\t\t\t\tbranches: [\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\tcase: { $eq: ['$couponDocs.couponType', CouponType.REFERRAL_CODE] },\n\t\t\t\t\t\t\t\t\t\t\tthen: secondaryReferralReceiverValue,\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\t\tdefault: getRoundSecondaryCurrencyStage({\n\t\t\t\t\t\t\t\t\t\t$multiply: ['$couponDocs.value', exchangeRate],\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},\n\t\t\t\t\t\t],\n\t\t\t\t\t},\n\n\t\t\t\t\t'couponDocs.secondaryCurrencyMaxDiscountLimit': {\n\t\t\t\t\t\t$switch: {\n\t\t\t\t\t\t\tbranches: [\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tcase: { $eq: ['$couponDocs.couponType', CouponType.REFERRAL_CODE] },\n\t\t\t\t\t\t\t\t\tthen: null,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\tdefault: getRoundSecondaryCurrencyStage({\n\t\t\t\t\t\t\t\t$multiply: ['$couponDocs.maxDiscountLimit', exchangeRate],\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\t'couponDocs.secondaryCurrencyMinOrderValue': {\n\t\t\t\t\t\t$switch: {\n\t\t\t\t\t\t\tbranches: [\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tcase: { $eq: ['$couponDocs.couponType', CouponType.REFERRAL_CODE] },\n\t\t\t\t\t\t\t\t\tthen: secondaryReferralReceiverMinOrderAmount,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\tdefault: getRoundSecondaryCurrencyStage({\n\t\t\t\t\t\t\t\t$multiply: ['$couponDocs.minOrderValue', exchangeRate],\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\n\t\t\t// Category logic\n\t\t\t{\n\t\t\t\t$addFields: {\n\t\t\t\t\tcategory: {\n\t\t\t\t\t\t$cond: [\n\t\t\t\t\t\t\t'$isExpired',\n\t\t\t\t\t\t\t'expired',\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t$cond: [\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t$and: [\n\t\t\t\t\t\t\t\t\t\t\t{ $gt: ['$usedCount', 0] },\n\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t$or: [\n\t\t\t\t\t\t\t\t\t\t\t\t\t{ $not: ['$couponDocs.orderLimitPerUser'] },\n\t\t\t\t\t\t\t\t\t\t\t\t\t{ $lt: ['$usedCount', '$couponDocs.orderLimitPerUser'] },\n\t\t\t\t\t\t\t\t\t\t\t\t],\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},\n\t\t\t\t\t\t\t\t\t'available',\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t$cond: [{ $gt: ['$usedCount', 0] }, 'used', 'available'],\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},\n\t\t\t\t\t\t],\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\n\t\t\t// Group into arrays\n\t\t\t{\n\t\t\t\t$group: {\n\t\t\t\t\t_id: '$_id',\n\t\t\t\t\tavailable: {\n\t\t\t\t\t\t$push: {\n\t\t\t\t\t\t\t$cond: [{ $eq: ['$category', 'available'] }, '$couponDocs', '$$REMOVE'],\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tused: {\n\t\t\t\t\t\t$push: {\n\t\t\t\t\t\t\t$cond: [{ $eq: ['$category', 'used'] }, '$usageData.snap', '$$REMOVE'],\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\texpired: {\n\t\t\t\t\t\t$push: {\n\t\t\t\t\t\t\t$cond: [{ $eq: ['$category', 'expired'] }, '$couponDocs', '$$REMOVE'],\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\t{\n\t\t\t\t$project: {\n\t\t\t\t\t_id: 0,\n\t\t\t\t},\n\t\t\t},\n\t\t];\n\n\t\tconst [results] = await this.userModel.aggregate(pipeline);\n\n\t\tif (!results) {\n\t\t\treturn {\n\t\t\t\tavailable: [],\t\n\t\t\t\tused: [],\n\t\t\t\texpired: [],\n\t\t\t};\n\t\t}\n\n\t\tconst populatedResults = await this.userModel.populate(results, {\n\t\t\tpath: 'available.referringUser',\n\t\t\tmodel: this.coreUserModel,\n\t\t\tselect: { _id: 0, name: 1 },\n\t\t});\n\n\t\treturn populatedResults;\n\t}\n\n\tpublic addLabelsToAllCoupons(coupons: any): any {\n\t\treturn {\n\t\t\tavailable: this.addLabelsToCoupons(coupons.available).reverse(), // Just to make newly added coupon at the top\n\t\t\tused: this.addLabelsToCoupons(coupons.used).reverse(), // Just to make newly added coupon at the top\n\t\t\texpired: this.addLabelsToCoupons(coupons.expired).reverse(), // Just to make newly added coupon at the top\n\t\t};\n\t}\n\n\tpublic addLabelsToCoupons(coupons: any[]): any[] {\n\t\tconst resultsWithLabels = coupons.map(coupon => {\n\t\t\t// couponOfferLabel\n\t\t\tconst valuePart =\n\t\t\t\tcoupon.valueType === 'fixed'\n\t\t\t\t\t? this.formatCurrency(coupon.value, coupon.secondaryCurrencyValue)\n\t\t\t\t\t: `${coupon.value}%`;\n\n\t\t\tconst maxDiscountPart =\n\t\t\t\tcoupon.isMaxDiscountLimitEnabled && coupon.maxDiscountLimit > 0\n\t\t\t\t\t? ` up to ${this.formatCurrency(coupon.maxDiscountLimit, coupon.secondaryCurrencyMaxDiscountLimit)}`\n\t\t\t\t\t: '';\n\n\t\t\tconst influencerPart = coupon.referringUser ? ` (Referred by ${coupon.referringUser.name})` : '';\n\n\t\t\tcoupon.couponOfferLabel = `Save ${valuePart}${maxDiscountPart}${influencerPart}`;\n\n\t\t\t// couponValidityLabel\n\t\t\tlet validityParts: string[] = [];\n\n\t\t\t// 1. Minimum Order\n\t\t\tif (coupon.isMinOrderValueEnabled && coupon.minOrderValue > 0) {\n\t\t\t\tvalidityParts.push(\n\t\t\t\t\t`Minimum order ${this.formatCurrency(coupon.minOrderValue, coupon.secondaryCurrencyMinOrderValue)}`\n\t\t\t\t);\n\t\t\t}\n\n\t\t\t// 2. Order Limit\n\t\t\tif (coupon.isOrderLimitPerUserEnabled && coupon.orderLimitPerUser > 0) {\n\t\t\t\tvalidityParts.push(`applied on ${coupon.orderLimitPerUser} order`);\n\t\t\t}\n\n\t\t\t// if(coupon.couponType === CouponType.REFERRAL_CODE || coupon.couponType === CouponType.REFERRAL_REWARD){\n\t\t\t// \tvalidityParts = [];\n\t\t\t// \tvalidityParts.push(`Applied on 1 Order`);\n\t\t\t// }\n\n\t\t\tcoupon.couponValidityLabel = validityParts.join('. ');\n\n\t\t\treturn coupon;\n\t\t});\n\n\t\treturn resultsWithLabels;\n\t}\n\n\tprivate formatCurrency(value: any, secondaryCurrencyValue: any) {\n\t\t// Use coma separator for thousands and round secondary currency value\n\t\tconst formatterUSD = new Intl.NumberFormat('en-US', {\n\t\t\tminimumFractionDigits: 0,\n\t\t\tmaximumFractionDigits: 2,\n\t\t});\n\n\t\tconst formatterLBP = new Intl.NumberFormat('en-US', {\n\t\t\tminimumFractionDigits: 0,\n\t\t});\n\n\t\tif (secondaryCurrencyValue !== null && secondaryCurrencyValue !== undefined) {\n\t\t\treturn 'LBP ' + formatterLBP.format(Number(secondaryCurrencyValue));\n\t\t}\n\n\t\treturn '$' + formatterUSD.format(Number(value ?? 0));\n\t}\n\n\tprivate filterShopCoupons(\n\t\tshop: mongoose.Types.ObjectId | undefined,\n\t\titemType: ItemType | undefined\n\t): mongoose.PipelineStage {\n\t\treturn {\n\t\t\t$match: {\n\t\t\t\t$expr: {\n\t\t\t\t\t// If shopId is undefined → skip filtering (always true)\n\t\t\t\t\t$cond: [\n\t\t\t\t\t\t{ $not: [shop] }, // means shopId is null/undefined\n\t\t\t\t\t\ttrue, // skip filtering\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t$or: [\n\t\t\t\t\t\t\t\t// Case 1: INDIVIDUAL_STORE → shop must match\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t$and: [\n\t\t\t\t\t\t\t\t\t\t{ $eq: ['$couponDocs.couponType', CouponType.INDIVIDUAL_STORE] },\n\t\t\t\t\t\t\t\t\t\t{ $eq: ['$couponDocs.shop._id', shop] },\n\t\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\t},\n\n\t\t\t\t\t\t\t\t// Case 2: SHOP_CATEGORY\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t$and: [\n\t\t\t\t\t\t\t\t\t\t{ $eq: ['$couponDocs.couponType', CouponType.SHOPS_CATEGORIES] },\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t$or: [\n\t\t\t\t\t\t\t\t\t\t\t\t// itemType matches\n\t\t\t\t\t\t\t\t\t\t\t\t{ $eq: ['$couponDocs.itemType', itemType] },\n\n\t\t\t\t\t\t\t\t\t\t\t\t// or shopId is inside couponDocs.shops[]\n\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t$in: [shop, { $ifNull: ['$couponDocs.shops', []] }],\n\t\t\t\t\t\t\t\t\t\t\t\t},\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],\n\t\t\t\t\t\t\t\t},\n\n\t\t\t\t\t\t\t\t// Case 3: All other coupon types → keep\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t$not: [\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t$in: [\n\t\t\t\t\t\t\t\t\t\t\t\t'$couponDocs.couponType',\n\t\t\t\t\t\t\t\t\t\t\t\t[CouponType.INDIVIDUAL_STORE, CouponType.SHOPS_CATEGORIES],\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],\n\t\t\t\t\t\t\t\t},\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\t}\n\n\tprivate filterFirstOrderOnlyCoupons(shop?: mongoose.Types.ObjectId): mongoose.PipelineStage[] {\n\t\treturn [\n\t\t\t{\n\t\t\t\t$lookup: {\n\t\t\t\t\tfrom: 'orders',\n\t\t\t\t\tlet: {\n\t\t\t\t\t\tuserId: '$_id',\n\t\t\t\t\t\tshopId: shop ?? '$couponDocs.shop._id',\n\t\t\t\t\t\tcouponShops: { $ifNull: ['$couponDocs.shops', []] },\n\t\t\t\t\t},\n\t\t\t\t\tpipeline: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t$match: {\n\t\t\t\t\t\t\t\t$expr: {\n\t\t\t\t\t\t\t\t\t$and: [\n\t\t\t\t\t\t\t\t\t\t{ $eq: ['$user', '$$userId'] },\n\n\t\t\t\t\t\t\t\t\t\t{ $ne: ['$status', RegularOrderStatus.CANCELLED] },\n\n\t\t\t\t\t\t\t\t\t\t// If shop is provided → only that shop\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t$cond: [\n\t\t\t\t\t\t\t\t\t\t\t\t{ $ne: ['$$shopId', null] },\n\t\t\t\t\t\t\t\t\t\t\t\t{ $eq: ['$shop', '$$shopId'] },\n\n\t\t\t\t\t\t\t\t\t\t\t\t// Else → any shop in coupon.shops\n\t\t\t\t\t\t\t\t\t\t\t\t{ $in: ['$shop', '$$couponShops'] },\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],\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t$group: {\n\t\t\t\t\t\t\t\t_id: null,\n\t\t\t\t\t\t\t\torderedShops: { $addToSet: '$shop' },\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\tas: 'orderStats',\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\t$addFields: {\n\t\t\t\t\torderedShops: {\n\t\t\t\t\t\t$ifNull: [{ $arrayElemAt: ['$orderStats.orderedShops', 0] }, []],\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\t$addFields: {\n\t\t\t\t\t// Individual store logic\n\t\t\t\t\thasOrderedFromStore: {\n\t\t\t\t\t\t$cond: [\n\t\t\t\t\t\t\t{ $eq: ['$couponDocs.couponType', CouponType.INDIVIDUAL_STORE] },\n\t\t\t\t\t\t\t{ $in: [shop ?? '$couponDocs.shop._id', '$orderedShops'] },\n\t\t\t\t\t\t\tfalse,\n\t\t\t\t\t\t],\n\t\t\t\t\t},\n\n\t\t\t\t\t// Multiple store logic\n\t\t\t\t\thasUnusedShopInCategory: {\n\t\t\t\t\t\t$cond: [\n\t\t\t\t\t\t\t{ $eq: ['$couponDocs.couponType', CouponType.SHOPS_CATEGORIES] },\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t$cond: [\n\t\t\t\t\t\t\t\t\t{ $ifNull: [shop, false] },\n\t\t\t\t\t\t\t\t\t// shop provided → hide if user has ordered from this shop\n\t\t\t\t\t\t\t\t\t{ $in: [shop, '$orderedShops'] },\n\t\t\t\t\t\t\t\t\t// no shop provided → hide if no unused shops\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t$eq: [\n\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t$size: { $setDifference: [{ $ifNull: ['$couponDocs.shops', []] }, '$orderedShops'] },\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t0,\n\t\t\t\t\t\t\t\t\t\t],\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},\n\t\t\t\t\t\t\tfalse,\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\t{\n\t\t\t\t$match: {\n\t\t\t\t\t$expr: {\n\t\t\t\t\t\t$not: {\n\t\t\t\t\t\t\t$and: [\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t$in: ['$couponDocs.couponType', [CouponType.INDIVIDUAL_STORE, CouponType.SHOPS_CATEGORIES]],\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{ $eq: ['$couponDocs.firstOrderOnly', true] },\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t$or: ['$hasOrderedFromStore', '$hasUnusedShopInCategory'],\n\t\t\t\t\t\t\t\t},\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\t}\n}\n"]}
|
|
@@ -5,9 +5,18 @@ export declare class ReferralCodeCouponService {
|
|
|
5
5
|
private model;
|
|
6
6
|
private settingsModel;
|
|
7
7
|
private userModel;
|
|
8
|
+
private _coreUserModel;
|
|
8
9
|
constructor();
|
|
10
|
+
private get coreUserModel();
|
|
9
11
|
create(data: CreateDTO): Promise<DocumentType<Model>>;
|
|
10
12
|
update(id: string, data: UpdateDTO): Promise<DocumentType<Model>>;
|
|
13
|
+
private normalizeName;
|
|
14
|
+
private padToThree;
|
|
15
|
+
private containsArabic;
|
|
16
|
+
private generateRandomAlphaNumeric;
|
|
17
|
+
private generateThreeDigits;
|
|
18
|
+
private generateCouponFromName;
|
|
19
|
+
private splitName;
|
|
11
20
|
private generateCode;
|
|
12
21
|
private generateCouponCode;
|
|
13
22
|
createReferralCodeForUser(userId: mongoose.Types.ObjectId | undefined): Promise<DocumentType<Model>>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"referral-code-coupon.service.d.ts","sourceRoot":"/","sources":["modules/coupon/services/referral-code-coupon.service.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAEN,kBAAkB,IAAI,KAAK,
|
|
1
|
+
{"version":3,"file":"referral-code-coupon.service.d.ts","sourceRoot":"/","sources":["modules/coupon/services/referral-code-coupon.service.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAEN,kBAAkB,IAAI,KAAK,EAM3B,MAAM,2CAA2C,CAAC;AACnD,OAAO,EACN,yBAAyB,EACzB,2BAA2B,IAAI,SAAS,EACxC,6BAA6B,EAC7B,2BAA2B,IAAI,SAAS,EACxC,iBAAiB,EACjB,MAAM,6BAA6B,CAAC;AASrC,qBACa,yBAAyB;IACrC,OAAO,CAAC,KAAK,CAAC;IACd,OAAO,CAAC,aAAa,CAAiE;IACtF,OAAO,CAAC,SAAS,CAA2C;IAC5D,OAAO,CAAC,cAAc,CAAoD;;IAS1E,OAAO,KAAK,aAAa,GAKxB;IAMY,MAAM,CAAC,IAAI,EAAE,SAAS,GAAG,OAAO,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC;IASrD,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,GAAG,OAAO,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC;IA8B9E,OAAO,CAAC,aAAa;IAkBrB,OAAO,CAAC,UAAU;IAgBlB,OAAO,CAAC,cAAc;IAUtB,OAAO,CAAC,0BAA0B;IAgBlC,OAAO,CAAC,mBAAmB;IAa3B,OAAO,CAAC,sBAAsB;IAmC9B,OAAO,CAAC,SAAS;IAgBjB,OAAO,CAAC,YAAY;YAqBN,kBAAkB;IAiBnB,yBAAyB,CACrC,MAAM,EAAE,QAAQ,CAAC,KAAK,CAAC,QAAQ,GAAG,SAAS,GACzC,OAAO,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC;IAkClB,cAAc,CAC1B,IAAI,EAAE,iBAAiB,EACvB,MAAM,EAAE,YAAY,CAAC,KAAK,CAAC,GACzB,OAAO,CAAC,yBAAyB,CAAC;IA2ExB,qBAAqB,CACjC,MAAM,EAAE,QAAQ,CAAC,KAAK,CAAC,QAAQ,GAC7B,OAAO,CAAC,6BAA6B,CAAC;YAc3B,mBAAmB;CAKjC;AAED,eAAO,MAAM,yBAAyB,2BAA2C,CAAC"}
|