@payware/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/.env.example +92 -0
- package/MCP-SETUP.md +190 -0
- package/README.md +483 -0
- package/check-keys.js +52 -0
- package/keys/README.md +112 -0
- package/mcp-config.json +9 -0
- package/package.json +66 -0
- package/payware-mcp-config.json +12 -0
- package/src/auth/rsa-keys.js +82 -0
- package/src/auth/sandbox-setup.js +187 -0
- package/src/config/env.js +229 -0
- package/src/config/partner-types.js +143 -0
- package/src/core/auth/jwt-factory.js +182 -0
- package/src/core/auth/jwt-token.js +735 -0
- package/src/core/utils/json-serializer.js +100 -0
- package/src/core/utils/key-utils.js +133 -0
- package/src/index.js +237 -0
- package/src/isv/data/index.js +291 -0
- package/src/isv/deep-links/delete-product-link.js +154 -0
- package/src/isv/deep-links/delete-transaction-link.js +154 -0
- package/src/isv/deep-links/get-product-link.js +167 -0
- package/src/isv/deep-links/get-transaction-link.js +167 -0
- package/src/isv/deep-links/index.js +23 -0
- package/src/isv/index.js +103 -0
- package/src/isv/oauth2/create-token-simple.js +46 -0
- package/src/isv/oauth2/get-token-info.js +157 -0
- package/src/isv/oauth2/obtain-token.js +189 -0
- package/src/isv/oauth2/token-helper.js +151 -0
- package/src/isv/products/audios.js +470 -0
- package/src/isv/products/create-product.js +314 -0
- package/src/isv/products/delete-product.js +119 -0
- package/src/isv/products/get-product-image.js +247 -0
- package/src/isv/products/get-product.js +168 -0
- package/src/isv/products/index.js +65 -0
- package/src/isv/products/list-products.js +136 -0
- package/src/isv/products/schedules.js +522 -0
- package/src/isv/products/update-product.js +265 -0
- package/src/isv/transactions/cancel-transaction.js +129 -0
- package/src/isv/transactions/create-transaction.js +361 -0
- package/src/isv/transactions/get-status.js +217 -0
- package/src/isv/transactions/process-transaction.js +145 -0
- package/src/isv/transactions/simulate-callback.js +146 -0
- package/src/isv/transactions/transaction-history.js +186 -0
- package/src/isv/utils/auth.js +159 -0
- package/src/mcp-proxy.js +150 -0
- package/src/merchant/data/export-report.js +108 -0
- package/src/merchant/data/generate-report.js +151 -0
- package/src/merchant/data/get-report-status.js +120 -0
- package/src/merchant/data/index.js +351 -0
- package/src/merchant/deep-links/delete-product-link.js +121 -0
- package/src/merchant/deep-links/delete-transaction-link.js +121 -0
- package/src/merchant/deep-links/get-product-link.js +134 -0
- package/src/merchant/deep-links/get-transaction-link.js +134 -0
- package/src/merchant/deep-links/index.js +23 -0
- package/src/merchant/index.js +92 -0
- package/src/merchant/products/audios.js +606 -0
- package/src/merchant/products/create-product.js +288 -0
- package/src/merchant/products/delete-product.js +111 -0
- package/src/merchant/products/get-product-image.js +252 -0
- package/src/merchant/products/get-product.js +144 -0
- package/src/merchant/products/index.js +65 -0
- package/src/merchant/products/list-products.js +112 -0
- package/src/merchant/products/schedules.js +646 -0
- package/src/merchant/products/update-product.js +282 -0
- package/src/merchant/transactions/cancel-transaction.js +241 -0
- package/src/merchant/transactions/create-transaction.js +482 -0
- package/src/merchant/transactions/get-status.js +196 -0
- package/src/merchant/transactions/process-transaction.js +349 -0
- package/src/merchant/transactions/simulate-callback.js +246 -0
- package/src/merchant/transactions/transaction-history.js +258 -0
- package/src/payment-institution/data/index.js +280 -0
- package/src/payment-institution/deep-links/delete-transaction-link.js +128 -0
- package/src/payment-institution/deep-links/get-transaction-link.js +141 -0
- package/src/payment-institution/deep-links/index.js +17 -0
- package/src/payment-institution/index.js +92 -0
- package/src/payment-institution/transactions/create-pi-transaction.js +484 -0
- package/src/payment-institution/transactions/finalize-transaction.js +340 -0
- package/src/payment-institution/transactions/get-transaction-history.js +269 -0
- package/src/payment-institution/transactions/get-transaction-status.js +234 -0
- package/src/payment-institution/transactions/process-pi-transaction.js +421 -0
- package/src/payment-institution/transactions/simulate-pi-callback.js +326 -0
- package/src/payment-institution/transactions/soundbite-transaction.js +269 -0
- package/src/proxy-server.js +205 -0
- package/src/shared/data/data-api.js +372 -0
- package/src/shared/deep-links/api.js +214 -0
- package/src/shared/index.js +44 -0
- package/src/shared/products/products-api.js +872 -0
- package/src/tools/advanced-code-generator.js +2247 -0
- package/src/utils/code-examples/common/auth-examples.js +1482 -0
- package/src/utils/code-examples/common/helpers.js +416 -0
- package/src/utils/code-examples/common/utils-examples.js +591 -0
- package/src/utils/code-examples/frameworks/examples.js +859 -0
- package/src/utils/code-examples/index.js +441 -0
- package/src/utils/code-examples/isv/oauth2.js +600 -0
- package/src/utils/code-examples/isv/products.js +666 -0
- package/src/utils/code-examples/isv/transactions.js +813 -0
- package/src/utils/code-examples/merchant/products.js +497 -0
- package/src/utils/code-examples/merchant/transactions.js +623 -0
- package/src/utils/code-examples/payment-institution/transactions.js +388 -0
- package/src/utils/code-examples/shared/data.js +607 -0
- package/src/utils/code-examples/shared/deep-links.js +662 -0
- package/src/utils/code-examples/shared/soundbites.js +808 -0
- package/src/utils/code-examples.js +646 -0
- package/src/utils/format-request.js +363 -0
- package/src/utils/json-formatter.js +249 -0
- package/src/utils/server-info.js +132 -0
|
@@ -0,0 +1,872 @@
|
|
|
1
|
+
import axios from 'axios';
|
|
2
|
+
import FormData from 'form-data';
|
|
3
|
+
import { createJWTToken } from '../../core/auth/jwt-token.js';
|
|
4
|
+
import { createJWTForPartner } from '../../core/auth/jwt-factory.js';
|
|
5
|
+
import { createMinimizedJSON } from '../../core/utils/json-serializer.js';
|
|
6
|
+
import { getSandboxUrl, getProductionUrl } from '../../config/env.js';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Product types
|
|
10
|
+
*/
|
|
11
|
+
export const PRODUCT_TYPES = {
|
|
12
|
+
ITEM: 'ITEM',
|
|
13
|
+
SERVICE: 'SERVICE'
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Price correction types for schedules
|
|
18
|
+
*/
|
|
19
|
+
export const PRICE_CORRECTION_TYPES = {
|
|
20
|
+
DISCOUNT: 'DISCOUNT',
|
|
21
|
+
INCREMENT: 'INCREMENT'
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Correction methods for schedules
|
|
26
|
+
*/
|
|
27
|
+
export const CORRECTION_TYPES = {
|
|
28
|
+
PERCENTAGE: 'PERCENTAGE',
|
|
29
|
+
VALUE: 'VALUE'
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Overlap priority options
|
|
34
|
+
*/
|
|
35
|
+
export const OVERLAP_PRIORITY = {
|
|
36
|
+
LOWEST: 'LOWEST',
|
|
37
|
+
HIGHEST: 'HIGHEST'
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* QR code error correction levels
|
|
42
|
+
*/
|
|
43
|
+
export const QR_ERROR_CORRECTION = {
|
|
44
|
+
LOW: 'LOW',
|
|
45
|
+
MEDIUM: 'MEDIUM',
|
|
46
|
+
QUARTILE: 'QUARTILE',
|
|
47
|
+
HIGH: 'HIGH'
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Image formats
|
|
52
|
+
*/
|
|
53
|
+
export const IMAGE_FORMATS = {
|
|
54
|
+
PNG: 'PNG',
|
|
55
|
+
SVG: 'SVG',
|
|
56
|
+
JPG: 'JPG'
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Image types
|
|
61
|
+
*/
|
|
62
|
+
export const IMAGE_TYPES = {
|
|
63
|
+
QR: 'QR',
|
|
64
|
+
BARCODE: 'BARCODE'
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Barcode human readable locations
|
|
69
|
+
*/
|
|
70
|
+
export const BARCODE_LOCATIONS = {
|
|
71
|
+
NONE: 'NONE',
|
|
72
|
+
BOTTOM: 'BOTTOM',
|
|
73
|
+
TOP: 'TOP'
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Create authentication headers based on partner type
|
|
78
|
+
* @param {string} partnerType - merchant, isv, or payment_institution
|
|
79
|
+
* @param {Object} authParams - Authentication parameters
|
|
80
|
+
* @returns {Object} Headers for API request
|
|
81
|
+
*/
|
|
82
|
+
async function createAuthHeaders(partnerType, authParams) {
|
|
83
|
+
const baseHeaders = {
|
|
84
|
+
'Content-Type': 'application/json',
|
|
85
|
+
'Api-Version': '1'
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
let tokenData;
|
|
89
|
+
|
|
90
|
+
switch (partnerType) {
|
|
91
|
+
case 'merchant':
|
|
92
|
+
case 'payment_institution':
|
|
93
|
+
// Standard JWT authentication
|
|
94
|
+
tokenData = createJWTToken(
|
|
95
|
+
authParams.partnerId,
|
|
96
|
+
authParams.privateKey,
|
|
97
|
+
authParams.requestBody
|
|
98
|
+
);
|
|
99
|
+
break;
|
|
100
|
+
|
|
101
|
+
case 'isv':
|
|
102
|
+
// ISV JWT with OAuth2
|
|
103
|
+
tokenData = await createJWTForPartner({
|
|
104
|
+
partnerId: authParams.isvPartnerId,
|
|
105
|
+
privateKey: authParams.privateKey,
|
|
106
|
+
merchantId: authParams.merchantPartnerId,
|
|
107
|
+
oauth2Token: authParams.oauth2Token,
|
|
108
|
+
requestBody: authParams.requestBody
|
|
109
|
+
});
|
|
110
|
+
break;
|
|
111
|
+
|
|
112
|
+
default:
|
|
113
|
+
throw new Error(`Unknown partner type: ${partnerType}`);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
return {
|
|
117
|
+
...baseHeaders,
|
|
118
|
+
'Authorization': `Bearer ${tokenData.token}`
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Create authentication headers for multipart/form-data requests
|
|
124
|
+
*/
|
|
125
|
+
async function createMultipartAuthHeaders(partnerType, authParams) {
|
|
126
|
+
const headers = await createAuthHeaders(partnerType, authParams);
|
|
127
|
+
// Remove Content-Type to let axios set it with boundary for multipart
|
|
128
|
+
delete headers['Content-Type'];
|
|
129
|
+
return headers;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// ====================
|
|
133
|
+
// PRODUCT MANAGEMENT
|
|
134
|
+
// ====================
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Create a new product
|
|
138
|
+
*/
|
|
139
|
+
export async function createProduct({
|
|
140
|
+
name,
|
|
141
|
+
shortDescription,
|
|
142
|
+
longDescription,
|
|
143
|
+
sku,
|
|
144
|
+
upc,
|
|
145
|
+
shippable = 'FALSE',
|
|
146
|
+
active = 'FALSE',
|
|
147
|
+
shop,
|
|
148
|
+
prData = {},
|
|
149
|
+
prOptions = {},
|
|
150
|
+
partnerType,
|
|
151
|
+
useSandbox = false,
|
|
152
|
+
...authParams
|
|
153
|
+
}) {
|
|
154
|
+
if (!name) {
|
|
155
|
+
throw new Error('Product name is required');
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
const requestBody = {
|
|
159
|
+
name,
|
|
160
|
+
shippable,
|
|
161
|
+
active
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
// Optional fields
|
|
165
|
+
if (shop) requestBody.shop = shop;
|
|
166
|
+
if (shortDescription) requestBody.shortDescription = shortDescription;
|
|
167
|
+
if (longDescription) requestBody.longDescription = longDescription;
|
|
168
|
+
if (sku) requestBody.sku = sku;
|
|
169
|
+
if (upc) requestBody.upc = upc;
|
|
170
|
+
if (Object.keys(prData).length > 0) requestBody.prData = prData;
|
|
171
|
+
if (Object.keys(prOptions).length > 0) requestBody.prOptions = prOptions;
|
|
172
|
+
|
|
173
|
+
const minimizedBody = createMinimizedJSON(requestBody);
|
|
174
|
+
const headers = await createAuthHeaders(partnerType, { ...authParams, requestBody: minimizedBody });
|
|
175
|
+
const baseUrl = useSandbox ? getSandboxUrl() : getProductionUrl();
|
|
176
|
+
|
|
177
|
+
try {
|
|
178
|
+
const response = await axios.post(
|
|
179
|
+
`${baseUrl}/products`,
|
|
180
|
+
minimizedBody,
|
|
181
|
+
{ headers }
|
|
182
|
+
);
|
|
183
|
+
|
|
184
|
+
return {
|
|
185
|
+
success: true,
|
|
186
|
+
data: response.data,
|
|
187
|
+
requestInfo: {
|
|
188
|
+
url: `${baseUrl}/products`,
|
|
189
|
+
method: 'POST',
|
|
190
|
+
requestBody: minimizedBody,
|
|
191
|
+
statusCode: response.status
|
|
192
|
+
}
|
|
193
|
+
};
|
|
194
|
+
} catch (error) {
|
|
195
|
+
throw new Error(`Failed to create product: ${error.response?.data?.message || error.message}`);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* Get list of products
|
|
201
|
+
*/
|
|
202
|
+
export async function getProducts({
|
|
203
|
+
partnerType,
|
|
204
|
+
useSandbox = false,
|
|
205
|
+
...authParams
|
|
206
|
+
}) {
|
|
207
|
+
const headers = await createAuthHeaders(partnerType, authParams);
|
|
208
|
+
const baseUrl = useSandbox ? getSandboxUrl() : getProductionUrl();
|
|
209
|
+
|
|
210
|
+
try {
|
|
211
|
+
const response = await axios.get(
|
|
212
|
+
`${baseUrl}/products`,
|
|
213
|
+
{ headers }
|
|
214
|
+
);
|
|
215
|
+
|
|
216
|
+
return {
|
|
217
|
+
success: true,
|
|
218
|
+
data: response.data,
|
|
219
|
+
requestInfo: {
|
|
220
|
+
url: `${baseUrl}/products`,
|
|
221
|
+
method: 'GET',
|
|
222
|
+
statusCode: response.status
|
|
223
|
+
}
|
|
224
|
+
};
|
|
225
|
+
} catch (error) {
|
|
226
|
+
throw new Error(`Failed to get products: ${error.response?.data?.message || error.message}`);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* Get product information by ID
|
|
232
|
+
*/
|
|
233
|
+
export async function getProduct({
|
|
234
|
+
productId,
|
|
235
|
+
partnerType,
|
|
236
|
+
useSandbox = false,
|
|
237
|
+
...authParams
|
|
238
|
+
}) {
|
|
239
|
+
if (!productId) {
|
|
240
|
+
throw new Error('productId is required');
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
const headers = await createAuthHeaders(partnerType, authParams);
|
|
244
|
+
const baseUrl = useSandbox ? getSandboxUrl() : getProductionUrl();
|
|
245
|
+
|
|
246
|
+
try {
|
|
247
|
+
const response = await axios.get(
|
|
248
|
+
`${baseUrl}/products/${productId}`,
|
|
249
|
+
{ headers }
|
|
250
|
+
);
|
|
251
|
+
|
|
252
|
+
return {
|
|
253
|
+
success: true,
|
|
254
|
+
data: response.data,
|
|
255
|
+
requestInfo: {
|
|
256
|
+
url: `${baseUrl}/products/${productId}`,
|
|
257
|
+
method: 'GET',
|
|
258
|
+
statusCode: response.status
|
|
259
|
+
}
|
|
260
|
+
};
|
|
261
|
+
} catch (error) {
|
|
262
|
+
throw new Error(`Failed to get product: ${error.response?.data?.message || error.message}`);
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
/**
|
|
267
|
+
* Update product
|
|
268
|
+
*/
|
|
269
|
+
export async function updateProduct({
|
|
270
|
+
productId,
|
|
271
|
+
name,
|
|
272
|
+
shortDescription,
|
|
273
|
+
longDescription,
|
|
274
|
+
sku,
|
|
275
|
+
upc,
|
|
276
|
+
shippable,
|
|
277
|
+
active,
|
|
278
|
+
shop,
|
|
279
|
+
prData = {},
|
|
280
|
+
prOptions = {},
|
|
281
|
+
partnerType,
|
|
282
|
+
useSandbox = false,
|
|
283
|
+
...authParams
|
|
284
|
+
}) {
|
|
285
|
+
if (!productId) {
|
|
286
|
+
throw new Error('productId is required');
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
const requestBody = {};
|
|
290
|
+
|
|
291
|
+
// Only include fields that are provided
|
|
292
|
+
if (name !== undefined) requestBody.name = name;
|
|
293
|
+
if (shop !== undefined) requestBody.shop = shop;
|
|
294
|
+
if (shortDescription !== undefined) requestBody.shortDescription = shortDescription;
|
|
295
|
+
if (longDescription !== undefined) requestBody.longDescription = longDescription;
|
|
296
|
+
if (sku !== undefined) requestBody.sku = sku;
|
|
297
|
+
if (upc !== undefined) requestBody.upc = upc;
|
|
298
|
+
if (shippable !== undefined) requestBody.shippable = shippable;
|
|
299
|
+
if (active !== undefined) requestBody.active = active;
|
|
300
|
+
if (Object.keys(prData).length > 0) requestBody.prData = prData;
|
|
301
|
+
if (Object.keys(prOptions).length > 0) requestBody.prOptions = prOptions;
|
|
302
|
+
|
|
303
|
+
const minimizedBody = createMinimizedJSON(requestBody);
|
|
304
|
+
const headers = await createAuthHeaders(partnerType, { ...authParams, requestBody: minimizedBody });
|
|
305
|
+
const baseUrl = useSandbox ? getSandboxUrl() : getProductionUrl();
|
|
306
|
+
|
|
307
|
+
try {
|
|
308
|
+
const response = await axios.patch(
|
|
309
|
+
`${baseUrl}/products/${productId}`,
|
|
310
|
+
minimizedBody,
|
|
311
|
+
{ headers }
|
|
312
|
+
);
|
|
313
|
+
|
|
314
|
+
return {
|
|
315
|
+
success: true,
|
|
316
|
+
data: response.data,
|
|
317
|
+
requestInfo: {
|
|
318
|
+
url: `${baseUrl}/products/${productId}`,
|
|
319
|
+
method: 'PATCH',
|
|
320
|
+
requestBody: minimizedBody,
|
|
321
|
+
statusCode: response.status
|
|
322
|
+
}
|
|
323
|
+
};
|
|
324
|
+
} catch (error) {
|
|
325
|
+
throw new Error(`Failed to update product: ${error.response?.data?.message || error.message}`);
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
/**
|
|
330
|
+
* Delete product
|
|
331
|
+
*/
|
|
332
|
+
export async function deleteProduct({
|
|
333
|
+
productId,
|
|
334
|
+
partnerType,
|
|
335
|
+
useSandbox = false,
|
|
336
|
+
...authParams
|
|
337
|
+
}) {
|
|
338
|
+
if (!productId) {
|
|
339
|
+
throw new Error('productId is required');
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
const headers = await createAuthHeaders(partnerType, authParams);
|
|
343
|
+
const baseUrl = useSandbox ? getSandboxUrl() : getProductionUrl();
|
|
344
|
+
|
|
345
|
+
try {
|
|
346
|
+
const response = await axios.delete(
|
|
347
|
+
`${baseUrl}/products/${productId}`,
|
|
348
|
+
{ headers }
|
|
349
|
+
);
|
|
350
|
+
|
|
351
|
+
return {
|
|
352
|
+
success: true,
|
|
353
|
+
requestInfo: {
|
|
354
|
+
url: `${baseUrl}/products/${productId}`,
|
|
355
|
+
method: 'DELETE',
|
|
356
|
+
statusCode: response.status
|
|
357
|
+
}
|
|
358
|
+
};
|
|
359
|
+
} catch (error) {
|
|
360
|
+
throw new Error(`Failed to delete product: ${error.response?.data?.message || error.message}`);
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
/**
|
|
365
|
+
* Generate product image (QR code or barcode)
|
|
366
|
+
*/
|
|
367
|
+
export async function getProductImage({
|
|
368
|
+
productId,
|
|
369
|
+
type = IMAGE_TYPES.QR,
|
|
370
|
+
qrOptions = {},
|
|
371
|
+
barOptions = {},
|
|
372
|
+
partnerType,
|
|
373
|
+
useSandbox = false,
|
|
374
|
+
...authParams
|
|
375
|
+
}) {
|
|
376
|
+
if (!productId) {
|
|
377
|
+
throw new Error('productId is required');
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
const requestBody = {
|
|
381
|
+
type
|
|
382
|
+
};
|
|
383
|
+
|
|
384
|
+
if (type === IMAGE_TYPES.QR && Object.keys(qrOptions).length > 0) {
|
|
385
|
+
requestBody.qrOptions = qrOptions;
|
|
386
|
+
}
|
|
387
|
+
if (type === IMAGE_TYPES.BARCODE && Object.keys(barOptions).length > 0) {
|
|
388
|
+
requestBody.barOptions = barOptions;
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
const minimizedBody = createMinimizedJSON(requestBody);
|
|
392
|
+
const headers = await createAuthHeaders(partnerType, { ...authParams, requestBody: minimizedBody });
|
|
393
|
+
const baseUrl = useSandbox ? getSandboxUrl() : getProductionUrl();
|
|
394
|
+
|
|
395
|
+
try {
|
|
396
|
+
const response = await axios.post(
|
|
397
|
+
`${baseUrl}/products/${productId}/image`,
|
|
398
|
+
minimizedBody,
|
|
399
|
+
{ headers }
|
|
400
|
+
);
|
|
401
|
+
|
|
402
|
+
return {
|
|
403
|
+
success: true,
|
|
404
|
+
data: response.data,
|
|
405
|
+
requestInfo: {
|
|
406
|
+
url: `${baseUrl}/products/${productId}/image`,
|
|
407
|
+
method: 'POST',
|
|
408
|
+
requestBody: minimizedBody,
|
|
409
|
+
statusCode: response.status
|
|
410
|
+
}
|
|
411
|
+
};
|
|
412
|
+
} catch (error) {
|
|
413
|
+
throw new Error(`Failed to get product image: ${error.response?.data?.message || error.message}`);
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
// ====================
|
|
418
|
+
// PRICE SCHEDULES
|
|
419
|
+
// ====================
|
|
420
|
+
|
|
421
|
+
/**
|
|
422
|
+
* Create price schedule for a product
|
|
423
|
+
*/
|
|
424
|
+
export async function createPriceSchedule({
|
|
425
|
+
productId,
|
|
426
|
+
description,
|
|
427
|
+
priceCorrection = PRICE_CORRECTION_TYPES.DISCOUNT,
|
|
428
|
+
correctionType = CORRECTION_TYPES.PERCENTAGE,
|
|
429
|
+
correctionValue = '0.00',
|
|
430
|
+
dateFrom,
|
|
431
|
+
dateTo,
|
|
432
|
+
partnerType,
|
|
433
|
+
useSandbox = false,
|
|
434
|
+
...authParams
|
|
435
|
+
}) {
|
|
436
|
+
if (!productId) {
|
|
437
|
+
throw new Error('productId is required');
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
const requestBody = {
|
|
441
|
+
priceCorrection,
|
|
442
|
+
correctionType,
|
|
443
|
+
correctionValue
|
|
444
|
+
};
|
|
445
|
+
|
|
446
|
+
if (description) requestBody.description = description;
|
|
447
|
+
if (dateFrom) requestBody.dateFrom = dateFrom;
|
|
448
|
+
if (dateTo) requestBody.dateTo = dateTo;
|
|
449
|
+
|
|
450
|
+
const minimizedBody = createMinimizedJSON(requestBody);
|
|
451
|
+
const headers = await createAuthHeaders(partnerType, { ...authParams, requestBody: minimizedBody });
|
|
452
|
+
const baseUrl = useSandbox ? getSandboxUrl() : getProductionUrl();
|
|
453
|
+
|
|
454
|
+
try {
|
|
455
|
+
const response = await axios.post(
|
|
456
|
+
`${baseUrl}/products/${productId}/schedules`,
|
|
457
|
+
minimizedBody,
|
|
458
|
+
{ headers }
|
|
459
|
+
);
|
|
460
|
+
|
|
461
|
+
return {
|
|
462
|
+
success: true,
|
|
463
|
+
data: response.data,
|
|
464
|
+
requestInfo: {
|
|
465
|
+
url: `${baseUrl}/products/${productId}/schedules`,
|
|
466
|
+
method: 'POST',
|
|
467
|
+
requestBody: minimizedBody,
|
|
468
|
+
statusCode: response.status
|
|
469
|
+
}
|
|
470
|
+
};
|
|
471
|
+
} catch (error) {
|
|
472
|
+
throw new Error(`Failed to create price schedule: ${error.response?.data?.message || error.message}`);
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
/**
|
|
477
|
+
* Get product schedules
|
|
478
|
+
*/
|
|
479
|
+
export async function getProductSchedules({
|
|
480
|
+
productId,
|
|
481
|
+
partnerType,
|
|
482
|
+
useSandbox = false,
|
|
483
|
+
...authParams
|
|
484
|
+
}) {
|
|
485
|
+
if (!productId) {
|
|
486
|
+
throw new Error('productId is required');
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
const headers = await createAuthHeaders(partnerType, authParams);
|
|
490
|
+
const baseUrl = useSandbox ? getSandboxUrl() : getProductionUrl();
|
|
491
|
+
|
|
492
|
+
try {
|
|
493
|
+
const response = await axios.get(
|
|
494
|
+
`${baseUrl}/products/${productId}/schedules`,
|
|
495
|
+
{ headers }
|
|
496
|
+
);
|
|
497
|
+
|
|
498
|
+
return {
|
|
499
|
+
success: true,
|
|
500
|
+
data: response.data,
|
|
501
|
+
requestInfo: {
|
|
502
|
+
url: `${baseUrl}/products/${productId}/schedules`,
|
|
503
|
+
method: 'GET',
|
|
504
|
+
statusCode: response.status
|
|
505
|
+
}
|
|
506
|
+
};
|
|
507
|
+
} catch (error) {
|
|
508
|
+
throw new Error(`Failed to get product schedules: ${error.response?.data?.message || error.message}`);
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
/**
|
|
513
|
+
* Get schedule information
|
|
514
|
+
*/
|
|
515
|
+
export async function getSchedule({
|
|
516
|
+
productId,
|
|
517
|
+
scheduleId,
|
|
518
|
+
partnerType,
|
|
519
|
+
useSandbox = false,
|
|
520
|
+
...authParams
|
|
521
|
+
}) {
|
|
522
|
+
if (!productId) {
|
|
523
|
+
throw new Error('productId is required');
|
|
524
|
+
}
|
|
525
|
+
if (!scheduleId) {
|
|
526
|
+
throw new Error('scheduleId is required');
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
const headers = await createAuthHeaders(partnerType, authParams);
|
|
530
|
+
const baseUrl = useSandbox ? getSandboxUrl() : getProductionUrl();
|
|
531
|
+
|
|
532
|
+
try {
|
|
533
|
+
const response = await axios.get(
|
|
534
|
+
`${baseUrl}/products/${productId}/schedules/${scheduleId}`,
|
|
535
|
+
{ headers }
|
|
536
|
+
);
|
|
537
|
+
|
|
538
|
+
return {
|
|
539
|
+
success: true,
|
|
540
|
+
data: response.data,
|
|
541
|
+
requestInfo: {
|
|
542
|
+
url: `${baseUrl}/products/${productId}/schedules/${scheduleId}`,
|
|
543
|
+
method: 'GET',
|
|
544
|
+
statusCode: response.status
|
|
545
|
+
}
|
|
546
|
+
};
|
|
547
|
+
} catch (error) {
|
|
548
|
+
throw new Error(`Failed to get schedule: ${error.response?.data?.message || error.message}`);
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
/**
|
|
553
|
+
* Update price schedule
|
|
554
|
+
*/
|
|
555
|
+
export async function updatePriceSchedule({
|
|
556
|
+
productId,
|
|
557
|
+
scheduleId,
|
|
558
|
+
description,
|
|
559
|
+
priceCorrection,
|
|
560
|
+
correctionType,
|
|
561
|
+
correctionValue,
|
|
562
|
+
dateFrom,
|
|
563
|
+
dateTo,
|
|
564
|
+
partnerType,
|
|
565
|
+
useSandbox = false,
|
|
566
|
+
...authParams
|
|
567
|
+
}) {
|
|
568
|
+
if (!productId) {
|
|
569
|
+
throw new Error('productId is required');
|
|
570
|
+
}
|
|
571
|
+
if (!scheduleId) {
|
|
572
|
+
throw new Error('scheduleId is required');
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
const requestBody = {};
|
|
576
|
+
|
|
577
|
+
if (description !== undefined) requestBody.description = description;
|
|
578
|
+
if (priceCorrection !== undefined) requestBody.priceCorrection = priceCorrection;
|
|
579
|
+
if (correctionType !== undefined) requestBody.correctionType = correctionType;
|
|
580
|
+
if (correctionValue !== undefined) requestBody.correctionValue = correctionValue;
|
|
581
|
+
if (dateFrom !== undefined) requestBody.dateFrom = dateFrom;
|
|
582
|
+
if (dateTo !== undefined) requestBody.dateTo = dateTo;
|
|
583
|
+
|
|
584
|
+
const minimizedBody = createMinimizedJSON(requestBody);
|
|
585
|
+
const headers = await createAuthHeaders(partnerType, { ...authParams, requestBody: minimizedBody });
|
|
586
|
+
const baseUrl = useSandbox ? getSandboxUrl() : getProductionUrl();
|
|
587
|
+
|
|
588
|
+
try {
|
|
589
|
+
const response = await axios.patch(
|
|
590
|
+
`${baseUrl}/products/${productId}/schedules/${scheduleId}`,
|
|
591
|
+
minimizedBody,
|
|
592
|
+
{ headers }
|
|
593
|
+
);
|
|
594
|
+
|
|
595
|
+
return {
|
|
596
|
+
success: true,
|
|
597
|
+
data: response.data,
|
|
598
|
+
requestInfo: {
|
|
599
|
+
url: `${baseUrl}/products/${productId}/schedules/${scheduleId}`,
|
|
600
|
+
method: 'PATCH',
|
|
601
|
+
requestBody: minimizedBody,
|
|
602
|
+
statusCode: response.status
|
|
603
|
+
}
|
|
604
|
+
};
|
|
605
|
+
} catch (error) {
|
|
606
|
+
throw new Error(`Failed to update schedule: ${error.response?.data?.message || error.message}`);
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
/**
|
|
611
|
+
* Delete price schedule
|
|
612
|
+
*/
|
|
613
|
+
export async function deletePriceSchedule({
|
|
614
|
+
productId,
|
|
615
|
+
scheduleId,
|
|
616
|
+
partnerType,
|
|
617
|
+
useSandbox = false,
|
|
618
|
+
...authParams
|
|
619
|
+
}) {
|
|
620
|
+
if (!productId) {
|
|
621
|
+
throw new Error('productId is required');
|
|
622
|
+
}
|
|
623
|
+
if (!scheduleId) {
|
|
624
|
+
throw new Error('scheduleId is required');
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
const headers = await createAuthHeaders(partnerType, authParams);
|
|
628
|
+
const baseUrl = useSandbox ? getSandboxUrl() : getProductionUrl();
|
|
629
|
+
|
|
630
|
+
try {
|
|
631
|
+
const response = await axios.delete(
|
|
632
|
+
`${baseUrl}/products/${productId}/schedules/${scheduleId}`,
|
|
633
|
+
{ headers }
|
|
634
|
+
);
|
|
635
|
+
|
|
636
|
+
return {
|
|
637
|
+
success: true,
|
|
638
|
+
requestInfo: {
|
|
639
|
+
url: `${baseUrl}/products/${productId}/schedules/${scheduleId}`,
|
|
640
|
+
method: 'DELETE',
|
|
641
|
+
statusCode: response.status
|
|
642
|
+
}
|
|
643
|
+
};
|
|
644
|
+
} catch (error) {
|
|
645
|
+
throw new Error(`Failed to delete schedule: ${error.response?.data?.message || error.message}`);
|
|
646
|
+
}
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
// ====================
|
|
650
|
+
// AUDIO/SOUNDBITE MANAGEMENT
|
|
651
|
+
// ====================
|
|
652
|
+
|
|
653
|
+
/**
|
|
654
|
+
* Register audio file for a product
|
|
655
|
+
*/
|
|
656
|
+
export async function registerAudio({
|
|
657
|
+
productId,
|
|
658
|
+
audioFile,
|
|
659
|
+
audioPath,
|
|
660
|
+
partnerType,
|
|
661
|
+
useSandbox = false,
|
|
662
|
+
...authParams
|
|
663
|
+
}) {
|
|
664
|
+
if (!productId) {
|
|
665
|
+
throw new Error('productId is required');
|
|
666
|
+
}
|
|
667
|
+
if (!audioFile && !audioPath) {
|
|
668
|
+
throw new Error('Either audioFile buffer or audioPath is required');
|
|
669
|
+
}
|
|
670
|
+
|
|
671
|
+
const formData = new FormData();
|
|
672
|
+
|
|
673
|
+
if (audioFile) {
|
|
674
|
+
formData.append('file', audioFile);
|
|
675
|
+
} else if (audioPath) {
|
|
676
|
+
const fs = await import('fs');
|
|
677
|
+
formData.append('file', fs.createReadStream(audioPath));
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
const headers = await createMultipartAuthHeaders(partnerType, authParams);
|
|
681
|
+
const baseUrl = useSandbox ? getSandboxUrl() : getProductionUrl();
|
|
682
|
+
|
|
683
|
+
try {
|
|
684
|
+
const response = await axios.post(
|
|
685
|
+
`${baseUrl}/products/${productId}/audios/upload`,
|
|
686
|
+
formData,
|
|
687
|
+
{
|
|
688
|
+
headers: {
|
|
689
|
+
...headers,
|
|
690
|
+
...formData.getHeaders()
|
|
691
|
+
}
|
|
692
|
+
}
|
|
693
|
+
);
|
|
694
|
+
|
|
695
|
+
return {
|
|
696
|
+
success: true,
|
|
697
|
+
data: response.data,
|
|
698
|
+
requestInfo: {
|
|
699
|
+
url: `${baseUrl}/products/${productId}/audios/upload`,
|
|
700
|
+
method: 'POST',
|
|
701
|
+
statusCode: response.status
|
|
702
|
+
}
|
|
703
|
+
};
|
|
704
|
+
} catch (error) {
|
|
705
|
+
throw new Error(`Failed to register audio: ${error.response?.data?.message || error.message}`);
|
|
706
|
+
}
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
/**
|
|
710
|
+
* Get product audios
|
|
711
|
+
*/
|
|
712
|
+
export async function getProductAudios({
|
|
713
|
+
productId,
|
|
714
|
+
partnerType,
|
|
715
|
+
useSandbox = false,
|
|
716
|
+
...authParams
|
|
717
|
+
}) {
|
|
718
|
+
if (!productId) {
|
|
719
|
+
throw new Error('productId is required');
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
const headers = await createAuthHeaders(partnerType, authParams);
|
|
723
|
+
const baseUrl = useSandbox ? getSandboxUrl() : getProductionUrl();
|
|
724
|
+
|
|
725
|
+
try {
|
|
726
|
+
const response = await axios.get(
|
|
727
|
+
`${baseUrl}/products/${productId}/audios`,
|
|
728
|
+
{ headers }
|
|
729
|
+
);
|
|
730
|
+
|
|
731
|
+
return {
|
|
732
|
+
success: true,
|
|
733
|
+
data: response.data,
|
|
734
|
+
requestInfo: {
|
|
735
|
+
url: `${baseUrl}/products/${productId}/audios`,
|
|
736
|
+
method: 'GET',
|
|
737
|
+
statusCode: response.status
|
|
738
|
+
}
|
|
739
|
+
};
|
|
740
|
+
} catch (error) {
|
|
741
|
+
throw new Error(`Failed to get product audios: ${error.response?.data?.message || error.message}`);
|
|
742
|
+
}
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
/**
|
|
746
|
+
* Get audio information
|
|
747
|
+
*/
|
|
748
|
+
export async function getAudio({
|
|
749
|
+
productId,
|
|
750
|
+
audioId,
|
|
751
|
+
partnerType,
|
|
752
|
+
useSandbox = false,
|
|
753
|
+
...authParams
|
|
754
|
+
}) {
|
|
755
|
+
if (!productId) {
|
|
756
|
+
throw new Error('productId is required');
|
|
757
|
+
}
|
|
758
|
+
if (!audioId) {
|
|
759
|
+
throw new Error('audioId is required');
|
|
760
|
+
}
|
|
761
|
+
|
|
762
|
+
const headers = await createAuthHeaders(partnerType, authParams);
|
|
763
|
+
const baseUrl = useSandbox ? getSandboxUrl() : getProductionUrl();
|
|
764
|
+
|
|
765
|
+
try {
|
|
766
|
+
const response = await axios.get(
|
|
767
|
+
`${baseUrl}/products/${productId}/audios/${audioId}`,
|
|
768
|
+
{ headers }
|
|
769
|
+
);
|
|
770
|
+
|
|
771
|
+
return {
|
|
772
|
+
success: true,
|
|
773
|
+
data: response.data,
|
|
774
|
+
requestInfo: {
|
|
775
|
+
url: `${baseUrl}/products/${productId}/audios/${audioId}`,
|
|
776
|
+
method: 'GET',
|
|
777
|
+
statusCode: response.status
|
|
778
|
+
}
|
|
779
|
+
};
|
|
780
|
+
} catch (error) {
|
|
781
|
+
throw new Error(`Failed to get audio: ${error.response?.data?.message || error.message}`);
|
|
782
|
+
}
|
|
783
|
+
}
|
|
784
|
+
|
|
785
|
+
/**
|
|
786
|
+
* Update audio information
|
|
787
|
+
*/
|
|
788
|
+
export async function updateAudio({
|
|
789
|
+
productId,
|
|
790
|
+
audioId,
|
|
791
|
+
title,
|
|
792
|
+
newProductId,
|
|
793
|
+
partnerType,
|
|
794
|
+
useSandbox = false,
|
|
795
|
+
...authParams
|
|
796
|
+
}) {
|
|
797
|
+
if (!productId) {
|
|
798
|
+
throw new Error('productId is required');
|
|
799
|
+
}
|
|
800
|
+
if (!audioId) {
|
|
801
|
+
throw new Error('audioId is required');
|
|
802
|
+
}
|
|
803
|
+
|
|
804
|
+
const requestBody = {};
|
|
805
|
+
|
|
806
|
+
if (title !== undefined) requestBody.title = title;
|
|
807
|
+
if (newProductId !== undefined) requestBody.productId = newProductId;
|
|
808
|
+
|
|
809
|
+
const minimizedBody = createMinimizedJSON(requestBody);
|
|
810
|
+
const headers = await createAuthHeaders(partnerType, { ...authParams, requestBody: minimizedBody });
|
|
811
|
+
const baseUrl = useSandbox ? getSandboxUrl() : getProductionUrl();
|
|
812
|
+
|
|
813
|
+
try {
|
|
814
|
+
const response = await axios.patch(
|
|
815
|
+
`${baseUrl}/products/${productId}/audios/${audioId}`,
|
|
816
|
+
minimizedBody,
|
|
817
|
+
{ headers }
|
|
818
|
+
);
|
|
819
|
+
|
|
820
|
+
return {
|
|
821
|
+
success: true,
|
|
822
|
+
data: response.data,
|
|
823
|
+
requestInfo: {
|
|
824
|
+
url: `${baseUrl}/products/${productId}/audios/${audioId}`,
|
|
825
|
+
method: 'PATCH',
|
|
826
|
+
requestBody: minimizedBody,
|
|
827
|
+
statusCode: response.status
|
|
828
|
+
}
|
|
829
|
+
};
|
|
830
|
+
} catch (error) {
|
|
831
|
+
throw new Error(`Failed to update audio: ${error.response?.data?.message || error.message}`);
|
|
832
|
+
}
|
|
833
|
+
}
|
|
834
|
+
|
|
835
|
+
/**
|
|
836
|
+
* Delete audio
|
|
837
|
+
*/
|
|
838
|
+
export async function deleteAudio({
|
|
839
|
+
productId,
|
|
840
|
+
audioId,
|
|
841
|
+
partnerType,
|
|
842
|
+
useSandbox = false,
|
|
843
|
+
...authParams
|
|
844
|
+
}) {
|
|
845
|
+
if (!productId) {
|
|
846
|
+
throw new Error('productId is required');
|
|
847
|
+
}
|
|
848
|
+
if (!audioId) {
|
|
849
|
+
throw new Error('audioId is required');
|
|
850
|
+
}
|
|
851
|
+
|
|
852
|
+
const headers = await createAuthHeaders(partnerType, authParams);
|
|
853
|
+
const baseUrl = useSandbox ? getSandboxUrl() : getProductionUrl();
|
|
854
|
+
|
|
855
|
+
try {
|
|
856
|
+
const response = await axios.delete(
|
|
857
|
+
`${baseUrl}/products/${productId}/audios/${audioId}`,
|
|
858
|
+
{ headers }
|
|
859
|
+
);
|
|
860
|
+
|
|
861
|
+
return {
|
|
862
|
+
success: true,
|
|
863
|
+
requestInfo: {
|
|
864
|
+
url: `${baseUrl}/products/${productId}/audios/${audioId}`,
|
|
865
|
+
method: 'DELETE',
|
|
866
|
+
statusCode: response.status
|
|
867
|
+
}
|
|
868
|
+
};
|
|
869
|
+
} catch (error) {
|
|
870
|
+
throw new Error(`Failed to delete audio: ${error.response?.data?.message || error.message}`);
|
|
871
|
+
}
|
|
872
|
+
}
|