@klaudworks/shopify-mcp 1.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 +531 -0
- package/dist/index.js +107 -0
- package/dist/lib/formatters.js +72 -0
- package/dist/lib/shopifyAuth.js +96 -0
- package/dist/lib/toolUtils.js +36 -0
- package/dist/tools/completeDraftOrder.js +76 -0
- package/dist/tools/createCustomer.js +142 -0
- package/dist/tools/createDraftOrder.js +160 -0
- package/dist/tools/createFulfillment.js +100 -0
- package/dist/tools/createProduct.js +123 -0
- package/dist/tools/createRefund.js +115 -0
- package/dist/tools/deleteCustomer.js +47 -0
- package/dist/tools/deleteMetafields.js +54 -0
- package/dist/tools/deleteProduct.js +43 -0
- package/dist/tools/deleteProductVariants.js +82 -0
- package/dist/tools/getCollectionById.js +123 -0
- package/dist/tools/getCollections.js +88 -0
- package/dist/tools/getCustomerById.js +122 -0
- package/dist/tools/getCustomerOrders.js +131 -0
- package/dist/tools/getCustomers.js +125 -0
- package/dist/tools/getFulfillmentOrders.js +106 -0
- package/dist/tools/getInventoryItems.js +86 -0
- package/dist/tools/getInventoryLevels.js +82 -0
- package/dist/tools/getLocations.js +85 -0
- package/dist/tools/getMarkets.js +91 -0
- package/dist/tools/getMetafieldDefinitions.js +112 -0
- package/dist/tools/getMetafields.js +68 -0
- package/dist/tools/getOrderById.js +212 -0
- package/dist/tools/getOrderRefundDetails.js +131 -0
- package/dist/tools/getOrderTransactions.js +85 -0
- package/dist/tools/getOrders.js +148 -0
- package/dist/tools/getPriceLists.js +92 -0
- package/dist/tools/getProductById.js +171 -0
- package/dist/tools/getProductVariantsDetailed.js +139 -0
- package/dist/tools/getProducts.js +155 -0
- package/dist/tools/getShopInfo.js +74 -0
- package/dist/tools/manageCustomerAddress.js +149 -0
- package/dist/tools/manageProductOptions.js +293 -0
- package/dist/tools/manageProductVariants.js +203 -0
- package/dist/tools/manageTags.js +79 -0
- package/dist/tools/mergeCustomers.js +74 -0
- package/dist/tools/orderCancel.js +77 -0
- package/dist/tools/orderCloseOpen.js +74 -0
- package/dist/tools/orderMarkAsPaid.js +51 -0
- package/dist/tools/registry.js +106 -0
- package/dist/tools/setInventoryQuantities.js +74 -0
- package/dist/tools/setMetafields.js +61 -0
- package/dist/tools/updateCustomer.js +119 -0
- package/dist/tools/updateOrder.js +131 -0
- package/dist/tools/updateProduct.js +132 -0
- package/package.json +66 -0
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
import { gql } from "graphql-request";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
import { checkUserErrors, handleToolError } from "../lib/toolUtils.js";
|
|
4
|
+
// Input schema for manageProductVariants
|
|
5
|
+
const VariantOptionSchema = z.object({
|
|
6
|
+
optionName: z.string().describe("Option name, e.g. 'Size' or 'Color'"),
|
|
7
|
+
name: z.string().describe("Option value, e.g. '8x10' or 'Black'"),
|
|
8
|
+
});
|
|
9
|
+
const VariantSchema = z.object({
|
|
10
|
+
id: z.string().optional().describe("Variant GID for updates. Omit to create new."),
|
|
11
|
+
price: z.string().optional().describe("Price as string, e.g. '49.00'"),
|
|
12
|
+
compareAtPrice: z.string().optional().describe("Compare-at price for showing discounts, e.g. '79.00'"),
|
|
13
|
+
sku: z.string().optional().describe("SKU for the variant (mapped to inventoryItem.sku)"),
|
|
14
|
+
tracked: z.boolean().optional().describe("Whether inventory is tracked. Set false for print-on-demand."),
|
|
15
|
+
taxable: z.boolean().optional().describe("Whether the variant is taxable"),
|
|
16
|
+
barcode: z.string().optional(),
|
|
17
|
+
weight: z.number().optional().describe("Weight of the variant"),
|
|
18
|
+
weightUnit: z.enum(["GRAMS", "KILOGRAMS", "OUNCES", "POUNDS"]).optional().describe("Unit of weight"),
|
|
19
|
+
optionValues: z.array(VariantOptionSchema).optional(),
|
|
20
|
+
});
|
|
21
|
+
const ManageProductVariantsInputSchema = z.object({
|
|
22
|
+
productId: z.string().min(1).describe("Shopify product GID"),
|
|
23
|
+
variants: z.array(VariantSchema).min(1).describe("Variants to create or update"),
|
|
24
|
+
strategy: z
|
|
25
|
+
.enum(["DEFAULT", "REMOVE_STANDALONE_VARIANT", "PRESERVE_STANDALONE_VARIANT"])
|
|
26
|
+
.optional()
|
|
27
|
+
.describe("Strategy for handling the standalone 'Default Title' variant when creating. DEFAULT removes it automatically."),
|
|
28
|
+
});
|
|
29
|
+
// Will be initialized in index.ts
|
|
30
|
+
let shopifyClient;
|
|
31
|
+
const manageProductVariants = {
|
|
32
|
+
name: "manage-product-variants",
|
|
33
|
+
description: "Create or update product variants. Omit variant id to create new, include id to update existing.",
|
|
34
|
+
schema: ManageProductVariantsInputSchema,
|
|
35
|
+
initialize(client) {
|
|
36
|
+
shopifyClient = client;
|
|
37
|
+
},
|
|
38
|
+
execute: async (input) => {
|
|
39
|
+
try {
|
|
40
|
+
const { productId, variants } = input;
|
|
41
|
+
// Split into creates and updates
|
|
42
|
+
const toCreate = variants.filter((v) => !v.id);
|
|
43
|
+
const toUpdate = variants.filter((v) => v.id);
|
|
44
|
+
const results = {
|
|
45
|
+
created: [],
|
|
46
|
+
updated: [],
|
|
47
|
+
};
|
|
48
|
+
// Bulk create new variants
|
|
49
|
+
if (toCreate.length > 0) {
|
|
50
|
+
const createQuery = gql `
|
|
51
|
+
#graphql
|
|
52
|
+
|
|
53
|
+
mutation productVariantsBulkCreate(
|
|
54
|
+
$productId: ID!
|
|
55
|
+
$variants: [ProductVariantsBulkInput!]!
|
|
56
|
+
$strategy: ProductVariantsBulkCreateStrategy
|
|
57
|
+
) {
|
|
58
|
+
productVariantsBulkCreate(
|
|
59
|
+
productId: $productId
|
|
60
|
+
variants: $variants
|
|
61
|
+
strategy: $strategy
|
|
62
|
+
) {
|
|
63
|
+
productVariants {
|
|
64
|
+
id
|
|
65
|
+
title
|
|
66
|
+
price
|
|
67
|
+
sku
|
|
68
|
+
selectedOptions {
|
|
69
|
+
name
|
|
70
|
+
value
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
userErrors {
|
|
74
|
+
field
|
|
75
|
+
message
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
`;
|
|
80
|
+
const createVariants = toCreate.map((v) => {
|
|
81
|
+
const variant = {};
|
|
82
|
+
if (v.price)
|
|
83
|
+
variant.price = v.price;
|
|
84
|
+
if (v.compareAtPrice)
|
|
85
|
+
variant.compareAtPrice = v.compareAtPrice;
|
|
86
|
+
if (v.barcode)
|
|
87
|
+
variant.barcode = v.barcode;
|
|
88
|
+
if (v.taxable !== undefined)
|
|
89
|
+
variant.taxable = v.taxable;
|
|
90
|
+
// sku and tracked both go under inventoryItem
|
|
91
|
+
const inventoryItem = {};
|
|
92
|
+
if (v.sku)
|
|
93
|
+
inventoryItem.sku = v.sku;
|
|
94
|
+
if (v.tracked !== undefined)
|
|
95
|
+
inventoryItem.tracked = v.tracked;
|
|
96
|
+
if (v.weight !== undefined) {
|
|
97
|
+
inventoryItem.measurement = { weight: { value: v.weight, unit: v.weightUnit || 'GRAMS' } };
|
|
98
|
+
}
|
|
99
|
+
if (Object.keys(inventoryItem).length > 0)
|
|
100
|
+
variant.inventoryItem = inventoryItem;
|
|
101
|
+
if (v.optionValues) {
|
|
102
|
+
variant.optionValues = v.optionValues.map((ov) => ({
|
|
103
|
+
optionName: ov.optionName,
|
|
104
|
+
name: ov.name,
|
|
105
|
+
}));
|
|
106
|
+
}
|
|
107
|
+
return variant;
|
|
108
|
+
});
|
|
109
|
+
const createData = (await shopifyClient.request(createQuery, {
|
|
110
|
+
productId,
|
|
111
|
+
variants: createVariants,
|
|
112
|
+
...(input.strategy && { strategy: input.strategy }),
|
|
113
|
+
}));
|
|
114
|
+
checkUserErrors(createData.productVariantsBulkCreate.userErrors, "create variants");
|
|
115
|
+
results.created =
|
|
116
|
+
createData.productVariantsBulkCreate.productVariants.map((v) => ({
|
|
117
|
+
id: v.id,
|
|
118
|
+
title: v.title,
|
|
119
|
+
price: v.price,
|
|
120
|
+
sku: v.sku,
|
|
121
|
+
options: v.selectedOptions,
|
|
122
|
+
}));
|
|
123
|
+
}
|
|
124
|
+
// Bulk update existing variants
|
|
125
|
+
if (toUpdate.length > 0) {
|
|
126
|
+
const updateQuery = gql `
|
|
127
|
+
#graphql
|
|
128
|
+
|
|
129
|
+
mutation productVariantsBulkUpdate(
|
|
130
|
+
$productId: ID!
|
|
131
|
+
$variants: [ProductVariantsBulkInput!]!
|
|
132
|
+
) {
|
|
133
|
+
productVariantsBulkUpdate(
|
|
134
|
+
productId: $productId
|
|
135
|
+
variants: $variants
|
|
136
|
+
) {
|
|
137
|
+
productVariants {
|
|
138
|
+
id
|
|
139
|
+
title
|
|
140
|
+
price
|
|
141
|
+
sku
|
|
142
|
+
selectedOptions {
|
|
143
|
+
name
|
|
144
|
+
value
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
userErrors {
|
|
148
|
+
field
|
|
149
|
+
message
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
`;
|
|
154
|
+
const updateVariants = toUpdate.map((v) => {
|
|
155
|
+
const variant = { id: v.id };
|
|
156
|
+
if (v.price)
|
|
157
|
+
variant.price = v.price;
|
|
158
|
+
if (v.compareAtPrice)
|
|
159
|
+
variant.compareAtPrice = v.compareAtPrice;
|
|
160
|
+
if (v.barcode)
|
|
161
|
+
variant.barcode = v.barcode;
|
|
162
|
+
if (v.taxable !== undefined)
|
|
163
|
+
variant.taxable = v.taxable;
|
|
164
|
+
const inventoryItem = {};
|
|
165
|
+
if (v.sku)
|
|
166
|
+
inventoryItem.sku = v.sku;
|
|
167
|
+
if (v.tracked !== undefined)
|
|
168
|
+
inventoryItem.tracked = v.tracked;
|
|
169
|
+
if (v.weight !== undefined) {
|
|
170
|
+
inventoryItem.measurement = { weight: { value: v.weight, unit: v.weightUnit || 'GRAMS' } };
|
|
171
|
+
}
|
|
172
|
+
if (Object.keys(inventoryItem).length > 0)
|
|
173
|
+
variant.inventoryItem = inventoryItem;
|
|
174
|
+
if (v.optionValues) {
|
|
175
|
+
variant.optionValues = v.optionValues.map((ov) => ({
|
|
176
|
+
optionName: ov.optionName,
|
|
177
|
+
name: ov.name,
|
|
178
|
+
}));
|
|
179
|
+
}
|
|
180
|
+
return variant;
|
|
181
|
+
});
|
|
182
|
+
const updateData = (await shopifyClient.request(updateQuery, {
|
|
183
|
+
productId,
|
|
184
|
+
variants: updateVariants,
|
|
185
|
+
}));
|
|
186
|
+
checkUserErrors(updateData.productVariantsBulkUpdate.userErrors, "update variants");
|
|
187
|
+
results.updated =
|
|
188
|
+
updateData.productVariantsBulkUpdate.productVariants.map((v) => ({
|
|
189
|
+
id: v.id,
|
|
190
|
+
title: v.title,
|
|
191
|
+
price: v.price,
|
|
192
|
+
sku: v.sku,
|
|
193
|
+
options: v.selectedOptions,
|
|
194
|
+
}));
|
|
195
|
+
}
|
|
196
|
+
return results;
|
|
197
|
+
}
|
|
198
|
+
catch (error) {
|
|
199
|
+
handleToolError("manage product variants", error);
|
|
200
|
+
}
|
|
201
|
+
},
|
|
202
|
+
};
|
|
203
|
+
export { manageProductVariants };
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { gql } from "graphql-request";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
import { checkUserErrors, handleToolError } from "../lib/toolUtils.js";
|
|
4
|
+
const ManageTagsInputSchema = z.object({
|
|
5
|
+
id: z.string().describe("GID of the resource (order, product, customer, draft order, or article)"),
|
|
6
|
+
tags: z.array(z.string()).min(1).describe("Tags to add or remove"),
|
|
7
|
+
action: z.enum(["add", "remove"]).describe("Whether to add or remove the tags"),
|
|
8
|
+
});
|
|
9
|
+
let shopifyClient;
|
|
10
|
+
const manageTags = {
|
|
11
|
+
name: "manage-tags",
|
|
12
|
+
description: "Add or remove tags on any taggable resource (orders, products, customers, draft orders, articles).",
|
|
13
|
+
schema: ManageTagsInputSchema,
|
|
14
|
+
initialize(client) {
|
|
15
|
+
shopifyClient = client;
|
|
16
|
+
},
|
|
17
|
+
execute: async (input) => {
|
|
18
|
+
try {
|
|
19
|
+
if (input.action === "add") {
|
|
20
|
+
const query = gql `
|
|
21
|
+
#graphql
|
|
22
|
+
|
|
23
|
+
mutation tagsAdd($id: ID!, $tags: [String!]!) {
|
|
24
|
+
tagsAdd(id: $id, tags: $tags) {
|
|
25
|
+
node {
|
|
26
|
+
id
|
|
27
|
+
}
|
|
28
|
+
userErrors {
|
|
29
|
+
field
|
|
30
|
+
message
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
`;
|
|
35
|
+
const data = (await shopifyClient.request(query, {
|
|
36
|
+
id: input.id,
|
|
37
|
+
tags: input.tags,
|
|
38
|
+
}));
|
|
39
|
+
checkUserErrors(data.tagsAdd.userErrors, "add tags");
|
|
40
|
+
return {
|
|
41
|
+
id: data.tagsAdd.node?.id,
|
|
42
|
+
action: "add",
|
|
43
|
+
tags: input.tags,
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
const query = gql `
|
|
48
|
+
#graphql
|
|
49
|
+
|
|
50
|
+
mutation tagsRemove($id: ID!, $tags: [String!]!) {
|
|
51
|
+
tagsRemove(id: $id, tags: $tags) {
|
|
52
|
+
node {
|
|
53
|
+
id
|
|
54
|
+
}
|
|
55
|
+
userErrors {
|
|
56
|
+
field
|
|
57
|
+
message
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
`;
|
|
62
|
+
const data = (await shopifyClient.request(query, {
|
|
63
|
+
id: input.id,
|
|
64
|
+
tags: input.tags,
|
|
65
|
+
}));
|
|
66
|
+
checkUserErrors(data.tagsRemove.userErrors, "remove tags");
|
|
67
|
+
return {
|
|
68
|
+
id: data.tagsRemove.node?.id,
|
|
69
|
+
action: "remove",
|
|
70
|
+
tags: input.tags,
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
catch (error) {
|
|
75
|
+
handleToolError(`${input.action} tags`, error);
|
|
76
|
+
}
|
|
77
|
+
},
|
|
78
|
+
};
|
|
79
|
+
export { manageTags };
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { gql } from "graphql-request";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
import { checkUserErrors, handleToolError } from "../lib/toolUtils.js";
|
|
4
|
+
const MergeCustomersInputSchema = z.object({
|
|
5
|
+
customerOneId: z.string().describe("GID of the first customer"),
|
|
6
|
+
customerTwoId: z.string().describe("GID of the second customer"),
|
|
7
|
+
overrideFields: z
|
|
8
|
+
.object({
|
|
9
|
+
customerIdOfFirstNameToKeep: z.string().optional().describe("Customer GID whose first name to keep"),
|
|
10
|
+
customerIdOfLastNameToKeep: z.string().optional().describe("Customer GID whose last name to keep"),
|
|
11
|
+
customerIdOfEmailToKeep: z.string().optional().describe("Customer GID whose email to keep"),
|
|
12
|
+
customerIdOfPhoneNumberToKeep: z.string().optional().describe("Customer GID whose phone to keep"),
|
|
13
|
+
customerIdOfDefaultAddressToKeep: z.string().optional().describe("Customer GID whose default address to keep"),
|
|
14
|
+
note: z.string().optional().describe("Note to keep on the merged customer"),
|
|
15
|
+
tags: z.array(z.string()).optional().describe("Tags to keep on the merged customer"),
|
|
16
|
+
})
|
|
17
|
+
.optional()
|
|
18
|
+
.describe("Override default merge rules for specific fields"),
|
|
19
|
+
});
|
|
20
|
+
let shopifyClient;
|
|
21
|
+
const mergeCustomers = {
|
|
22
|
+
name: "customer-merge",
|
|
23
|
+
description: "Merge two customer records into one. Optionally override which fields to keep from which customer.",
|
|
24
|
+
schema: MergeCustomersInputSchema,
|
|
25
|
+
initialize(client) {
|
|
26
|
+
shopifyClient = client;
|
|
27
|
+
},
|
|
28
|
+
execute: async (input) => {
|
|
29
|
+
try {
|
|
30
|
+
const query = gql `
|
|
31
|
+
#graphql
|
|
32
|
+
|
|
33
|
+
mutation customerMerge(
|
|
34
|
+
$customerOneId: ID!
|
|
35
|
+
$customerTwoId: ID!
|
|
36
|
+
$overrideFields: CustomerMergeOverrideFields
|
|
37
|
+
) {
|
|
38
|
+
customerMerge(
|
|
39
|
+
customerOneId: $customerOneId
|
|
40
|
+
customerTwoId: $customerTwoId
|
|
41
|
+
overrideFields: $overrideFields
|
|
42
|
+
) {
|
|
43
|
+
resultingCustomerId
|
|
44
|
+
job {
|
|
45
|
+
id
|
|
46
|
+
done
|
|
47
|
+
}
|
|
48
|
+
userErrors {
|
|
49
|
+
field
|
|
50
|
+
message
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
`;
|
|
55
|
+
const variables = {
|
|
56
|
+
customerOneId: input.customerOneId,
|
|
57
|
+
customerTwoId: input.customerTwoId,
|
|
58
|
+
};
|
|
59
|
+
if (input.overrideFields) {
|
|
60
|
+
variables.overrideFields = input.overrideFields;
|
|
61
|
+
}
|
|
62
|
+
const data = (await shopifyClient.request(query, variables));
|
|
63
|
+
checkUserErrors(data.customerMerge.userErrors, "merge customers");
|
|
64
|
+
return {
|
|
65
|
+
resultingCustomerId: data.customerMerge.resultingCustomerId,
|
|
66
|
+
job: data.customerMerge.job,
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
catch (error) {
|
|
70
|
+
handleToolError("merge customers", error);
|
|
71
|
+
}
|
|
72
|
+
},
|
|
73
|
+
};
|
|
74
|
+
export { mergeCustomers };
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { gql } from "graphql-request";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
import { checkUserErrors, handleToolError } from "../lib/toolUtils.js";
|
|
4
|
+
const OrderCancelInputSchema = z.object({
|
|
5
|
+
orderId: z.string().describe("The order GID, e.g. gid://shopify/Order/123"),
|
|
6
|
+
reason: z.enum(["CUSTOMER", "DECLINED", "FRAUD", "INVENTORY", "OTHER", "STAFF"]).describe("Reason for cancellation"),
|
|
7
|
+
restock: z.boolean().describe("Whether to restock inventory"),
|
|
8
|
+
notifyCustomer: z.boolean().default(false).describe("Whether to notify the customer"),
|
|
9
|
+
staffNote: z.string().optional().describe("Internal note (not visible to customer)"),
|
|
10
|
+
refund: z.boolean().optional().describe("Whether to refund to the original payment method"),
|
|
11
|
+
});
|
|
12
|
+
let shopifyClient;
|
|
13
|
+
const orderCancel = {
|
|
14
|
+
name: "order-cancel",
|
|
15
|
+
description: "Cancel an order with options for refunding, restocking inventory, and customer notification. Cancellation is irreversible.",
|
|
16
|
+
schema: OrderCancelInputSchema,
|
|
17
|
+
initialize(client) {
|
|
18
|
+
shopifyClient = client;
|
|
19
|
+
},
|
|
20
|
+
execute: async (input) => {
|
|
21
|
+
try {
|
|
22
|
+
const query = gql `
|
|
23
|
+
#graphql
|
|
24
|
+
|
|
25
|
+
mutation orderCancel(
|
|
26
|
+
$orderId: ID!
|
|
27
|
+
$reason: OrderCancelReason!
|
|
28
|
+
$restock: Boolean!
|
|
29
|
+
$notifyCustomer: Boolean
|
|
30
|
+
$staffNote: String
|
|
31
|
+
$refundMethod: OrderCancelRefundMethodInput
|
|
32
|
+
) {
|
|
33
|
+
orderCancel(
|
|
34
|
+
orderId: $orderId
|
|
35
|
+
reason: $reason
|
|
36
|
+
restock: $restock
|
|
37
|
+
notifyCustomer: $notifyCustomer
|
|
38
|
+
staffNote: $staffNote
|
|
39
|
+
refundMethod: $refundMethod
|
|
40
|
+
) {
|
|
41
|
+
job {
|
|
42
|
+
id
|
|
43
|
+
done
|
|
44
|
+
}
|
|
45
|
+
orderCancelUserErrors {
|
|
46
|
+
field
|
|
47
|
+
message
|
|
48
|
+
code
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
`;
|
|
53
|
+
const variables = {
|
|
54
|
+
orderId: input.orderId,
|
|
55
|
+
reason: input.reason,
|
|
56
|
+
restock: input.restock,
|
|
57
|
+
notifyCustomer: input.notifyCustomer,
|
|
58
|
+
...(input.staffNote && { staffNote: input.staffNote }),
|
|
59
|
+
};
|
|
60
|
+
if (input.refund !== undefined) {
|
|
61
|
+
variables.refundMethod = {
|
|
62
|
+
originalPaymentMethodsRefund: input.refund,
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
const data = (await shopifyClient.request(query, variables));
|
|
66
|
+
checkUserErrors(data.orderCancel.orderCancelUserErrors, "cancel order");
|
|
67
|
+
return {
|
|
68
|
+
job: data.orderCancel.job,
|
|
69
|
+
message: "Order cancellation initiated successfully",
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
catch (error) {
|
|
73
|
+
handleToolError("cancel order", error);
|
|
74
|
+
}
|
|
75
|
+
},
|
|
76
|
+
};
|
|
77
|
+
export { orderCancel };
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { gql } from "graphql-request";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
import { checkUserErrors, handleToolError } from "../lib/toolUtils.js";
|
|
4
|
+
const OrderCloseOpenInputSchema = z.object({
|
|
5
|
+
orderId: z.string().describe("The order GID, e.g. gid://shopify/Order/123"),
|
|
6
|
+
action: z.enum(["close", "open"]).describe("Whether to close or open the order"),
|
|
7
|
+
});
|
|
8
|
+
let shopifyClient;
|
|
9
|
+
const orderCloseOpen = {
|
|
10
|
+
name: "order-close-open",
|
|
11
|
+
description: "Close or reopen an order. Closing marks all items fulfilled and finances complete. Opening reopens a closed order.",
|
|
12
|
+
schema: OrderCloseOpenInputSchema,
|
|
13
|
+
initialize(client) {
|
|
14
|
+
shopifyClient = client;
|
|
15
|
+
},
|
|
16
|
+
execute: async (input) => {
|
|
17
|
+
try {
|
|
18
|
+
if (input.action === "close") {
|
|
19
|
+
const query = gql `
|
|
20
|
+
#graphql
|
|
21
|
+
|
|
22
|
+
mutation orderClose($input: OrderCloseInput!) {
|
|
23
|
+
orderClose(input: $input) {
|
|
24
|
+
order {
|
|
25
|
+
id
|
|
26
|
+
name
|
|
27
|
+
closed
|
|
28
|
+
closedAt
|
|
29
|
+
}
|
|
30
|
+
userErrors {
|
|
31
|
+
field
|
|
32
|
+
message
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
`;
|
|
37
|
+
const data = (await shopifyClient.request(query, {
|
|
38
|
+
input: { id: input.orderId },
|
|
39
|
+
}));
|
|
40
|
+
checkUserErrors(data.orderClose.userErrors, "close order");
|
|
41
|
+
return { order: data.orderClose.order };
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
const query = gql `
|
|
45
|
+
#graphql
|
|
46
|
+
|
|
47
|
+
mutation orderOpen($input: OrderOpenInput!) {
|
|
48
|
+
orderOpen(input: $input) {
|
|
49
|
+
order {
|
|
50
|
+
id
|
|
51
|
+
name
|
|
52
|
+
closed
|
|
53
|
+
closedAt
|
|
54
|
+
}
|
|
55
|
+
userErrors {
|
|
56
|
+
field
|
|
57
|
+
message
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
`;
|
|
62
|
+
const data = (await shopifyClient.request(query, {
|
|
63
|
+
input: { id: input.orderId },
|
|
64
|
+
}));
|
|
65
|
+
checkUserErrors(data.orderOpen.userErrors, "open order");
|
|
66
|
+
return { order: data.orderOpen.order };
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
catch (error) {
|
|
70
|
+
handleToolError(`${input.action} order`, error);
|
|
71
|
+
}
|
|
72
|
+
},
|
|
73
|
+
};
|
|
74
|
+
export { orderCloseOpen };
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { gql } from "graphql-request";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
import { checkUserErrors, handleToolError } from "../lib/toolUtils.js";
|
|
4
|
+
const OrderMarkAsPaidInputSchema = z.object({
|
|
5
|
+
orderId: z.string().describe("The order GID, e.g. gid://shopify/Order/123"),
|
|
6
|
+
});
|
|
7
|
+
let shopifyClient;
|
|
8
|
+
const orderMarkAsPaid = {
|
|
9
|
+
name: "order-mark-as-paid",
|
|
10
|
+
description: "Mark an order as paid. Useful for manual/offline payments (cash, bank deposit, etc.).",
|
|
11
|
+
schema: OrderMarkAsPaidInputSchema,
|
|
12
|
+
initialize(client) {
|
|
13
|
+
shopifyClient = client;
|
|
14
|
+
},
|
|
15
|
+
execute: async (input) => {
|
|
16
|
+
try {
|
|
17
|
+
const query = gql `
|
|
18
|
+
#graphql
|
|
19
|
+
|
|
20
|
+
mutation orderMarkAsPaid($input: OrderMarkAsPaidInput!) {
|
|
21
|
+
orderMarkAsPaid(input: $input) {
|
|
22
|
+
order {
|
|
23
|
+
id
|
|
24
|
+
name
|
|
25
|
+
displayFinancialStatus
|
|
26
|
+
totalPriceSet {
|
|
27
|
+
shopMoney {
|
|
28
|
+
amount
|
|
29
|
+
currencyCode
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
userErrors {
|
|
34
|
+
field
|
|
35
|
+
message
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
`;
|
|
40
|
+
const data = (await shopifyClient.request(query, {
|
|
41
|
+
input: { id: input.orderId },
|
|
42
|
+
}));
|
|
43
|
+
checkUserErrors(data.orderMarkAsPaid.userErrors, "mark order as paid");
|
|
44
|
+
return { order: data.orderMarkAsPaid.order };
|
|
45
|
+
}
|
|
46
|
+
catch (error) {
|
|
47
|
+
handleToolError("mark order as paid", error);
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
};
|
|
51
|
+
export { orderMarkAsPaid };
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
// Product tools
|
|
2
|
+
import { getProducts } from "./getProducts.js";
|
|
3
|
+
import { getProductById } from "./getProductById.js";
|
|
4
|
+
import { createProduct } from "./createProduct.js";
|
|
5
|
+
import { updateProduct } from "./updateProduct.js";
|
|
6
|
+
import { deleteProduct } from "./deleteProduct.js";
|
|
7
|
+
import { manageProductVariants } from "./manageProductVariants.js";
|
|
8
|
+
import { deleteProductVariants } from "./deleteProductVariants.js";
|
|
9
|
+
import { manageProductOptions } from "./manageProductOptions.js";
|
|
10
|
+
// Order tools
|
|
11
|
+
import { getOrders } from "./getOrders.js";
|
|
12
|
+
import { getOrderById } from "./getOrderById.js";
|
|
13
|
+
import { updateOrder } from "./updateOrder.js";
|
|
14
|
+
import { createDraftOrder } from "./createDraftOrder.js";
|
|
15
|
+
import { completeDraftOrder } from "./completeDraftOrder.js";
|
|
16
|
+
import { orderCancel } from "./orderCancel.js";
|
|
17
|
+
import { orderCloseOpen } from "./orderCloseOpen.js";
|
|
18
|
+
import { orderMarkAsPaid } from "./orderMarkAsPaid.js";
|
|
19
|
+
import { createFulfillment } from "./createFulfillment.js";
|
|
20
|
+
import { createRefund } from "./createRefund.js";
|
|
21
|
+
// Customer tools
|
|
22
|
+
import { getCustomers } from "./getCustomers.js";
|
|
23
|
+
import { getCustomerById } from "./getCustomerById.js";
|
|
24
|
+
import { getCustomerOrders } from "./getCustomerOrders.js";
|
|
25
|
+
import { createCustomer } from "./createCustomer.js";
|
|
26
|
+
import { updateCustomer } from "./updateCustomer.js";
|
|
27
|
+
import { deleteCustomer } from "./deleteCustomer.js";
|
|
28
|
+
import { mergeCustomers } from "./mergeCustomers.js";
|
|
29
|
+
import { manageCustomerAddress } from "./manageCustomerAddress.js";
|
|
30
|
+
// Metafield tools
|
|
31
|
+
import { getMetafields } from "./getMetafields.js";
|
|
32
|
+
import { setMetafields } from "./setMetafields.js";
|
|
33
|
+
import { deleteMetafields } from "./deleteMetafields.js";
|
|
34
|
+
// Convenience / cross-resource tools
|
|
35
|
+
import { manageTags } from "./manageTags.js";
|
|
36
|
+
import { setInventoryQuantities } from "./setInventoryQuantities.js";
|
|
37
|
+
// Configuration & discovery tools
|
|
38
|
+
import { getShopInfo } from "./getShopInfo.js";
|
|
39
|
+
import { getMetafieldDefinitions } from "./getMetafieldDefinitions.js";
|
|
40
|
+
import { getLocations } from "./getLocations.js";
|
|
41
|
+
import { getMarkets } from "./getMarkets.js";
|
|
42
|
+
import { getCollections } from "./getCollections.js";
|
|
43
|
+
// Enhanced order & fulfillment tools
|
|
44
|
+
import { getOrderTransactions } from "./getOrderTransactions.js";
|
|
45
|
+
import { getFulfillmentOrders } from "./getFulfillmentOrders.js";
|
|
46
|
+
import { getOrderRefundDetails } from "./getOrderRefundDetails.js";
|
|
47
|
+
import { getCollectionById } from "./getCollectionById.js";
|
|
48
|
+
// Inventory & pricing read tools
|
|
49
|
+
import { getInventoryLevels } from "./getInventoryLevels.js";
|
|
50
|
+
import { getInventoryItems } from "./getInventoryItems.js";
|
|
51
|
+
import { getPriceLists } from "./getPriceLists.js";
|
|
52
|
+
import { getProductVariantsDetailed } from "./getProductVariantsDetailed.js";
|
|
53
|
+
export const tools = [
|
|
54
|
+
// Products (8)
|
|
55
|
+
getProducts,
|
|
56
|
+
getProductById,
|
|
57
|
+
createProduct,
|
|
58
|
+
updateProduct,
|
|
59
|
+
deleteProduct,
|
|
60
|
+
manageProductVariants,
|
|
61
|
+
deleteProductVariants,
|
|
62
|
+
manageProductOptions,
|
|
63
|
+
// Orders (10)
|
|
64
|
+
getOrders,
|
|
65
|
+
getOrderById,
|
|
66
|
+
updateOrder,
|
|
67
|
+
createDraftOrder,
|
|
68
|
+
completeDraftOrder,
|
|
69
|
+
orderCancel,
|
|
70
|
+
orderCloseOpen,
|
|
71
|
+
orderMarkAsPaid,
|
|
72
|
+
createFulfillment,
|
|
73
|
+
createRefund,
|
|
74
|
+
// Customers (8)
|
|
75
|
+
getCustomers,
|
|
76
|
+
getCustomerById,
|
|
77
|
+
getCustomerOrders,
|
|
78
|
+
createCustomer,
|
|
79
|
+
updateCustomer,
|
|
80
|
+
deleteCustomer,
|
|
81
|
+
mergeCustomers,
|
|
82
|
+
manageCustomerAddress,
|
|
83
|
+
// Metafields (3)
|
|
84
|
+
getMetafields,
|
|
85
|
+
setMetafields,
|
|
86
|
+
deleteMetafields,
|
|
87
|
+
// Convenience (2)
|
|
88
|
+
manageTags,
|
|
89
|
+
setInventoryQuantities,
|
|
90
|
+
// Configuration & discovery (5)
|
|
91
|
+
getShopInfo,
|
|
92
|
+
getMetafieldDefinitions,
|
|
93
|
+
getLocations,
|
|
94
|
+
getMarkets,
|
|
95
|
+
getCollections,
|
|
96
|
+
// Enhanced order & fulfillment (4)
|
|
97
|
+
getOrderTransactions,
|
|
98
|
+
getFulfillmentOrders,
|
|
99
|
+
getOrderRefundDetails,
|
|
100
|
+
getCollectionById,
|
|
101
|
+
// Inventory & pricing reads (4)
|
|
102
|
+
getInventoryLevels,
|
|
103
|
+
getInventoryItems,
|
|
104
|
+
getPriceLists,
|
|
105
|
+
getProductVariantsDetailed,
|
|
106
|
+
];
|