@lonca/trendyol 0.4.0 → 0.6.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/dist/index.cjs +904 -20
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +822 -1
- package/dist/index.d.ts +822 -1
- package/dist/index.js +895 -21
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -234,6 +234,254 @@ function extractAttributeList(data) {
|
|
|
234
234
|
}
|
|
235
235
|
return null;
|
|
236
236
|
}
|
|
237
|
+
function toIso(epochMs) {
|
|
238
|
+
if (typeof epochMs !== "number" || !Number.isFinite(epochMs) || epochMs === 0) {
|
|
239
|
+
return void 0;
|
|
240
|
+
}
|
|
241
|
+
return new Date(epochMs).toISOString();
|
|
242
|
+
}
|
|
243
|
+
function normalizeClaim(node) {
|
|
244
|
+
const out = {
|
|
245
|
+
id: node.id ?? node.claimId ?? "",
|
|
246
|
+
orderNumber: node.orderNumber ?? "",
|
|
247
|
+
raw: node
|
|
248
|
+
};
|
|
249
|
+
const orderDate = toIso(node.orderDate);
|
|
250
|
+
if (orderDate) out.orderDate = orderDate;
|
|
251
|
+
const claimDate = toIso(node.claimDate);
|
|
252
|
+
if (claimDate) out.claimDate = claimDate;
|
|
253
|
+
if (node.customerFirstName !== void 0) out.customerFirstName = node.customerFirstName;
|
|
254
|
+
if (node.customerLastName !== void 0) out.customerLastName = node.customerLastName;
|
|
255
|
+
return out;
|
|
256
|
+
}
|
|
257
|
+
var ClaimsResource = class {
|
|
258
|
+
constructor(transport, sellerId, limiter) {
|
|
259
|
+
this.transport = transport;
|
|
260
|
+
this.sellerId = sellerId;
|
|
261
|
+
this.limiter = limiter ?? new core.TokenBucketRateLimiter({ capacity: 1e3, intervalMs: 6e4 });
|
|
262
|
+
}
|
|
263
|
+
transport;
|
|
264
|
+
sellerId;
|
|
265
|
+
limiter;
|
|
266
|
+
/**
|
|
267
|
+
* Create a return claim against an order. Use this to file a return on
|
|
268
|
+
* behalf of a customer (e.g. when they called your CS line). For
|
|
269
|
+
* customer-initiated returns coming from trendyol.com, you receive them
|
|
270
|
+
* via `claims.list()` — no need to call `create`.
|
|
271
|
+
*
|
|
272
|
+
* Returns whatever Trendyol returns (typically the new claim's identifier).
|
|
273
|
+
*
|
|
274
|
+
* @throws {ValidationError} when `claimItems` is empty.
|
|
275
|
+
*/
|
|
276
|
+
async create(input) {
|
|
277
|
+
if (!Array.isArray(input?.claimItems) || input.claimItems.length === 0) {
|
|
278
|
+
throw new core.ValidationError({ message: "claims.create: claimItems must not be empty" });
|
|
279
|
+
}
|
|
280
|
+
return this.transport.request({
|
|
281
|
+
method: "POST",
|
|
282
|
+
path: `/integration/order/sellers/${this.sellerId}/claims/create`,
|
|
283
|
+
body: input,
|
|
284
|
+
rateLimiter: this.limiter
|
|
285
|
+
});
|
|
286
|
+
}
|
|
287
|
+
/**
|
|
288
|
+
* File a seller-side rejection ("ret talebi") against a customer claim.
|
|
289
|
+
*
|
|
290
|
+
* **Wire format: `multipart/form-data`** — the SDK builds the FormData
|
|
291
|
+
* internally from the typed input. `claimItemIdList` is joined with
|
|
292
|
+
* commas (Trendyol expects a single comma-separated string field).
|
|
293
|
+
* Attach supporting docs (PDF / JPEG) via `files: [Blob, ...]`.
|
|
294
|
+
*/
|
|
295
|
+
async createIssue(claimId, input) {
|
|
296
|
+
if (!Array.isArray(input?.claimItemIdList) || input.claimItemIdList.length === 0) {
|
|
297
|
+
throw new core.ValidationError({
|
|
298
|
+
message: "claims.createIssue: claimItemIdList must not be empty"
|
|
299
|
+
});
|
|
300
|
+
}
|
|
301
|
+
if (typeof input.description !== "string" || input.description.length === 0) {
|
|
302
|
+
throw new core.ValidationError({ message: "claims.createIssue: description is required" });
|
|
303
|
+
}
|
|
304
|
+
if (input.description.length > 500) {
|
|
305
|
+
throw new core.ValidationError({
|
|
306
|
+
message: `claims.createIssue: description must be \u2264500 chars (got ${input.description.length})`
|
|
307
|
+
});
|
|
308
|
+
}
|
|
309
|
+
const form = new FormData();
|
|
310
|
+
form.append("claimIssueReasonId", String(input.claimIssueReasonId));
|
|
311
|
+
form.append("claimItemIdList", input.claimItemIdList.join(","));
|
|
312
|
+
form.append("description", input.description);
|
|
313
|
+
if (input.files) {
|
|
314
|
+
for (const file of input.files) {
|
|
315
|
+
form.append("files", file);
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
return this.transport.request({
|
|
319
|
+
method: "POST",
|
|
320
|
+
path: `/integration/order/sellers/${this.sellerId}/claims/${encodeURIComponent(claimId)}/issue`,
|
|
321
|
+
body: form,
|
|
322
|
+
rateLimiter: this.limiter
|
|
323
|
+
});
|
|
324
|
+
}
|
|
325
|
+
/**
|
|
326
|
+
* Approve specific claim line items. After approval, Trendyol moves
|
|
327
|
+
* those line items into the post-approval refund / return-shipping flow.
|
|
328
|
+
*
|
|
329
|
+
* @throws {ValidationError} when `claimLineItemIdList` is empty.
|
|
330
|
+
*/
|
|
331
|
+
async approveLineItems(claimId, input) {
|
|
332
|
+
if (!Array.isArray(input?.claimLineItemIdList) || input.claimLineItemIdList.length === 0) {
|
|
333
|
+
throw new core.ValidationError({
|
|
334
|
+
message: "claims.approveLineItems: claimLineItemIdList must not be empty"
|
|
335
|
+
});
|
|
336
|
+
}
|
|
337
|
+
return this.transport.request({
|
|
338
|
+
method: "PUT",
|
|
339
|
+
path: `/integration/order/sellers/${this.sellerId}/claims/${encodeURIComponent(claimId)}/items/approve`,
|
|
340
|
+
body: input,
|
|
341
|
+
rateLimiter: this.limiter
|
|
342
|
+
});
|
|
343
|
+
}
|
|
344
|
+
/**
|
|
345
|
+
* List claims (page-based; SDK exposes opaque cursor convention).
|
|
346
|
+
*
|
|
347
|
+
* @example
|
|
348
|
+
* ```ts
|
|
349
|
+
* import { paginate } from '@lonca/core';
|
|
350
|
+
* for await (const c of paginate((p) =>
|
|
351
|
+
* client.claims.list({ ...p, claimItemStatus: 'WaitingInAction' }),
|
|
352
|
+
* )) {
|
|
353
|
+
* console.log(c.id, c.orderNumber, c.claimDate);
|
|
354
|
+
* }
|
|
355
|
+
* ```
|
|
356
|
+
*/
|
|
357
|
+
async list(params = {}) {
|
|
358
|
+
const size = Math.min(params.limit ?? 50, 200);
|
|
359
|
+
const page = params.cursor ? Number.parseInt(params.cursor, 10) : 0;
|
|
360
|
+
const query = { page, size };
|
|
361
|
+
if (params.startDate) query.startDate = params.startDate.getTime();
|
|
362
|
+
if (params.endDate) query.endDate = params.endDate.getTime();
|
|
363
|
+
if (params.claimItemStatus) query.claimItemStatus = params.claimItemStatus;
|
|
364
|
+
const data = await this.transport.request({
|
|
365
|
+
method: "GET",
|
|
366
|
+
path: `/integration/order/sellers/${this.sellerId}/claims`,
|
|
367
|
+
query,
|
|
368
|
+
rateLimiter: this.limiter
|
|
369
|
+
});
|
|
370
|
+
const items = (data.content ?? []).map(normalizeClaim);
|
|
371
|
+
const result = { items };
|
|
372
|
+
const totalPages = typeof data.totalPages === "number" ? data.totalPages : 0;
|
|
373
|
+
if (page + 1 < totalPages) {
|
|
374
|
+
result.nextCursor = String(page + 1);
|
|
375
|
+
}
|
|
376
|
+
return result;
|
|
377
|
+
}
|
|
378
|
+
/**
|
|
379
|
+
* Fetch the catalog of rejection-reason IDs the seller can use on
|
|
380
|
+
* `claims.createIssue()`. Cache the result — it changes rarely.
|
|
381
|
+
*
|
|
382
|
+
* Note: this endpoint is **not seller-scoped** (no `sellerId` in path).
|
|
383
|
+
*/
|
|
384
|
+
async getIssueReasons() {
|
|
385
|
+
const data = await this.transport.request({
|
|
386
|
+
method: "GET",
|
|
387
|
+
path: `/integration/order/claim-issue-reasons`,
|
|
388
|
+
rateLimiter: this.limiter
|
|
389
|
+
});
|
|
390
|
+
return (data ?? []).map((r) => ({
|
|
391
|
+
id: typeof r.id === "number" ? r.id : 0,
|
|
392
|
+
name: r.name ?? ""
|
|
393
|
+
}));
|
|
394
|
+
}
|
|
395
|
+
/**
|
|
396
|
+
* Fetch the audit log for a single claim item (state transitions,
|
|
397
|
+
* actor, timestamp). Trendyol's response shape varies — the SDK
|
|
398
|
+
* surfaces each row as `{ raw }` and leaves field extraction to the
|
|
399
|
+
* caller until we observe a stable shape on the wire.
|
|
400
|
+
*/
|
|
401
|
+
async getItemAudits(claimItemId) {
|
|
402
|
+
const data = await this.transport.request({
|
|
403
|
+
method: "GET",
|
|
404
|
+
path: `/integration/order/sellers/${this.sellerId}/claims/items/${encodeURIComponent(claimItemId)}/audit`,
|
|
405
|
+
rateLimiter: this.limiter
|
|
406
|
+
});
|
|
407
|
+
const rows = Array.isArray(data) ? data : Array.isArray(data?.content) ? data.content : [];
|
|
408
|
+
return rows.map((row) => ({ raw: row }));
|
|
409
|
+
}
|
|
410
|
+
};
|
|
411
|
+
function toIso2(epochMs) {
|
|
412
|
+
if (typeof epochMs !== "number" || !Number.isFinite(epochMs) || epochMs === 0) {
|
|
413
|
+
return void 0;
|
|
414
|
+
}
|
|
415
|
+
return new Date(epochMs).toISOString();
|
|
416
|
+
}
|
|
417
|
+
function normalizeRow(row) {
|
|
418
|
+
const out = {
|
|
419
|
+
id: row.id !== void 0 ? String(row.id) : "",
|
|
420
|
+
raw: row
|
|
421
|
+
};
|
|
422
|
+
const tx = toIso2(row.transactionDate);
|
|
423
|
+
if (tx) out.transactionDate = tx;
|
|
424
|
+
if (row.barcode !== void 0) out.barcode = row.barcode;
|
|
425
|
+
if (row.transactionType !== void 0) out.transactionType = row.transactionType;
|
|
426
|
+
if (row.receiptId !== void 0) out.receiptId = row.receiptId;
|
|
427
|
+
if (row.description !== void 0) out.description = row.description;
|
|
428
|
+
if (typeof row.debt === "number") out.debt = row.debt;
|
|
429
|
+
if (typeof row.credit === "number") out.credit = row.credit;
|
|
430
|
+
if (row.paymentPeriod !== void 0) out.paymentPeriod = row.paymentPeriod;
|
|
431
|
+
if (row.commissionRate !== void 0) out.commissionRate = row.commissionRate;
|
|
432
|
+
if (row.commissionAmount !== void 0) out.commissionAmount = row.commissionAmount;
|
|
433
|
+
if (row.commissionInvoiceSerialNumber !== void 0) {
|
|
434
|
+
out.commissionInvoiceSerialNumber = row.commissionInvoiceSerialNumber;
|
|
435
|
+
}
|
|
436
|
+
if (row.sellerRevenue !== void 0) out.sellerRevenue = row.sellerRevenue;
|
|
437
|
+
if (row.orderNumber !== void 0) out.orderNumber = row.orderNumber;
|
|
438
|
+
if (row.paymentOrderId !== void 0) out.paymentOrderId = row.paymentOrderId;
|
|
439
|
+
const pay = toIso2(row.paymentDate);
|
|
440
|
+
if (pay) out.paymentDate = pay;
|
|
441
|
+
if (typeof row.sellerId === "number") out.sellerId = row.sellerId;
|
|
442
|
+
if (row.storeId !== void 0) out.storeId = row.storeId;
|
|
443
|
+
if (row.storeName !== void 0) out.storeName = row.storeName;
|
|
444
|
+
if (row.storeAddress !== void 0) out.storeAddress = row.storeAddress;
|
|
445
|
+
if (row.country !== void 0) out.country = row.country;
|
|
446
|
+
return out;
|
|
447
|
+
}
|
|
448
|
+
var FinanceResource = class {
|
|
449
|
+
constructor(transport, sellerId, limiter) {
|
|
450
|
+
this.transport = transport;
|
|
451
|
+
this.sellerId = sellerId;
|
|
452
|
+
this.limiter = limiter ?? new core.TokenBucketRateLimiter({ capacity: 100, intervalMs: 6e4 });
|
|
453
|
+
}
|
|
454
|
+
transport;
|
|
455
|
+
sellerId;
|
|
456
|
+
limiter;
|
|
457
|
+
async getSettlements(params = {}) {
|
|
458
|
+
return this.queryPage(`/integration/sellers/${this.sellerId}/settlements`, params);
|
|
459
|
+
}
|
|
460
|
+
async getOtherFinancials(params = {}) {
|
|
461
|
+
return this.queryPage(`/integration/sellers/${this.sellerId}/otherfinancials`, params);
|
|
462
|
+
}
|
|
463
|
+
async queryPage(path, params) {
|
|
464
|
+
const size = Math.min(params.limit ?? 50, 200);
|
|
465
|
+
const page = params.cursor ? Number.parseInt(params.cursor, 10) : 0;
|
|
466
|
+
const query = { page, size };
|
|
467
|
+
if (params.startDate) query.startDate = params.startDate.getTime();
|
|
468
|
+
if (params.endDate) query.endDate = params.endDate.getTime();
|
|
469
|
+
if (params.transactionType) query.transactionType = params.transactionType;
|
|
470
|
+
const data = await this.transport.request({
|
|
471
|
+
method: "GET",
|
|
472
|
+
path,
|
|
473
|
+
query,
|
|
474
|
+
rateLimiter: this.limiter
|
|
475
|
+
});
|
|
476
|
+
const items = (data.content ?? []).map(normalizeRow);
|
|
477
|
+
const result = { items };
|
|
478
|
+
const totalPages = typeof data.totalPages === "number" ? data.totalPages : 0;
|
|
479
|
+
if (page + 1 < totalPages) {
|
|
480
|
+
result.nextCursor = String(page + 1);
|
|
481
|
+
}
|
|
482
|
+
return result;
|
|
483
|
+
}
|
|
484
|
+
};
|
|
237
485
|
var MAX_ITEMS_PER_REQUEST = 1e3;
|
|
238
486
|
var InventoryResource = class {
|
|
239
487
|
constructor(transport, sellerId) {
|
|
@@ -273,9 +521,212 @@ var InventoryResource = class {
|
|
|
273
521
|
return { batchRequestId: data.batchRequestId ?? "" };
|
|
274
522
|
}
|
|
275
523
|
};
|
|
524
|
+
var InvoicesResource = class {
|
|
525
|
+
constructor(transport, sellerId, limiter) {
|
|
526
|
+
this.transport = transport;
|
|
527
|
+
this.sellerId = sellerId;
|
|
528
|
+
this.limiter = limiter ?? new core.TokenBucketRateLimiter({ capacity: 500, intervalMs: 6e4 });
|
|
529
|
+
}
|
|
530
|
+
transport;
|
|
531
|
+
sellerId;
|
|
532
|
+
limiter;
|
|
533
|
+
/**
|
|
534
|
+
* Upload an invoice file for a shipment package. **Multipart**: the
|
|
535
|
+
* SDK builds the FormData internally from the typed input.
|
|
536
|
+
*
|
|
537
|
+
* Max 10 MB. Accepted formats: PDF, JPEG, PNG.
|
|
538
|
+
*/
|
|
539
|
+
async uploadFile(input) {
|
|
540
|
+
if (!input?.file) {
|
|
541
|
+
throw new core.ValidationError({ message: "invoices.uploadFile: file is required" });
|
|
542
|
+
}
|
|
543
|
+
if (!input.shipmentPackageId) {
|
|
544
|
+
throw new core.ValidationError({ message: "invoices.uploadFile: shipmentPackageId is required" });
|
|
545
|
+
}
|
|
546
|
+
const form = new FormData();
|
|
547
|
+
form.append("shipmentPackageId", String(input.shipmentPackageId));
|
|
548
|
+
form.append("file", input.file);
|
|
549
|
+
if (input.invoiceDateTime !== void 0) {
|
|
550
|
+
form.append("invoiceDateTime", String(input.invoiceDateTime));
|
|
551
|
+
}
|
|
552
|
+
if (input.invoiceNumber !== void 0) {
|
|
553
|
+
form.append("invoiceNumber", input.invoiceNumber);
|
|
554
|
+
}
|
|
555
|
+
return this.transport.request({
|
|
556
|
+
method: "POST",
|
|
557
|
+
path: `/integration/sellers/${this.sellerId}/seller-invoice-file`,
|
|
558
|
+
body: form,
|
|
559
|
+
rateLimiter: this.limiter
|
|
560
|
+
});
|
|
561
|
+
}
|
|
562
|
+
/** Register an invoice URL with Trendyol (alternative to uploading the file). */
|
|
563
|
+
async sendLink(input) {
|
|
564
|
+
if (!input?.invoiceLink) {
|
|
565
|
+
throw new core.ValidationError({ message: "invoices.sendLink: invoiceLink is required" });
|
|
566
|
+
}
|
|
567
|
+
return this.transport.request({
|
|
568
|
+
method: "POST",
|
|
569
|
+
path: `/integration/sellers/${this.sellerId}/seller-invoice-links`,
|
|
570
|
+
body: input,
|
|
571
|
+
rateLimiter: this.limiter
|
|
572
|
+
});
|
|
573
|
+
}
|
|
574
|
+
/** Remove a previously-registered invoice link. */
|
|
575
|
+
async deleteLink(input) {
|
|
576
|
+
return this.transport.request({
|
|
577
|
+
method: "POST",
|
|
578
|
+
path: `/integration/sellers/${this.sellerId}/seller-invoice-links/delete`,
|
|
579
|
+
body: input,
|
|
580
|
+
rateLimiter: this.limiter
|
|
581
|
+
});
|
|
582
|
+
}
|
|
583
|
+
};
|
|
584
|
+
var LabelsResource = class {
|
|
585
|
+
constructor(transport, sellerId, limiter) {
|
|
586
|
+
this.transport = transport;
|
|
587
|
+
this.sellerId = sellerId;
|
|
588
|
+
this.limiter = limiter ?? new core.TokenBucketRateLimiter({ capacity: 100, intervalMs: 6e4 });
|
|
589
|
+
}
|
|
590
|
+
transport;
|
|
591
|
+
sellerId;
|
|
592
|
+
limiter;
|
|
593
|
+
/**
|
|
594
|
+
* Request a common ZPL label for a cargo tracking number. After this
|
|
595
|
+
* returns, call `getCommon()` with the same `cargoTrackingNumber` to
|
|
596
|
+
* retrieve the generated label.
|
|
597
|
+
*
|
|
598
|
+
* @throws {ValidationError} when `format` is missing.
|
|
599
|
+
*/
|
|
600
|
+
async createCommon(cargoTrackingNumber, input) {
|
|
601
|
+
if (!input?.format) {
|
|
602
|
+
throw new core.ValidationError({ message: "labels.createCommon: format is required" });
|
|
603
|
+
}
|
|
604
|
+
return this.transport.request({
|
|
605
|
+
method: "POST",
|
|
606
|
+
path: `/integration/sellers/${this.sellerId}/common-label/${encodeURIComponent(String(cargoTrackingNumber))}`,
|
|
607
|
+
body: input,
|
|
608
|
+
rateLimiter: this.limiter
|
|
609
|
+
});
|
|
610
|
+
}
|
|
611
|
+
/**
|
|
612
|
+
* Retrieve the previously-created common label. Trendyol returns
|
|
613
|
+
* `{ data: [{ label, format }] }`; the SDK surfaces the array as
|
|
614
|
+
* `labels[]` for ergonomic access.
|
|
615
|
+
*
|
|
616
|
+
* Typically `labels.length === 1` per tracking number, but kept as an
|
|
617
|
+
* array to match the wire shape.
|
|
618
|
+
*/
|
|
619
|
+
async getCommon(cargoTrackingNumber) {
|
|
620
|
+
const raw = await this.transport.request({
|
|
621
|
+
method: "GET",
|
|
622
|
+
path: `/integration/sellers/${this.sellerId}/common-label/${encodeURIComponent(String(cargoTrackingNumber))}`,
|
|
623
|
+
rateLimiter: this.limiter
|
|
624
|
+
});
|
|
625
|
+
const labels = (raw?.data ?? []).map((row) => ({
|
|
626
|
+
label: row.label ?? "",
|
|
627
|
+
format: row.format ?? "ZPL"
|
|
628
|
+
}));
|
|
629
|
+
return { labels, raw: raw ?? {} };
|
|
630
|
+
}
|
|
631
|
+
};
|
|
632
|
+
function n(rows, extract) {
|
|
633
|
+
const list = Array.isArray(rows) ? rows : [];
|
|
634
|
+
return list.map((r) => {
|
|
635
|
+
const node = r;
|
|
636
|
+
return { ...extract(node), raw: node };
|
|
637
|
+
});
|
|
638
|
+
}
|
|
639
|
+
var LocationsResource = class {
|
|
640
|
+
constructor(transport, limiter) {
|
|
641
|
+
this.transport = transport;
|
|
642
|
+
this.limiter = limiter ?? new core.TokenBucketRateLimiter({ capacity: 60, intervalMs: 6e4 });
|
|
643
|
+
}
|
|
644
|
+
transport;
|
|
645
|
+
limiter;
|
|
646
|
+
/** List all supported countries (Türkiye + AZ + GULF + CEE). */
|
|
647
|
+
async getCountries() {
|
|
648
|
+
const data = await this.transport.request({
|
|
649
|
+
method: "GET",
|
|
650
|
+
path: `/integration/member/countries`,
|
|
651
|
+
rateLimiter: this.limiter
|
|
652
|
+
});
|
|
653
|
+
return n(data, (node) => ({
|
|
654
|
+
code: String(node.code ?? node.id ?? ""),
|
|
655
|
+
name: node.name
|
|
656
|
+
}));
|
|
657
|
+
}
|
|
658
|
+
// ─── Domestic (TR / AZ) ───────────────────────────────────────────────
|
|
659
|
+
async getTurkeyCities() {
|
|
660
|
+
return this.cities(`/integration/member/countries/domestic/TR/cities`);
|
|
661
|
+
}
|
|
662
|
+
async getTurkeyDistricts(cityCode) {
|
|
663
|
+
return this.districts(
|
|
664
|
+
`/integration/member/countries/domestic/TR/cities/${encodeURIComponent(String(cityCode))}/districts`
|
|
665
|
+
);
|
|
666
|
+
}
|
|
667
|
+
async getTurkeyNeighborhoods(cityCode, districtCode) {
|
|
668
|
+
return this.neighborhoods(
|
|
669
|
+
`/integration/member/countries/domestic/TR/cities/${encodeURIComponent(String(cityCode))}/districts/${encodeURIComponent(String(districtCode))}/neighborhoods`
|
|
670
|
+
);
|
|
671
|
+
}
|
|
672
|
+
async getAzerbaijanCities() {
|
|
673
|
+
return this.cities(`/integration/member/countries/domestic/AZ/cities`);
|
|
674
|
+
}
|
|
675
|
+
async getAzerbaijanDistricts(cityCode) {
|
|
676
|
+
return this.districts(
|
|
677
|
+
`/integration/member/countries/domestic/AZ/cities/${encodeURIComponent(String(cityCode))}/districts`
|
|
678
|
+
);
|
|
679
|
+
}
|
|
680
|
+
// ─── International (GULF / CEE) ───────────────────────────────────────
|
|
681
|
+
async getCitiesByCountry(countryCode) {
|
|
682
|
+
return this.cities(`/integration/member/countries/${encodeURIComponent(countryCode)}/cities`);
|
|
683
|
+
}
|
|
684
|
+
async getDistrictsByCity(countryCode, cityId) {
|
|
685
|
+
return this.districts(
|
|
686
|
+
`/integration/member/countries/${encodeURIComponent(countryCode)}/cities/${encodeURIComponent(String(cityId))}/districts`
|
|
687
|
+
);
|
|
688
|
+
}
|
|
689
|
+
// ─── Shared paginators ────────────────────────────────────────────────
|
|
690
|
+
async cities(path) {
|
|
691
|
+
const data = await this.transport.request({
|
|
692
|
+
method: "GET",
|
|
693
|
+
path,
|
|
694
|
+
rateLimiter: this.limiter
|
|
695
|
+
});
|
|
696
|
+
return n(data, (node) => ({
|
|
697
|
+
code: String(node.code ?? node.id ?? ""),
|
|
698
|
+
name: node.name,
|
|
699
|
+
countryCode: node.countryCode
|
|
700
|
+
}));
|
|
701
|
+
}
|
|
702
|
+
async districts(path) {
|
|
703
|
+
const data = await this.transport.request({
|
|
704
|
+
method: "GET",
|
|
705
|
+
path,
|
|
706
|
+
rateLimiter: this.limiter
|
|
707
|
+
});
|
|
708
|
+
return n(data, (node) => ({
|
|
709
|
+
code: String(node.code ?? node.id ?? ""),
|
|
710
|
+
name: node.name,
|
|
711
|
+
cityCode: node.cityCode !== void 0 ? String(node.cityCode) : void 0
|
|
712
|
+
}));
|
|
713
|
+
}
|
|
714
|
+
async neighborhoods(path) {
|
|
715
|
+
const data = await this.transport.request({
|
|
716
|
+
method: "GET",
|
|
717
|
+
path,
|
|
718
|
+
rateLimiter: this.limiter
|
|
719
|
+
});
|
|
720
|
+
return n(data, (node) => ({
|
|
721
|
+
code: String(node.code ?? node.id ?? ""),
|
|
722
|
+
name: node.name,
|
|
723
|
+
districtCode: node.districtCode !== void 0 ? String(node.districtCode) : void 0
|
|
724
|
+
}));
|
|
725
|
+
}
|
|
726
|
+
};
|
|
276
727
|
var MAX_PAGE_SIZE = 200;
|
|
277
728
|
var DEFAULT_PAGE_SIZE2 = 50;
|
|
278
|
-
function
|
|
729
|
+
function toIso3(epochMs) {
|
|
279
730
|
if (typeof epochMs !== "number" || !Number.isFinite(epochMs) || epochMs === 0) {
|
|
280
731
|
return void 0;
|
|
281
732
|
}
|
|
@@ -343,7 +794,7 @@ function normalizeLine(node) {
|
|
|
343
794
|
function normalizeHistory(node) {
|
|
344
795
|
const out = { raw: node };
|
|
345
796
|
if (node.status !== void 0) out.status = node.status;
|
|
346
|
-
const createdAt =
|
|
797
|
+
const createdAt = toIso3(node.createdDate);
|
|
347
798
|
if (createdAt) out.createdAt = createdAt;
|
|
348
799
|
return out;
|
|
349
800
|
}
|
|
@@ -358,6 +809,9 @@ function normalizeCustomer(node) {
|
|
|
358
809
|
if (node.identityNumber !== void 0) out.identityNumber = node.identityNumber;
|
|
359
810
|
return out;
|
|
360
811
|
}
|
|
812
|
+
function normalizeShipmentPackage(rawNode) {
|
|
813
|
+
return normalizePackage(rawNode ?? {});
|
|
814
|
+
}
|
|
361
815
|
function normalizePackage(node) {
|
|
362
816
|
const pkgId = node.shipmentPackageId ?? node.id;
|
|
363
817
|
const out = {
|
|
@@ -365,8 +819,8 @@ function normalizePackage(node) {
|
|
|
365
819
|
orderNumber: node.orderNumber ?? "",
|
|
366
820
|
status: node.status ?? "",
|
|
367
821
|
customer: normalizeCustomer(node),
|
|
368
|
-
orderDate:
|
|
369
|
-
lastModifiedDate:
|
|
822
|
+
orderDate: toIso3(node.orderDate) ?? "",
|
|
823
|
+
lastModifiedDate: toIso3(node.lastModifiedDate) ?? "",
|
|
370
824
|
currencyCode: node.currencyCode ?? "",
|
|
371
825
|
packageTotalPrice: typeof node.packageTotalPrice === "number" ? node.packageTotalPrice : 0,
|
|
372
826
|
packageGrossAmount: typeof node.packageGrossAmount === "number" ? node.packageGrossAmount : 0,
|
|
@@ -386,13 +840,13 @@ function normalizePackage(node) {
|
|
|
386
840
|
if (node.shipmentPackageStatus !== void 0) {
|
|
387
841
|
out.shipmentPackageStatus = node.shipmentPackageStatus;
|
|
388
842
|
}
|
|
389
|
-
const agreed =
|
|
843
|
+
const agreed = toIso3(node.agreedDeliveryDate);
|
|
390
844
|
if (agreed) out.agreedDeliveryDate = agreed;
|
|
391
|
-
const estStart =
|
|
845
|
+
const estStart = toIso3(node.estimatedDeliveryStartDate);
|
|
392
846
|
if (estStart) out.estimatedDeliveryStartDate = estStart;
|
|
393
|
-
const estEnd =
|
|
847
|
+
const estEnd = toIso3(node.estimatedDeliveryEndDate);
|
|
394
848
|
if (estEnd) out.estimatedDeliveryEndDate = estEnd;
|
|
395
|
-
const origin =
|
|
849
|
+
const origin = toIso3(node.originShipmentDate);
|
|
396
850
|
if (origin) out.originShipmentDate = origin;
|
|
397
851
|
const invoice = normalizeAddress(node.invoiceAddress);
|
|
398
852
|
if (invoice) out.invoiceAddress = invoice;
|
|
@@ -802,6 +1256,101 @@ var OrdersResource = class {
|
|
|
802
1256
|
}
|
|
803
1257
|
return result;
|
|
804
1258
|
}
|
|
1259
|
+
/**
|
|
1260
|
+
* Notify Trendyol that a shipped package was returned to you (manual
|
|
1261
|
+
* return flow, e.g. customer dropped it at your address or you got the
|
|
1262
|
+
* package back without going through Trendyol's return cargo).
|
|
1263
|
+
*
|
|
1264
|
+
* No body; Trendyol responds with 200 + empty body on success.
|
|
1265
|
+
*/
|
|
1266
|
+
async manualReturnByPackageId(packageId) {
|
|
1267
|
+
await this.transport.request({
|
|
1268
|
+
method: "PUT",
|
|
1269
|
+
path: `${this.packagePath(packageId)}/manual-return`,
|
|
1270
|
+
rateLimiter: this.limiter
|
|
1271
|
+
});
|
|
1272
|
+
}
|
|
1273
|
+
/**
|
|
1274
|
+
* Manual-return variant that takes the cargo tracking number instead of
|
|
1275
|
+
* the package ID. Useful when the cargo provider's webhook only carries
|
|
1276
|
+
* the tracking number.
|
|
1277
|
+
*
|
|
1278
|
+
* Sibling path (not under `/{packageId}/...`).
|
|
1279
|
+
*/
|
|
1280
|
+
async manualReturnByTrackingNumber(cargoTrackingNumber) {
|
|
1281
|
+
await this.transport.request({
|
|
1282
|
+
method: "PUT",
|
|
1283
|
+
path: `/integration/order/sellers/${this.sellerId}/shipment-packages/manual-return-by-tracking-number/${encodeURIComponent(String(cargoTrackingNumber))}`,
|
|
1284
|
+
rateLimiter: this.limiter
|
|
1285
|
+
});
|
|
1286
|
+
}
|
|
1287
|
+
/**
|
|
1288
|
+
* Fetch Trendyol Express compensation tickets (claims filed when a
|
|
1289
|
+
* shipment is lost or damaged in transit). Page-based pagination
|
|
1290
|
+
* internally; the SDK exposes the cursor convention.
|
|
1291
|
+
*
|
|
1292
|
+
* Note the different base path — `/integration/tex/compensation/...`,
|
|
1293
|
+
* not the regular `/integration/order/...`.
|
|
1294
|
+
*
|
|
1295
|
+
* @example
|
|
1296
|
+
* ```ts
|
|
1297
|
+
* import { paginate } from '@lonca/core';
|
|
1298
|
+
* const tickets = await client.orders.getCompensationTickets({
|
|
1299
|
+
* startDate: new Date('2026-01-01'),
|
|
1300
|
+
* endDate: new Date('2026-02-01'),
|
|
1301
|
+
* });
|
|
1302
|
+
* for (const t of tickets.items) {
|
|
1303
|
+
* console.log(t.orderNumber, t.currentState, t.stateMessage);
|
|
1304
|
+
* }
|
|
1305
|
+
* ```
|
|
1306
|
+
*/
|
|
1307
|
+
async getCompensationTickets(params = {}) {
|
|
1308
|
+
const size = Math.min(params.limit ?? 200, 200);
|
|
1309
|
+
const page = params.cursor ? Number.parseInt(params.cursor, 10) : 0;
|
|
1310
|
+
const query = { page, size };
|
|
1311
|
+
if (params.startDate) query.startDate = params.startDate.getTime();
|
|
1312
|
+
if (params.endDate) query.endDate = params.endDate.getTime();
|
|
1313
|
+
const res = await this.transport.request({
|
|
1314
|
+
method: "GET",
|
|
1315
|
+
path: `/integration/tex/compensation/sellers/${this.sellerId}/tickets`,
|
|
1316
|
+
query,
|
|
1317
|
+
rateLimiter: this.limiter
|
|
1318
|
+
});
|
|
1319
|
+
const tickets = Array.isArray(res.data) ? res.data : res.data?.items ?? res.data?.content ?? res.content ?? [];
|
|
1320
|
+
const items = tickets.map((t) => {
|
|
1321
|
+
const itemDetails = (t.itemDetails ?? []).map((d) => {
|
|
1322
|
+
const out2 = {};
|
|
1323
|
+
if (typeof d.itemAmount === "number") out2.itemAmount = d.itemAmount;
|
|
1324
|
+
if (d.itemCode !== void 0) out2.itemCode = d.itemCode;
|
|
1325
|
+
if (typeof d.itemCount === "number") out2.itemCount = d.itemCount;
|
|
1326
|
+
if (d.itemName !== void 0) out2.itemName = d.itemName;
|
|
1327
|
+
return out2;
|
|
1328
|
+
});
|
|
1329
|
+
const out = {
|
|
1330
|
+
itemDetails,
|
|
1331
|
+
raw: t
|
|
1332
|
+
};
|
|
1333
|
+
if (t.cargoProvider !== void 0) out.cargoProvider = t.cargoProvider;
|
|
1334
|
+
if (t.compensateReason !== void 0) out.compensateReason = t.compensateReason;
|
|
1335
|
+
const createdAt = toIso3(t.createDate);
|
|
1336
|
+
if (createdAt) out.createdAt = createdAt;
|
|
1337
|
+
if (t.currentState !== void 0) {
|
|
1338
|
+
out.currentState = t.currentState;
|
|
1339
|
+
}
|
|
1340
|
+
if (t.deliveryNumber !== void 0) out.deliveryNumber = t.deliveryNumber;
|
|
1341
|
+
if (t.orderNumber !== void 0) out.orderNumber = t.orderNumber;
|
|
1342
|
+
if (t.requestedBy !== void 0) out.requestedBy = t.requestedBy;
|
|
1343
|
+
if (t.stateMessage !== void 0) out.stateMessage = t.stateMessage;
|
|
1344
|
+
if (t.totalItemsAmount !== void 0) out.totalItemsAmount = t.totalItemsAmount;
|
|
1345
|
+
return out;
|
|
1346
|
+
});
|
|
1347
|
+
const result = { items };
|
|
1348
|
+
const total = typeof res.totalCount === "number" ? res.totalCount : 0;
|
|
1349
|
+
if ((page + 1) * size < total) {
|
|
1350
|
+
result.nextCursor = String(page + 1);
|
|
1351
|
+
}
|
|
1352
|
+
return result;
|
|
1353
|
+
}
|
|
805
1354
|
packagePath(packageId) {
|
|
806
1355
|
return `/integration/order/sellers/${this.sellerId}/shipment-packages/${encodeURIComponent(String(packageId))}`;
|
|
807
1356
|
}
|
|
@@ -851,7 +1400,7 @@ function normalizeVariant(variant) {
|
|
|
851
1400
|
if (stock !== void 0) out.stock = stock;
|
|
852
1401
|
return out;
|
|
853
1402
|
}
|
|
854
|
-
function
|
|
1403
|
+
function toIso4(epochMs) {
|
|
855
1404
|
if (typeof epochMs !== "number" || !Number.isFinite(epochMs)) return void 0;
|
|
856
1405
|
return new Date(epochMs).toISOString();
|
|
857
1406
|
}
|
|
@@ -865,8 +1414,8 @@ function normalizeProduct(node) {
|
|
|
865
1414
|
images: normalizeImages(node.images),
|
|
866
1415
|
attributes: (node.attributes ?? []).map(normalizeAttribute2),
|
|
867
1416
|
variants: (node.variants ?? []).map(normalizeVariant),
|
|
868
|
-
createdAt:
|
|
869
|
-
updatedAt:
|
|
1417
|
+
createdAt: toIso4(node.creationDate) ?? "",
|
|
1418
|
+
updatedAt: toIso4(node.lastModifiedDate) ?? "",
|
|
870
1419
|
raw: node
|
|
871
1420
|
};
|
|
872
1421
|
if (node.description !== void 0) out.description = node.description;
|
|
@@ -912,13 +1461,13 @@ function normalizeUnapproved(node) {
|
|
|
912
1461
|
out.specialConsumptionTax = node.specialConsumptionTax;
|
|
913
1462
|
}
|
|
914
1463
|
if (node.sgrPrice !== void 0) out.sgrPrice = node.sgrPrice;
|
|
915
|
-
const createdAt =
|
|
1464
|
+
const createdAt = toIso4(node.createDateTime);
|
|
916
1465
|
if (createdAt) out.createdAt = createdAt;
|
|
917
|
-
const updatedAt =
|
|
1466
|
+
const updatedAt = toIso4(node.lastUpdateDate);
|
|
918
1467
|
if (updatedAt) out.updatedAt = updatedAt;
|
|
919
|
-
const priceChanged =
|
|
1468
|
+
const priceChanged = toIso4(node.lastPriceChangeDate);
|
|
920
1469
|
if (priceChanged) out.lastPriceChangedAt = priceChanged;
|
|
921
|
-
const stockChanged =
|
|
1470
|
+
const stockChanged = toIso4(node.lastStockChangeDate);
|
|
922
1471
|
if (stockChanged) out.lastStockChangedAt = stockChanged;
|
|
923
1472
|
return out;
|
|
924
1473
|
}
|
|
@@ -943,7 +1492,7 @@ function normalizeProductBase(data) {
|
|
|
943
1492
|
archived: !!data.archived,
|
|
944
1493
|
raw: data
|
|
945
1494
|
};
|
|
946
|
-
const approvedAt =
|
|
1495
|
+
const approvedAt = toIso4(data.approvedDate);
|
|
947
1496
|
if (approvedAt) out.approvedAt = approvedAt;
|
|
948
1497
|
if (data.listingId !== void 0) out.listingId = data.listingId;
|
|
949
1498
|
if (data.contentId !== void 0) out.contentId = String(data.contentId);
|
|
@@ -965,9 +1514,9 @@ function normalizeBatchResult(data) {
|
|
|
965
1514
|
};
|
|
966
1515
|
if (typeof data.itemCount === "number") out.itemCount = data.itemCount;
|
|
967
1516
|
if (typeof data.failedItemCount === "number") out.failedItemCount = data.failedItemCount;
|
|
968
|
-
const createdAt =
|
|
1517
|
+
const createdAt = toIso4(data.creationDate);
|
|
969
1518
|
if (createdAt) out.createdAt = createdAt;
|
|
970
|
-
const lastModifiedAt =
|
|
1519
|
+
const lastModifiedAt = toIso4(data.lastModification);
|
|
971
1520
|
if (lastModifiedAt) out.lastModifiedAt = lastModifiedAt;
|
|
972
1521
|
if (data.sourceType !== void 0) out.sourceType = data.sourceType;
|
|
973
1522
|
if (data.batchRequestType !== void 0) out.batchRequestType = data.batchRequestType;
|
|
@@ -1313,6 +1862,120 @@ var ProductsResource = class {
|
|
|
1313
1862
|
return { batchRequestId: data?.batchRequestId ?? "" };
|
|
1314
1863
|
}
|
|
1315
1864
|
};
|
|
1865
|
+
function toIso5(epochMs) {
|
|
1866
|
+
if (typeof epochMs !== "number" || !Number.isFinite(epochMs) || epochMs === 0) {
|
|
1867
|
+
return void 0;
|
|
1868
|
+
}
|
|
1869
|
+
return new Date(epochMs).toISOString();
|
|
1870
|
+
}
|
|
1871
|
+
function normalizeAnswer(a) {
|
|
1872
|
+
if (!a) return void 0;
|
|
1873
|
+
const out = {};
|
|
1874
|
+
if (a.text !== void 0) out.text = a.text;
|
|
1875
|
+
const createdAt = toIso5(a.creationDate);
|
|
1876
|
+
if (createdAt) out.createdAt = createdAt;
|
|
1877
|
+
if (a.status !== void 0) out.status = a.status;
|
|
1878
|
+
return out;
|
|
1879
|
+
}
|
|
1880
|
+
function normalizeQuestion(node) {
|
|
1881
|
+
const out = {
|
|
1882
|
+
id: node.id !== void 0 ? String(node.id) : "",
|
|
1883
|
+
raw: node
|
|
1884
|
+
};
|
|
1885
|
+
if (node.text !== void 0) out.text = node.text;
|
|
1886
|
+
if (node.customerId !== void 0) out.customerId = String(node.customerId);
|
|
1887
|
+
if (node.userName !== void 0) out.userName = node.userName;
|
|
1888
|
+
if (typeof node.showUserName === "boolean") out.showUserName = node.showUserName;
|
|
1889
|
+
if (node.status !== void 0) out.status = node.status;
|
|
1890
|
+
if (typeof node.public === "boolean") out.public = node.public;
|
|
1891
|
+
if (node.productMainId !== void 0) out.productMainId = node.productMainId;
|
|
1892
|
+
if (node.productName !== void 0) out.productName = node.productName;
|
|
1893
|
+
if (node.imageUrl !== void 0) out.imageUrl = node.imageUrl;
|
|
1894
|
+
if (node.webUrl !== void 0) out.webUrl = node.webUrl;
|
|
1895
|
+
const createdAt = toIso5(node.creationDate);
|
|
1896
|
+
if (createdAt) out.createdAt = createdAt;
|
|
1897
|
+
if (node.answeredDateMessage !== void 0) out.answeredDateMessage = node.answeredDateMessage;
|
|
1898
|
+
const answer = normalizeAnswer(node.answer);
|
|
1899
|
+
if (answer) out.answer = answer;
|
|
1900
|
+
const rejectedAnswer = normalizeAnswer(node.rejectedAnswer);
|
|
1901
|
+
if (rejectedAnswer) out.rejectedAnswer = rejectedAnswer;
|
|
1902
|
+
const rejectedAt = toIso5(node.rejectedDate);
|
|
1903
|
+
if (rejectedAt) out.rejectedAt = rejectedAt;
|
|
1904
|
+
if (node.reason !== void 0) out.reason = node.reason;
|
|
1905
|
+
if (node.reportReason !== void 0) out.reportReason = node.reportReason;
|
|
1906
|
+
const reportedAt = toIso5(node.reportedDate);
|
|
1907
|
+
if (reportedAt) out.reportedAt = reportedAt;
|
|
1908
|
+
return out;
|
|
1909
|
+
}
|
|
1910
|
+
var QuestionsResource = class {
|
|
1911
|
+
constructor(transport, sellerId, limiter) {
|
|
1912
|
+
this.transport = transport;
|
|
1913
|
+
this.sellerId = sellerId;
|
|
1914
|
+
this.limiter = limiter ?? new core.TokenBucketRateLimiter({ capacity: 500, intervalMs: 6e4 });
|
|
1915
|
+
}
|
|
1916
|
+
transport;
|
|
1917
|
+
sellerId;
|
|
1918
|
+
limiter;
|
|
1919
|
+
/** Fetch a single question by its numeric ID. */
|
|
1920
|
+
async get(questionId) {
|
|
1921
|
+
const data = await this.transport.request({
|
|
1922
|
+
method: "GET",
|
|
1923
|
+
path: `/integration/qna/sellers/${this.sellerId}/questions/${encodeURIComponent(String(questionId))}`,
|
|
1924
|
+
rateLimiter: this.limiter
|
|
1925
|
+
});
|
|
1926
|
+
return normalizeQuestion(data);
|
|
1927
|
+
}
|
|
1928
|
+
/**
|
|
1929
|
+
* Filter questions by barcode / date range / status. Page-based
|
|
1930
|
+
* pagination internally; SDK exposes the opaque-cursor convention.
|
|
1931
|
+
*/
|
|
1932
|
+
async list(params = {}) {
|
|
1933
|
+
const size = Math.min(params.limit ?? 50, 200);
|
|
1934
|
+
const page = params.cursor ? Number.parseInt(params.cursor, 10) : 0;
|
|
1935
|
+
const query = { page, size };
|
|
1936
|
+
if (params.barcode) query.barcode = params.barcode;
|
|
1937
|
+
if (params.startDate) query.startDate = params.startDate.getTime();
|
|
1938
|
+
if (params.endDate) query.endDate = params.endDate.getTime();
|
|
1939
|
+
if (params.status) query.status = params.status;
|
|
1940
|
+
const data = await this.transport.request({
|
|
1941
|
+
method: "GET",
|
|
1942
|
+
path: `/integration/qna/sellers/${this.sellerId}/questions/filter`,
|
|
1943
|
+
query,
|
|
1944
|
+
rateLimiter: this.limiter
|
|
1945
|
+
});
|
|
1946
|
+
const items = (data.content ?? []).map(normalizeQuestion);
|
|
1947
|
+
const result = { items };
|
|
1948
|
+
const totalPages = typeof data.totalPages === "number" ? data.totalPages : 0;
|
|
1949
|
+
if (page + 1 < totalPages) {
|
|
1950
|
+
result.nextCursor = String(page + 1);
|
|
1951
|
+
}
|
|
1952
|
+
return result;
|
|
1953
|
+
}
|
|
1954
|
+
/**
|
|
1955
|
+
* Reply to a question. Trendyol enforces 10–2000 characters on the
|
|
1956
|
+
* answer text; the SDK pre-validates client-side.
|
|
1957
|
+
*
|
|
1958
|
+
* @throws {ValidationError} when `text` is outside the 10–2000 char range.
|
|
1959
|
+
*/
|
|
1960
|
+
async answer(questionId, text) {
|
|
1961
|
+
if (typeof text !== "string" || text.length < 10) {
|
|
1962
|
+
throw new core.ValidationError({
|
|
1963
|
+
message: `questions.answer: text must be at least 10 chars (got ${text?.length ?? 0})`
|
|
1964
|
+
});
|
|
1965
|
+
}
|
|
1966
|
+
if (text.length > 2e3) {
|
|
1967
|
+
throw new core.ValidationError({
|
|
1968
|
+
message: `questions.answer: text must be at most 2000 chars (got ${text.length})`
|
|
1969
|
+
});
|
|
1970
|
+
}
|
|
1971
|
+
return this.transport.request({
|
|
1972
|
+
method: "POST",
|
|
1973
|
+
path: `/integration/qna/sellers/${this.sellerId}/questions/${encodeURIComponent(String(questionId))}/answers`,
|
|
1974
|
+
body: { text },
|
|
1975
|
+
rateLimiter: this.limiter
|
|
1976
|
+
});
|
|
1977
|
+
}
|
|
1978
|
+
};
|
|
1316
1979
|
var VALID_TYPES = /* @__PURE__ */ new Set([
|
|
1317
1980
|
"SHIPMENT",
|
|
1318
1981
|
"RETURNING",
|
|
@@ -1393,6 +2056,170 @@ var SuppliersResource = class {
|
|
|
1393
2056
|
return items;
|
|
1394
2057
|
}
|
|
1395
2058
|
};
|
|
2059
|
+
var TestOrdersResource = class {
|
|
2060
|
+
constructor(transport, sellerId, limiter) {
|
|
2061
|
+
this.transport = transport;
|
|
2062
|
+
this.sellerId = sellerId;
|
|
2063
|
+
this.limiter = limiter ?? new core.TokenBucketRateLimiter({ capacity: 60, intervalMs: 6e4 });
|
|
2064
|
+
}
|
|
2065
|
+
transport;
|
|
2066
|
+
sellerId;
|
|
2067
|
+
limiter;
|
|
2068
|
+
/**
|
|
2069
|
+
* Create a test order with the given customer / addresses / lines. The
|
|
2070
|
+
* SDK forwards the typed payload verbatim — drill into Trendyol's
|
|
2071
|
+
* `createTestOrder` doc for inner field rules.
|
|
2072
|
+
*
|
|
2073
|
+
* @throws {ValidationError} when required top-level fields are missing.
|
|
2074
|
+
*/
|
|
2075
|
+
async create(input) {
|
|
2076
|
+
for (const k of ["customer", "invoiceAddress", "shippingAddress", "seller", "lines"]) {
|
|
2077
|
+
if (!input?.[k]) {
|
|
2078
|
+
throw new core.ValidationError({ message: `testOrders.create: ${k} is required` });
|
|
2079
|
+
}
|
|
2080
|
+
}
|
|
2081
|
+
return this.transport.request({
|
|
2082
|
+
method: "POST",
|
|
2083
|
+
path: `/integration/test/order/orders/core`,
|
|
2084
|
+
body: input,
|
|
2085
|
+
rateLimiter: this.limiter
|
|
2086
|
+
});
|
|
2087
|
+
}
|
|
2088
|
+
/** Push a test shipment package to the given status. */
|
|
2089
|
+
async updateStatus(packageId, status) {
|
|
2090
|
+
return this.transport.request({
|
|
2091
|
+
method: "PUT",
|
|
2092
|
+
path: `/integration/test/order/sellers/${this.sellerId}/shipment-packages/${encodeURIComponent(String(packageId))}/status`,
|
|
2093
|
+
body: { status },
|
|
2094
|
+
rateLimiter: this.limiter
|
|
2095
|
+
});
|
|
2096
|
+
}
|
|
2097
|
+
/** Move test claims to the `WaitingInAction` state. */
|
|
2098
|
+
async setClaimsWaitingInAction() {
|
|
2099
|
+
return this.transport.request({
|
|
2100
|
+
method: "PUT",
|
|
2101
|
+
path: `/integration/test/order/sellers/${this.sellerId}/claims/waiting-in-action`,
|
|
2102
|
+
rateLimiter: this.limiter
|
|
2103
|
+
});
|
|
2104
|
+
}
|
|
2105
|
+
};
|
|
2106
|
+
function normalizeWebhook(node) {
|
|
2107
|
+
const out = {
|
|
2108
|
+
id: node.id !== void 0 ? String(node.id) : "",
|
|
2109
|
+
raw: node
|
|
2110
|
+
};
|
|
2111
|
+
if (node.url !== void 0) out.url = node.url;
|
|
2112
|
+
if (node.authenticationType !== void 0) out.authenticationType = node.authenticationType;
|
|
2113
|
+
if (node.username !== void 0) out.username = node.username;
|
|
2114
|
+
if (node.apiKey !== void 0) out.apiKey = node.apiKey;
|
|
2115
|
+
if (node.subscribedStatuses !== void 0) out.subscribedStatuses = node.subscribedStatuses;
|
|
2116
|
+
if (typeof node.active === "boolean") out.active = node.active;
|
|
2117
|
+
else if (typeof node.isActive === "boolean") out.active = node.isActive;
|
|
2118
|
+
else if (typeof node.status === "string") out.active = node.status.toUpperCase() === "ACTIVE";
|
|
2119
|
+
return out;
|
|
2120
|
+
}
|
|
2121
|
+
var WebhooksResource = class {
|
|
2122
|
+
constructor(transport, sellerId, limiter) {
|
|
2123
|
+
this.transport = transport;
|
|
2124
|
+
this.sellerId = sellerId;
|
|
2125
|
+
this.limiter = limiter ?? new core.TokenBucketRateLimiter({ capacity: 50, intervalMs: 6e4 });
|
|
2126
|
+
}
|
|
2127
|
+
transport;
|
|
2128
|
+
sellerId;
|
|
2129
|
+
limiter;
|
|
2130
|
+
/**
|
|
2131
|
+
* Create a new webhook subscription. Trendyol caps subscriptions at 15
|
|
2132
|
+
* per seller — the SDK does NOT pre-check (you'd need to call `list()`
|
|
2133
|
+
* first), but Trendyol returns 400 when the cap is exceeded.
|
|
2134
|
+
*
|
|
2135
|
+
* @throws {ValidationError} when `url` or `authenticationType` is missing.
|
|
2136
|
+
*/
|
|
2137
|
+
async create(input) {
|
|
2138
|
+
this.validateInput(input, "create");
|
|
2139
|
+
return this.transport.request({
|
|
2140
|
+
method: "POST",
|
|
2141
|
+
path: `/integration/sellers/${this.sellerId}/webhooks`,
|
|
2142
|
+
body: input,
|
|
2143
|
+
rateLimiter: this.limiter
|
|
2144
|
+
});
|
|
2145
|
+
}
|
|
2146
|
+
/** List all registered webhook subscriptions. */
|
|
2147
|
+
async list() {
|
|
2148
|
+
const data = await this.transport.request({
|
|
2149
|
+
method: "GET",
|
|
2150
|
+
path: `/integration/sellers/${this.sellerId}/webhooks`,
|
|
2151
|
+
rateLimiter: this.limiter
|
|
2152
|
+
});
|
|
2153
|
+
const rows = Array.isArray(data) ? data : Array.isArray(data?.webhooks) ? data.webhooks : Array.isArray(data?.content) ? data.content : [];
|
|
2154
|
+
return rows.map((r) => normalizeWebhook(r));
|
|
2155
|
+
}
|
|
2156
|
+
/**
|
|
2157
|
+
* Update a webhook subscription. Same input shape as `create`; replaces
|
|
2158
|
+
* the whole subscription (Trendyol does NOT partially update).
|
|
2159
|
+
*/
|
|
2160
|
+
async update(webhookId, input) {
|
|
2161
|
+
this.validateInput(input, "update");
|
|
2162
|
+
return this.transport.request({
|
|
2163
|
+
method: "PUT",
|
|
2164
|
+
path: this.webhookPath(webhookId),
|
|
2165
|
+
body: input,
|
|
2166
|
+
rateLimiter: this.limiter
|
|
2167
|
+
});
|
|
2168
|
+
}
|
|
2169
|
+
/** Permanently delete a webhook subscription. */
|
|
2170
|
+
async delete(webhookId) {
|
|
2171
|
+
return this.transport.request({
|
|
2172
|
+
method: "DELETE",
|
|
2173
|
+
path: this.webhookPath(webhookId),
|
|
2174
|
+
rateLimiter: this.limiter
|
|
2175
|
+
});
|
|
2176
|
+
}
|
|
2177
|
+
/** Re-activate a previously-deactivated webhook subscription. */
|
|
2178
|
+
async activate(webhookId) {
|
|
2179
|
+
return this.transport.request({
|
|
2180
|
+
method: "PUT",
|
|
2181
|
+
path: `${this.webhookPath(webhookId)}/activate`,
|
|
2182
|
+
rateLimiter: this.limiter
|
|
2183
|
+
});
|
|
2184
|
+
}
|
|
2185
|
+
/**
|
|
2186
|
+
* Deactivate a webhook subscription. Trendyol automatically deactivates
|
|
2187
|
+
* a subscription after persistent delivery failures (and sends 2 emails);
|
|
2188
|
+
* use `activate()` to bring it back online once your endpoint is healthy.
|
|
2189
|
+
*/
|
|
2190
|
+
async deactivate(webhookId) {
|
|
2191
|
+
return this.transport.request({
|
|
2192
|
+
method: "PUT",
|
|
2193
|
+
path: `${this.webhookPath(webhookId)}/deactivate`,
|
|
2194
|
+
rateLimiter: this.limiter
|
|
2195
|
+
});
|
|
2196
|
+
}
|
|
2197
|
+
validateInput(input, method) {
|
|
2198
|
+
if (!input?.url || typeof input.url !== "string") {
|
|
2199
|
+
throw new core.ValidationError({ message: `webhooks.${method}: url is required` });
|
|
2200
|
+
}
|
|
2201
|
+
if (input.authenticationType !== "BASIC_AUTHENTICATION" && input.authenticationType !== "API_KEY") {
|
|
2202
|
+
throw new core.ValidationError({
|
|
2203
|
+
message: `webhooks.${method}: authenticationType must be 'BASIC_AUTHENTICATION' or 'API_KEY'`
|
|
2204
|
+
});
|
|
2205
|
+
}
|
|
2206
|
+
if (input.authenticationType === "BASIC_AUTHENTICATION") {
|
|
2207
|
+
if (!input.username || !input.password) {
|
|
2208
|
+
throw new core.ValidationError({
|
|
2209
|
+
message: `webhooks.${method}: BASIC_AUTHENTICATION requires username + password`
|
|
2210
|
+
});
|
|
2211
|
+
}
|
|
2212
|
+
} else if (!input.apiKey) {
|
|
2213
|
+
throw new core.ValidationError({
|
|
2214
|
+
message: `webhooks.${method}: API_KEY requires apiKey`
|
|
2215
|
+
});
|
|
2216
|
+
}
|
|
2217
|
+
if (input.subscribedStatuses && input.subscribedStatuses.length === 0) ;
|
|
2218
|
+
}
|
|
2219
|
+
webhookPath(webhookId) {
|
|
2220
|
+
return `/integration/sellers/${this.sellerId}/webhooks/${encodeURIComponent(String(webhookId))}`;
|
|
2221
|
+
}
|
|
2222
|
+
};
|
|
1396
2223
|
|
|
1397
2224
|
// src/auth.ts
|
|
1398
2225
|
function buildAuthHeader(apiKey, apiSecret) {
|
|
@@ -1485,7 +2312,12 @@ var TrendyolTransport = class {
|
|
|
1485
2312
|
signal: this.composeSignal(opts.signal)
|
|
1486
2313
|
};
|
|
1487
2314
|
if (opts.body !== void 0 && opts.method !== "GET") {
|
|
1488
|
-
|
|
2315
|
+
if (opts.body instanceof FormData) {
|
|
2316
|
+
init.body = opts.body;
|
|
2317
|
+
delete headers["Content-Type"];
|
|
2318
|
+
} else {
|
|
2319
|
+
init.body = JSON.stringify(opts.body);
|
|
2320
|
+
}
|
|
1489
2321
|
}
|
|
1490
2322
|
this.logger.debug("trendyol.request", {
|
|
1491
2323
|
method: opts.method,
|
|
@@ -1600,16 +2432,68 @@ function createTrendyolClient(opts) {
|
|
|
1600
2432
|
suppliers: new SuppliersResource(transport, opts.sellerId),
|
|
1601
2433
|
products: new ProductsResource(transport, opts.sellerId),
|
|
1602
2434
|
inventory: new InventoryResource(transport, opts.sellerId),
|
|
1603
|
-
orders: new OrdersResource(transport, opts.sellerId)
|
|
2435
|
+
orders: new OrdersResource(transport, opts.sellerId),
|
|
2436
|
+
claims: new ClaimsResource(transport, opts.sellerId),
|
|
2437
|
+
webhooks: new WebhooksResource(transport, opts.sellerId),
|
|
2438
|
+
questions: new QuestionsResource(transport, opts.sellerId),
|
|
2439
|
+
invoices: new InvoicesResource(transport, opts.sellerId),
|
|
2440
|
+
finance: new FinanceResource(transport, opts.sellerId),
|
|
2441
|
+
labels: new LabelsResource(transport, opts.sellerId),
|
|
2442
|
+
testOrders: new TestOrdersResource(transport, opts.sellerId),
|
|
2443
|
+
locations: new LocationsResource(transport)
|
|
2444
|
+
};
|
|
2445
|
+
}
|
|
2446
|
+
function parseWebhookEvent(rawBody) {
|
|
2447
|
+
let body;
|
|
2448
|
+
if (typeof rawBody === "string") {
|
|
2449
|
+
try {
|
|
2450
|
+
body = JSON.parse(rawBody);
|
|
2451
|
+
} catch {
|
|
2452
|
+
throw new core.ValidationError({
|
|
2453
|
+
message: "parseWebhookEvent: rawBody is not valid JSON"
|
|
2454
|
+
});
|
|
2455
|
+
}
|
|
2456
|
+
} else if (rawBody && typeof rawBody === "object") {
|
|
2457
|
+
body = rawBody;
|
|
2458
|
+
} else {
|
|
2459
|
+
throw new core.ValidationError({
|
|
2460
|
+
message: "parseWebhookEvent: rawBody must be an object or JSON string"
|
|
2461
|
+
});
|
|
2462
|
+
}
|
|
2463
|
+
const content = body.content;
|
|
2464
|
+
if (!Array.isArray(content)) {
|
|
2465
|
+
throw new core.ValidationError({
|
|
2466
|
+
message: "parseWebhookEvent: body.content must be an array"
|
|
2467
|
+
});
|
|
2468
|
+
}
|
|
2469
|
+
return {
|
|
2470
|
+
packages: content.map(normalizeShipmentPackage),
|
|
2471
|
+
pageInfo: {
|
|
2472
|
+
totalElements: typeof body.totalElements === "number" ? body.totalElements : void 0,
|
|
2473
|
+
totalPages: typeof body.totalPages === "number" ? body.totalPages : void 0,
|
|
2474
|
+
page: typeof body.page === "number" ? body.page : void 0,
|
|
2475
|
+
size: typeof body.size === "number" ? body.size : void 0
|
|
2476
|
+
},
|
|
2477
|
+
raw: body
|
|
1604
2478
|
};
|
|
1605
2479
|
}
|
|
1606
2480
|
|
|
1607
2481
|
exports.BrandsResource = BrandsResource;
|
|
1608
2482
|
exports.CategoriesResource = CategoriesResource;
|
|
2483
|
+
exports.ClaimsResource = ClaimsResource;
|
|
2484
|
+
exports.FinanceResource = FinanceResource;
|
|
1609
2485
|
exports.InventoryResource = InventoryResource;
|
|
2486
|
+
exports.InvoicesResource = InvoicesResource;
|
|
2487
|
+
exports.LabelsResource = LabelsResource;
|
|
2488
|
+
exports.LocationsResource = LocationsResource;
|
|
1610
2489
|
exports.OrdersResource = OrdersResource;
|
|
1611
2490
|
exports.ProductsResource = ProductsResource;
|
|
2491
|
+
exports.QuestionsResource = QuestionsResource;
|
|
1612
2492
|
exports.SuppliersResource = SuppliersResource;
|
|
2493
|
+
exports.TestOrdersResource = TestOrdersResource;
|
|
2494
|
+
exports.WebhooksResource = WebhooksResource;
|
|
1613
2495
|
exports.createTrendyolClient = createTrendyolClient;
|
|
2496
|
+
exports.normalizeShipmentPackage = normalizeShipmentPackage;
|
|
2497
|
+
exports.parseWebhookEvent = parseWebhookEvent;
|
|
1614
2498
|
//# sourceMappingURL=index.cjs.map
|
|
1615
2499
|
//# sourceMappingURL=index.cjs.map
|