@open-loyalty/mcp-server 1.3.7 → 1.5.3
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/config.d.ts +4 -3
- package/dist/config.js +9 -7
- package/dist/instructions.d.ts +1 -1
- package/dist/instructions.js +26 -8
- package/dist/tools/achievement/handlers.js +60 -1
- package/dist/tools/achievement/index.d.ts +8 -8
- package/dist/tools/achievement/index.js +10 -11
- package/dist/tools/achievement/schemas.d.ts +8 -8
- package/dist/tools/achievement/schemas.js +36 -32
- package/dist/tools/analytics.js +9 -9
- package/dist/tools/badge.js +4 -4
- package/dist/tools/campaign/handlers.js +35 -1
- package/dist/tools/campaign/index.d.ts +97 -34
- package/dist/tools/campaign/index.js +14 -12
- package/dist/tools/campaign/schemas.d.ts +96 -33
- package/dist/tools/campaign/schemas.js +89 -55
- package/dist/tools/custom-event.js +10 -9
- package/dist/tools/export.js +4 -4
- package/dist/tools/import.d.ts +1 -1
- package/dist/tools/import.js +11 -6
- package/dist/tools/index.js +4 -4
- package/dist/tools/member/handlers.js +48 -1
- package/dist/tools/member/index.d.ts +1 -1
- package/dist/tools/member/index.js +3 -1
- package/dist/tools/member/schemas.js +12 -12
- package/dist/tools/points/handlers.d.ts +75 -0
- package/dist/tools/{points.js → points/handlers.js} +21 -112
- package/dist/tools/points/index.d.ts +84 -0
- package/dist/tools/points/index.js +63 -0
- package/dist/tools/points/schemas.d.ts +45 -0
- package/dist/tools/points/schemas.js +47 -0
- package/dist/tools/referral/schemas.js +3 -3
- package/dist/tools/reward/handlers.d.ts +2 -0
- package/dist/tools/reward/handlers.js +79 -6
- package/dist/tools/reward/index.d.ts +2 -0
- package/dist/tools/reward/index.js +10 -10
- package/dist/tools/reward/schemas.d.ts +2 -0
- package/dist/tools/reward/schemas.js +42 -23
- package/dist/tools/segment/index.js +7 -5
- package/dist/tools/segment/schemas.js +11 -11
- package/dist/tools/tierset/handlers.d.ts +26 -0
- package/dist/tools/tierset/handlers.js +196 -0
- package/dist/tools/tierset/index.d.ts +124 -0
- package/dist/tools/tierset/index.js +88 -0
- package/dist/tools/tierset/schemas.d.ts +127 -0
- package/dist/tools/tierset/schemas.js +62 -0
- package/dist/tools/transaction/handlers.d.ts +89 -0
- package/dist/tools/transaction/handlers.js +159 -0
- package/dist/tools/transaction/index.d.ts +153 -0
- package/dist/tools/transaction/index.js +54 -0
- package/dist/tools/transaction/schemas.d.ts +126 -0
- package/dist/tools/transaction/schemas.js +60 -0
- package/dist/tools/wallet-type/handlers.d.ts +63 -0
- package/dist/tools/{wallet-type.js → wallet-type/handlers.js} +15 -78
- package/dist/tools/{wallet-type.d.ts → wallet-type/index.d.ts} +3 -64
- package/dist/tools/wallet-type/index.js +65 -0
- package/dist/tools/wallet-type/schemas.d.ts +1 -0
- package/dist/tools/wallet-type/schemas.js +1 -0
- package/dist/tools/webhook.js +6 -6
- package/dist/types/schemas/achievement.d.ts +48 -48
- package/dist/types/schemas/admin.d.ts +10 -10
- package/dist/types/schemas/campaign.d.ts +12 -12
- package/dist/types/schemas/common.js +1 -1
- package/dist/types/schemas/member.d.ts +18 -18
- package/dist/types/schemas/role.d.ts +4 -4
- package/dist/types/schemas/tierset.js +2 -1
- package/dist/types/schemas/transaction.d.ts +12 -12
- package/dist/types/schemas/wallet-type.js +12 -10
- package/dist/types/schemas/webhook.d.ts +6 -6
- package/dist/utils/errors.js +40 -0
- package/package.json +3 -2
- package/dist/prompts/fan-engagement-setup.d.ts +0 -107
- package/dist/prompts/fan-engagement-setup.js +0 -492
- package/dist/tools/achievement.d.ts +0 -1017
- package/dist/tools/achievement.js +0 -354
- package/dist/tools/campaign.d.ts +0 -1800
- package/dist/tools/campaign.js +0 -737
- package/dist/tools/member.d.ts +0 -366
- package/dist/tools/member.js +0 -352
- package/dist/tools/points.d.ts +0 -201
- package/dist/tools/reward.d.ts +0 -279
- package/dist/tools/reward.js +0 -361
- package/dist/tools/segment.d.ts +0 -816
- package/dist/tools/segment.js +0 -333
- package/dist/tools/tierset.d.ts +0 -273
- package/dist/tools/tierset.js +0 -289
- package/dist/tools/transaction.d.ts +0 -365
- package/dist/tools/transaction.js +0 -259
- package/dist/workflows/app-login-streak.d.ts +0 -39
- package/dist/workflows/app-login-streak.js +0 -298
- package/dist/workflows/early-arrival.d.ts +0 -33
- package/dist/workflows/early-arrival.js +0 -148
- package/dist/workflows/index.d.ts +0 -101
- package/dist/workflows/index.js +0 -208
- package/dist/workflows/match-attendance.d.ts +0 -45
- package/dist/workflows/match-attendance.js +0 -308
- package/dist/workflows/sportsbar-visit.d.ts +0 -41
- package/dist/workflows/sportsbar-visit.js +0 -284
- package/dist/workflows/vod-watching.d.ts +0 -43
- package/dist/workflows/vod-watching.js +0 -326
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
export declare function transactionCreate(input: {
|
|
2
|
+
storeCode?: string;
|
|
3
|
+
header: {
|
|
4
|
+
documentNumber: string;
|
|
5
|
+
purchasedAt: string;
|
|
6
|
+
documentType?: string;
|
|
7
|
+
linkedDocumentNumber?: string;
|
|
8
|
+
purchasePlace?: string;
|
|
9
|
+
labels?: Array<{
|
|
10
|
+
key: string;
|
|
11
|
+
value: string;
|
|
12
|
+
}>;
|
|
13
|
+
};
|
|
14
|
+
items: Array<{
|
|
15
|
+
sku: string;
|
|
16
|
+
name: string;
|
|
17
|
+
grossValue: number;
|
|
18
|
+
category: string;
|
|
19
|
+
quantity?: number;
|
|
20
|
+
highPrecisionQuantity?: number;
|
|
21
|
+
maker?: string;
|
|
22
|
+
labels?: Array<{
|
|
23
|
+
key: string;
|
|
24
|
+
value: string;
|
|
25
|
+
}>;
|
|
26
|
+
}>;
|
|
27
|
+
customerData?: {
|
|
28
|
+
customerId?: string;
|
|
29
|
+
email?: string;
|
|
30
|
+
name?: string;
|
|
31
|
+
phone?: string;
|
|
32
|
+
loyaltyCardNumber?: string;
|
|
33
|
+
};
|
|
34
|
+
}): Promise<{
|
|
35
|
+
transactionId: string;
|
|
36
|
+
pointsEarned?: number;
|
|
37
|
+
}>;
|
|
38
|
+
export declare function transactionGet(input: {
|
|
39
|
+
storeCode?: string;
|
|
40
|
+
transactionId: string;
|
|
41
|
+
}): Promise<{
|
|
42
|
+
transactionId: string;
|
|
43
|
+
documentNumber: string;
|
|
44
|
+
documentType: string;
|
|
45
|
+
items: unknown[];
|
|
46
|
+
customerData?: unknown;
|
|
47
|
+
matched: boolean;
|
|
48
|
+
grossValue: number;
|
|
49
|
+
pointsEarned?: number;
|
|
50
|
+
purchasedAt?: string;
|
|
51
|
+
}>;
|
|
52
|
+
export declare function transactionList(input: {
|
|
53
|
+
storeCode?: string;
|
|
54
|
+
cursor?: string;
|
|
55
|
+
page?: number;
|
|
56
|
+
perPage?: number;
|
|
57
|
+
customerId?: string;
|
|
58
|
+
documentNumber?: string;
|
|
59
|
+
documentType?: string;
|
|
60
|
+
matched?: boolean;
|
|
61
|
+
purchasedAtFrom?: string;
|
|
62
|
+
purchasedAtTo?: string;
|
|
63
|
+
}): Promise<{
|
|
64
|
+
transactions: Array<{
|
|
65
|
+
transactionId: string;
|
|
66
|
+
documentNumber: string;
|
|
67
|
+
grossValue: number;
|
|
68
|
+
matched: boolean;
|
|
69
|
+
customerId?: string;
|
|
70
|
+
pointsEarned?: number;
|
|
71
|
+
purchasedAt?: string;
|
|
72
|
+
}>;
|
|
73
|
+
total: {
|
|
74
|
+
all?: number;
|
|
75
|
+
filtered?: number;
|
|
76
|
+
};
|
|
77
|
+
cursor?: string;
|
|
78
|
+
}>;
|
|
79
|
+
export declare function transactionAssignMember(input: {
|
|
80
|
+
storeCode?: string;
|
|
81
|
+
documentNumber: string;
|
|
82
|
+
customerId?: string;
|
|
83
|
+
loyaltyCardNumber?: string;
|
|
84
|
+
phone?: string;
|
|
85
|
+
}): Promise<{
|
|
86
|
+
transactionId: string;
|
|
87
|
+
customerId: string;
|
|
88
|
+
pointsEarned?: number;
|
|
89
|
+
}>;
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
import { apiGet, apiPost } from "../../client/http.js";
|
|
2
|
+
import { formatApiError, OpenLoyaltyError } from "../../utils/errors.js";
|
|
3
|
+
import { getStoreCode } from "../../config.js";
|
|
4
|
+
import { buildPaginationParams, normalizeDateToISO } from "../../utils/pagination.js";
|
|
5
|
+
// Handler functions
|
|
6
|
+
export async function transactionCreate(input) {
|
|
7
|
+
const storeCode = getStoreCode(input.storeCode);
|
|
8
|
+
const transactionPayload = {
|
|
9
|
+
header: {
|
|
10
|
+
documentNumber: input.header.documentNumber,
|
|
11
|
+
documentType: input.header.documentType || "sell",
|
|
12
|
+
purchasedAt: input.header.purchasedAt,
|
|
13
|
+
purchasePlace: input.header.purchasePlace,
|
|
14
|
+
linkedDocumentNumber: input.header.linkedDocumentNumber,
|
|
15
|
+
labels: input.header.labels,
|
|
16
|
+
},
|
|
17
|
+
items: input.items.map((item) => ({
|
|
18
|
+
sku: item.sku,
|
|
19
|
+
name: item.name,
|
|
20
|
+
grossValue: item.grossValue,
|
|
21
|
+
category: item.category,
|
|
22
|
+
highPrecisionQuantity: item.highPrecisionQuantity || item.quantity || 1,
|
|
23
|
+
maker: item.maker,
|
|
24
|
+
labels: item.labels,
|
|
25
|
+
})),
|
|
26
|
+
};
|
|
27
|
+
if (input.customerData) {
|
|
28
|
+
transactionPayload.customerData = input.customerData;
|
|
29
|
+
}
|
|
30
|
+
try {
|
|
31
|
+
const response = await apiPost(`/${storeCode}/transaction`, { transaction: transactionPayload });
|
|
32
|
+
return {
|
|
33
|
+
transactionId: response.transactionId,
|
|
34
|
+
pointsEarned: response.pointsEarned,
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
catch (error) {
|
|
38
|
+
// Check for duplicate document number error
|
|
39
|
+
// Must check axios response data, not just error.message
|
|
40
|
+
const axiosError = error;
|
|
41
|
+
const apiErrors = axiosError.response?.data?.errors || [];
|
|
42
|
+
const allErrorMessages = apiErrors.map(e => e.message).join(" ").toLowerCase();
|
|
43
|
+
if (allErrorMessages.includes("document number") && allErrorMessages.includes("unique")) {
|
|
44
|
+
throw new OpenLoyaltyError({
|
|
45
|
+
code: "DUPLICATE_DOCUMENT",
|
|
46
|
+
message: `Transaction with document number '${input.header.documentNumber}' already exists`,
|
|
47
|
+
hint: `Each transaction must have a unique documentNumber. Use transaction_list(documentNumber: "${input.header.documentNumber}") to check if it exists, or generate a new unique document number (e.g., add timestamp suffix).`,
|
|
48
|
+
relatedTool: "ol_transaction_create",
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
throw formatApiError(error, "ol_transaction_create");
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
export async function transactionGet(input) {
|
|
55
|
+
const storeCode = getStoreCode(input.storeCode);
|
|
56
|
+
try {
|
|
57
|
+
const response = await apiGet(`/${storeCode}/transaction/${input.transactionId}`);
|
|
58
|
+
const header = response.header;
|
|
59
|
+
return {
|
|
60
|
+
transactionId: response.transactionId,
|
|
61
|
+
documentNumber: (header?.documentNumber || response.documentNumber),
|
|
62
|
+
documentType: (header?.documentType || response.documentType || "sell"),
|
|
63
|
+
items: (response.items || []),
|
|
64
|
+
customerData: response.customerData,
|
|
65
|
+
matched: (response.matched ?? response.customerId != null),
|
|
66
|
+
grossValue: (response.grossValue || 0),
|
|
67
|
+
pointsEarned: response.pointsEarned,
|
|
68
|
+
purchasedAt: (header?.purchasedAt || response.purchasedAt),
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
catch (error) {
|
|
72
|
+
throw formatApiError(error, "ol_transaction_get");
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
export async function transactionList(input) {
|
|
76
|
+
const storeCode = getStoreCode(input.storeCode);
|
|
77
|
+
const params = new URLSearchParams();
|
|
78
|
+
// Enforce max perPage of 50 (API limit)
|
|
79
|
+
const perPage = input.perPage ? Math.min(input.perPage, 50) : undefined;
|
|
80
|
+
// Use buildPaginationParams for cursor/page handling
|
|
81
|
+
buildPaginationParams({ cursor: input.cursor, page: input.page, perPage }, params);
|
|
82
|
+
if (input.customerId)
|
|
83
|
+
params.append("customerId", input.customerId);
|
|
84
|
+
if (input.documentNumber)
|
|
85
|
+
params.append("header:documentNumber", input.documentNumber);
|
|
86
|
+
if (input.documentType)
|
|
87
|
+
params.append("header:documentType", input.documentType);
|
|
88
|
+
if (input.matched !== undefined)
|
|
89
|
+
params.append("matched", String(input.matched));
|
|
90
|
+
if (input.purchasedAtFrom)
|
|
91
|
+
params.append("header:purchasedAt[gte]", normalizeDateToISO(input.purchasedAtFrom, "from"));
|
|
92
|
+
if (input.purchasedAtTo)
|
|
93
|
+
params.append("header:purchasedAt[lte]", normalizeDateToISO(input.purchasedAtTo, "to"));
|
|
94
|
+
const queryString = params.toString();
|
|
95
|
+
const url = `/${storeCode}/transaction${queryString ? `?${queryString}` : ""}`;
|
|
96
|
+
try {
|
|
97
|
+
const response = await apiGet(url);
|
|
98
|
+
const items = response.items || response.transactions || [];
|
|
99
|
+
const transactions = items.map((t) => {
|
|
100
|
+
const txn = t;
|
|
101
|
+
const header = txn.header;
|
|
102
|
+
const customerId = txn.customerId;
|
|
103
|
+
return {
|
|
104
|
+
transactionId: txn.transactionId,
|
|
105
|
+
documentNumber: (header?.documentNumber || txn.documentNumber),
|
|
106
|
+
grossValue: (txn.grossValue || 0),
|
|
107
|
+
matched: (txn.matched ?? customerId != null),
|
|
108
|
+
customerId,
|
|
109
|
+
pointsEarned: txn.pointsEarned,
|
|
110
|
+
purchasedAt: (header?.purchasedAt || txn.purchasedAt),
|
|
111
|
+
};
|
|
112
|
+
});
|
|
113
|
+
const total = response.total || {};
|
|
114
|
+
return {
|
|
115
|
+
transactions,
|
|
116
|
+
total: {
|
|
117
|
+
all: typeof total.all === 'number' ? total.all : undefined,
|
|
118
|
+
filtered: typeof total.filtered === 'number' ? total.filtered : undefined,
|
|
119
|
+
},
|
|
120
|
+
cursor: response.scroll,
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
catch (error) {
|
|
124
|
+
throw formatApiError(error, "ol_transaction_list");
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
export async function transactionAssignMember(input) {
|
|
128
|
+
const storeCode = getStoreCode(input.storeCode);
|
|
129
|
+
// At least one identifier required
|
|
130
|
+
if (!input.customerId && !input.loyaltyCardNumber && !input.phone) {
|
|
131
|
+
throw new OpenLoyaltyError({
|
|
132
|
+
code: "MISSING_IDENTIFIER",
|
|
133
|
+
message: "At least one member identifier required: customerId, loyaltyCardNumber, or phone.",
|
|
134
|
+
hint: `Provide one of: customerId (UUID from ol_member_get), loyaltyCardNumber, or phone. Use ol_member_list() to find member details.`,
|
|
135
|
+
relatedTool: "ol_transaction_assign_member",
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
const assignPayload = {
|
|
139
|
+
transactionDocumentNumber: input.documentNumber,
|
|
140
|
+
};
|
|
141
|
+
if (input.customerId)
|
|
142
|
+
assignPayload.customerId = input.customerId;
|
|
143
|
+
if (input.loyaltyCardNumber)
|
|
144
|
+
assignPayload.customerLoyaltyCardNumber = input.loyaltyCardNumber;
|
|
145
|
+
if (input.phone)
|
|
146
|
+
assignPayload.customerPhoneNumber = input.phone;
|
|
147
|
+
try {
|
|
148
|
+
// API uses /transaction/assign with assign wrapper, not /transaction/customer/assign
|
|
149
|
+
const response = await apiPost(`/${storeCode}/transaction/assign`, { assign: assignPayload });
|
|
150
|
+
return {
|
|
151
|
+
transactionId: response.transactionId,
|
|
152
|
+
customerId: response.customerId,
|
|
153
|
+
pointsEarned: response.pointsEarned,
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
catch (error) {
|
|
157
|
+
throw formatApiError(error, "ol_transaction_assign_member");
|
|
158
|
+
}
|
|
159
|
+
}
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
export { TransactionCreateInputSchema, TransactionGetInputSchema, TransactionListInputSchema, TransactionAssignMemberInputSchema, } from "./schemas.js";
|
|
2
|
+
export { transactionCreate, transactionGet, transactionList, transactionAssignMember, } from "./handlers.js";
|
|
3
|
+
import { transactionCreate, transactionGet, transactionList, transactionAssignMember } from "./handlers.js";
|
|
4
|
+
export declare const transactionToolDefinitions: readonly [{
|
|
5
|
+
readonly name: "ol_transaction_create";
|
|
6
|
+
readonly title: "Record Purchase";
|
|
7
|
+
readonly description: string;
|
|
8
|
+
readonly readOnly: false;
|
|
9
|
+
readonly inputSchema: {
|
|
10
|
+
storeCode: import("zod").ZodOptional<import("zod").ZodString>;
|
|
11
|
+
header: import("zod").ZodObject<{
|
|
12
|
+
documentNumber: import("zod").ZodString;
|
|
13
|
+
purchasedAt: import("zod").ZodString;
|
|
14
|
+
documentType: import("zod").ZodOptional<import("zod").ZodEnum<["sell", "return"]>>;
|
|
15
|
+
linkedDocumentNumber: import("zod").ZodOptional<import("zod").ZodString>;
|
|
16
|
+
purchasePlace: import("zod").ZodOptional<import("zod").ZodString>;
|
|
17
|
+
labels: import("zod").ZodOptional<import("zod").ZodArray<import("zod").ZodObject<{
|
|
18
|
+
key: import("zod").ZodString;
|
|
19
|
+
value: import("zod").ZodString;
|
|
20
|
+
}, "strip", import("zod").ZodTypeAny, {
|
|
21
|
+
value: string;
|
|
22
|
+
key: string;
|
|
23
|
+
}, {
|
|
24
|
+
value: string;
|
|
25
|
+
key: string;
|
|
26
|
+
}>, "many">>;
|
|
27
|
+
}, "strip", import("zod").ZodTypeAny, {
|
|
28
|
+
documentNumber: string;
|
|
29
|
+
purchasedAt: string;
|
|
30
|
+
documentType?: "sell" | "return" | undefined;
|
|
31
|
+
linkedDocumentNumber?: string | undefined;
|
|
32
|
+
purchasePlace?: string | undefined;
|
|
33
|
+
labels?: {
|
|
34
|
+
value: string;
|
|
35
|
+
key: string;
|
|
36
|
+
}[] | undefined;
|
|
37
|
+
}, {
|
|
38
|
+
documentNumber: string;
|
|
39
|
+
purchasedAt: string;
|
|
40
|
+
documentType?: "sell" | "return" | undefined;
|
|
41
|
+
linkedDocumentNumber?: string | undefined;
|
|
42
|
+
purchasePlace?: string | undefined;
|
|
43
|
+
labels?: {
|
|
44
|
+
value: string;
|
|
45
|
+
key: string;
|
|
46
|
+
}[] | undefined;
|
|
47
|
+
}>;
|
|
48
|
+
items: import("zod").ZodArray<import("zod").ZodObject<{
|
|
49
|
+
sku: import("zod").ZodString;
|
|
50
|
+
name: import("zod").ZodString;
|
|
51
|
+
grossValue: import("zod").ZodNumber;
|
|
52
|
+
category: import("zod").ZodString;
|
|
53
|
+
quantity: import("zod").ZodOptional<import("zod").ZodNumber>;
|
|
54
|
+
highPrecisionQuantity: import("zod").ZodOptional<import("zod").ZodNumber>;
|
|
55
|
+
maker: import("zod").ZodOptional<import("zod").ZodString>;
|
|
56
|
+
labels: import("zod").ZodOptional<import("zod").ZodArray<import("zod").ZodObject<{
|
|
57
|
+
key: import("zod").ZodString;
|
|
58
|
+
value: import("zod").ZodString;
|
|
59
|
+
}, "strip", import("zod").ZodTypeAny, {
|
|
60
|
+
value: string;
|
|
61
|
+
key: string;
|
|
62
|
+
}, {
|
|
63
|
+
value: string;
|
|
64
|
+
key: string;
|
|
65
|
+
}>, "many">>;
|
|
66
|
+
}, "strip", import("zod").ZodTypeAny, {
|
|
67
|
+
name: string;
|
|
68
|
+
sku: string;
|
|
69
|
+
grossValue: number;
|
|
70
|
+
category: string;
|
|
71
|
+
quantity?: number | undefined;
|
|
72
|
+
labels?: {
|
|
73
|
+
value: string;
|
|
74
|
+
key: string;
|
|
75
|
+
}[] | undefined;
|
|
76
|
+
highPrecisionQuantity?: number | undefined;
|
|
77
|
+
maker?: string | undefined;
|
|
78
|
+
}, {
|
|
79
|
+
name: string;
|
|
80
|
+
sku: string;
|
|
81
|
+
grossValue: number;
|
|
82
|
+
category: string;
|
|
83
|
+
quantity?: number | undefined;
|
|
84
|
+
labels?: {
|
|
85
|
+
value: string;
|
|
86
|
+
key: string;
|
|
87
|
+
}[] | undefined;
|
|
88
|
+
highPrecisionQuantity?: number | undefined;
|
|
89
|
+
maker?: string | undefined;
|
|
90
|
+
}>, "many">;
|
|
91
|
+
customerData: import("zod").ZodOptional<import("zod").ZodObject<{
|
|
92
|
+
customerId: import("zod").ZodOptional<import("zod").ZodString>;
|
|
93
|
+
email: import("zod").ZodOptional<import("zod").ZodString>;
|
|
94
|
+
name: import("zod").ZodOptional<import("zod").ZodString>;
|
|
95
|
+
phone: import("zod").ZodOptional<import("zod").ZodString>;
|
|
96
|
+
loyaltyCardNumber: import("zod").ZodOptional<import("zod").ZodString>;
|
|
97
|
+
}, "strip", import("zod").ZodTypeAny, {
|
|
98
|
+
name?: string | undefined;
|
|
99
|
+
email?: string | undefined;
|
|
100
|
+
phone?: string | undefined;
|
|
101
|
+
loyaltyCardNumber?: string | undefined;
|
|
102
|
+
customerId?: string | undefined;
|
|
103
|
+
}, {
|
|
104
|
+
name?: string | undefined;
|
|
105
|
+
email?: string | undefined;
|
|
106
|
+
phone?: string | undefined;
|
|
107
|
+
loyaltyCardNumber?: string | undefined;
|
|
108
|
+
customerId?: string | undefined;
|
|
109
|
+
}>>;
|
|
110
|
+
};
|
|
111
|
+
readonly handler: typeof transactionCreate;
|
|
112
|
+
}, {
|
|
113
|
+
readonly name: "ol_transaction_get";
|
|
114
|
+
readonly title: "Get Transaction Details";
|
|
115
|
+
readonly description: "Get transaction details including items, customerData, matched status, and pointsEarned.";
|
|
116
|
+
readonly readOnly: true;
|
|
117
|
+
readonly inputSchema: {
|
|
118
|
+
storeCode: import("zod").ZodOptional<import("zod").ZodString>;
|
|
119
|
+
transactionId: import("zod").ZodString;
|
|
120
|
+
};
|
|
121
|
+
readonly handler: typeof transactionGet;
|
|
122
|
+
}, {
|
|
123
|
+
readonly name: "ol_transaction_list";
|
|
124
|
+
readonly title: "Search Transactions";
|
|
125
|
+
readonly description: string;
|
|
126
|
+
readonly readOnly: true;
|
|
127
|
+
readonly inputSchema: {
|
|
128
|
+
storeCode: import("zod").ZodOptional<import("zod").ZodString>;
|
|
129
|
+
cursor: import("zod").ZodOptional<import("zod").ZodString>;
|
|
130
|
+
page: import("zod").ZodOptional<import("zod").ZodNumber>;
|
|
131
|
+
perPage: import("zod").ZodOptional<import("zod").ZodNumber>;
|
|
132
|
+
customerId: import("zod").ZodOptional<import("zod").ZodString>;
|
|
133
|
+
documentNumber: import("zod").ZodOptional<import("zod").ZodString>;
|
|
134
|
+
documentType: import("zod").ZodOptional<import("zod").ZodEnum<["sell", "return"]>>;
|
|
135
|
+
matched: import("zod").ZodOptional<import("zod").ZodBoolean>;
|
|
136
|
+
purchasedAtFrom: import("zod").ZodOptional<import("zod").ZodString>;
|
|
137
|
+
purchasedAtTo: import("zod").ZodOptional<import("zod").ZodString>;
|
|
138
|
+
};
|
|
139
|
+
readonly handler: typeof transactionList;
|
|
140
|
+
}, {
|
|
141
|
+
readonly name: "ol_transaction_assign_member";
|
|
142
|
+
readonly title: "Link Transaction to Member";
|
|
143
|
+
readonly description: string;
|
|
144
|
+
readonly readOnly: false;
|
|
145
|
+
readonly inputSchema: {
|
|
146
|
+
storeCode: import("zod").ZodOptional<import("zod").ZodString>;
|
|
147
|
+
documentNumber: import("zod").ZodString;
|
|
148
|
+
customerId: import("zod").ZodOptional<import("zod").ZodString>;
|
|
149
|
+
loyaltyCardNumber: import("zod").ZodOptional<import("zod").ZodString>;
|
|
150
|
+
phone: import("zod").ZodOptional<import("zod").ZodString>;
|
|
151
|
+
};
|
|
152
|
+
readonly handler: typeof transactionAssignMember;
|
|
153
|
+
}];
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
// Re-export schemas
|
|
2
|
+
export { TransactionCreateInputSchema, TransactionGetInputSchema, TransactionListInputSchema, TransactionAssignMemberInputSchema, } from "./schemas.js";
|
|
3
|
+
// Re-export handlers
|
|
4
|
+
export { transactionCreate, transactionGet, transactionList, transactionAssignMember, } from "./handlers.js";
|
|
5
|
+
// Imports for tool definitions
|
|
6
|
+
import { TransactionCreateInputSchema, TransactionGetInputSchema, TransactionListInputSchema, TransactionAssignMemberInputSchema, } from "./schemas.js";
|
|
7
|
+
import { transactionCreate, transactionGet, transactionList, transactionAssignMember, } from "./handlers.js";
|
|
8
|
+
// Tool definitions
|
|
9
|
+
export const transactionToolDefinitions = [
|
|
10
|
+
{
|
|
11
|
+
name: "ol_transaction_create",
|
|
12
|
+
title: "Record Purchase",
|
|
13
|
+
description: "Record a purchase transaction. If customerData provided, auto-matches to member and triggers point campaigns. " +
|
|
14
|
+
"For returns, set documentType='return' and provide linkedDocumentNumber referencing original sale. " +
|
|
15
|
+
"REQUIRED: header (documentNumber, purchasedAt), items (sku, name, grossValue, category). " +
|
|
16
|
+
"NOTE: Use 'purchasedAt' NOT 'purchaseDate'. Pass sku as STRING, NOT object. " +
|
|
17
|
+
"Returns transactionId and pointsEarned if campaigns triggered.",
|
|
18
|
+
readOnly: false,
|
|
19
|
+
inputSchema: TransactionCreateInputSchema,
|
|
20
|
+
handler: transactionCreate,
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
name: "ol_transaction_get",
|
|
24
|
+
title: "Get Transaction Details",
|
|
25
|
+
description: "Get transaction details including items, customerData, matched status, and pointsEarned.",
|
|
26
|
+
readOnly: true,
|
|
27
|
+
inputSchema: TransactionGetInputSchema,
|
|
28
|
+
handler: transactionGet,
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
name: "ol_transaction_list",
|
|
32
|
+
title: "Search Transactions",
|
|
33
|
+
description: "List transactions with optional filters. Filter by customerId, documentNumber, documentType, matched status, or date range (purchasedAtFrom/purchasedAtTo). " +
|
|
34
|
+
"Use ISO date format for date filters (e.g., '2025-07-01' or '2025-07-01T00:00:00Z'). " +
|
|
35
|
+
"Supports cursor pagination: provide 'cursor' from previous response to get next page. " +
|
|
36
|
+
"Returns customerId for matched transactions - use this for aggregation queries like 'top spenders'. " +
|
|
37
|
+
"IMPORTANT FOR AGGREGATION QUERIES: Always use cursor pagination and iterate through ALL pages, even for large datasets (1000+ transactions). " +
|
|
38
|
+
"Do NOT try to optimize or find shortcuts - the cursor approach is the correct and only way to get accurate results. " +
|
|
39
|
+
"Start with cursor='' (empty string), then use returned cursor for subsequent requests until no more data. " +
|
|
40
|
+
"Use perPage=50 to minimize API calls. Aggregate by customerId in your code, then use member_get for names.",
|
|
41
|
+
readOnly: true,
|
|
42
|
+
inputSchema: TransactionListInputSchema,
|
|
43
|
+
handler: transactionList,
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
name: "ol_transaction_assign_member",
|
|
47
|
+
title: "Link Transaction to Member",
|
|
48
|
+
description: "Assign unmatched transaction to member by ID, card number, or phone. Triggers point campaigns. " +
|
|
49
|
+
"Use this to link a transaction that wasn't matched at creation time. Returns transactionId, customerId, and pointsEarned.",
|
|
50
|
+
readOnly: false,
|
|
51
|
+
inputSchema: TransactionAssignMemberInputSchema,
|
|
52
|
+
handler: transactionAssignMember,
|
|
53
|
+
},
|
|
54
|
+
];
|
|
@@ -0,0 +1,126 @@
|
|
|
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
|
+
};
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
// Input Schemas
|
|
3
|
+
const LabelInputSchema = z.object({
|
|
4
|
+
key: z.string(),
|
|
5
|
+
value: z.string(),
|
|
6
|
+
});
|
|
7
|
+
const TransactionHeaderInputSchema = z.object({
|
|
8
|
+
documentNumber: z.string().describe("Unique document number (required, unique per store)."),
|
|
9
|
+
purchasedAt: z.string().describe("Purchase date/time in ISO format (required). Use 'purchasedAt' NOT 'purchaseDate'. Example: '2026-01-15T10:00:00Z'."),
|
|
10
|
+
documentType: z.enum(["sell", "return"]).optional().describe("Document type: sell (default) or return."),
|
|
11
|
+
linkedDocumentNumber: z.string().optional().describe("Original document number (required for returns)."),
|
|
12
|
+
purchasePlace: z.string().optional().describe("Location/store where purchase was made."),
|
|
13
|
+
labels: z.array(LabelInputSchema).optional().describe("Custom key-value labels."),
|
|
14
|
+
});
|
|
15
|
+
const TransactionItemInputSchema = z.object({
|
|
16
|
+
sku: z.string().describe("Product SKU as a STRING (required). Use 'sku: \"PROD-123\"' NOT 'sku: { code: \"...\" }'."),
|
|
17
|
+
name: z.string().describe("Product name (required, max 255 chars)."),
|
|
18
|
+
grossValue: z.number().describe("Item gross value (required)."),
|
|
19
|
+
category: z.string().describe("Product category (required, max 255 chars)."),
|
|
20
|
+
quantity: z.number().optional().describe("Item quantity (integer)."),
|
|
21
|
+
highPrecisionQuantity: z.number().optional().describe("High precision quantity (up to 3 decimals, recommended)."),
|
|
22
|
+
maker: z.string().optional().describe("Product brand/maker."),
|
|
23
|
+
labels: z.array(LabelInputSchema).optional().describe("Custom key-value labels."),
|
|
24
|
+
});
|
|
25
|
+
const CustomerDataInputSchema = z.object({
|
|
26
|
+
customerId: z.string().optional().describe("Member ID (UUID) for explicit assignment."),
|
|
27
|
+
email: z.string().optional().describe("Email for auto-matching to member."),
|
|
28
|
+
name: z.string().optional().describe("Customer name."),
|
|
29
|
+
phone: z.string().optional().describe("Phone for auto-matching to member."),
|
|
30
|
+
loyaltyCardNumber: z.string().optional().describe("Loyalty card for auto-matching."),
|
|
31
|
+
});
|
|
32
|
+
export const TransactionCreateInputSchema = {
|
|
33
|
+
storeCode: z.string().optional().describe("INTERNAL: Auto-configured from server settings. NEVER ask the user for this value. Only set if the user explicitly requests a different store."),
|
|
34
|
+
header: TransactionHeaderInputSchema.describe("Transaction header with document info."),
|
|
35
|
+
items: z.array(TransactionItemInputSchema).describe("Array of purchased items (at least 1 required)."),
|
|
36
|
+
customerData: CustomerDataInputSchema.optional().describe("Customer data for auto-matching to member. If provided, triggers point campaigns."),
|
|
37
|
+
};
|
|
38
|
+
export const TransactionGetInputSchema = {
|
|
39
|
+
storeCode: z.string().optional().describe("INTERNAL: Auto-configured from server settings. NEVER ask the user for this value. Only set if the user explicitly requests a different store."),
|
|
40
|
+
transactionId: z.string().describe("The transaction ID (UUID) to retrieve."),
|
|
41
|
+
};
|
|
42
|
+
export const TransactionListInputSchema = {
|
|
43
|
+
storeCode: z.string().optional().describe("INTERNAL: Auto-configured from server settings. NEVER ask the user for this value. Only set if the user explicitly requests a different store."),
|
|
44
|
+
cursor: z.string().optional().describe("Pagination cursor from previous response. If provided, page/perPage are ignored."),
|
|
45
|
+
page: z.number().optional().describe("Page number (default: 1)."),
|
|
46
|
+
perPage: z.number().max(50).optional().describe("Items per page (default: 10, max: 50). Use 50 for aggregation queries to reduce API calls."),
|
|
47
|
+
customerId: z.string().optional().describe("Filter by member ID."),
|
|
48
|
+
documentNumber: z.string().optional().describe("Filter by document number."),
|
|
49
|
+
documentType: z.enum(["sell", "return"]).optional().describe("Filter by document type."),
|
|
50
|
+
matched: z.boolean().optional().describe("Filter by matched status."),
|
|
51
|
+
purchasedAtFrom: z.string().optional().describe("Filter transactions purchased on or after this date (ISO format: YYYY-MM-DD or YYYY-MM-DDTHH:mm:ssZ)."),
|
|
52
|
+
purchasedAtTo: z.string().optional().describe("Filter transactions purchased on or before this date (ISO format: YYYY-MM-DD or YYYY-MM-DDTHH:mm:ssZ)."),
|
|
53
|
+
};
|
|
54
|
+
export const TransactionAssignMemberInputSchema = {
|
|
55
|
+
storeCode: z.string().optional().describe("INTERNAL: Auto-configured from server settings. NEVER ask the user for this value. Only set if the user explicitly requests a different store."),
|
|
56
|
+
documentNumber: z.string().describe("Document number of the transaction to assign."),
|
|
57
|
+
customerId: z.string().optional().describe("Member ID (UUID) to assign."),
|
|
58
|
+
loyaltyCardNumber: z.string().optional().describe("Loyalty card number to match member."),
|
|
59
|
+
phone: z.string().optional().describe("Phone number to match member."),
|
|
60
|
+
};
|