@open-loyalty/mcp-server 1.0.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 +654 -0
- package/dist/client/http.d.ts +8 -0
- package/dist/client/http.js +69 -0
- package/dist/config.d.ts +17 -0
- package/dist/config.js +40 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +20 -0
- package/dist/server.d.ts +4 -0
- package/dist/server.js +334 -0
- package/dist/tools/achievement.d.ts +983 -0
- package/dist/tools/achievement.js +311 -0
- package/dist/tools/admin.d.ts +153 -0
- package/dist/tools/admin.js +193 -0
- package/dist/tools/analytics.d.ts +162 -0
- package/dist/tools/analytics.js +245 -0
- package/dist/tools/apikey.d.ts +72 -0
- package/dist/tools/apikey.js +78 -0
- package/dist/tools/audit.d.ts +107 -0
- package/dist/tools/audit.js +90 -0
- package/dist/tools/badge.d.ts +135 -0
- package/dist/tools/badge.js +165 -0
- package/dist/tools/campaign.d.ts +1775 -0
- package/dist/tools/campaign.js +724 -0
- package/dist/tools/export.d.ts +110 -0
- package/dist/tools/export.js +147 -0
- package/dist/tools/import.d.ts +110 -0
- package/dist/tools/import.js +126 -0
- package/dist/tools/index.d.ts +22 -0
- package/dist/tools/index.js +527 -0
- package/dist/tools/member.d.ts +345 -0
- package/dist/tools/member.js +358 -0
- package/dist/tools/member.test.d.ts +1 -0
- package/dist/tools/member.test.js +213 -0
- package/dist/tools/points.d.ts +188 -0
- package/dist/tools/points.js +306 -0
- package/dist/tools/points.test.d.ts +1 -0
- package/dist/tools/points.test.js +292 -0
- package/dist/tools/reward.d.ts +261 -0
- package/dist/tools/reward.js +371 -0
- package/dist/tools/reward.test.d.ts +1 -0
- package/dist/tools/reward.test.js +240 -0
- package/dist/tools/role.d.ts +161 -0
- package/dist/tools/role.js +160 -0
- package/dist/tools/segment.d.ts +797 -0
- package/dist/tools/segment.js +299 -0
- package/dist/tools/store.d.ts +101 -0
- package/dist/tools/store.js +117 -0
- package/dist/tools/tierset.d.ts +288 -0
- package/dist/tools/tierset.js +244 -0
- package/dist/tools/transaction.d.ts +357 -0
- package/dist/tools/transaction.js +242 -0
- package/dist/tools/transaction.test.d.ts +1 -0
- package/dist/tools/transaction.test.js +235 -0
- package/dist/tools/wallet-type.d.ts +32 -0
- package/dist/tools/wallet-type.js +58 -0
- package/dist/tools/webhook.d.ts +179 -0
- package/dist/tools/webhook.js +171 -0
- package/dist/types/schemas/achievement.d.ts +1116 -0
- package/dist/types/schemas/achievement.js +172 -0
- package/dist/types/schemas/admin.d.ts +263 -0
- package/dist/types/schemas/admin.js +99 -0
- package/dist/types/schemas/analytics.d.ts +542 -0
- package/dist/types/schemas/analytics.js +130 -0
- package/dist/types/schemas/badge.d.ts +131 -0
- package/dist/types/schemas/badge.js +48 -0
- package/dist/types/schemas/campaign.d.ts +2005 -0
- package/dist/types/schemas/campaign.js +189 -0
- package/dist/types/schemas/common.d.ts +52 -0
- package/dist/types/schemas/common.js +26 -0
- package/dist/types/schemas/export.d.ts +127 -0
- package/dist/types/schemas/export.js +43 -0
- package/dist/types/schemas/import.d.ts +344 -0
- package/dist/types/schemas/import.js +68 -0
- package/dist/types/schemas/member.d.ts +443 -0
- package/dist/types/schemas/member.js +92 -0
- package/dist/types/schemas/points.d.ts +188 -0
- package/dist/types/schemas/points.js +54 -0
- package/dist/types/schemas/reward.d.ts +278 -0
- package/dist/types/schemas/reward.js +69 -0
- package/dist/types/schemas/role.d.ts +260 -0
- package/dist/types/schemas/role.js +75 -0
- package/dist/types/schemas/segment.d.ts +592 -0
- package/dist/types/schemas/segment.js +114 -0
- package/dist/types/schemas/tierset.d.ts +552 -0
- package/dist/types/schemas/tierset.js +87 -0
- package/dist/types/schemas/transaction.d.ts +1022 -0
- package/dist/types/schemas/transaction.js +63 -0
- package/dist/types/schemas/wallet-type.d.ts +99 -0
- package/dist/types/schemas/wallet-type.js +17 -0
- package/dist/types/schemas/webhook.d.ts +195 -0
- package/dist/types/schemas/webhook.js +39 -0
- package/dist/utils/cursor.d.ts +84 -0
- package/dist/utils/cursor.js +117 -0
- package/dist/utils/errors.d.ts +12 -0
- package/dist/utils/errors.js +69 -0
- package/dist/utils/pagination.d.ts +39 -0
- package/dist/utils/pagination.js +77 -0
- package/package.json +65 -0
|
@@ -0,0 +1,357 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export declare const TransactionCreateInputSchema: {
|
|
3
|
+
storeCode: z.ZodOptional<z.ZodString>;
|
|
4
|
+
header: z.ZodObject<{
|
|
5
|
+
documentNumber: z.ZodString;
|
|
6
|
+
purchasedAt: z.ZodString;
|
|
7
|
+
documentType: z.ZodOptional<z.ZodEnum<["sell", "return"]>>;
|
|
8
|
+
linkedDocumentNumber: z.ZodOptional<z.ZodString>;
|
|
9
|
+
purchasePlace: z.ZodOptional<z.ZodString>;
|
|
10
|
+
labels: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
11
|
+
key: z.ZodString;
|
|
12
|
+
value: z.ZodString;
|
|
13
|
+
}, "strip", z.ZodTypeAny, {
|
|
14
|
+
value: string;
|
|
15
|
+
key: string;
|
|
16
|
+
}, {
|
|
17
|
+
value: string;
|
|
18
|
+
key: string;
|
|
19
|
+
}>, "many">>;
|
|
20
|
+
}, "strip", z.ZodTypeAny, {
|
|
21
|
+
documentNumber: string;
|
|
22
|
+
purchasedAt: string;
|
|
23
|
+
documentType?: "sell" | "return" | undefined;
|
|
24
|
+
linkedDocumentNumber?: string | undefined;
|
|
25
|
+
purchasePlace?: string | undefined;
|
|
26
|
+
labels?: {
|
|
27
|
+
value: string;
|
|
28
|
+
key: string;
|
|
29
|
+
}[] | undefined;
|
|
30
|
+
}, {
|
|
31
|
+
documentNumber: string;
|
|
32
|
+
purchasedAt: string;
|
|
33
|
+
documentType?: "sell" | "return" | undefined;
|
|
34
|
+
linkedDocumentNumber?: string | undefined;
|
|
35
|
+
purchasePlace?: string | undefined;
|
|
36
|
+
labels?: {
|
|
37
|
+
value: string;
|
|
38
|
+
key: string;
|
|
39
|
+
}[] | undefined;
|
|
40
|
+
}>;
|
|
41
|
+
items: z.ZodArray<z.ZodObject<{
|
|
42
|
+
sku: z.ZodString;
|
|
43
|
+
name: z.ZodString;
|
|
44
|
+
grossValue: z.ZodNumber;
|
|
45
|
+
category: z.ZodString;
|
|
46
|
+
quantity: z.ZodOptional<z.ZodNumber>;
|
|
47
|
+
highPrecisionQuantity: z.ZodOptional<z.ZodNumber>;
|
|
48
|
+
maker: z.ZodOptional<z.ZodString>;
|
|
49
|
+
labels: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
50
|
+
key: z.ZodString;
|
|
51
|
+
value: z.ZodString;
|
|
52
|
+
}, "strip", z.ZodTypeAny, {
|
|
53
|
+
value: string;
|
|
54
|
+
key: string;
|
|
55
|
+
}, {
|
|
56
|
+
value: string;
|
|
57
|
+
key: string;
|
|
58
|
+
}>, "many">>;
|
|
59
|
+
}, "strip", z.ZodTypeAny, {
|
|
60
|
+
name: string;
|
|
61
|
+
sku: string;
|
|
62
|
+
grossValue: number;
|
|
63
|
+
category: string;
|
|
64
|
+
quantity?: number | undefined;
|
|
65
|
+
labels?: {
|
|
66
|
+
value: string;
|
|
67
|
+
key: string;
|
|
68
|
+
}[] | undefined;
|
|
69
|
+
highPrecisionQuantity?: number | undefined;
|
|
70
|
+
maker?: string | undefined;
|
|
71
|
+
}, {
|
|
72
|
+
name: string;
|
|
73
|
+
sku: string;
|
|
74
|
+
grossValue: number;
|
|
75
|
+
category: string;
|
|
76
|
+
quantity?: number | undefined;
|
|
77
|
+
labels?: {
|
|
78
|
+
value: string;
|
|
79
|
+
key: string;
|
|
80
|
+
}[] | undefined;
|
|
81
|
+
highPrecisionQuantity?: number | undefined;
|
|
82
|
+
maker?: string | undefined;
|
|
83
|
+
}>, "many">;
|
|
84
|
+
customerData: z.ZodOptional<z.ZodObject<{
|
|
85
|
+
customerId: z.ZodOptional<z.ZodString>;
|
|
86
|
+
email: z.ZodOptional<z.ZodString>;
|
|
87
|
+
name: z.ZodOptional<z.ZodString>;
|
|
88
|
+
phone: z.ZodOptional<z.ZodString>;
|
|
89
|
+
loyaltyCardNumber: z.ZodOptional<z.ZodString>;
|
|
90
|
+
}, "strip", z.ZodTypeAny, {
|
|
91
|
+
name?: string | undefined;
|
|
92
|
+
email?: string | undefined;
|
|
93
|
+
phone?: string | undefined;
|
|
94
|
+
loyaltyCardNumber?: string | undefined;
|
|
95
|
+
customerId?: string | undefined;
|
|
96
|
+
}, {
|
|
97
|
+
name?: string | undefined;
|
|
98
|
+
email?: string | undefined;
|
|
99
|
+
phone?: string | undefined;
|
|
100
|
+
loyaltyCardNumber?: string | undefined;
|
|
101
|
+
customerId?: string | undefined;
|
|
102
|
+
}>>;
|
|
103
|
+
};
|
|
104
|
+
export declare const TransactionGetInputSchema: {
|
|
105
|
+
storeCode: z.ZodOptional<z.ZodString>;
|
|
106
|
+
transactionId: z.ZodString;
|
|
107
|
+
};
|
|
108
|
+
export declare const TransactionListInputSchema: {
|
|
109
|
+
storeCode: z.ZodOptional<z.ZodString>;
|
|
110
|
+
cursor: z.ZodOptional<z.ZodString>;
|
|
111
|
+
page: z.ZodOptional<z.ZodNumber>;
|
|
112
|
+
perPage: z.ZodOptional<z.ZodNumber>;
|
|
113
|
+
customerId: z.ZodOptional<z.ZodString>;
|
|
114
|
+
documentNumber: z.ZodOptional<z.ZodString>;
|
|
115
|
+
documentType: z.ZodOptional<z.ZodEnum<["sell", "return"]>>;
|
|
116
|
+
matched: z.ZodOptional<z.ZodBoolean>;
|
|
117
|
+
purchasedAtFrom: z.ZodOptional<z.ZodString>;
|
|
118
|
+
purchasedAtTo: z.ZodOptional<z.ZodString>;
|
|
119
|
+
};
|
|
120
|
+
export declare const TransactionAssignMemberInputSchema: {
|
|
121
|
+
storeCode: z.ZodOptional<z.ZodString>;
|
|
122
|
+
documentNumber: z.ZodString;
|
|
123
|
+
customerId: z.ZodOptional<z.ZodString>;
|
|
124
|
+
loyaltyCardNumber: z.ZodOptional<z.ZodString>;
|
|
125
|
+
phone: z.ZodOptional<z.ZodString>;
|
|
126
|
+
};
|
|
127
|
+
export declare function transactionCreate(input: {
|
|
128
|
+
storeCode?: string;
|
|
129
|
+
header: {
|
|
130
|
+
documentNumber: string;
|
|
131
|
+
purchasedAt: string;
|
|
132
|
+
documentType?: string;
|
|
133
|
+
linkedDocumentNumber?: string;
|
|
134
|
+
purchasePlace?: string;
|
|
135
|
+
labels?: Array<{
|
|
136
|
+
key: string;
|
|
137
|
+
value: string;
|
|
138
|
+
}>;
|
|
139
|
+
};
|
|
140
|
+
items: Array<{
|
|
141
|
+
sku: string;
|
|
142
|
+
name: string;
|
|
143
|
+
grossValue: number;
|
|
144
|
+
category: string;
|
|
145
|
+
quantity?: number;
|
|
146
|
+
highPrecisionQuantity?: number;
|
|
147
|
+
maker?: string;
|
|
148
|
+
labels?: Array<{
|
|
149
|
+
key: string;
|
|
150
|
+
value: string;
|
|
151
|
+
}>;
|
|
152
|
+
}>;
|
|
153
|
+
customerData?: {
|
|
154
|
+
customerId?: string;
|
|
155
|
+
email?: string;
|
|
156
|
+
name?: string;
|
|
157
|
+
phone?: string;
|
|
158
|
+
loyaltyCardNumber?: string;
|
|
159
|
+
};
|
|
160
|
+
}): Promise<{
|
|
161
|
+
transactionId: string;
|
|
162
|
+
pointsEarned?: number;
|
|
163
|
+
}>;
|
|
164
|
+
export declare function transactionGet(input: {
|
|
165
|
+
storeCode?: string;
|
|
166
|
+
transactionId: string;
|
|
167
|
+
}): Promise<{
|
|
168
|
+
transactionId: string;
|
|
169
|
+
documentNumber: string;
|
|
170
|
+
documentType: string;
|
|
171
|
+
items: unknown[];
|
|
172
|
+
customerData?: unknown;
|
|
173
|
+
matched: boolean;
|
|
174
|
+
grossValue: number;
|
|
175
|
+
pointsEarned?: number;
|
|
176
|
+
purchasedAt?: string;
|
|
177
|
+
}>;
|
|
178
|
+
export declare function transactionList(input: {
|
|
179
|
+
storeCode?: string;
|
|
180
|
+
cursor?: string;
|
|
181
|
+
page?: number;
|
|
182
|
+
perPage?: number;
|
|
183
|
+
customerId?: string;
|
|
184
|
+
documentNumber?: string;
|
|
185
|
+
documentType?: string;
|
|
186
|
+
matched?: boolean;
|
|
187
|
+
purchasedAtFrom?: string;
|
|
188
|
+
purchasedAtTo?: string;
|
|
189
|
+
}): Promise<{
|
|
190
|
+
transactions: Array<{
|
|
191
|
+
transactionId: string;
|
|
192
|
+
documentNumber: string;
|
|
193
|
+
grossValue: number;
|
|
194
|
+
matched: boolean;
|
|
195
|
+
customerId?: string;
|
|
196
|
+
pointsEarned?: number;
|
|
197
|
+
purchasedAt?: string;
|
|
198
|
+
}>;
|
|
199
|
+
total: {
|
|
200
|
+
all?: number;
|
|
201
|
+
filtered?: number;
|
|
202
|
+
};
|
|
203
|
+
cursor?: string;
|
|
204
|
+
}>;
|
|
205
|
+
export declare function transactionAssignMember(input: {
|
|
206
|
+
storeCode?: string;
|
|
207
|
+
documentNumber: string;
|
|
208
|
+
customerId?: string;
|
|
209
|
+
loyaltyCardNumber?: string;
|
|
210
|
+
phone?: string;
|
|
211
|
+
}): Promise<{
|
|
212
|
+
transactionId: string;
|
|
213
|
+
customerId: string;
|
|
214
|
+
pointsEarned?: number;
|
|
215
|
+
}>;
|
|
216
|
+
export declare const transactionToolDefinitions: readonly [{
|
|
217
|
+
readonly name: "openloyalty_transaction_create";
|
|
218
|
+
readonly description: string;
|
|
219
|
+
readonly inputSchema: {
|
|
220
|
+
storeCode: z.ZodOptional<z.ZodString>;
|
|
221
|
+
header: z.ZodObject<{
|
|
222
|
+
documentNumber: z.ZodString;
|
|
223
|
+
purchasedAt: z.ZodString;
|
|
224
|
+
documentType: z.ZodOptional<z.ZodEnum<["sell", "return"]>>;
|
|
225
|
+
linkedDocumentNumber: z.ZodOptional<z.ZodString>;
|
|
226
|
+
purchasePlace: z.ZodOptional<z.ZodString>;
|
|
227
|
+
labels: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
228
|
+
key: z.ZodString;
|
|
229
|
+
value: z.ZodString;
|
|
230
|
+
}, "strip", z.ZodTypeAny, {
|
|
231
|
+
value: string;
|
|
232
|
+
key: string;
|
|
233
|
+
}, {
|
|
234
|
+
value: string;
|
|
235
|
+
key: string;
|
|
236
|
+
}>, "many">>;
|
|
237
|
+
}, "strip", z.ZodTypeAny, {
|
|
238
|
+
documentNumber: string;
|
|
239
|
+
purchasedAt: string;
|
|
240
|
+
documentType?: "sell" | "return" | undefined;
|
|
241
|
+
linkedDocumentNumber?: string | undefined;
|
|
242
|
+
purchasePlace?: string | undefined;
|
|
243
|
+
labels?: {
|
|
244
|
+
value: string;
|
|
245
|
+
key: string;
|
|
246
|
+
}[] | undefined;
|
|
247
|
+
}, {
|
|
248
|
+
documentNumber: string;
|
|
249
|
+
purchasedAt: string;
|
|
250
|
+
documentType?: "sell" | "return" | undefined;
|
|
251
|
+
linkedDocumentNumber?: string | undefined;
|
|
252
|
+
purchasePlace?: string | undefined;
|
|
253
|
+
labels?: {
|
|
254
|
+
value: string;
|
|
255
|
+
key: string;
|
|
256
|
+
}[] | undefined;
|
|
257
|
+
}>;
|
|
258
|
+
items: z.ZodArray<z.ZodObject<{
|
|
259
|
+
sku: z.ZodString;
|
|
260
|
+
name: z.ZodString;
|
|
261
|
+
grossValue: z.ZodNumber;
|
|
262
|
+
category: z.ZodString;
|
|
263
|
+
quantity: z.ZodOptional<z.ZodNumber>;
|
|
264
|
+
highPrecisionQuantity: z.ZodOptional<z.ZodNumber>;
|
|
265
|
+
maker: z.ZodOptional<z.ZodString>;
|
|
266
|
+
labels: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
267
|
+
key: z.ZodString;
|
|
268
|
+
value: z.ZodString;
|
|
269
|
+
}, "strip", z.ZodTypeAny, {
|
|
270
|
+
value: string;
|
|
271
|
+
key: string;
|
|
272
|
+
}, {
|
|
273
|
+
value: string;
|
|
274
|
+
key: string;
|
|
275
|
+
}>, "many">>;
|
|
276
|
+
}, "strip", z.ZodTypeAny, {
|
|
277
|
+
name: string;
|
|
278
|
+
sku: string;
|
|
279
|
+
grossValue: number;
|
|
280
|
+
category: string;
|
|
281
|
+
quantity?: number | undefined;
|
|
282
|
+
labels?: {
|
|
283
|
+
value: string;
|
|
284
|
+
key: string;
|
|
285
|
+
}[] | undefined;
|
|
286
|
+
highPrecisionQuantity?: number | undefined;
|
|
287
|
+
maker?: string | undefined;
|
|
288
|
+
}, {
|
|
289
|
+
name: string;
|
|
290
|
+
sku: string;
|
|
291
|
+
grossValue: number;
|
|
292
|
+
category: string;
|
|
293
|
+
quantity?: number | undefined;
|
|
294
|
+
labels?: {
|
|
295
|
+
value: string;
|
|
296
|
+
key: string;
|
|
297
|
+
}[] | undefined;
|
|
298
|
+
highPrecisionQuantity?: number | undefined;
|
|
299
|
+
maker?: string | undefined;
|
|
300
|
+
}>, "many">;
|
|
301
|
+
customerData: z.ZodOptional<z.ZodObject<{
|
|
302
|
+
customerId: z.ZodOptional<z.ZodString>;
|
|
303
|
+
email: z.ZodOptional<z.ZodString>;
|
|
304
|
+
name: z.ZodOptional<z.ZodString>;
|
|
305
|
+
phone: z.ZodOptional<z.ZodString>;
|
|
306
|
+
loyaltyCardNumber: z.ZodOptional<z.ZodString>;
|
|
307
|
+
}, "strip", z.ZodTypeAny, {
|
|
308
|
+
name?: string | undefined;
|
|
309
|
+
email?: string | undefined;
|
|
310
|
+
phone?: string | undefined;
|
|
311
|
+
loyaltyCardNumber?: string | undefined;
|
|
312
|
+
customerId?: string | undefined;
|
|
313
|
+
}, {
|
|
314
|
+
name?: string | undefined;
|
|
315
|
+
email?: string | undefined;
|
|
316
|
+
phone?: string | undefined;
|
|
317
|
+
loyaltyCardNumber?: string | undefined;
|
|
318
|
+
customerId?: string | undefined;
|
|
319
|
+
}>>;
|
|
320
|
+
};
|
|
321
|
+
readonly handler: typeof transactionCreate;
|
|
322
|
+
}, {
|
|
323
|
+
readonly name: "openloyalty_transaction_get";
|
|
324
|
+
readonly description: "Get transaction details including items, customerData, matched status, and pointsEarned.";
|
|
325
|
+
readonly inputSchema: {
|
|
326
|
+
storeCode: z.ZodOptional<z.ZodString>;
|
|
327
|
+
transactionId: z.ZodString;
|
|
328
|
+
};
|
|
329
|
+
readonly handler: typeof transactionGet;
|
|
330
|
+
}, {
|
|
331
|
+
readonly name: "openloyalty_transaction_list";
|
|
332
|
+
readonly description: string;
|
|
333
|
+
readonly inputSchema: {
|
|
334
|
+
storeCode: z.ZodOptional<z.ZodString>;
|
|
335
|
+
cursor: z.ZodOptional<z.ZodString>;
|
|
336
|
+
page: z.ZodOptional<z.ZodNumber>;
|
|
337
|
+
perPage: z.ZodOptional<z.ZodNumber>;
|
|
338
|
+
customerId: z.ZodOptional<z.ZodString>;
|
|
339
|
+
documentNumber: z.ZodOptional<z.ZodString>;
|
|
340
|
+
documentType: z.ZodOptional<z.ZodEnum<["sell", "return"]>>;
|
|
341
|
+
matched: z.ZodOptional<z.ZodBoolean>;
|
|
342
|
+
purchasedAtFrom: z.ZodOptional<z.ZodString>;
|
|
343
|
+
purchasedAtTo: z.ZodOptional<z.ZodString>;
|
|
344
|
+
};
|
|
345
|
+
readonly handler: typeof transactionList;
|
|
346
|
+
}, {
|
|
347
|
+
readonly name: "openloyalty_transaction_assign_member";
|
|
348
|
+
readonly description: string;
|
|
349
|
+
readonly inputSchema: {
|
|
350
|
+
storeCode: z.ZodOptional<z.ZodString>;
|
|
351
|
+
documentNumber: z.ZodString;
|
|
352
|
+
customerId: z.ZodOptional<z.ZodString>;
|
|
353
|
+
loyaltyCardNumber: z.ZodOptional<z.ZodString>;
|
|
354
|
+
phone: z.ZodOptional<z.ZodString>;
|
|
355
|
+
};
|
|
356
|
+
readonly handler: typeof transactionAssignMember;
|
|
357
|
+
}];
|
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { apiGet, apiPost } from "../client/http.js";
|
|
3
|
+
import { formatApiError } from "../utils/errors.js";
|
|
4
|
+
import { getConfig } from "../config.js";
|
|
5
|
+
import { buildPaginationParams, normalizeDateToISO } from "../utils/pagination.js";
|
|
6
|
+
// Input Schemas
|
|
7
|
+
const LabelInputSchema = z.object({
|
|
8
|
+
key: z.string(),
|
|
9
|
+
value: z.string(),
|
|
10
|
+
});
|
|
11
|
+
const TransactionHeaderInputSchema = z.object({
|
|
12
|
+
documentNumber: z.string().describe("Unique document number (required, unique per store)."),
|
|
13
|
+
purchasedAt: z.string().describe("Purchase date/time in ISO format (required)."),
|
|
14
|
+
documentType: z.enum(["sell", "return"]).optional().describe("Document type: sell (default) or return."),
|
|
15
|
+
linkedDocumentNumber: z.string().optional().describe("Original document number (required for returns)."),
|
|
16
|
+
purchasePlace: z.string().optional().describe("Location/store where purchase was made."),
|
|
17
|
+
labels: z.array(LabelInputSchema).optional().describe("Custom key-value labels."),
|
|
18
|
+
});
|
|
19
|
+
const TransactionItemInputSchema = z.object({
|
|
20
|
+
sku: z.string().describe("Product SKU (required, max 255 chars)."),
|
|
21
|
+
name: z.string().describe("Product name (required, max 255 chars)."),
|
|
22
|
+
grossValue: z.number().describe("Item gross value (required)."),
|
|
23
|
+
category: z.string().describe("Product category (required, max 255 chars)."),
|
|
24
|
+
quantity: z.number().optional().describe("Item quantity (integer)."),
|
|
25
|
+
highPrecisionQuantity: z.number().optional().describe("High precision quantity (up to 3 decimals, recommended)."),
|
|
26
|
+
maker: z.string().optional().describe("Product brand/maker."),
|
|
27
|
+
labels: z.array(LabelInputSchema).optional().describe("Custom key-value labels."),
|
|
28
|
+
});
|
|
29
|
+
const CustomerDataInputSchema = z.object({
|
|
30
|
+
customerId: z.string().optional().describe("Member ID (UUID) for explicit assignment."),
|
|
31
|
+
email: z.string().optional().describe("Email for auto-matching to member."),
|
|
32
|
+
name: z.string().optional().describe("Customer name."),
|
|
33
|
+
phone: z.string().optional().describe("Phone for auto-matching to member."),
|
|
34
|
+
loyaltyCardNumber: z.string().optional().describe("Loyalty card for auto-matching."),
|
|
35
|
+
});
|
|
36
|
+
export const TransactionCreateInputSchema = {
|
|
37
|
+
storeCode: z.string().optional().describe("Store code. If not provided, uses the default store code from configuration."),
|
|
38
|
+
header: TransactionHeaderInputSchema.describe("Transaction header with document info."),
|
|
39
|
+
items: z.array(TransactionItemInputSchema).describe("Array of purchased items (at least 1 required)."),
|
|
40
|
+
customerData: CustomerDataInputSchema.optional().describe("Customer data for auto-matching to member. If provided, triggers point campaigns."),
|
|
41
|
+
};
|
|
42
|
+
export const TransactionGetInputSchema = {
|
|
43
|
+
storeCode: z.string().optional().describe("Store code. If not provided, uses the default store code from configuration."),
|
|
44
|
+
transactionId: z.string().describe("The transaction ID (UUID) to retrieve."),
|
|
45
|
+
};
|
|
46
|
+
export const TransactionListInputSchema = {
|
|
47
|
+
storeCode: z.string().optional().describe("Store code. If not provided, uses the default store code from configuration."),
|
|
48
|
+
cursor: z.string().optional().describe("Pagination cursor from previous response. If provided, page/perPage are ignored."),
|
|
49
|
+
page: z.number().optional().describe("Page number (default: 1)."),
|
|
50
|
+
perPage: z.number().max(50).optional().describe("Items per page (default: 10, max: 50). Use 50 for aggregation queries to reduce API calls."),
|
|
51
|
+
customerId: z.string().optional().describe("Filter by member ID."),
|
|
52
|
+
documentNumber: z.string().optional().describe("Filter by document number."),
|
|
53
|
+
documentType: z.enum(["sell", "return"]).optional().describe("Filter by document type."),
|
|
54
|
+
matched: z.boolean().optional().describe("Filter by matched status."),
|
|
55
|
+
purchasedAtFrom: z.string().optional().describe("Filter transactions purchased on or after this date (ISO format: YYYY-MM-DD or YYYY-MM-DDTHH:mm:ssZ)."),
|
|
56
|
+
purchasedAtTo: z.string().optional().describe("Filter transactions purchased on or before this date (ISO format: YYYY-MM-DD or YYYY-MM-DDTHH:mm:ssZ)."),
|
|
57
|
+
};
|
|
58
|
+
export const TransactionAssignMemberInputSchema = {
|
|
59
|
+
storeCode: z.string().optional().describe("Store code. If not provided, uses the default store code from configuration."),
|
|
60
|
+
documentNumber: z.string().describe("Document number of the transaction to assign."),
|
|
61
|
+
customerId: z.string().optional().describe("Member ID (UUID) to assign."),
|
|
62
|
+
loyaltyCardNumber: z.string().optional().describe("Loyalty card number to match member."),
|
|
63
|
+
phone: z.string().optional().describe("Phone number to match member."),
|
|
64
|
+
};
|
|
65
|
+
// Handler functions
|
|
66
|
+
export async function transactionCreate(input) {
|
|
67
|
+
const config = getConfig();
|
|
68
|
+
const storeCode = input.storeCode || config.defaultStoreCode;
|
|
69
|
+
const transactionPayload = {
|
|
70
|
+
header: {
|
|
71
|
+
documentNumber: input.header.documentNumber,
|
|
72
|
+
documentType: input.header.documentType || "sell",
|
|
73
|
+
purchasedAt: input.header.purchasedAt,
|
|
74
|
+
purchasePlace: input.header.purchasePlace,
|
|
75
|
+
linkedDocumentNumber: input.header.linkedDocumentNumber,
|
|
76
|
+
labels: input.header.labels,
|
|
77
|
+
},
|
|
78
|
+
items: input.items.map((item) => ({
|
|
79
|
+
sku: item.sku,
|
|
80
|
+
name: item.name,
|
|
81
|
+
grossValue: item.grossValue,
|
|
82
|
+
category: item.category,
|
|
83
|
+
highPrecisionQuantity: item.highPrecisionQuantity || item.quantity || 1,
|
|
84
|
+
maker: item.maker,
|
|
85
|
+
labels: item.labels,
|
|
86
|
+
})),
|
|
87
|
+
};
|
|
88
|
+
if (input.customerData) {
|
|
89
|
+
transactionPayload.customerData = input.customerData;
|
|
90
|
+
}
|
|
91
|
+
try {
|
|
92
|
+
const response = await apiPost(`/${storeCode}/transaction`, { transaction: transactionPayload });
|
|
93
|
+
return {
|
|
94
|
+
transactionId: response.transactionId,
|
|
95
|
+
pointsEarned: response.pointsEarned,
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
catch (error) {
|
|
99
|
+
throw formatApiError(error, "openloyalty_transaction_create");
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
export async function transactionGet(input) {
|
|
103
|
+
const config = getConfig();
|
|
104
|
+
const storeCode = input.storeCode || config.defaultStoreCode;
|
|
105
|
+
try {
|
|
106
|
+
const response = await apiGet(`/${storeCode}/transaction/${input.transactionId}`);
|
|
107
|
+
const header = response.header;
|
|
108
|
+
return {
|
|
109
|
+
transactionId: response.transactionId,
|
|
110
|
+
documentNumber: (header?.documentNumber || response.documentNumber),
|
|
111
|
+
documentType: (header?.documentType || response.documentType || "sell"),
|
|
112
|
+
items: (response.items || []),
|
|
113
|
+
customerData: response.customerData,
|
|
114
|
+
matched: (response.matched ?? response.customerId != null),
|
|
115
|
+
grossValue: (response.grossValue || 0),
|
|
116
|
+
pointsEarned: response.pointsEarned,
|
|
117
|
+
purchasedAt: (header?.purchasedAt || response.purchasedAt),
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
catch (error) {
|
|
121
|
+
throw formatApiError(error, "openloyalty_transaction_get");
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
export async function transactionList(input) {
|
|
125
|
+
const config = getConfig();
|
|
126
|
+
const storeCode = input.storeCode || config.defaultStoreCode;
|
|
127
|
+
const params = new URLSearchParams();
|
|
128
|
+
// Enforce max perPage of 50 (API limit)
|
|
129
|
+
const perPage = input.perPage ? Math.min(input.perPage, 50) : undefined;
|
|
130
|
+
// Use buildPaginationParams for cursor/page handling
|
|
131
|
+
buildPaginationParams({ cursor: input.cursor, page: input.page, perPage }, params);
|
|
132
|
+
if (input.customerId)
|
|
133
|
+
params.append("customerId", input.customerId);
|
|
134
|
+
if (input.documentNumber)
|
|
135
|
+
params.append("header:documentNumber", input.documentNumber);
|
|
136
|
+
if (input.documentType)
|
|
137
|
+
params.append("header:documentType", input.documentType);
|
|
138
|
+
if (input.matched !== undefined)
|
|
139
|
+
params.append("matched", String(input.matched));
|
|
140
|
+
if (input.purchasedAtFrom)
|
|
141
|
+
params.append("header:purchasedAt[gte]", normalizeDateToISO(input.purchasedAtFrom, "from"));
|
|
142
|
+
if (input.purchasedAtTo)
|
|
143
|
+
params.append("header:purchasedAt[lte]", normalizeDateToISO(input.purchasedAtTo, "to"));
|
|
144
|
+
const queryString = params.toString();
|
|
145
|
+
const url = `/${storeCode}/transaction${queryString ? `?${queryString}` : ""}`;
|
|
146
|
+
try {
|
|
147
|
+
const response = await apiGet(url);
|
|
148
|
+
const items = response.items || response.transactions || [];
|
|
149
|
+
const transactions = items.map((t) => {
|
|
150
|
+
const txn = t;
|
|
151
|
+
const header = txn.header;
|
|
152
|
+
const customerId = txn.customerId;
|
|
153
|
+
return {
|
|
154
|
+
transactionId: txn.transactionId,
|
|
155
|
+
documentNumber: (header?.documentNumber || txn.documentNumber),
|
|
156
|
+
grossValue: (txn.grossValue || 0),
|
|
157
|
+
matched: (txn.matched ?? customerId != null),
|
|
158
|
+
customerId,
|
|
159
|
+
pointsEarned: txn.pointsEarned,
|
|
160
|
+
purchasedAt: (header?.purchasedAt || txn.purchasedAt),
|
|
161
|
+
};
|
|
162
|
+
});
|
|
163
|
+
const total = response.total || {};
|
|
164
|
+
return {
|
|
165
|
+
transactions,
|
|
166
|
+
total: {
|
|
167
|
+
all: typeof total.all === 'number' ? total.all : undefined,
|
|
168
|
+
filtered: typeof total.filtered === 'number' ? total.filtered : undefined,
|
|
169
|
+
},
|
|
170
|
+
cursor: response.scroll,
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
catch (error) {
|
|
174
|
+
throw formatApiError(error, "openloyalty_transaction_list");
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
export async function transactionAssignMember(input) {
|
|
178
|
+
const config = getConfig();
|
|
179
|
+
const storeCode = input.storeCode || config.defaultStoreCode;
|
|
180
|
+
// At least one identifier required
|
|
181
|
+
if (!input.customerId && !input.loyaltyCardNumber && !input.phone) {
|
|
182
|
+
throw new Error("At least one member identifier required: customerId, loyaltyCardNumber, or phone.");
|
|
183
|
+
}
|
|
184
|
+
const assignPayload = {
|
|
185
|
+
transactionDocumentNumber: input.documentNumber,
|
|
186
|
+
};
|
|
187
|
+
if (input.customerId)
|
|
188
|
+
assignPayload.customerId = input.customerId;
|
|
189
|
+
if (input.loyaltyCardNumber)
|
|
190
|
+
assignPayload.customerLoyaltyCardNumber = input.loyaltyCardNumber;
|
|
191
|
+
if (input.phone)
|
|
192
|
+
assignPayload.customerPhoneNumber = input.phone;
|
|
193
|
+
try {
|
|
194
|
+
// API uses /transaction/assign with assign wrapper, not /transaction/customer/assign
|
|
195
|
+
const response = await apiPost(`/${storeCode}/transaction/assign`, { assign: assignPayload });
|
|
196
|
+
return {
|
|
197
|
+
transactionId: response.transactionId,
|
|
198
|
+
customerId: response.customerId,
|
|
199
|
+
pointsEarned: response.pointsEarned,
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
catch (error) {
|
|
203
|
+
throw formatApiError(error, "openloyalty_transaction_assign_member");
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
// Tool definitions
|
|
207
|
+
export const transactionToolDefinitions = [
|
|
208
|
+
{
|
|
209
|
+
name: "openloyalty_transaction_create",
|
|
210
|
+
description: "Record a purchase transaction. If customerData provided, auto-matches to member and triggers point campaigns. " +
|
|
211
|
+
"For returns, set documentType='return' and provide linkedDocumentNumber referencing original sale. " +
|
|
212
|
+
"Returns transactionId and pointsEarned if campaigns triggered.",
|
|
213
|
+
inputSchema: TransactionCreateInputSchema,
|
|
214
|
+
handler: transactionCreate,
|
|
215
|
+
},
|
|
216
|
+
{
|
|
217
|
+
name: "openloyalty_transaction_get",
|
|
218
|
+
description: "Get transaction details including items, customerData, matched status, and pointsEarned.",
|
|
219
|
+
inputSchema: TransactionGetInputSchema,
|
|
220
|
+
handler: transactionGet,
|
|
221
|
+
},
|
|
222
|
+
{
|
|
223
|
+
name: "openloyalty_transaction_list",
|
|
224
|
+
description: "List transactions with optional filters. Filter by customerId, documentNumber, documentType, matched status, or date range (purchasedAtFrom/purchasedAtTo). " +
|
|
225
|
+
"Use ISO date format for date filters (e.g., '2025-07-01' or '2025-07-01T00:00:00Z'). " +
|
|
226
|
+
"Supports cursor pagination: provide 'cursor' from previous response to get next page. " +
|
|
227
|
+
"Returns customerId for matched transactions - use this for aggregation queries like 'top spenders'. " +
|
|
228
|
+
"IMPORTANT FOR AGGREGATION QUERIES: Always use cursor pagination and iterate through ALL pages, even for large datasets (1000+ transactions). " +
|
|
229
|
+
"Do NOT try to optimize or find shortcuts - the cursor approach is the correct and only way to get accurate results. " +
|
|
230
|
+
"Start with cursor='' (empty string), then use returned cursor for subsequent requests until no more data. " +
|
|
231
|
+
"Use perPage=50 to minimize API calls. Aggregate by customerId in your code, then use member_get for names.",
|
|
232
|
+
inputSchema: TransactionListInputSchema,
|
|
233
|
+
handler: transactionList,
|
|
234
|
+
},
|
|
235
|
+
{
|
|
236
|
+
name: "openloyalty_transaction_assign_member",
|
|
237
|
+
description: "Assign unmatched transaction to member by ID, card number, or phone. Triggers point campaigns. " +
|
|
238
|
+
"Use this to link a transaction that wasn't matched at creation time. Returns transactionId, customerId, and pointsEarned.",
|
|
239
|
+
inputSchema: TransactionAssignMemberInputSchema,
|
|
240
|
+
handler: transactionAssignMember,
|
|
241
|
+
},
|
|
242
|
+
];
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|