@classytic/promo 0.1.0
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/LICENSE +21 -0
- package/README.md +41 -0
- package/dist/config-iZjn_8pp.d.mts +71 -0
- package/dist/constants-BVajdyL3.mjs +45 -0
- package/dist/domain/enums/index.d.mts +2 -0
- package/dist/domain/enums/index.mjs +2 -0
- package/dist/domain/index.d.mts +61 -0
- package/dist/domain/index.mjs +4 -0
- package/dist/domain-errors-BEkXvy5O.mjs +80 -0
- package/dist/event-emitter.port-DaodlJSG.d.mts +8 -0
- package/dist/event-types-CsTV1FKX.mjs +25 -0
- package/dist/events/index.d.mts +2 -0
- package/dist/events/index.mjs +3 -0
- package/dist/events-CprEWlN7.mjs +25 -0
- package/dist/index-B7lLH19a.d.mts +13 -0
- package/dist/index-C52zSBkI.d.mts +96 -0
- package/dist/index-Cu9iwy4v.d.mts +99 -0
- package/dist/index-J5BC20DN.d.mts +21 -0
- package/dist/index-l09KqnlE.d.mts +81 -0
- package/dist/index.d.mts +20 -0
- package/dist/index.mjs +86 -0
- package/dist/models/index.d.mts +2 -0
- package/dist/models/index.mjs +2 -0
- package/dist/models-DdBNae7h.mjs +277 -0
- package/dist/repositories/index.d.mts +2 -0
- package/dist/repositories/index.mjs +2 -0
- package/dist/repositories-DgZIY9wD.mjs +295 -0
- package/dist/results-Ca5ZCNbN.d.mts +218 -0
- package/dist/services/index.d.mts +2 -0
- package/dist/services/index.mjs +2 -0
- package/dist/services-Cz0gHrmX.mjs +815 -0
- package/dist/types/index.d.mts +3 -0
- package/dist/types/index.mjs +1 -0
- package/dist/unit-of-work.port-DaMW8WZK.d.mts +7 -0
- package/dist/voucher.port-yxfb3MHJ.d.mts +146 -0
- package/package.json +108 -0
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { c as Rule, i as ProgramPort, l as Reward, n as RulePort, o as Voucher, r as RewardPort, t as VoucherPort, u as Program } from "./voucher.port-yxfb3MHJ.mjs";
|
|
2
|
+
import { t as PromoModels } from "./index-B7lLH19a.mjs";
|
|
3
|
+
import { Model } from "mongoose";
|
|
4
|
+
import { PluginType } from "@classytic/mongokit";
|
|
5
|
+
|
|
6
|
+
//#region src/repositories/program.repository.d.ts
|
|
7
|
+
declare class ProgramRepository implements ProgramPort {
|
|
8
|
+
private repo;
|
|
9
|
+
private tenantField;
|
|
10
|
+
constructor(model: Model<any>, plugins?: PluginType[], tenantField?: string);
|
|
11
|
+
create(data: Record<string, unknown>, session?: unknown): Promise<Program>;
|
|
12
|
+
getById(id: string, tenantId?: string): Promise<Program | null>;
|
|
13
|
+
update(id: string, data: Record<string, unknown>, tenantId?: string, session?: unknown): Promise<Program>;
|
|
14
|
+
findMany(query: Record<string, unknown>, options?: Record<string, unknown>): Promise<Program[]>;
|
|
15
|
+
findActive(tenantId?: string, now?: Date): Promise<Program[]>;
|
|
16
|
+
incrementUsage(id: string, tenantId?: string, session?: unknown): Promise<Program>;
|
|
17
|
+
decrementUsage(id: string, tenantId?: string, session?: unknown): Promise<Program>;
|
|
18
|
+
getCustomerUsage(id: string, customerId: string, tenantId?: string): Promise<number>;
|
|
19
|
+
incrementCustomerUsage(id: string, customerId: string, tenantId?: string, session?: unknown): Promise<Program>;
|
|
20
|
+
}
|
|
21
|
+
//#endregion
|
|
22
|
+
//#region src/repositories/reward.repository.d.ts
|
|
23
|
+
declare class RewardRepository implements RewardPort {
|
|
24
|
+
private repo;
|
|
25
|
+
private tenantField;
|
|
26
|
+
constructor(model: Model<any>, plugins?: PluginType[], tenantField?: string);
|
|
27
|
+
create(data: Record<string, unknown>, session?: unknown): Promise<Reward>;
|
|
28
|
+
getById(id: string, tenantId?: string): Promise<Reward | null>;
|
|
29
|
+
update(id: string, data: Record<string, unknown>, tenantId?: string, session?: unknown): Promise<Reward>;
|
|
30
|
+
delete(id: string, tenantId?: string, session?: unknown): Promise<void>;
|
|
31
|
+
findByProgramId(programId: string, tenantId?: string): Promise<Reward[]>;
|
|
32
|
+
findByProgramIds(programIds: string[], tenantId?: string): Promise<Reward[]>;
|
|
33
|
+
}
|
|
34
|
+
//#endregion
|
|
35
|
+
//#region src/repositories/rule.repository.d.ts
|
|
36
|
+
declare class RuleRepository implements RulePort {
|
|
37
|
+
private repo;
|
|
38
|
+
private tenantField;
|
|
39
|
+
constructor(model: Model<any>, plugins?: PluginType[], tenantField?: string);
|
|
40
|
+
create(data: Record<string, unknown>, session?: unknown): Promise<Rule>;
|
|
41
|
+
getById(id: string, tenantId?: string): Promise<Rule | null>;
|
|
42
|
+
update(id: string, data: Record<string, unknown>, tenantId?: string, session?: unknown): Promise<Rule>;
|
|
43
|
+
delete(id: string, tenantId?: string, session?: unknown): Promise<void>;
|
|
44
|
+
findByProgramId(programId: string, tenantId?: string): Promise<Rule[]>;
|
|
45
|
+
findByCode(code: string, tenantId?: string): Promise<Rule | null>;
|
|
46
|
+
findByProgramIds(programIds: string[], tenantId?: string): Promise<Rule[]>;
|
|
47
|
+
}
|
|
48
|
+
//#endregion
|
|
49
|
+
//#region src/repositories/voucher.repository.d.ts
|
|
50
|
+
declare class VoucherRepository implements VoucherPort {
|
|
51
|
+
private repo;
|
|
52
|
+
private tenantField;
|
|
53
|
+
constructor(model: Model<any>, plugins?: PluginType[], tenantField?: string);
|
|
54
|
+
create(data: Record<string, unknown>, session?: unknown): Promise<Voucher>;
|
|
55
|
+
createMany(data: Record<string, unknown>[], session?: unknown): Promise<Voucher[]>;
|
|
56
|
+
getById(id: string, tenantId?: string): Promise<Voucher | null>;
|
|
57
|
+
getByCode(code: string, tenantId?: string): Promise<Voucher | null>;
|
|
58
|
+
update(id: string, data: Record<string, unknown>, tenantId?: string, session?: unknown): Promise<Voucher>;
|
|
59
|
+
findMany(query: Record<string, unknown>, options?: Record<string, unknown>): Promise<Voucher[]>;
|
|
60
|
+
incrementUsage(id: string, redemption: Record<string, unknown>, tenantId?: string, session?: unknown): Promise<Voucher>;
|
|
61
|
+
addLedgerEntry(id: string, entry: Record<string, unknown>, balanceDelta: number, tenantId?: string, session?: unknown): Promise<Voucher>;
|
|
62
|
+
expireByDate(before: Date, tenantId?: string): Promise<number>;
|
|
63
|
+
hasIdempotencyKey(id: string, key: string): Promise<boolean>;
|
|
64
|
+
}
|
|
65
|
+
//#endregion
|
|
66
|
+
//#region src/repositories/index.d.ts
|
|
67
|
+
interface PromoRepositories {
|
|
68
|
+
program: ProgramRepository;
|
|
69
|
+
rule: RuleRepository;
|
|
70
|
+
reward: RewardRepository;
|
|
71
|
+
voucher: VoucherRepository;
|
|
72
|
+
}
|
|
73
|
+
interface RepositoryPluginsMap {
|
|
74
|
+
program?: PluginType[];
|
|
75
|
+
rule?: PluginType[];
|
|
76
|
+
reward?: PluginType[];
|
|
77
|
+
voucher?: PluginType[];
|
|
78
|
+
}
|
|
79
|
+
declare function createRepositories(models: PromoModels, plugins?: RepositoryPluginsMap, tenantField?: string): PromoRepositories;
|
|
80
|
+
//#endregion
|
|
81
|
+
export { RuleRepository as a, VoucherRepository as i, RepositoryPluginsMap as n, RewardRepository as o, createRepositories as r, ProgramRepository as s, PromoRepositories as t };
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { a as BalanceLedgerEntry, c as Rule, l as Reward, o as Voucher, s as VoucherRedemption, u as Program } from "./voucher.port-yxfb3MHJ.mjs";
|
|
2
|
+
import { t as EventEmitterPort } from "./event-emitter.port-DaodlJSG.mjs";
|
|
3
|
+
import { o as PromoEvents } from "./index-C52zSBkI.mjs";
|
|
4
|
+
import { i as PromoConfig, o as ResolvedConfig, s as ResolvedTenant } from "./config-iZjn_8pp.mjs";
|
|
5
|
+
import { t as PromoModels } from "./index-B7lLH19a.mjs";
|
|
6
|
+
import { t as PromoRepositories } from "./index-l09KqnlE.mjs";
|
|
7
|
+
import { C as UpdateRuleInput, S as UpdateRewardInput, _ as GiftCardTopUpInput, a as GiftCardBalance, b as RedeemVoucherInput, c as VoucherValidation, d as CreateRewardInput, f as CreateRuleInput, g as GiftCardSpendInput, h as GenerateSingleCodeInput, i as FreeProductLine, l as CartItem, m as GenerateCodesInput, n as DiscountLine, o as PaginatedResult, p as EvaluateInput, r as EvaluationResult, s as RejectedCode, t as CommitResult, u as CreateProgramInput, v as ListQuery, x as UpdateProgramInput, y as PromoContext } from "./results-Ca5ZCNbN.mjs";
|
|
8
|
+
import { i as FullProgram, t as PromoServices } from "./index-Cu9iwy4v.mjs";
|
|
9
|
+
|
|
10
|
+
//#region src/index.d.ts
|
|
11
|
+
declare function resolveConfig(config: PromoConfig): ResolvedConfig;
|
|
12
|
+
interface PromoEngine {
|
|
13
|
+
models: PromoModels;
|
|
14
|
+
repositories: PromoRepositories;
|
|
15
|
+
services: PromoServices;
|
|
16
|
+
events: EventEmitterPort;
|
|
17
|
+
}
|
|
18
|
+
declare function createPromoEngine(config: PromoConfig): PromoEngine;
|
|
19
|
+
//#endregion
|
|
20
|
+
export { type BalanceLedgerEntry, type CartItem, type CommitResult, type CreateProgramInput, type CreateRewardInput, type CreateRuleInput, type DiscountLine, type EvaluateInput, type EvaluationResult, type EventEmitterPort, type FreeProductLine, type FullProgram, type GenerateCodesInput, type GenerateSingleCodeInput, type GiftCardBalance, type GiftCardSpendInput, type GiftCardTopUpInput, type ListQuery, type PaginatedResult, type Program, type PromoConfig, type PromoContext, PromoEngine, PromoEvents, type PromoModels, type PromoRepositories, type PromoServices, type RedeemVoucherInput, type RejectedCode, type ResolvedConfig, type ResolvedTenant, type Reward, type Rule, type UpdateProgramInput, type UpdateRewardInput, type UpdateRuleInput, type Voucher, type VoucherRedemption, type VoucherValidation, createPromoEngine, resolveConfig };
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { n as DEFAULT_TENANT_TYPE, t as DEFAULT_TENANT_FIELD } from "./constants-BVajdyL3.mjs";
|
|
2
|
+
import { l as ValidationError } from "./domain-errors-BEkXvy5O.mjs";
|
|
3
|
+
import { t as InProcessEventBus } from "./events-CprEWlN7.mjs";
|
|
4
|
+
import { t as createModels } from "./models-DdBNae7h.mjs";
|
|
5
|
+
import { t as createRepositories } from "./repositories-DgZIY9wD.mjs";
|
|
6
|
+
import { t as PromoEvents } from "./event-types-CsTV1FKX.mjs";
|
|
7
|
+
import { t as createServices } from "./services-Cz0gHrmX.mjs";
|
|
8
|
+
//#region src/index.ts
|
|
9
|
+
function resolveConfig(config) {
|
|
10
|
+
let tenant;
|
|
11
|
+
if (config.tenant === false) tenant = {
|
|
12
|
+
enabled: false,
|
|
13
|
+
field: "",
|
|
14
|
+
type: "ObjectId",
|
|
15
|
+
contextKey: ""
|
|
16
|
+
};
|
|
17
|
+
else if (config.tenant === void 0) tenant = {
|
|
18
|
+
enabled: true,
|
|
19
|
+
field: DEFAULT_TENANT_FIELD,
|
|
20
|
+
type: DEFAULT_TENANT_TYPE,
|
|
21
|
+
contextKey: DEFAULT_TENANT_FIELD
|
|
22
|
+
};
|
|
23
|
+
else tenant = {
|
|
24
|
+
enabled: true,
|
|
25
|
+
field: config.tenant.field ?? "organizationId",
|
|
26
|
+
type: config.tenant.type ?? "ObjectId",
|
|
27
|
+
contextKey: config.tenant.contextKey ?? config.tenant.field ?? "organizationId",
|
|
28
|
+
...config.tenant.ref ? { ref: config.tenant.ref } : {}
|
|
29
|
+
};
|
|
30
|
+
const resolved = {
|
|
31
|
+
evaluation: {
|
|
32
|
+
maxStackablePromotions: config.evaluation?.maxStackablePromotions ?? 5,
|
|
33
|
+
allowExclusiveAndStackable: config.evaluation?.allowExclusiveAndStackable ?? true
|
|
34
|
+
},
|
|
35
|
+
voucher: {
|
|
36
|
+
codeLength: config.voucher?.codeLength ?? 8,
|
|
37
|
+
codePrefix: config.voucher?.codePrefix ?? "",
|
|
38
|
+
defaultExpiryDays: config.voucher?.defaultExpiryDays ?? null
|
|
39
|
+
},
|
|
40
|
+
giftCard: {
|
|
41
|
+
allowNegativeBalance: config.giftCard?.allowNegativeBalance ?? false,
|
|
42
|
+
maxBalance: config.giftCard?.maxBalance ?? null
|
|
43
|
+
},
|
|
44
|
+
tenant
|
|
45
|
+
};
|
|
46
|
+
if (resolved.voucher.codeLength < 4) throw new ValidationError("voucher codeLength must be >= 4");
|
|
47
|
+
if (resolved.evaluation.maxStackablePromotions < 1) throw new ValidationError("maxStackablePromotions must be >= 1");
|
|
48
|
+
return resolved;
|
|
49
|
+
}
|
|
50
|
+
var MongoUnitOfWork = class {
|
|
51
|
+
constructor(connection) {
|
|
52
|
+
this.connection = connection;
|
|
53
|
+
}
|
|
54
|
+
async withTransaction(cb) {
|
|
55
|
+
const session = await this.connection.startSession();
|
|
56
|
+
try {
|
|
57
|
+
let result;
|
|
58
|
+
await session.withTransaction(async () => {
|
|
59
|
+
result = await cb(session);
|
|
60
|
+
});
|
|
61
|
+
return result;
|
|
62
|
+
} finally {
|
|
63
|
+
await session.endSession();
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
function createPromoEngine(config) {
|
|
68
|
+
const resolvedConfig = resolveConfig(config);
|
|
69
|
+
const models = createModels(config.mongoose, resolvedConfig.tenant, config.indexes);
|
|
70
|
+
const repositories = createRepositories(models, config.plugins, resolvedConfig.tenant.field);
|
|
71
|
+
const unitOfWork = new MongoUnitOfWork(config.mongoose);
|
|
72
|
+
const events = config.events?.adapter ?? new InProcessEventBus();
|
|
73
|
+
return {
|
|
74
|
+
models,
|
|
75
|
+
repositories,
|
|
76
|
+
services: createServices({
|
|
77
|
+
repositories,
|
|
78
|
+
unitOfWork,
|
|
79
|
+
events,
|
|
80
|
+
config: resolvedConfig
|
|
81
|
+
}),
|
|
82
|
+
events
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
//#endregion
|
|
86
|
+
export { PromoEvents, createPromoEngine, resolveConfig };
|
|
@@ -0,0 +1,277 @@
|
|
|
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 };
|
|
@@ -0,0 +1,2 @@
|
|
|
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 };
|