@thorprovider/types 3.3.0 → 3.4.1
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/README.md +10 -0
- package/dist/index.d.mts +925 -17
- package/dist/index.d.ts +925 -17
- package/dist/index.js +56 -0
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +56 -0
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/admin/DropshippingAdmin.ts +995 -0
- package/src/admin/index.ts +1 -0
- package/src/auth.ts +28 -15
- package/src/commerce-provider.ts +42 -0
- package/src/index.ts +106 -1
- package/src/provider.ts +57 -1
|
@@ -0,0 +1,995 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @thorprovider/types — Dropshipping Admin Types
|
|
3
|
+
*
|
|
4
|
+
* Type definitions for all dropshipping API operations on the Thor Commerce
|
|
5
|
+
* extended backend plugin (`/admin/thor/dropshipper/`).
|
|
6
|
+
*
|
|
7
|
+
* These types map 1:1 to the API contract defined in
|
|
8
|
+
* `dropshipping-api-contract.md`.
|
|
9
|
+
*
|
|
10
|
+
* Actors:
|
|
11
|
+
* X = ThorProvider admin (role "Admin")
|
|
12
|
+
* Y = Dropshipper (role "Dropshipper")
|
|
13
|
+
* V = End customer (store)
|
|
14
|
+
*
|
|
15
|
+
* @module admin/DropshippingAdmin
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
import type { Address } from '../customer';
|
|
19
|
+
|
|
20
|
+
// ============================================================
|
|
21
|
+
// Shared primitives
|
|
22
|
+
// ============================================================
|
|
23
|
+
|
|
24
|
+
/** Slim reference to a dropshipper account */
|
|
25
|
+
export interface DropshipperAccountRef {
|
|
26
|
+
id: string;
|
|
27
|
+
provider_name: string;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// ============================================================
|
|
31
|
+
// Onboarding (Solo X)
|
|
32
|
+
// ============================================================
|
|
33
|
+
|
|
34
|
+
/** Body for `POST /admin/thor/dropshipper/onboard` */
|
|
35
|
+
export interface OnboardDropshipperBody {
|
|
36
|
+
/** Business name — used as SalesChannel name and DropshipperAccount.provider_name */
|
|
37
|
+
business_name: string;
|
|
38
|
+
/** Dropshipper user email. Must be unique in the system. */
|
|
39
|
+
email: string;
|
|
40
|
+
/** Initial password. Y should change it on first access. */
|
|
41
|
+
password: string;
|
|
42
|
+
/** Contact phone number */
|
|
43
|
+
phone?: string;
|
|
44
|
+
/** Name of the account contact person */
|
|
45
|
+
contact_name?: string;
|
|
46
|
+
/** Payment terms in days after delivery. Default: 15 */
|
|
47
|
+
payment_terms_days?: number;
|
|
48
|
+
/** Primary currency code. Default: "usd" */
|
|
49
|
+
currency_code?: string;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/** Response for `POST /admin/thor/dropshipper/onboard` */
|
|
53
|
+
export interface OnboardDropshipperResponse {
|
|
54
|
+
dropshipper: {
|
|
55
|
+
user_id: string;
|
|
56
|
+
email: string;
|
|
57
|
+
sales_channel_id: string;
|
|
58
|
+
sales_channel_name: string;
|
|
59
|
+
account_id: string;
|
|
60
|
+
price_list_id: string;
|
|
61
|
+
/** Publishable API key token for the storefront */
|
|
62
|
+
publishable_key_token: string;
|
|
63
|
+
role: 'Dropshipper';
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// ============================================================
|
|
68
|
+
// Variant Costs (Solo X)
|
|
69
|
+
// ============================================================
|
|
70
|
+
|
|
71
|
+
/** A single variant cost record */
|
|
72
|
+
export interface VariantCost {
|
|
73
|
+
id: string;
|
|
74
|
+
account_id: string;
|
|
75
|
+
variant_id: string;
|
|
76
|
+
variant_title?: string;
|
|
77
|
+
product_title?: string;
|
|
78
|
+
cost_amount: number;
|
|
79
|
+
currency_code: string;
|
|
80
|
+
created_at?: string;
|
|
81
|
+
updated_at: string;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/** Options for `GET /admin/thor/dropshipper/variant-costs` */
|
|
85
|
+
export interface GetVariantCostsOptions {
|
|
86
|
+
/** Filter by dropshipper account */
|
|
87
|
+
account_id?: string;
|
|
88
|
+
variant_id?: string;
|
|
89
|
+
currency_code?: string;
|
|
90
|
+
limit?: number;
|
|
91
|
+
offset?: number;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/** Response for `GET /admin/thor/dropshipper/variant-costs` */
|
|
95
|
+
export interface GetVariantCostsResponse {
|
|
96
|
+
variant_costs: VariantCost[];
|
|
97
|
+
count: number;
|
|
98
|
+
offset: number;
|
|
99
|
+
limit: number;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/** Body for `POST /admin/thor/dropshipper/variant-costs` (upsert) */
|
|
103
|
+
export interface CreateVariantCostBody {
|
|
104
|
+
account_id: string;
|
|
105
|
+
variant_id: string;
|
|
106
|
+
cost_amount: number;
|
|
107
|
+
currency_code: string;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/** Response for `POST /admin/thor/dropshipper/variant-costs` */
|
|
111
|
+
export interface CreateVariantCostResponse {
|
|
112
|
+
variant_cost: VariantCost;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/** Single item in a batch variant cost update */
|
|
116
|
+
export interface BatchVariantCostItem {
|
|
117
|
+
variant_id: string;
|
|
118
|
+
cost_amount: number;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/** Body for `POST /admin/thor/dropshipper/variant-costs/batch` */
|
|
122
|
+
export interface BatchVariantCostsBody {
|
|
123
|
+
account_id: string;
|
|
124
|
+
currency_code: string;
|
|
125
|
+
costs: BatchVariantCostItem[];
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/** Response for `POST /admin/thor/dropshipper/variant-costs/batch` */
|
|
129
|
+
export interface BatchVariantCostsResponse {
|
|
130
|
+
updated: number;
|
|
131
|
+
errors: unknown[];
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/** Response for `DELETE /admin/thor/dropshipper/variant-costs/:id` */
|
|
135
|
+
export interface DeleteVariantCostResponse {
|
|
136
|
+
deleted: true;
|
|
137
|
+
id: string;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// ============================================================
|
|
141
|
+
// Products & Sale Prices (Solo Y)
|
|
142
|
+
// ============================================================
|
|
143
|
+
|
|
144
|
+
/** A product variant as seen by the dropshipper */
|
|
145
|
+
export interface DropshipperVariant {
|
|
146
|
+
id: string;
|
|
147
|
+
title: string;
|
|
148
|
+
sku: string | null;
|
|
149
|
+
stock_quantity: number;
|
|
150
|
+
/** Price Y pays to X. Read-only for Y. */
|
|
151
|
+
cost_price: number;
|
|
152
|
+
cost_price_currency: string;
|
|
153
|
+
/** "custom" if from DropshipperVariantCost, "base_price" if fallback */
|
|
154
|
+
cost_price_source: 'custom' | 'base_price';
|
|
155
|
+
/** Price Y charges to V. From the channel's price list. */
|
|
156
|
+
sale_price: number;
|
|
157
|
+
sale_price_currency: string;
|
|
158
|
+
/** sale_price - cost_price (calculated by backend) */
|
|
159
|
+
margin: number;
|
|
160
|
+
/** (margin / sale_price) × 100 (calculated by backend) */
|
|
161
|
+
margin_percent: number;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/** A product as seen by the dropshipper */
|
|
165
|
+
export interface DropshipperProduct {
|
|
166
|
+
id: string;
|
|
167
|
+
title: string;
|
|
168
|
+
thumbnail: string | null;
|
|
169
|
+
status: 'published' | 'draft' | string;
|
|
170
|
+
variants: DropshipperVariant[];
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/** Options for `GET /admin/thor/dropshipper/products` */
|
|
174
|
+
export interface GetDropshipperProductsOptions {
|
|
175
|
+
/** Search by product or variant title */
|
|
176
|
+
q?: string;
|
|
177
|
+
category_id?: string;
|
|
178
|
+
status?: 'published' | 'draft';
|
|
179
|
+
in_stock?: boolean;
|
|
180
|
+
limit?: number;
|
|
181
|
+
offset?: number;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/** Response for `GET /admin/thor/dropshipper/products` */
|
|
185
|
+
export interface GetDropshipperProductsResponse {
|
|
186
|
+
products: DropshipperProduct[];
|
|
187
|
+
count: number;
|
|
188
|
+
offset: number;
|
|
189
|
+
limit: number;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/** Single price update item */
|
|
193
|
+
export interface DropshipperPriceItem {
|
|
194
|
+
variant_id: string;
|
|
195
|
+
amount: number;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/** Body for `PUT /admin/thor/dropshipper/prices` */
|
|
199
|
+
export interface UpdateDropshipperPricesBody {
|
|
200
|
+
currency_code: string;
|
|
201
|
+
prices: DropshipperPriceItem[];
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/** Response for `PUT /admin/thor/dropshipper/prices` */
|
|
205
|
+
export interface UpdateDropshipperPricesResponse {
|
|
206
|
+
updated: number;
|
|
207
|
+
price_list_id: string;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// ============================================================
|
|
211
|
+
// Orders (Solo Y, except set-payment-collector which is Solo X)
|
|
212
|
+
// ============================================================
|
|
213
|
+
|
|
214
|
+
/** Slim customer reference on an order */
|
|
215
|
+
export interface DropshipperOrderCustomer {
|
|
216
|
+
id: string;
|
|
217
|
+
full_name: string;
|
|
218
|
+
email: string;
|
|
219
|
+
phone?: string;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/** Slim order row as returned in list responses */
|
|
223
|
+
export interface DropshipperOrder {
|
|
224
|
+
id: string;
|
|
225
|
+
display_id: number;
|
|
226
|
+
status: string;
|
|
227
|
+
fulfillment_status: string | null;
|
|
228
|
+
created_at: string;
|
|
229
|
+
customer: DropshipperOrderCustomer;
|
|
230
|
+
currency_code: string;
|
|
231
|
+
total: number;
|
|
232
|
+
profit: number;
|
|
233
|
+
margin_percent: number;
|
|
234
|
+
items_count: number;
|
|
235
|
+
payment_collected_by: 'dropshipper' | 'provider' | null;
|
|
236
|
+
settlement_status: 'settled' | 'unsettled';
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/** Options for `GET /admin/thor/dropshipper/orders` */
|
|
240
|
+
export interface GetDropshipperOrdersOptions {
|
|
241
|
+
status?: string;
|
|
242
|
+
payment_collector?: 'dropshipper' | 'provider';
|
|
243
|
+
settlement_status?: 'settled' | 'unsettled';
|
|
244
|
+
from?: string;
|
|
245
|
+
to?: string;
|
|
246
|
+
q?: string;
|
|
247
|
+
limit?: number;
|
|
248
|
+
offset?: number;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
/** Response for `GET /admin/thor/dropshipper/orders` */
|
|
252
|
+
export interface GetDropshipperOrdersResponse {
|
|
253
|
+
orders: DropshipperOrder[];
|
|
254
|
+
count: number;
|
|
255
|
+
offset: number;
|
|
256
|
+
limit: number;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
/** A shipping address on an order */
|
|
260
|
+
export interface DropshipperOrderShippingAddress {
|
|
261
|
+
full_name: string;
|
|
262
|
+
address_1: string;
|
|
263
|
+
city: string;
|
|
264
|
+
province: string | null;
|
|
265
|
+
postal_code: string;
|
|
266
|
+
country_code: string;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
/** A line item with cost and profit breakdown */
|
|
270
|
+
export interface DropshipperOrderItem {
|
|
271
|
+
id: string;
|
|
272
|
+
title: string;
|
|
273
|
+
variant_title: string;
|
|
274
|
+
sku: string | null;
|
|
275
|
+
quantity: number;
|
|
276
|
+
unit_price: number;
|
|
277
|
+
cost_price: number;
|
|
278
|
+
subtotal: number;
|
|
279
|
+
cost_subtotal: number;
|
|
280
|
+
profit: number;
|
|
281
|
+
thumbnail: string | null;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
/** Order totals with profit breakdown */
|
|
285
|
+
export interface DropshipperOrderTotals {
|
|
286
|
+
subtotal: number;
|
|
287
|
+
shipping_total: number;
|
|
288
|
+
discount_total: number;
|
|
289
|
+
total: number;
|
|
290
|
+
cost_total: number;
|
|
291
|
+
profit: number;
|
|
292
|
+
margin_percent: number;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
/** Timeline event on an order */
|
|
296
|
+
export interface DropshipperOrderTimelineEvent {
|
|
297
|
+
event: string;
|
|
298
|
+
timestamp: string;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
/** Full order detail as returned by GET /admin/thor/dropshipper/orders/:id */
|
|
302
|
+
export interface DropshipperOrderDetail {
|
|
303
|
+
id: string;
|
|
304
|
+
display_id: number;
|
|
305
|
+
status: string;
|
|
306
|
+
fulfillment_status: string | null;
|
|
307
|
+
created_at: string;
|
|
308
|
+
currency_code: string;
|
|
309
|
+
customer: DropshipperOrderCustomer & { phone?: string };
|
|
310
|
+
shipping_address: DropshipperOrderShippingAddress;
|
|
311
|
+
items: DropshipperOrderItem[];
|
|
312
|
+
totals: DropshipperOrderTotals;
|
|
313
|
+
payment_collected_by: 'dropshipper' | 'provider' | null;
|
|
314
|
+
settlement_status: 'settled' | 'unsettled';
|
|
315
|
+
timeline: DropshipperOrderTimelineEvent[];
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
/** Response for `GET /admin/thor/dropshipper/orders/:id` */
|
|
319
|
+
export interface GetDropshipperOrderDetailResponse {
|
|
320
|
+
order: DropshipperOrderDetail;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
/** A line item in a manual order creation */
|
|
324
|
+
export interface CreateOrderItem {
|
|
325
|
+
variant_id: string;
|
|
326
|
+
quantity: number;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
/** Body for `POST /admin/thor/dropshipper/orders` */
|
|
330
|
+
export interface CreateDropshipperOrderBody {
|
|
331
|
+
customer_id: string;
|
|
332
|
+
currency_code: string;
|
|
333
|
+
items: CreateOrderItem[];
|
|
334
|
+
shipping_address: DropshipperOrderShippingAddress & { phone?: string };
|
|
335
|
+
shipping_method_id?: string;
|
|
336
|
+
notes?: string;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
/** Response for `POST /admin/thor/dropshipper/orders` */
|
|
340
|
+
export interface CreateDropshipperOrderResponse {
|
|
341
|
+
order: {
|
|
342
|
+
id: string;
|
|
343
|
+
display_id: number;
|
|
344
|
+
status: string;
|
|
345
|
+
total: number;
|
|
346
|
+
profit: number;
|
|
347
|
+
created_at: string;
|
|
348
|
+
};
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
/** Body for `POST /admin/thor/dropshipper/orders/:id/set-payment-collector` */
|
|
352
|
+
export interface SetPaymentCollectorBody {
|
|
353
|
+
payment_collected_by: 'dropshipper' | 'provider';
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
/** Response for `POST /admin/thor/dropshipper/orders/:id/set-payment-collector` */
|
|
357
|
+
export interface SetPaymentCollectorResponse {
|
|
358
|
+
order_id: string;
|
|
359
|
+
payment_collected_by: 'dropshipper' | 'provider';
|
|
360
|
+
updated_at: string;
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
/** Response for `POST /admin/thor/dropshipper/orders/:id/cancel` */
|
|
364
|
+
export interface CancelDropshipperOrderResponse {
|
|
365
|
+
order: { id: string; status: string; [key: string]: unknown }
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
// ============================================================
|
|
369
|
+
// Order Edits (Solo Y)
|
|
370
|
+
// ============================================================
|
|
371
|
+
|
|
372
|
+
/** Body for `POST /admin/thor/dropshipper/orders/:id/edits` */
|
|
373
|
+
export interface CreateOrderEditBody {
|
|
374
|
+
internal_note?: string
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
/** Response for `POST /admin/thor/dropshipper/orders/:id/edits` */
|
|
378
|
+
export interface CreateOrderEditResponse {
|
|
379
|
+
order_edit: { id: string; order_id: string; status: string; [key: string]: unknown }
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
/** Body for `POST /admin/thor/dropshipper/orders/:id/edits/:edit_id/items` */
|
|
383
|
+
export interface AddOrderEditItemBody {
|
|
384
|
+
variant_id: string
|
|
385
|
+
quantity: number
|
|
386
|
+
unit_price?: number
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
/** Response for `POST /admin/thor/dropshipper/orders/:id/edits/:edit_id/items` */
|
|
390
|
+
export interface AddOrderEditItemResponse {
|
|
391
|
+
order_edit: { id: string; [key: string]: unknown }
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
/** Response for `POST /admin/thor/dropshipper/orders/:id/edits/:edit_id/confirm` */
|
|
395
|
+
export interface ConfirmOrderEditResponse {
|
|
396
|
+
order: { id: string; [key: string]: unknown }
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
// ============================================================
|
|
400
|
+
// Custom Categories (Solo Y)
|
|
401
|
+
// ============================================================
|
|
402
|
+
|
|
403
|
+
/** A dropshipper custom category node */
|
|
404
|
+
export interface DropshipperCategory {
|
|
405
|
+
id: string;
|
|
406
|
+
name: string;
|
|
407
|
+
handle: string;
|
|
408
|
+
description?: string | null;
|
|
409
|
+
position: number;
|
|
410
|
+
parent_id: string | null;
|
|
411
|
+
sales_channel_id?: string;
|
|
412
|
+
products_count?: number;
|
|
413
|
+
children?: DropshipperCategory[];
|
|
414
|
+
created_at?: string;
|
|
415
|
+
updated_at?: string;
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
/** Options for `GET /admin/thor/dropshipper/categories` */
|
|
419
|
+
export interface GetDropshipperCategoriesOptions {
|
|
420
|
+
parent_id?: string;
|
|
421
|
+
include_children?: boolean;
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
/** Response for `GET /admin/thor/dropshipper/categories` */
|
|
425
|
+
export interface GetDropshipperCategoriesResponse {
|
|
426
|
+
categories: DropshipperCategory[];
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
/** Body for `POST /admin/thor/dropshipper/categories` */
|
|
430
|
+
export interface CreateDropshipperCategoryBody {
|
|
431
|
+
name: string;
|
|
432
|
+
/** Auto-generated from name if omitted. Must be unique within the channel. */
|
|
433
|
+
handle?: string;
|
|
434
|
+
description?: string;
|
|
435
|
+
parent_id?: string | null;
|
|
436
|
+
position?: number;
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
/** Body for `PUT /admin/thor/dropshipper/categories/:id` */
|
|
440
|
+
export interface UpdateDropshipperCategoryBody {
|
|
441
|
+
name?: string;
|
|
442
|
+
description?: string;
|
|
443
|
+
handle?: string;
|
|
444
|
+
parent_id?: string | null;
|
|
445
|
+
position?: number;
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
/** Response for `DELETE /admin/thor/dropshipper/categories/:id` */
|
|
449
|
+
export interface DeleteDropshipperCategoryResponse {
|
|
450
|
+
deleted: true;
|
|
451
|
+
id: string;
|
|
452
|
+
/** Number of products unmapped from the deleted category */
|
|
453
|
+
unmapped_products: number;
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
/** Body for `POST /admin/thor/dropshipper/category-mappings` */
|
|
457
|
+
export interface CreateCategoryMappingBody {
|
|
458
|
+
category_id: string;
|
|
459
|
+
product_id: string;
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
/** Response for `POST /admin/thor/dropshipper/category-mappings` */
|
|
463
|
+
export interface CreateCategoryMappingResponse {
|
|
464
|
+
mapping: {
|
|
465
|
+
id: string;
|
|
466
|
+
category_id: string;
|
|
467
|
+
product_id: string;
|
|
468
|
+
created_at: string;
|
|
469
|
+
};
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
/** Response for `DELETE /admin/thor/dropshipper/category-mappings/:id` */
|
|
473
|
+
export interface DeleteCategoryMappingResponse {
|
|
474
|
+
deleted: true;
|
|
475
|
+
id: string;
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
// ============================================================
|
|
479
|
+
// Customers (Solo Y)
|
|
480
|
+
// ============================================================
|
|
481
|
+
|
|
482
|
+
/** A customer as seen by the dropshipper (list view) */
|
|
483
|
+
export interface DropshipperCustomer {
|
|
484
|
+
id: string;
|
|
485
|
+
first_name: string | null;
|
|
486
|
+
last_name: string | null;
|
|
487
|
+
email: string;
|
|
488
|
+
phone: string | null;
|
|
489
|
+
created_at: string;
|
|
490
|
+
total_orders: number;
|
|
491
|
+
total_spent: number;
|
|
492
|
+
currency_code: string;
|
|
493
|
+
last_order_at: string | null;
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
/** Stats on a customer as seen by the dropshipper */
|
|
497
|
+
export interface DropshipperCustomerStats {
|
|
498
|
+
total_orders: number;
|
|
499
|
+
total_spent: number;
|
|
500
|
+
total_profit_generated: number;
|
|
501
|
+
avg_order_value: number;
|
|
502
|
+
currency_code: string;
|
|
503
|
+
first_order_at: string | null;
|
|
504
|
+
last_order_at: string | null;
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
/** Slim order reference for customer detail */
|
|
508
|
+
export interface DropshipperCustomerOrderRef {
|
|
509
|
+
id: string;
|
|
510
|
+
display_id: number;
|
|
511
|
+
status: string;
|
|
512
|
+
total: number;
|
|
513
|
+
created_at: string;
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
/** Full customer detail as seen by the dropshipper */
|
|
517
|
+
export interface DropshipperCustomerDetail {
|
|
518
|
+
id: string;
|
|
519
|
+
first_name: string | null;
|
|
520
|
+
last_name: string | null;
|
|
521
|
+
email: string;
|
|
522
|
+
phone: string | null;
|
|
523
|
+
created_at: string;
|
|
524
|
+
default_shipping_address?: DropshipperOrderShippingAddress | null;
|
|
525
|
+
stats: DropshipperCustomerStats;
|
|
526
|
+
recent_orders: DropshipperCustomerOrderRef[];
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
/** Options for `GET /admin/thor/dropshipper/customers` */
|
|
530
|
+
export interface GetDropshipperCustomersOptions {
|
|
531
|
+
q?: string;
|
|
532
|
+
has_orders?: boolean;
|
|
533
|
+
from?: string;
|
|
534
|
+
limit?: number;
|
|
535
|
+
offset?: number;
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
/** Response for `GET /admin/thor/dropshipper/customers` */
|
|
539
|
+
export interface GetDropshipperCustomersResponse {
|
|
540
|
+
customers: DropshipperCustomer[];
|
|
541
|
+
count: number;
|
|
542
|
+
offset: number;
|
|
543
|
+
limit: number;
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
/** Response for `GET /admin/thor/dropshipper/customers/:id` */
|
|
547
|
+
export interface GetDropshipperCustomerDetailResponse {
|
|
548
|
+
customer: DropshipperCustomerDetail;
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
/** Body for `POST /admin/thor/dropshipper/customers` */
|
|
552
|
+
export interface CreateDropshipperCustomerBody {
|
|
553
|
+
first_name?: string;
|
|
554
|
+
last_name?: string;
|
|
555
|
+
email: string;
|
|
556
|
+
phone?: string;
|
|
557
|
+
password: string;
|
|
558
|
+
shipping_address?: {
|
|
559
|
+
address_1?: string;
|
|
560
|
+
city?: string;
|
|
561
|
+
province?: string;
|
|
562
|
+
postal_code?: string;
|
|
563
|
+
country_code?: string;
|
|
564
|
+
};
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
/** Response for `POST /admin/thor/dropshipper/customers` */
|
|
568
|
+
export interface CreateDropshipperCustomerResponse {
|
|
569
|
+
customer: {
|
|
570
|
+
id: string;
|
|
571
|
+
email: string;
|
|
572
|
+
first_name: string | null;
|
|
573
|
+
last_name: string | null;
|
|
574
|
+
sales_channel_id: string;
|
|
575
|
+
created_at: string;
|
|
576
|
+
};
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
// ============================================================
|
|
580
|
+
// Account & Settlements (Y read-only + X creates/confirms)
|
|
581
|
+
// ============================================================
|
|
582
|
+
|
|
583
|
+
/** Balance breakdown for a dropshipper account */
|
|
584
|
+
export interface DropshipperBalance {
|
|
585
|
+
/** Sum of cost_price × qty for delivered orders where Y collected payment. Unsettled. */
|
|
586
|
+
payable_to_provider: number;
|
|
587
|
+
/** Sum of profit for delivered orders where X collected payment (COD). Unsettled. */
|
|
588
|
+
receivable_from_provider: number;
|
|
589
|
+
/** receivable - payable. Negative = Y owes X; positive = X owes Y. */
|
|
590
|
+
net_balance: number;
|
|
591
|
+
net_balance_label: string;
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
/** Pending order counts for a balance summary */
|
|
595
|
+
export interface DropshipperPendingOrders {
|
|
596
|
+
payable_count: number;
|
|
597
|
+
payable_total: number;
|
|
598
|
+
receivable_count: number;
|
|
599
|
+
receivable_total: number;
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
/** Full account record as returned by `GET /admin/thor/dropshipper/account` */
|
|
603
|
+
export interface DropshipperAccount {
|
|
604
|
+
id: string;
|
|
605
|
+
provider_name: string;
|
|
606
|
+
currency_code: string;
|
|
607
|
+
payment_terms_days: number;
|
|
608
|
+
balance: DropshipperBalance;
|
|
609
|
+
pending_orders: DropshipperPendingOrders;
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
/** Response for `GET /admin/thor/dropshipper/account` */
|
|
613
|
+
export interface GetDropshipperAccountResponse {
|
|
614
|
+
account: DropshipperAccount;
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
/** A payable order row */
|
|
618
|
+
export interface DropshipperPayableOrder {
|
|
619
|
+
id: string;
|
|
620
|
+
display_id: number;
|
|
621
|
+
fulfilled_at: string;
|
|
622
|
+
due_date: string;
|
|
623
|
+
customer_name: string;
|
|
624
|
+
sale_total: number;
|
|
625
|
+
cost_total: number;
|
|
626
|
+
amount_payable: number;
|
|
627
|
+
days_overdue: number;
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
/** Response for `GET /admin/thor/dropshipper/account/payable` */
|
|
631
|
+
export interface GetDropshipperPayableResponse {
|
|
632
|
+
orders: DropshipperPayableOrder[];
|
|
633
|
+
total_payable: number;
|
|
634
|
+
count: number;
|
|
635
|
+
offset: number;
|
|
636
|
+
limit: number;
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
/** A receivable order row */
|
|
640
|
+
export interface DropshipperReceivableOrder {
|
|
641
|
+
id: string;
|
|
642
|
+
display_id: number;
|
|
643
|
+
fulfilled_at: string;
|
|
644
|
+
customer_name: string;
|
|
645
|
+
sale_total: number;
|
|
646
|
+
cost_total: number;
|
|
647
|
+
commission_amount: number;
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
/** Response for `GET /admin/thor/dropshipper/account/receivable` */
|
|
651
|
+
export interface GetDropshipperReceivableResponse {
|
|
652
|
+
orders: DropshipperReceivableOrder[];
|
|
653
|
+
total_receivable: number;
|
|
654
|
+
count: number;
|
|
655
|
+
offset: number;
|
|
656
|
+
limit: number;
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
/** A settlement record */
|
|
660
|
+
export interface SettlementRecord {
|
|
661
|
+
id: string;
|
|
662
|
+
type: 'payment_to_provider' | 'commission_from_provider';
|
|
663
|
+
amount: number;
|
|
664
|
+
order_ids_count?: number;
|
|
665
|
+
status: 'pending' | 'confirmed' | 'cancelled';
|
|
666
|
+
notes?: string | null;
|
|
667
|
+
created_at: string;
|
|
668
|
+
settled_at: string | null;
|
|
669
|
+
confirmed_by: string | null;
|
|
670
|
+
account?: DropshipperAccountRef;
|
|
671
|
+
orders?: Array<{ id: string; display_id: number; fulfilled_at: string; cost_total: number }>;
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
/** Options for listing settlements */
|
|
675
|
+
export interface GetSettlementsOptions {
|
|
676
|
+
status?: 'pending' | 'confirmed' | 'cancelled';
|
|
677
|
+
type?: 'payment_to_provider' | 'commission_from_provider';
|
|
678
|
+
account_id?: string;
|
|
679
|
+
limit?: number;
|
|
680
|
+
offset?: number;
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
/** Response for `GET /admin/thor/dropshipper/settlements` */
|
|
684
|
+
export interface GetSettlementsResponse {
|
|
685
|
+
settlements: SettlementRecord[];
|
|
686
|
+
count: number;
|
|
687
|
+
offset: number;
|
|
688
|
+
limit: number;
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
/** Response for `GET /admin/thor/dropshipper/settlements/:id` */
|
|
692
|
+
export interface GetSettlementDetailResponse {
|
|
693
|
+
settlement: SettlementRecord;
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
/** Body for `POST /admin/thor/dropshipper/admin/settlements` (Solo X) */
|
|
697
|
+
export interface CreateSettlementBody {
|
|
698
|
+
account_id: string;
|
|
699
|
+
type: 'payment_to_provider' | 'commission_from_provider';
|
|
700
|
+
order_ids: string[];
|
|
701
|
+
amount: number;
|
|
702
|
+
notes?: string;
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
/** Response for `POST /admin/thor/dropshipper/admin/settlements` */
|
|
706
|
+
export interface CreateSettlementResponse {
|
|
707
|
+
settlement: SettlementRecord;
|
|
708
|
+
}
|
|
709
|
+
|
|
710
|
+
/** Body for `POST /admin/thor/dropshipper/admin/settlements/:id/confirm` */
|
|
711
|
+
export interface ConfirmSettlementBody {
|
|
712
|
+
notes?: string;
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
/** Body for `POST /admin/thor/dropshipper/admin/settlements/:id/cancel` */
|
|
716
|
+
export interface CancelSettlementBody {
|
|
717
|
+
reason?: string;
|
|
718
|
+
}
|
|
719
|
+
|
|
720
|
+
/** Response for confirm/cancel settlement */
|
|
721
|
+
export interface UpdateSettlementStatusResponse {
|
|
722
|
+
settlement: SettlementRecord;
|
|
723
|
+
}
|
|
724
|
+
|
|
725
|
+
// ============================================================
|
|
726
|
+
// Admin Account Management (Solo X)
|
|
727
|
+
// ============================================================
|
|
728
|
+
|
|
729
|
+
/** Full account record with channel info as seen by X */
|
|
730
|
+
export interface AdminDropshipperAccount {
|
|
731
|
+
id: string;
|
|
732
|
+
provider_name: string;
|
|
733
|
+
provider_email?: string;
|
|
734
|
+
sales_channel_id: string;
|
|
735
|
+
sales_channel_name: string;
|
|
736
|
+
currency_code: string;
|
|
737
|
+
payment_terms_days: number;
|
|
738
|
+
created_at?: string;
|
|
739
|
+
}
|
|
740
|
+
|
|
741
|
+
/** Response for `GET /admin/thor/dropshipper/admin/accounts` */
|
|
742
|
+
export interface GetAdminDropshipperAccountsResponse {
|
|
743
|
+
accounts: AdminDropshipperAccount[];
|
|
744
|
+
}
|
|
745
|
+
|
|
746
|
+
/** Extended balance for admin view of a specific account */
|
|
747
|
+
export interface AdminDropshipperBalance extends DropshipperBalance {
|
|
748
|
+
payable_count: number;
|
|
749
|
+
payable_order_ids: string[];
|
|
750
|
+
payable_orders: DropshipperPayableOrder[];
|
|
751
|
+
receivable_count: number;
|
|
752
|
+
receivable_order_ids: string[];
|
|
753
|
+
receivable_orders: DropshipperReceivableOrder[];
|
|
754
|
+
unclassified_orders: number;
|
|
755
|
+
}
|
|
756
|
+
|
|
757
|
+
/** Response for `GET /admin/thor/dropshipper/admin/accounts/:id/balance` */
|
|
758
|
+
export interface GetAdminAccountBalanceResponse {
|
|
759
|
+
account: Pick<AdminDropshipperAccount, 'id' | 'provider_name' | 'currency_code' | 'payment_terms_days' | 'sales_channel_id'>;
|
|
760
|
+
balance: AdminDropshipperBalance;
|
|
761
|
+
}
|
|
762
|
+
|
|
763
|
+
/** Response for `GET /admin/thor/dropshipper/admin/price-lists` */
|
|
764
|
+
export interface GetAdminPriceListsResponse {
|
|
765
|
+
price_lists: Array<{
|
|
766
|
+
id: string;
|
|
767
|
+
sales_channel_id: string;
|
|
768
|
+
sales_channel_name: string;
|
|
769
|
+
provider_name: string;
|
|
770
|
+
}>;
|
|
771
|
+
}
|
|
772
|
+
|
|
773
|
+
/** Response for `GET /admin/thor/dropshipper/admin/user-channel` */
|
|
774
|
+
export interface GetUserChannelResponse {
|
|
775
|
+
links: Array<{ sales_channel_id: string }>;
|
|
776
|
+
}
|
|
777
|
+
|
|
778
|
+
// ============================================================
|
|
779
|
+
// Promotions (Solo Y)
|
|
780
|
+
// ============================================================
|
|
781
|
+
|
|
782
|
+
/** A dropshipper promotion record */
|
|
783
|
+
export interface DropshipperPromotion {
|
|
784
|
+
id: string;
|
|
785
|
+
code: string;
|
|
786
|
+
/** Maps to application_method.type */
|
|
787
|
+
type: 'percentage' | 'fixed';
|
|
788
|
+
value: number;
|
|
789
|
+
status: 'active' | 'inactive' | string;
|
|
790
|
+
usage_limit: number | null;
|
|
791
|
+
usage_count: number;
|
|
792
|
+
starts_at: string | null;
|
|
793
|
+
ends_at: string | null;
|
|
794
|
+
target_type?: 'order' | 'items';
|
|
795
|
+
min_amount?: number | null;
|
|
796
|
+
currency_code?: string;
|
|
797
|
+
}
|
|
798
|
+
|
|
799
|
+
/** Options for `GET /admin/thor/dropshipper/promotions` */
|
|
800
|
+
export interface GetDropshipperPromotionsOptions {
|
|
801
|
+
type?: 'percentage' | 'fixed';
|
|
802
|
+
limit?: number;
|
|
803
|
+
offset?: number;
|
|
804
|
+
}
|
|
805
|
+
|
|
806
|
+
/** Response for `GET /admin/thor/dropshipper/promotions` */
|
|
807
|
+
export interface GetDropshipperPromotionsResponse {
|
|
808
|
+
promotions: DropshipperPromotion[];
|
|
809
|
+
count: number;
|
|
810
|
+
offset: number;
|
|
811
|
+
limit: number;
|
|
812
|
+
}
|
|
813
|
+
|
|
814
|
+
/** An additional targeting rule for a promotion */
|
|
815
|
+
export interface PromotionRule {
|
|
816
|
+
attribute: string;
|
|
817
|
+
operator: string;
|
|
818
|
+
values: string[];
|
|
819
|
+
}
|
|
820
|
+
|
|
821
|
+
/** Body for `POST /admin/thor/dropshipper/promotions` */
|
|
822
|
+
export interface CreateDropshipperPromotionBody {
|
|
823
|
+
code: string;
|
|
824
|
+
type: 'percentage' | 'fixed';
|
|
825
|
+
value: number;
|
|
826
|
+
currency_code?: string;
|
|
827
|
+
target_type?: 'order' | 'items';
|
|
828
|
+
allocation?: 'each' | 'across';
|
|
829
|
+
usage_limit?: number | null;
|
|
830
|
+
starts_at?: string | null;
|
|
831
|
+
ends_at?: string | null;
|
|
832
|
+
rules?: PromotionRule[];
|
|
833
|
+
}
|
|
834
|
+
|
|
835
|
+
/** Body for `PUT /admin/thor/dropshipper/promotions/:id` */
|
|
836
|
+
export interface UpdateDropshipperPromotionBody {
|
|
837
|
+
value?: number;
|
|
838
|
+
ends_at?: string | null;
|
|
839
|
+
usage_limit?: number | null;
|
|
840
|
+
}
|
|
841
|
+
|
|
842
|
+
/** Response for `DELETE /admin/thor/dropshipper/promotions/:id` */
|
|
843
|
+
export interface DeleteDropshipperPromotionResponse {
|
|
844
|
+
deleted: true;
|
|
845
|
+
id: string;
|
|
846
|
+
}
|
|
847
|
+
|
|
848
|
+
// ============================================================
|
|
849
|
+
// Dashboard & Stats (Solo Y)
|
|
850
|
+
// ============================================================
|
|
851
|
+
|
|
852
|
+
/** Options for `GET /admin/thor/dropshipper/dashboard/stats` */
|
|
853
|
+
export interface GetDashboardStatsOptions {
|
|
854
|
+
period?: '7d' | '30d' | '90d' | 'custom';
|
|
855
|
+
/** Required when period = "custom" */
|
|
856
|
+
from?: string;
|
|
857
|
+
/** Required when period = "custom" */
|
|
858
|
+
to?: string;
|
|
859
|
+
currency_code?: string;
|
|
860
|
+
}
|
|
861
|
+
|
|
862
|
+
/** Core period metrics */
|
|
863
|
+
export interface DashboardPeriodMetrics {
|
|
864
|
+
orders_count: number;
|
|
865
|
+
revenue_total: number;
|
|
866
|
+
profit_total: number;
|
|
867
|
+
avg_margin_percent: number;
|
|
868
|
+
avg_order_value: number;
|
|
869
|
+
customers_active?: number;
|
|
870
|
+
customers_new?: number;
|
|
871
|
+
currency_code: string;
|
|
872
|
+
}
|
|
873
|
+
|
|
874
|
+
/** Percentage changes vs. previous period */
|
|
875
|
+
export interface DashboardChanges {
|
|
876
|
+
orders_count_pct: number;
|
|
877
|
+
revenue_total_pct: number;
|
|
878
|
+
profit_total_pct: number;
|
|
879
|
+
avg_margin_percent_pct: number;
|
|
880
|
+
}
|
|
881
|
+
|
|
882
|
+
/** Top product row by profit */
|
|
883
|
+
export interface DashboardTopProduct {
|
|
884
|
+
product_id: string;
|
|
885
|
+
product_title: string;
|
|
886
|
+
variant_id: string;
|
|
887
|
+
variant_title: string;
|
|
888
|
+
units_sold: number;
|
|
889
|
+
revenue: number;
|
|
890
|
+
profit: number;
|
|
891
|
+
margin_percent: number;
|
|
892
|
+
thumbnail: string | null;
|
|
893
|
+
}
|
|
894
|
+
|
|
895
|
+
/** Full dashboard stats response */
|
|
896
|
+
export interface DashboardStats {
|
|
897
|
+
period: {
|
|
898
|
+
from: string;
|
|
899
|
+
to: string;
|
|
900
|
+
label: string;
|
|
901
|
+
};
|
|
902
|
+
current: DashboardPeriodMetrics;
|
|
903
|
+
previous: DashboardPeriodMetrics;
|
|
904
|
+
changes: DashboardChanges;
|
|
905
|
+
orders_by_status: Record<string, number>;
|
|
906
|
+
settlement_summary: DropshipperBalance & {
|
|
907
|
+
pending_settlement_records: number;
|
|
908
|
+
currency_code: string;
|
|
909
|
+
};
|
|
910
|
+
recent_orders: Array<{
|
|
911
|
+
id: string;
|
|
912
|
+
display_id: number;
|
|
913
|
+
customer_name: string;
|
|
914
|
+
total: number;
|
|
915
|
+
profit: number;
|
|
916
|
+
status: string;
|
|
917
|
+
created_at: string;
|
|
918
|
+
}>;
|
|
919
|
+
top_products_by_profit: DashboardTopProduct[];
|
|
920
|
+
}
|
|
921
|
+
|
|
922
|
+
/** Response for `GET /admin/thor/dropshipper/dashboard/stats` */
|
|
923
|
+
export interface GetDashboardStatsResponse {
|
|
924
|
+
stats?: DashboardStats;
|
|
925
|
+
// Some backends may return the stats object directly
|
|
926
|
+
[key: string]: unknown;
|
|
927
|
+
}
|
|
928
|
+
|
|
929
|
+
// ============================================================
|
|
930
|
+
// Order Notes (Solo Y + Admin X can read)
|
|
931
|
+
// ============================================================
|
|
932
|
+
|
|
933
|
+
/** A note attached to an order */
|
|
934
|
+
export interface OrderNote {
|
|
935
|
+
id: string;
|
|
936
|
+
order_id: string;
|
|
937
|
+
author_id: string;
|
|
938
|
+
text: string;
|
|
939
|
+
created_at: string;
|
|
940
|
+
}
|
|
941
|
+
|
|
942
|
+
/** Body for `POST /admin/thor/dropshipper/orders/:id/notes` */
|
|
943
|
+
export interface CreateOrderNoteBody {
|
|
944
|
+
text: string;
|
|
945
|
+
}
|
|
946
|
+
|
|
947
|
+
/** Response for `GET /admin/thor/dropshipper/orders/:id/notes` */
|
|
948
|
+
export interface GetOrderNotesResponse {
|
|
949
|
+
notes: OrderNote[];
|
|
950
|
+
}
|
|
951
|
+
|
|
952
|
+
/** Response for `DELETE /admin/thor/dropshipper/orders/:id/notes/:note_id` */
|
|
953
|
+
export interface DeleteOrderNoteResponse {
|
|
954
|
+
id: string;
|
|
955
|
+
deleted: boolean;
|
|
956
|
+
}
|
|
957
|
+
|
|
958
|
+
// ============================================================
|
|
959
|
+
// Dropshipper Addresses (Solo Y, scoped by channel)
|
|
960
|
+
// ============================================================
|
|
961
|
+
|
|
962
|
+
/** Body for creating/updating a dropshipper address */
|
|
963
|
+
export interface DropshipperAddressBody {
|
|
964
|
+
first_name: string;
|
|
965
|
+
last_name: string;
|
|
966
|
+
company?: string;
|
|
967
|
+
address_1: string;
|
|
968
|
+
address_2?: string;
|
|
969
|
+
city: string;
|
|
970
|
+
province?: string;
|
|
971
|
+
postal_code: string;
|
|
972
|
+
country_code: string;
|
|
973
|
+
phone?: string;
|
|
974
|
+
is_default?: boolean;
|
|
975
|
+
}
|
|
976
|
+
|
|
977
|
+
/** Response for creating or updating a dropshipper address */
|
|
978
|
+
export interface DropshipperAddressResponse {
|
|
979
|
+
address: Address;
|
|
980
|
+
}
|
|
981
|
+
|
|
982
|
+
/** Response for getting dropshipper addresses for a customer */
|
|
983
|
+
export interface GetDropshipperAddressesResponse {
|
|
984
|
+
addresses: Address[];
|
|
985
|
+
count: number;
|
|
986
|
+
}
|
|
987
|
+
|
|
988
|
+
// ============================================================
|
|
989
|
+
// Storefront (V — end customer, uses publishable API key)
|
|
990
|
+
// ============================================================
|
|
991
|
+
|
|
992
|
+
/** Response for `GET /store/thor/dropshipper-categories` */
|
|
993
|
+
export interface GetStorefrontDropshipperCategoriesResponse {
|
|
994
|
+
categories: DropshipperCategory[];
|
|
995
|
+
}
|