@classytic/promo 0.1.0 → 0.2.1
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/CHANGELOG.md +128 -0
- package/README.md +226 -22
- package/dist/{index-J5BC20DN.d.mts → constants-CrbSSQG5.d.mts} +1 -3
- package/dist/{constants-BVajdyL3.mjs → constants-D0Rntp2f.mjs} +1 -3
- package/dist/index.d.mts +1301 -10
- package/dist/index.mjs +2165 -46
- package/dist/schemas/index.d.mts +253 -0
- package/dist/schemas/index.mjs +134 -0
- package/package.json +23 -37
- package/dist/config-iZjn_8pp.d.mts +0 -71
- package/dist/domain/enums/index.d.mts +0 -2
- package/dist/domain/enums/index.mjs +0 -2
- package/dist/domain/index.d.mts +0 -61
- package/dist/domain/index.mjs +0 -4
- package/dist/domain-errors-BEkXvy5O.mjs +0 -80
- package/dist/event-emitter.port-DaodlJSG.d.mts +0 -8
- package/dist/event-types-CsTV1FKX.mjs +0 -25
- package/dist/events/index.d.mts +0 -2
- package/dist/events/index.mjs +0 -3
- package/dist/events-CprEWlN7.mjs +0 -25
- package/dist/index-B7lLH19a.d.mts +0 -13
- package/dist/index-C52zSBkI.d.mts +0 -96
- package/dist/index-Cu9iwy4v.d.mts +0 -99
- package/dist/index-l09KqnlE.d.mts +0 -81
- package/dist/models/index.d.mts +0 -2
- package/dist/models/index.mjs +0 -2
- package/dist/models-DdBNae7h.mjs +0 -277
- package/dist/repositories/index.d.mts +0 -2
- package/dist/repositories/index.mjs +0 -2
- package/dist/repositories-DgZIY9wD.mjs +0 -295
- package/dist/results-Ca5ZCNbN.d.mts +0 -218
- package/dist/services/index.d.mts +0 -2
- package/dist/services/index.mjs +0 -2
- package/dist/services-Cz0gHrmX.mjs +0 -815
- package/dist/types/index.d.mts +0 -3
- package/dist/types/index.mjs +0 -1
- package/dist/unit-of-work.port-DaMW8WZK.d.mts +0 -7
- package/dist/voucher.port-yxfb3MHJ.d.mts +0 -146
package/dist/models-DdBNae7h.mjs
DELETED
|
@@ -1,277 +0,0 @@
|
|
|
1
|
-
import { a as PROGRAM_STATUSES, c as REWARD_TYPES, d as VOUCHER_STATUSES, i as DISCOUNT_SCOPES, l as STACKING_MODES, r as DISCOUNT_MODES, s as PROGRAM_TYPES, u as TRIGGER_MODES } from "./constants-BVajdyL3.mjs";
|
|
2
|
-
import mongoose from "mongoose";
|
|
3
|
-
//#region src/models/create-model.ts
|
|
4
|
-
function injectTenantField(schema, tenant) {
|
|
5
|
-
if (!tenant.enabled) return;
|
|
6
|
-
schema.add({ [tenant.field]: {
|
|
7
|
-
type: tenant.type === "ObjectId" ? mongoose.Schema.Types.ObjectId : String,
|
|
8
|
-
required: true,
|
|
9
|
-
index: true,
|
|
10
|
-
...tenant.ref ? { ref: tenant.ref } : {}
|
|
11
|
-
} });
|
|
12
|
-
const existingIndexes = schema._indexes;
|
|
13
|
-
if (existingIndexes && existingIndexes.length > 0) for (const indexEntry of existingIndexes) {
|
|
14
|
-
const fields = indexEntry[0];
|
|
15
|
-
const newFields = { [tenant.field]: 1 };
|
|
16
|
-
for (const [key, val] of Object.entries(fields)) newFields[key] = val;
|
|
17
|
-
indexEntry[0] = newFields;
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
function applyUserIndexes(schema, indexes, tenant) {
|
|
21
|
-
for (const def of indexes) {
|
|
22
|
-
const fields = tenant.enabled ? {
|
|
23
|
-
[tenant.field]: 1,
|
|
24
|
-
...def.fields
|
|
25
|
-
} : { ...def.fields };
|
|
26
|
-
schema.index(fields, def.options ?? {});
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
//#endregion
|
|
30
|
-
//#region src/models/schemas/program.schema.ts
|
|
31
|
-
const { Schema: Schema$3 } = mongoose;
|
|
32
|
-
function createProgramSchema() {
|
|
33
|
-
const schema = new Schema$3({
|
|
34
|
-
name: {
|
|
35
|
-
type: String,
|
|
36
|
-
required: true
|
|
37
|
-
},
|
|
38
|
-
description: { type: String },
|
|
39
|
-
programType: {
|
|
40
|
-
type: String,
|
|
41
|
-
enum: PROGRAM_TYPES,
|
|
42
|
-
required: true
|
|
43
|
-
},
|
|
44
|
-
triggerMode: {
|
|
45
|
-
type: String,
|
|
46
|
-
enum: TRIGGER_MODES,
|
|
47
|
-
required: true
|
|
48
|
-
},
|
|
49
|
-
status: {
|
|
50
|
-
type: String,
|
|
51
|
-
enum: PROGRAM_STATUSES,
|
|
52
|
-
default: "draft"
|
|
53
|
-
},
|
|
54
|
-
stackingMode: {
|
|
55
|
-
type: String,
|
|
56
|
-
enum: STACKING_MODES,
|
|
57
|
-
default: "exclusive"
|
|
58
|
-
},
|
|
59
|
-
priority: {
|
|
60
|
-
type: Number,
|
|
61
|
-
default: 0
|
|
62
|
-
},
|
|
63
|
-
startsAt: { type: Date },
|
|
64
|
-
endsAt: { type: Date },
|
|
65
|
-
maxUsageTotal: { type: Number },
|
|
66
|
-
usedCount: {
|
|
67
|
-
type: Number,
|
|
68
|
-
default: 0
|
|
69
|
-
},
|
|
70
|
-
maxUsagePerCustomer: { type: Number },
|
|
71
|
-
applicableCustomerIds: [{ type: String }],
|
|
72
|
-
applicableCustomerTags: [{ type: String }],
|
|
73
|
-
customerUsageCounts: {
|
|
74
|
-
type: Map,
|
|
75
|
-
of: Number,
|
|
76
|
-
default: () => /* @__PURE__ */ new Map()
|
|
77
|
-
},
|
|
78
|
-
metadata: { type: Schema$3.Types.Mixed }
|
|
79
|
-
}, { timestamps: true });
|
|
80
|
-
schema.index({
|
|
81
|
-
status: 1,
|
|
82
|
-
programType: 1,
|
|
83
|
-
priority: -1
|
|
84
|
-
});
|
|
85
|
-
schema.index({
|
|
86
|
-
status: 1,
|
|
87
|
-
startsAt: 1,
|
|
88
|
-
endsAt: 1
|
|
89
|
-
});
|
|
90
|
-
schema.index({
|
|
91
|
-
status: 1,
|
|
92
|
-
priority: -1,
|
|
93
|
-
_id: -1
|
|
94
|
-
});
|
|
95
|
-
return schema;
|
|
96
|
-
}
|
|
97
|
-
//#endregion
|
|
98
|
-
//#region src/models/schemas/reward.schema.ts
|
|
99
|
-
const { Schema: Schema$2 } = mongoose;
|
|
100
|
-
function createRewardSchema() {
|
|
101
|
-
const schema = new Schema$2({
|
|
102
|
-
programId: {
|
|
103
|
-
type: Schema$2.Types.ObjectId,
|
|
104
|
-
required: true
|
|
105
|
-
},
|
|
106
|
-
ruleId: { type: Schema$2.Types.ObjectId },
|
|
107
|
-
rewardType: {
|
|
108
|
-
type: String,
|
|
109
|
-
enum: REWARD_TYPES,
|
|
110
|
-
required: true
|
|
111
|
-
},
|
|
112
|
-
discountMode: {
|
|
113
|
-
type: String,
|
|
114
|
-
enum: DISCOUNT_MODES
|
|
115
|
-
},
|
|
116
|
-
discountAmount: { type: Number },
|
|
117
|
-
maxDiscountAmount: { type: Number },
|
|
118
|
-
discountScope: {
|
|
119
|
-
type: String,
|
|
120
|
-
enum: DISCOUNT_SCOPES,
|
|
121
|
-
default: "order"
|
|
122
|
-
},
|
|
123
|
-
applicableProductIds: [{ type: String }],
|
|
124
|
-
freeProductId: { type: String },
|
|
125
|
-
freeProductSku: { type: String },
|
|
126
|
-
freeQuantity: {
|
|
127
|
-
type: Number,
|
|
128
|
-
default: 1
|
|
129
|
-
},
|
|
130
|
-
giftCardAmount: { type: Number },
|
|
131
|
-
metadata: { type: Schema$2.Types.Mixed }
|
|
132
|
-
}, { timestamps: true });
|
|
133
|
-
schema.index({ programId: 1 });
|
|
134
|
-
schema.index({ ruleId: 1 }, { sparse: true });
|
|
135
|
-
return schema;
|
|
136
|
-
}
|
|
137
|
-
//#endregion
|
|
138
|
-
//#region src/models/schemas/rule.schema.ts
|
|
139
|
-
const { Schema: Schema$1 } = mongoose;
|
|
140
|
-
function createRuleSchema() {
|
|
141
|
-
const schema = new Schema$1({
|
|
142
|
-
programId: {
|
|
143
|
-
type: Schema$1.Types.ObjectId,
|
|
144
|
-
required: true
|
|
145
|
-
},
|
|
146
|
-
name: { type: String },
|
|
147
|
-
minimumAmount: {
|
|
148
|
-
type: Number,
|
|
149
|
-
default: 0
|
|
150
|
-
},
|
|
151
|
-
minimumQuantity: {
|
|
152
|
-
type: Number,
|
|
153
|
-
default: 0
|
|
154
|
-
},
|
|
155
|
-
applicableProductIds: [{ type: String }],
|
|
156
|
-
applicableCategories: [{ type: String }],
|
|
157
|
-
applicableSkus: [{ type: String }],
|
|
158
|
-
buyQuantity: { type: Number },
|
|
159
|
-
code: {
|
|
160
|
-
type: String,
|
|
161
|
-
uppercase: true,
|
|
162
|
-
trim: true
|
|
163
|
-
},
|
|
164
|
-
startsAt: { type: Date },
|
|
165
|
-
endsAt: { type: Date },
|
|
166
|
-
metadata: { type: Schema$1.Types.Mixed }
|
|
167
|
-
}, { timestamps: true });
|
|
168
|
-
schema.index({ programId: 1 });
|
|
169
|
-
schema.index({ code: 1 }, { sparse: true });
|
|
170
|
-
return schema;
|
|
171
|
-
}
|
|
172
|
-
//#endregion
|
|
173
|
-
//#region src/models/schemas/voucher.schema.ts
|
|
174
|
-
const { Schema } = mongoose;
|
|
175
|
-
function createVoucherSchema() {
|
|
176
|
-
const schema = new Schema({
|
|
177
|
-
programId: {
|
|
178
|
-
type: Schema.Types.ObjectId,
|
|
179
|
-
required: true,
|
|
180
|
-
index: true
|
|
181
|
-
},
|
|
182
|
-
code: {
|
|
183
|
-
type: String,
|
|
184
|
-
required: true,
|
|
185
|
-
uppercase: true,
|
|
186
|
-
trim: true
|
|
187
|
-
},
|
|
188
|
-
status: {
|
|
189
|
-
type: String,
|
|
190
|
-
enum: VOUCHER_STATUSES,
|
|
191
|
-
default: "active"
|
|
192
|
-
},
|
|
193
|
-
customerId: { type: String },
|
|
194
|
-
usageLimit: {
|
|
195
|
-
type: Number,
|
|
196
|
-
default: 1
|
|
197
|
-
},
|
|
198
|
-
usedCount: {
|
|
199
|
-
type: Number,
|
|
200
|
-
default: 0
|
|
201
|
-
},
|
|
202
|
-
initialBalance: { type: Number },
|
|
203
|
-
currentBalance: { type: Number },
|
|
204
|
-
balanceLedger: [{
|
|
205
|
-
amount: {
|
|
206
|
-
type: Number,
|
|
207
|
-
required: true
|
|
208
|
-
},
|
|
209
|
-
orderId: { type: String },
|
|
210
|
-
description: { type: String },
|
|
211
|
-
createdAt: {
|
|
212
|
-
type: Date,
|
|
213
|
-
default: Date.now
|
|
214
|
-
},
|
|
215
|
-
idempotencyKey: { type: String }
|
|
216
|
-
}],
|
|
217
|
-
expiresAt: { type: Date },
|
|
218
|
-
redemptions: [{
|
|
219
|
-
orderId: {
|
|
220
|
-
type: String,
|
|
221
|
-
required: true
|
|
222
|
-
},
|
|
223
|
-
customerId: { type: String },
|
|
224
|
-
discountAmount: {
|
|
225
|
-
type: Number,
|
|
226
|
-
required: true
|
|
227
|
-
},
|
|
228
|
-
redeemedAt: {
|
|
229
|
-
type: Date,
|
|
230
|
-
default: Date.now
|
|
231
|
-
},
|
|
232
|
-
idempotencyKey: { type: String }
|
|
233
|
-
}],
|
|
234
|
-
metadata: { type: Schema.Types.Mixed }
|
|
235
|
-
}, { timestamps: true });
|
|
236
|
-
schema.index({ code: 1 }, { unique: true });
|
|
237
|
-
schema.index({
|
|
238
|
-
programId: 1,
|
|
239
|
-
status: 1
|
|
240
|
-
});
|
|
241
|
-
schema.index({
|
|
242
|
-
customerId: 1,
|
|
243
|
-
status: 1
|
|
244
|
-
}, { sparse: true });
|
|
245
|
-
schema.index({ expiresAt: 1 }, { sparse: true });
|
|
246
|
-
return schema;
|
|
247
|
-
}
|
|
248
|
-
//#endregion
|
|
249
|
-
//#region src/models/index.ts
|
|
250
|
-
function createModels(connection, tenant, indexes) {
|
|
251
|
-
if (connection.models.PromoProgram && connection.models.PromoRule && connection.models.PromoReward && connection.models.PromoVoucher) return {
|
|
252
|
-
Program: connection.models.PromoProgram,
|
|
253
|
-
Rule: connection.models.PromoRule,
|
|
254
|
-
Reward: connection.models.PromoReward,
|
|
255
|
-
Voucher: connection.models.PromoVoucher
|
|
256
|
-
};
|
|
257
|
-
const programSchema = createProgramSchema();
|
|
258
|
-
const ruleSchema = createRuleSchema();
|
|
259
|
-
const rewardSchema = createRewardSchema();
|
|
260
|
-
const voucherSchema = createVoucherSchema();
|
|
261
|
-
injectTenantField(programSchema, tenant);
|
|
262
|
-
injectTenantField(ruleSchema, tenant);
|
|
263
|
-
injectTenantField(rewardSchema, tenant);
|
|
264
|
-
injectTenantField(voucherSchema, tenant);
|
|
265
|
-
if (indexes?.program) applyUserIndexes(programSchema, indexes.program, tenant);
|
|
266
|
-
if (indexes?.rule) applyUserIndexes(ruleSchema, indexes.rule, tenant);
|
|
267
|
-
if (indexes?.reward) applyUserIndexes(rewardSchema, indexes.reward, tenant);
|
|
268
|
-
if (indexes?.voucher) applyUserIndexes(voucherSchema, indexes.voucher, tenant);
|
|
269
|
-
return {
|
|
270
|
-
Program: connection.models.PromoProgram ?? connection.model("PromoProgram", programSchema),
|
|
271
|
-
Rule: connection.models.PromoRule ?? connection.model("PromoRule", ruleSchema),
|
|
272
|
-
Reward: connection.models.PromoReward ?? connection.model("PromoReward", rewardSchema),
|
|
273
|
-
Voucher: connection.models.PromoVoucher ?? connection.model("PromoVoucher", voucherSchema)
|
|
274
|
-
};
|
|
275
|
-
}
|
|
276
|
-
//#endregion
|
|
277
|
-
export { createModels as t };
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
import { a as RuleRepository, i as VoucherRepository, n as RepositoryPluginsMap, o as RewardRepository, r as createRepositories, s as ProgramRepository, t as PromoRepositories } from "../index-l09KqnlE.mjs";
|
|
2
|
-
export { ProgramRepository, PromoRepositories, RepositoryPluginsMap, RewardRepository, RuleRepository, VoucherRepository, createRepositories };
|
|
@@ -1,295 +0,0 @@
|
|
|
1
|
-
import { createRepository } from "@classytic/mongokit";
|
|
2
|
-
//#region src/utils/mongoose.ts
|
|
3
|
-
function toDoc(doc) {
|
|
4
|
-
if (doc == null) return doc;
|
|
5
|
-
const d = doc;
|
|
6
|
-
return typeof d.toObject === "function" ? d.toObject({ virtuals: true }) : doc;
|
|
7
|
-
}
|
|
8
|
-
function toDocs(docs) {
|
|
9
|
-
return docs.map((d) => toDoc(d));
|
|
10
|
-
}
|
|
11
|
-
//#endregion
|
|
12
|
-
//#region src/repositories/program.repository.ts
|
|
13
|
-
var ProgramRepository = class {
|
|
14
|
-
repo;
|
|
15
|
-
tenantField;
|
|
16
|
-
constructor(model, plugins = [], tenantField = "organizationId") {
|
|
17
|
-
this.repo = createRepository(model, plugins);
|
|
18
|
-
this.tenantField = tenantField;
|
|
19
|
-
}
|
|
20
|
-
async create(data, session) {
|
|
21
|
-
return toDoc(await this.repo.create(data, { session }));
|
|
22
|
-
}
|
|
23
|
-
async getById(id, tenantId) {
|
|
24
|
-
if (tenantId) return toDoc(await this.repo.getByQuery({
|
|
25
|
-
_id: id,
|
|
26
|
-
[this.tenantField]: tenantId
|
|
27
|
-
}, { throwOnNotFound: false }));
|
|
28
|
-
return toDoc(await this.repo.getById(id, { throwOnNotFound: false }));
|
|
29
|
-
}
|
|
30
|
-
async update(id, data, tenantId, session) {
|
|
31
|
-
const opts = {
|
|
32
|
-
session,
|
|
33
|
-
lean: true
|
|
34
|
-
};
|
|
35
|
-
if (tenantId) opts.query = { [this.tenantField]: tenantId };
|
|
36
|
-
return toDoc(await this.repo.update(id, data, opts));
|
|
37
|
-
}
|
|
38
|
-
async findMany(query, options) {
|
|
39
|
-
return toDocs((await this.repo.getAll({
|
|
40
|
-
filters: query,
|
|
41
|
-
limit: options?.limit ?? 100,
|
|
42
|
-
page: options?.page ?? 1,
|
|
43
|
-
sort: options?.sort ?? "-priority"
|
|
44
|
-
})).docs);
|
|
45
|
-
}
|
|
46
|
-
async findActive(tenantId, now) {
|
|
47
|
-
const currentDate = now ?? /* @__PURE__ */ new Date();
|
|
48
|
-
const query = {
|
|
49
|
-
status: "active",
|
|
50
|
-
$or: [
|
|
51
|
-
{ startsAt: { $lte: currentDate } },
|
|
52
|
-
{ startsAt: { $exists: false } },
|
|
53
|
-
{ startsAt: null }
|
|
54
|
-
]
|
|
55
|
-
};
|
|
56
|
-
if (tenantId) query[this.tenantField] = tenantId;
|
|
57
|
-
return toDocs(await this.repo.Model.find(query).sort({
|
|
58
|
-
priority: -1,
|
|
59
|
-
_id: -1
|
|
60
|
-
}).limit(200).lean()).filter((p) => !p.endsAt || p.endsAt >= currentDate);
|
|
61
|
-
}
|
|
62
|
-
async incrementUsage(id, tenantId, session) {
|
|
63
|
-
const opts = {
|
|
64
|
-
session,
|
|
65
|
-
lean: true
|
|
66
|
-
};
|
|
67
|
-
if (tenantId) opts.query = { [this.tenantField]: tenantId };
|
|
68
|
-
return toDoc(await this.repo.update(id, { $inc: { usedCount: 1 } }, opts));
|
|
69
|
-
}
|
|
70
|
-
async decrementUsage(id, tenantId, session) {
|
|
71
|
-
const opts = {
|
|
72
|
-
session,
|
|
73
|
-
lean: true
|
|
74
|
-
};
|
|
75
|
-
if (tenantId) opts.query = { [this.tenantField]: tenantId };
|
|
76
|
-
return toDoc(await this.repo.update(id, { $inc: { usedCount: -1 } }, opts));
|
|
77
|
-
}
|
|
78
|
-
async getCustomerUsage(id, customerId, tenantId) {
|
|
79
|
-
const query = { _id: id };
|
|
80
|
-
if (tenantId) query[this.tenantField] = tenantId;
|
|
81
|
-
const doc = await this.repo.getByQuery(query, {
|
|
82
|
-
throwOnNotFound: false,
|
|
83
|
-
lean: true
|
|
84
|
-
});
|
|
85
|
-
if (!doc) return 0;
|
|
86
|
-
const counts = doc.customerUsageCounts;
|
|
87
|
-
if (!counts) return 0;
|
|
88
|
-
if (counts instanceof Map) return counts.get(customerId) ?? 0;
|
|
89
|
-
return counts[customerId] ?? 0;
|
|
90
|
-
}
|
|
91
|
-
async incrementCustomerUsage(id, customerId, tenantId, session) {
|
|
92
|
-
const opts = {
|
|
93
|
-
session,
|
|
94
|
-
lean: true
|
|
95
|
-
};
|
|
96
|
-
if (tenantId) opts.query = { [this.tenantField]: tenantId };
|
|
97
|
-
return toDoc(await this.repo.update(id, { $inc: { [`customerUsageCounts.${customerId}`]: 1 } }, opts));
|
|
98
|
-
}
|
|
99
|
-
};
|
|
100
|
-
//#endregion
|
|
101
|
-
//#region src/repositories/reward.repository.ts
|
|
102
|
-
var RewardRepository = class {
|
|
103
|
-
repo;
|
|
104
|
-
tenantField;
|
|
105
|
-
constructor(model, plugins = [], tenantField = "organizationId") {
|
|
106
|
-
this.repo = createRepository(model, plugins);
|
|
107
|
-
this.tenantField = tenantField;
|
|
108
|
-
}
|
|
109
|
-
async create(data, session) {
|
|
110
|
-
return toDoc(await this.repo.create(data, { session }));
|
|
111
|
-
}
|
|
112
|
-
async getById(id, tenantId) {
|
|
113
|
-
if (tenantId) return toDoc(await this.repo.getByQuery({
|
|
114
|
-
_id: id,
|
|
115
|
-
[this.tenantField]: tenantId
|
|
116
|
-
}, { throwOnNotFound: false }));
|
|
117
|
-
return toDoc(await this.repo.getById(id, { throwOnNotFound: false }));
|
|
118
|
-
}
|
|
119
|
-
async update(id, data, tenantId, session) {
|
|
120
|
-
if (tenantId) return toDoc(await this.repo.Model.findOneAndUpdate({
|
|
121
|
-
_id: id,
|
|
122
|
-
[this.tenantField]: tenantId
|
|
123
|
-
}, { $set: data }, {
|
|
124
|
-
returnDocument: "after",
|
|
125
|
-
...session ? { session } : {}
|
|
126
|
-
}));
|
|
127
|
-
return toDoc(await this.repo.update(id, data, { session }));
|
|
128
|
-
}
|
|
129
|
-
async delete(id, tenantId, session) {
|
|
130
|
-
if (tenantId) {
|
|
131
|
-
await this.repo.Model.deleteOne({
|
|
132
|
-
_id: id,
|
|
133
|
-
[this.tenantField]: tenantId
|
|
134
|
-
}, { ...session ? { session } : {} });
|
|
135
|
-
return;
|
|
136
|
-
}
|
|
137
|
-
await this.repo.delete(id, { session });
|
|
138
|
-
}
|
|
139
|
-
async findByProgramId(programId, tenantId) {
|
|
140
|
-
const query = { programId };
|
|
141
|
-
if (tenantId) query[this.tenantField] = tenantId;
|
|
142
|
-
return toDocs(await this.repo.findAll(query));
|
|
143
|
-
}
|
|
144
|
-
async findByProgramIds(programIds, tenantId) {
|
|
145
|
-
const query = { programId: { $in: programIds } };
|
|
146
|
-
if (tenantId) query[this.tenantField] = tenantId;
|
|
147
|
-
return toDocs(await this.repo.findAll(query));
|
|
148
|
-
}
|
|
149
|
-
};
|
|
150
|
-
//#endregion
|
|
151
|
-
//#region src/repositories/rule.repository.ts
|
|
152
|
-
var RuleRepository = class {
|
|
153
|
-
repo;
|
|
154
|
-
tenantField;
|
|
155
|
-
constructor(model, plugins = [], tenantField = "organizationId") {
|
|
156
|
-
this.repo = createRepository(model, plugins);
|
|
157
|
-
this.tenantField = tenantField;
|
|
158
|
-
}
|
|
159
|
-
async create(data, session) {
|
|
160
|
-
return toDoc(await this.repo.create(data, { session }));
|
|
161
|
-
}
|
|
162
|
-
async getById(id, tenantId) {
|
|
163
|
-
if (tenantId) return toDoc(await this.repo.getByQuery({
|
|
164
|
-
_id: id,
|
|
165
|
-
[this.tenantField]: tenantId
|
|
166
|
-
}, { throwOnNotFound: false }));
|
|
167
|
-
return toDoc(await this.repo.getById(id, { throwOnNotFound: false }));
|
|
168
|
-
}
|
|
169
|
-
async update(id, data, tenantId, session) {
|
|
170
|
-
if (tenantId) return toDoc(await this.repo.Model.findOneAndUpdate({
|
|
171
|
-
_id: id,
|
|
172
|
-
[this.tenantField]: tenantId
|
|
173
|
-
}, { $set: data }, {
|
|
174
|
-
returnDocument: "after",
|
|
175
|
-
...session ? { session } : {}
|
|
176
|
-
}));
|
|
177
|
-
return toDoc(await this.repo.update(id, data, { session }));
|
|
178
|
-
}
|
|
179
|
-
async delete(id, tenantId, session) {
|
|
180
|
-
if (tenantId) {
|
|
181
|
-
await this.repo.Model.deleteOne({
|
|
182
|
-
_id: id,
|
|
183
|
-
[this.tenantField]: tenantId
|
|
184
|
-
}, { ...session ? { session } : {} });
|
|
185
|
-
return;
|
|
186
|
-
}
|
|
187
|
-
await this.repo.delete(id, { session });
|
|
188
|
-
}
|
|
189
|
-
async findByProgramId(programId, tenantId) {
|
|
190
|
-
const query = { programId };
|
|
191
|
-
if (tenantId) query[this.tenantField] = tenantId;
|
|
192
|
-
return toDocs(await this.repo.findAll(query));
|
|
193
|
-
}
|
|
194
|
-
async findByCode(code, tenantId) {
|
|
195
|
-
const query = { code: code.toUpperCase() };
|
|
196
|
-
if (tenantId) query[this.tenantField] = tenantId;
|
|
197
|
-
return toDoc(await this.repo.getByQuery(query, { throwOnNotFound: false }));
|
|
198
|
-
}
|
|
199
|
-
async findByProgramIds(programIds, tenantId) {
|
|
200
|
-
const query = { programId: { $in: programIds } };
|
|
201
|
-
if (tenantId) query[this.tenantField] = tenantId;
|
|
202
|
-
return toDocs(await this.repo.findAll(query));
|
|
203
|
-
}
|
|
204
|
-
};
|
|
205
|
-
//#endregion
|
|
206
|
-
//#region src/repositories/voucher.repository.ts
|
|
207
|
-
var VoucherRepository = class {
|
|
208
|
-
repo;
|
|
209
|
-
tenantField;
|
|
210
|
-
constructor(model, plugins = [], tenantField = "organizationId") {
|
|
211
|
-
this.repo = createRepository(model, plugins);
|
|
212
|
-
this.tenantField = tenantField;
|
|
213
|
-
}
|
|
214
|
-
async create(data, session) {
|
|
215
|
-
return toDoc(await this.repo.create(data, { session }));
|
|
216
|
-
}
|
|
217
|
-
async createMany(data, session) {
|
|
218
|
-
return toDocs(await this.repo.createMany(data, { session }));
|
|
219
|
-
}
|
|
220
|
-
async getById(id, tenantId) {
|
|
221
|
-
if (tenantId) return toDoc(await this.repo.getByQuery({
|
|
222
|
-
_id: id,
|
|
223
|
-
[this.tenantField]: tenantId
|
|
224
|
-
}, { throwOnNotFound: false }));
|
|
225
|
-
return toDoc(await this.repo.getById(id, { throwOnNotFound: false }));
|
|
226
|
-
}
|
|
227
|
-
async getByCode(code, tenantId) {
|
|
228
|
-
const query = { code: code.toUpperCase() };
|
|
229
|
-
if (tenantId) query[this.tenantField] = tenantId;
|
|
230
|
-
return toDoc(await this.repo.getByQuery(query, { throwOnNotFound: false }));
|
|
231
|
-
}
|
|
232
|
-
async update(id, data, tenantId, session) {
|
|
233
|
-
const opts = {
|
|
234
|
-
session,
|
|
235
|
-
lean: true
|
|
236
|
-
};
|
|
237
|
-
if (tenantId) opts.query = { [this.tenantField]: tenantId };
|
|
238
|
-
return toDoc(await this.repo.update(id, data, opts));
|
|
239
|
-
}
|
|
240
|
-
async findMany(query, options) {
|
|
241
|
-
return toDocs((await this.repo.getAll({
|
|
242
|
-
filters: query,
|
|
243
|
-
limit: options?.limit ?? 100,
|
|
244
|
-
page: options?.page ?? 1
|
|
245
|
-
})).docs);
|
|
246
|
-
}
|
|
247
|
-
async incrementUsage(id, redemption, tenantId, session) {
|
|
248
|
-
const opts = {
|
|
249
|
-
session,
|
|
250
|
-
lean: true
|
|
251
|
-
};
|
|
252
|
-
if (tenantId) opts.query = { [this.tenantField]: tenantId };
|
|
253
|
-
return toDoc(await this.repo.update(id, {
|
|
254
|
-
$inc: { usedCount: 1 },
|
|
255
|
-
$push: { redemptions: redemption }
|
|
256
|
-
}, opts));
|
|
257
|
-
}
|
|
258
|
-
async addLedgerEntry(id, entry, balanceDelta, tenantId, session) {
|
|
259
|
-
const opts = {
|
|
260
|
-
session,
|
|
261
|
-
lean: true
|
|
262
|
-
};
|
|
263
|
-
if (tenantId) opts.query = { [this.tenantField]: tenantId };
|
|
264
|
-
return toDoc(await this.repo.update(id, {
|
|
265
|
-
$inc: { currentBalance: balanceDelta },
|
|
266
|
-
$push: { balanceLedger: entry }
|
|
267
|
-
}, opts));
|
|
268
|
-
}
|
|
269
|
-
async expireByDate(before, tenantId) {
|
|
270
|
-
const filter = {
|
|
271
|
-
status: "active",
|
|
272
|
-
expiresAt: { $lte: before }
|
|
273
|
-
};
|
|
274
|
-
if (tenantId) filter[this.tenantField] = tenantId;
|
|
275
|
-
return (await this.repo.Model.updateMany(filter, { $set: { status: "expired" } })).modifiedCount;
|
|
276
|
-
}
|
|
277
|
-
async hasIdempotencyKey(id, key) {
|
|
278
|
-
return await this.repo.Model.countDocuments({
|
|
279
|
-
_id: id,
|
|
280
|
-
$or: [{ "redemptions.idempotencyKey": key }, { "balanceLedger.idempotencyKey": key }]
|
|
281
|
-
}) > 0;
|
|
282
|
-
}
|
|
283
|
-
};
|
|
284
|
-
//#endregion
|
|
285
|
-
//#region src/repositories/index.ts
|
|
286
|
-
function createRepositories(models, plugins, tenantField = "organizationId") {
|
|
287
|
-
return {
|
|
288
|
-
program: new ProgramRepository(models.Program, plugins?.program, tenantField),
|
|
289
|
-
rule: new RuleRepository(models.Rule, plugins?.rule, tenantField),
|
|
290
|
-
reward: new RewardRepository(models.Reward, plugins?.reward, tenantField),
|
|
291
|
-
voucher: new VoucherRepository(models.Voucher, plugins?.voucher, tenantField)
|
|
292
|
-
};
|
|
293
|
-
}
|
|
294
|
-
//#endregion
|
|
295
|
-
export { ProgramRepository as a, RewardRepository as i, VoucherRepository as n, RuleRepository as r, createRepositories as t };
|