vantuz 3.4.2 β 3.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +45 -45
- package/admin-keygen.js +51 -0
- package/cli.js +685 -585
- package/config.js +733 -733
- package/core/agent-loop.js +190 -190
- package/core/ai-provider.js +298 -261
- package/core/automation.js +523 -523
- package/core/brand-analyst.js +101 -0
- package/core/channels.js +167 -167
- package/core/dashboard.js +230 -230
- package/core/database.js +135 -37
- package/core/eia-monitor.js +3 -1
- package/core/engine.js +648 -636
- package/core/gateway.js +447 -447
- package/core/learning.js +214 -214
- package/core/license.js +113 -0
- package/core/marketplace-adapter.js +168 -168
- package/core/memory.js +190 -190
- package/core/migrations/001-initial-schema.sql +1 -1
- package/core/queue.js +120 -120
- package/core/self-healer.js +314 -314
- package/core/unified-product.js +214 -214
- package/core/vision-service.js +113 -113
- package/index.js +217 -174
- package/modules/crm/sentiment-crm.js +231 -231
- package/modules/healer/listing-healer.js +201 -201
- package/modules/oracle/predictor.js +214 -214
- package/modules/researcher/agent.js +169 -169
- package/modules/team/agents/base.js +92 -92
- package/modules/team/agents/dev.js +33 -33
- package/modules/team/agents/josh.js +40 -40
- package/modules/team/agents/marketing.js +33 -33
- package/modules/team/agents/milo.js +36 -36
- package/modules/team/index.js +78 -78
- package/modules/team/shared-memory.js +87 -87
- package/modules/war-room/competitor-tracker.js +250 -250
- package/modules/war-room/pricing-engine.js +308 -308
- package/nodes/warehouse.js +238 -238
- package/onboard.js +1 -1
- package/package.json +7 -5
- package/platforms/pttavm.js +14 -14
- package/plugins/vantuz/index.js +528 -528
- package/plugins/vantuz/memory/hippocampus.js +465 -465
- package/plugins/vantuz/package.json +20 -20
- package/plugins/vantuz/platforms/_template.js +118 -118
- package/plugins/vantuz/platforms/amazon.js +236 -236
- package/plugins/vantuz/platforms/ciceksepeti.js +166 -166
- package/plugins/vantuz/platforms/hepsiburada.js +180 -180
- package/plugins/vantuz/platforms/index.js +165 -165
- package/plugins/vantuz/platforms/n11.js +229 -229
- package/plugins/vantuz/platforms/pazarama.js +154 -154
- package/plugins/vantuz/platforms/pttavm.js +127 -127
- package/plugins/vantuz/platforms/trendyol.js +326 -326
- package/plugins/vantuz/services/alerts.js +253 -253
- package/plugins/vantuz/services/license.js +34 -34
- package/plugins/vantuz/services/scheduler.js +232 -232
- package/plugins/vantuz/tools/analytics.js +152 -152
- package/plugins/vantuz/tools/crossborder.js +187 -187
- package/plugins/vantuz/tools/nl-parser.js +211 -211
- package/plugins/vantuz/tools/product.js +110 -110
- package/plugins/vantuz/tools/quick-report.js +175 -175
- package/plugins/vantuz/tools/repricer.js +314 -314
- package/plugins/vantuz/tools/sentiment.js +115 -115
- package/plugins/vantuz/tools/vision.js +257 -257
- package/private.pem +28 -0
- package/public.pem +9 -0
- package/server/app.js +260 -260
- package/server/public/index.html +514 -514
- package/start.bat +33 -33
- package/vantuz.sqlite +0 -0
|
@@ -1,62 +1,62 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* π TRENDYOL API v2 Entegrasyonu
|
|
3
|
-
* developers.trendyol.com/v2.0
|
|
4
|
-
*
|
|
5
|
-
* Base URL: https://apigw.trendyol.com/integration
|
|
6
|
-
* Auth: Basic (API Key:API Secret β Base64)
|
|
7
|
-
* User-Agent: {SellerId} - SelfIntegration
|
|
8
|
-
* Rate Limit: 50 req / 10 sec per endpoint
|
|
9
|
-
*/
|
|
10
|
-
|
|
1
|
+
/**
|
|
2
|
+
* π TRENDYOL API v2 Entegrasyonu
|
|
3
|
+
* developers.trendyol.com/v2.0
|
|
4
|
+
*
|
|
5
|
+
* Base URL: https://apigw.trendyol.com/integration
|
|
6
|
+
* Auth: Basic (API Key:API Secret β Base64)
|
|
7
|
+
* User-Agent: {SellerId} - SelfIntegration
|
|
8
|
+
* Rate Limit: 50 req / 10 sec per endpoint
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
11
|
import axios from 'axios';
|
|
12
12
|
import { log } from '../../../core/ai-provider.js';
|
|
13
13
|
import { requestWithRetry } from './_request.js';
|
|
14
|
-
|
|
15
|
-
const BASE_URL = 'https://apigw.trendyol.com/integration';
|
|
16
|
-
const STAGE_URL = 'https://stageapigw.trendyol.com/integration';
|
|
17
|
-
|
|
18
|
-
export class TrendyolAPI {
|
|
19
|
-
constructor(config) {
|
|
20
|
-
this.supplierId = config.supplierId;
|
|
21
|
-
this.apiKey = config.apiKey;
|
|
22
|
-
this.apiSecret = config.apiSecret;
|
|
23
|
-
this.isStage = config.isStage || false;
|
|
24
|
-
|
|
25
|
-
this.baseUrl = this.isStage ? STAGE_URL : BASE_URL;
|
|
26
|
-
this.auth = Buffer.from(`${this.apiKey}:${this.apiSecret}`).toString('base64');
|
|
27
|
-
|
|
28
|
-
// DEBUG: Interceptor to see what's actually being sent
|
|
29
|
-
this.client = axios.create();
|
|
30
|
-
this.client.interceptors.request.use(request => {
|
|
31
|
-
log('DEBUG', '[Axios Final Request]', {
|
|
32
|
-
url: request.url,
|
|
33
|
-
method: request.method,
|
|
34
|
-
headers: request.headers
|
|
35
|
-
});
|
|
36
|
-
return request;
|
|
37
|
-
});
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
_headers() {
|
|
41
|
-
const headers = {
|
|
42
|
-
'Authorization': `Basic ${this.auth}`,
|
|
43
|
-
// 'Content-Type': 'application/json', // REMOVED: Managed in _request
|
|
44
|
-
'User-Agent': `${this.supplierId} - SelfIntegration`,
|
|
45
|
-
'X-Correlation-Id': `${this.supplierId}-${Date.now()}`
|
|
46
|
-
};
|
|
47
|
-
return headers;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
async _request(method, endpoint, data = null, params = null) {
|
|
51
|
-
try {
|
|
52
|
-
const url = `${this.baseUrl}${endpoint}`;
|
|
53
|
-
log('DEBUG', `[Trendyol] ${method} ${url}`);
|
|
54
|
-
|
|
55
|
-
const headers = this._headers();
|
|
56
|
-
if (method === 'POST' || method === 'PUT') {
|
|
57
|
-
headers['Content-Type'] = 'application/json';
|
|
58
|
-
}
|
|
59
|
-
|
|
14
|
+
|
|
15
|
+
const BASE_URL = 'https://apigw.trendyol.com/integration';
|
|
16
|
+
const STAGE_URL = 'https://stageapigw.trendyol.com/integration';
|
|
17
|
+
|
|
18
|
+
export class TrendyolAPI {
|
|
19
|
+
constructor(config) {
|
|
20
|
+
this.supplierId = config.supplierId;
|
|
21
|
+
this.apiKey = config.apiKey;
|
|
22
|
+
this.apiSecret = config.apiSecret;
|
|
23
|
+
this.isStage = config.isStage || false;
|
|
24
|
+
|
|
25
|
+
this.baseUrl = this.isStage ? STAGE_URL : BASE_URL;
|
|
26
|
+
this.auth = Buffer.from(`${this.apiKey}:${this.apiSecret}`).toString('base64');
|
|
27
|
+
|
|
28
|
+
// DEBUG: Interceptor to see what's actually being sent
|
|
29
|
+
this.client = axios.create();
|
|
30
|
+
this.client.interceptors.request.use(request => {
|
|
31
|
+
log('DEBUG', '[Axios Final Request]', {
|
|
32
|
+
url: request.url,
|
|
33
|
+
method: request.method,
|
|
34
|
+
headers: request.headers
|
|
35
|
+
});
|
|
36
|
+
return request;
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
_headers() {
|
|
41
|
+
const headers = {
|
|
42
|
+
'Authorization': `Basic ${this.auth}`,
|
|
43
|
+
// 'Content-Type': 'application/json', // REMOVED: Managed in _request
|
|
44
|
+
'User-Agent': `${this.supplierId} - SelfIntegration`,
|
|
45
|
+
'X-Correlation-Id': `${this.supplierId}-${Date.now()}`
|
|
46
|
+
};
|
|
47
|
+
return headers;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
async _request(method, endpoint, data = null, params = null) {
|
|
51
|
+
try {
|
|
52
|
+
const url = `${this.baseUrl}${endpoint}`;
|
|
53
|
+
log('DEBUG', `[Trendyol] ${method} ${url}`);
|
|
54
|
+
|
|
55
|
+
const headers = this._headers();
|
|
56
|
+
if (method === 'POST' || method === 'PUT') {
|
|
57
|
+
headers['Content-Type'] = 'application/json';
|
|
58
|
+
}
|
|
59
|
+
|
|
60
60
|
const response = await requestWithRetry(this.client, {
|
|
61
61
|
method,
|
|
62
62
|
url,
|
|
@@ -70,273 +70,273 @@ export class TrendyolAPI {
|
|
|
70
70
|
maxDelayMs: 4000
|
|
71
71
|
});
|
|
72
72
|
return { success: true, data: response.data };
|
|
73
|
-
} catch (error) {
|
|
74
|
-
const errorMsg = error.response?.data?.errors?.[0]?.message || error.message;
|
|
75
|
-
const statusCode = error.response?.status;
|
|
76
|
-
|
|
77
|
-
console.error(`[Trendyol] API HatasΔ± (${statusCode}): ${errorMsg}`);
|
|
78
|
-
if (error.response?.data) {
|
|
79
|
-
try {
|
|
80
|
-
const dataStr = typeof error.response.data === 'string'
|
|
81
|
-
? error.response.data.substring(0, 200)
|
|
82
|
-
: JSON.stringify(error.response.data).substring(0, 200);
|
|
83
|
-
console.error('[Trendyol] Hata DetayΔ±:', dataStr);
|
|
84
|
-
} catch (e) { }
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
return {
|
|
88
|
-
success: false,
|
|
89
|
-
error: errorMsg,
|
|
90
|
-
status: statusCode
|
|
91
|
-
};
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
96
|
-
// ΓRΓN Δ°ΕLEMLERΔ°
|
|
97
|
-
// Prefix: /product/sellers/{sellerId}/...
|
|
98
|
-
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
99
|
-
|
|
100
|
-
async getProducts(params = {}) {
|
|
101
|
-
const { page = 0, size = 50, barcode, approved, onSale, date } = params;
|
|
102
|
-
return await this._request('GET', `/product/sellers/${this.supplierId}/products`, null, {
|
|
103
|
-
page, size, barcode, approved, onSale, date
|
|
104
|
-
});
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
async getProductByBarcode(barcode) {
|
|
108
|
-
const result = await this.getProducts({ barcode });
|
|
109
|
-
if (result.success && result.data.content?.length > 0) {
|
|
110
|
-
return { success: true, data: result.data.content[0] };
|
|
111
|
-
}
|
|
112
|
-
return { success: false, error: 'ΓrΓΌn bulunamadΔ±' };
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
async createProducts(products) {
|
|
116
|
-
// items: [{ barcode, title, productMainId, brandId, categoryId, ... }]
|
|
117
|
-
return await this._request('POST', `/product/sellers/${this.supplierId}/v2/products`, { items: products });
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
async updateProducts(products) {
|
|
121
|
-
return await this._request('PUT', `/product/sellers/${this.supplierId}/v2/products`, { items: products });
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
async deleteProducts(barcodes) {
|
|
125
|
-
const items = barcodes.map(barcode => ({ barcode }));
|
|
126
|
-
return await this._request('DELETE', `/product/sellers/${this.supplierId}/products`, { items });
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
async getBatchRequestResult(batchRequestId) {
|
|
130
|
-
return await this._request('GET', `/product/sellers/${this.supplierId}/products/batch-requests/${batchRequestId}`);
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
134
|
-
// FΔ°YAT & STOK
|
|
135
|
-
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
136
|
-
|
|
137
|
-
async updatePriceAndStock(items) {
|
|
138
|
-
// items: [{ barcode, quantity, salePrice, listPrice }]
|
|
139
|
-
return await this._request('POST', `/product/sellers/${this.supplierId}/products/price-and-inventory`, { items });
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
async updatePrice(barcode, salePrice, listPrice = null) {
|
|
143
|
-
return await this.updatePriceAndStock([{
|
|
144
|
-
barcode,
|
|
145
|
-
salePrice,
|
|
146
|
-
listPrice: listPrice || salePrice
|
|
147
|
-
}]);
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
async updateStock(barcode, quantity) {
|
|
151
|
-
return await this.updatePriceAndStock([{ barcode, quantity }]);
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
async bulkPriceUpdate(updates) {
|
|
155
|
-
// updates: [{ barcode, price, listPrice? }]
|
|
156
|
-
const items = updates.map(u => ({
|
|
157
|
-
barcode: u.barcode,
|
|
158
|
-
salePrice: u.price,
|
|
159
|
-
listPrice: u.listPrice || u.price
|
|
160
|
-
}));
|
|
161
|
-
return await this.updatePriceAndStock(items);
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
165
|
-
// SΔ°PARΔ°Ε Δ°ΕLEMLERΔ°
|
|
166
|
-
// Prefix: /order/sellers/{sellerId}/...
|
|
167
|
-
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
168
|
-
|
|
169
|
-
async getOrders(params = {}) {
|
|
170
|
-
const {
|
|
171
|
-
status,
|
|
172
|
-
startDate = new Date(Date.now() - 30 * 24 * 60 * 60 * 1000).getTime(),
|
|
173
|
-
endDate = Date.now(),
|
|
174
|
-
page = 0,
|
|
175
|
-
size = 50,
|
|
176
|
-
orderNumber
|
|
177
|
-
} = params;
|
|
178
|
-
|
|
179
|
-
return await this._request('GET', `/order/sellers/${this.supplierId}/orders`, null, {
|
|
180
|
-
status, startDate, endDate, page, size, orderNumber,
|
|
181
|
-
orderByDirection: 'DESC',
|
|
182
|
-
orderByField: 'PackageLastModifiedDate'
|
|
183
|
-
});
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
async getOrderByNumber(orderNumber) {
|
|
187
|
-
const result = await this.getOrders({ orderNumber });
|
|
188
|
-
if (result.success && result.data.content?.length > 0) {
|
|
189
|
-
return { success: true, data: result.data.content[0] };
|
|
190
|
-
}
|
|
191
|
-
return { success: false, error: 'SipariΕ bulunamadΔ±' };
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
async updateOrderStatus(lines, status, params = {}) {
|
|
195
|
-
const endpoint = `/order/sellers/${this.supplierId}/shipment-packages`;
|
|
196
|
-
|
|
197
|
-
if (status === 'Picking') {
|
|
198
|
-
return await this._request('PUT', endpoint, { lines, status: 'Picking' });
|
|
199
|
-
} else if (status === 'Invoiced') {
|
|
200
|
-
return await this._request('PUT', endpoint, {
|
|
201
|
-
lines,
|
|
202
|
-
status: 'Invoiced',
|
|
203
|
-
invoiceNumber: params.invoiceNumber
|
|
204
|
-
});
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
return { success: false, error: 'GeΓ§ersiz durum' };
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
async shipOrder(shipmentPackageId, trackingNumber, cargoKey = 'YURTICI') {
|
|
211
|
-
return await this._request('PUT',
|
|
212
|
-
`/order/sellers/${this.supplierId}/shipment-packages/${shipmentPackageId}`,
|
|
213
|
-
{
|
|
214
|
-
trackingNumber,
|
|
215
|
-
cargoProviderCode: cargoKey,
|
|
216
|
-
status: 'Shipped'
|
|
217
|
-
}
|
|
218
|
-
);
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
async getShipmentProviders() {
|
|
222
|
-
return await this._request('GET', '/shipment-providers');
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
226
|
-
// KATEGORΔ° & MARKA
|
|
227
|
-
// Prefix: /product/...
|
|
228
|
-
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
229
|
-
|
|
230
|
-
async getCategories() {
|
|
231
|
-
return await this._request('GET', '/product/product-categories');
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
async getCategoryAttributes(categoryId) {
|
|
235
|
-
return await this._request('GET', `/product/product-categories/${categoryId}/attributes`);
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
async searchBrands(name) {
|
|
239
|
-
return await this._request('GET', '/product/brands', null, { name });
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
async getBrandsByCategory(categoryId) {
|
|
243
|
-
return await this._request('GET', `/product/product-categories/${categoryId}/brands`);
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
247
|
-
// ADRES BΔ°LGΔ°LERΔ°
|
|
248
|
-
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
249
|
-
|
|
250
|
-
async getAddresses() {
|
|
251
|
-
return await this._request('GET', `/sellers/${this.supplierId}/addresses`);
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
255
|
-
// RAKΔ°P ANALΔ°ZΔ°
|
|
256
|
-
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
257
|
-
|
|
258
|
-
async getCompetitorPrices(barcode) {
|
|
259
|
-
try {
|
|
260
|
-
return {
|
|
261
|
-
success: true,
|
|
262
|
-
competitors: [],
|
|
263
|
-
message: 'Rakip analizi iΓ§in web_search tool kullanΔ±n'
|
|
264
|
-
};
|
|
265
|
-
} catch (error) {
|
|
266
|
-
return { success: false, error: error.message };
|
|
267
|
-
}
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
271
|
-
// SORU & CEVAP
|
|
272
|
-
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
273
|
-
|
|
274
|
-
async getQuestions(params = {}) {
|
|
275
|
-
const { status = 'WAITING_FOR_ANSWER', page = 0, size = 50 } = params;
|
|
276
|
-
return await this._request('GET', `/order/sellers/${this.supplierId}/questions/filter`, null, {
|
|
277
|
-
status, page, size
|
|
278
|
-
});
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
async answerQuestion(questionId, answer) {
|
|
282
|
-
return await this._request('POST', `/order/sellers/${this.supplierId}/questions/${questionId}/answers`, {
|
|
283
|
-
text: answer
|
|
284
|
-
});
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
288
|
-
// YARDIMCI METODLAR
|
|
289
|
-
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
290
|
-
|
|
291
|
-
async testConnection() {
|
|
292
|
-
const result = await this.getProducts({ page: 0, size: 1 });
|
|
293
|
-
return result.success;
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
isConnected() {
|
|
297
|
-
return !!(this.supplierId && this.apiKey && this.apiSecret);
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
formatProduct(raw) {
|
|
301
|
-
return {
|
|
302
|
-
id: raw.id,
|
|
303
|
-
barcode: raw.barcode,
|
|
304
|
-
title: raw.title,
|
|
305
|
-
brand: raw.brand,
|
|
306
|
-
category: raw.categoryName,
|
|
307
|
-
price: raw.salePrice,
|
|
308
|
-
listPrice: raw.listPrice,
|
|
309
|
-
stock: raw.quantity,
|
|
310
|
-
images: raw.images?.map(i => i.url) || [],
|
|
311
|
-
approved: raw.approved,
|
|
312
|
-
onSale: raw.onSale,
|
|
313
|
-
url: `https://www.trendyol.com/p/-p-${raw.id}`
|
|
314
|
-
};
|
|
315
|
-
}
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
// Singleton instance
|
|
319
|
-
let instance = null;
|
|
320
|
-
|
|
321
|
-
export const trendyolApi = {
|
|
322
|
-
init(config) {
|
|
323
|
-
instance = new TrendyolAPI(config);
|
|
324
|
-
return instance;
|
|
325
|
-
},
|
|
326
|
-
|
|
327
|
-
getInstance() {
|
|
328
|
-
return instance;
|
|
329
|
-
},
|
|
330
|
-
|
|
331
|
-
isConnected() {
|
|
332
|
-
return instance?.isConnected() || false;
|
|
333
|
-
},
|
|
334
|
-
|
|
335
|
-
// Proxy methods
|
|
336
|
-
async getProducts(params) { return instance?.getProducts(params); },
|
|
337
|
-
async updatePrice(barcode, price) { return instance?.updatePrice(barcode, price); },
|
|
338
|
-
async updateStock(barcode, qty) { return instance?.updateStock(barcode, qty); },
|
|
339
|
-
async getOrders(params) { return instance?.getOrders(params); },
|
|
340
|
-
async getCompetitors(barcode) { return instance?.getCompetitorPrices(barcode); },
|
|
341
|
-
async testConnection() { return instance?.testConnection(); }
|
|
342
|
-
};
|
|
73
|
+
} catch (error) {
|
|
74
|
+
const errorMsg = error.response?.data?.errors?.[0]?.message || error.message;
|
|
75
|
+
const statusCode = error.response?.status;
|
|
76
|
+
|
|
77
|
+
console.error(`[Trendyol] API HatasΔ± (${statusCode}): ${errorMsg}`);
|
|
78
|
+
if (error.response?.data) {
|
|
79
|
+
try {
|
|
80
|
+
const dataStr = typeof error.response.data === 'string'
|
|
81
|
+
? error.response.data.substring(0, 200)
|
|
82
|
+
: JSON.stringify(error.response.data).substring(0, 200);
|
|
83
|
+
console.error('[Trendyol] Hata DetayΔ±:', dataStr);
|
|
84
|
+
} catch (e) { }
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
return {
|
|
88
|
+
success: false,
|
|
89
|
+
error: errorMsg,
|
|
90
|
+
status: statusCode
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
96
|
+
// ΓRΓN Δ°ΕLEMLERΔ°
|
|
97
|
+
// Prefix: /product/sellers/{sellerId}/...
|
|
98
|
+
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
99
|
+
|
|
100
|
+
async getProducts(params = {}) {
|
|
101
|
+
const { page = 0, size = 50, barcode, approved, onSale, date } = params;
|
|
102
|
+
return await this._request('GET', `/product/sellers/${this.supplierId}/products`, null, {
|
|
103
|
+
page, size, barcode, approved, onSale, date
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
async getProductByBarcode(barcode) {
|
|
108
|
+
const result = await this.getProducts({ barcode });
|
|
109
|
+
if (result.success && result.data.content?.length > 0) {
|
|
110
|
+
return { success: true, data: result.data.content[0] };
|
|
111
|
+
}
|
|
112
|
+
return { success: false, error: 'ΓrΓΌn bulunamadΔ±' };
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
async createProducts(products) {
|
|
116
|
+
// items: [{ barcode, title, productMainId, brandId, categoryId, ... }]
|
|
117
|
+
return await this._request('POST', `/product/sellers/${this.supplierId}/v2/products`, { items: products });
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
async updateProducts(products) {
|
|
121
|
+
return await this._request('PUT', `/product/sellers/${this.supplierId}/v2/products`, { items: products });
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
async deleteProducts(barcodes) {
|
|
125
|
+
const items = barcodes.map(barcode => ({ barcode }));
|
|
126
|
+
return await this._request('DELETE', `/product/sellers/${this.supplierId}/products`, { items });
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
async getBatchRequestResult(batchRequestId) {
|
|
130
|
+
return await this._request('GET', `/product/sellers/${this.supplierId}/products/batch-requests/${batchRequestId}`);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
134
|
+
// FΔ°YAT & STOK
|
|
135
|
+
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
136
|
+
|
|
137
|
+
async updatePriceAndStock(items) {
|
|
138
|
+
// items: [{ barcode, quantity, salePrice, listPrice }]
|
|
139
|
+
return await this._request('POST', `/product/sellers/${this.supplierId}/products/price-and-inventory`, { items });
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
async updatePrice(barcode, salePrice, listPrice = null) {
|
|
143
|
+
return await this.updatePriceAndStock([{
|
|
144
|
+
barcode,
|
|
145
|
+
salePrice,
|
|
146
|
+
listPrice: listPrice || salePrice
|
|
147
|
+
}]);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
async updateStock(barcode, quantity) {
|
|
151
|
+
return await this.updatePriceAndStock([{ barcode, quantity }]);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
async bulkPriceUpdate(updates) {
|
|
155
|
+
// updates: [{ barcode, price, listPrice? }]
|
|
156
|
+
const items = updates.map(u => ({
|
|
157
|
+
barcode: u.barcode,
|
|
158
|
+
salePrice: u.price,
|
|
159
|
+
listPrice: u.listPrice || u.price
|
|
160
|
+
}));
|
|
161
|
+
return await this.updatePriceAndStock(items);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
165
|
+
// SΔ°PARΔ°Ε Δ°ΕLEMLERΔ°
|
|
166
|
+
// Prefix: /order/sellers/{sellerId}/...
|
|
167
|
+
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
168
|
+
|
|
169
|
+
async getOrders(params = {}) {
|
|
170
|
+
const {
|
|
171
|
+
status,
|
|
172
|
+
startDate = new Date(Date.now() - 30 * 24 * 60 * 60 * 1000).getTime(),
|
|
173
|
+
endDate = Date.now(),
|
|
174
|
+
page = 0,
|
|
175
|
+
size = 50,
|
|
176
|
+
orderNumber
|
|
177
|
+
} = params;
|
|
178
|
+
|
|
179
|
+
return await this._request('GET', `/order/sellers/${this.supplierId}/orders`, null, {
|
|
180
|
+
status, startDate, endDate, page, size, orderNumber,
|
|
181
|
+
orderByDirection: 'DESC',
|
|
182
|
+
orderByField: 'PackageLastModifiedDate'
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
async getOrderByNumber(orderNumber) {
|
|
187
|
+
const result = await this.getOrders({ orderNumber });
|
|
188
|
+
if (result.success && result.data.content?.length > 0) {
|
|
189
|
+
return { success: true, data: result.data.content[0] };
|
|
190
|
+
}
|
|
191
|
+
return { success: false, error: 'SipariΕ bulunamadΔ±' };
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
async updateOrderStatus(lines, status, params = {}) {
|
|
195
|
+
const endpoint = `/order/sellers/${this.supplierId}/shipment-packages`;
|
|
196
|
+
|
|
197
|
+
if (status === 'Picking') {
|
|
198
|
+
return await this._request('PUT', endpoint, { lines, status: 'Picking' });
|
|
199
|
+
} else if (status === 'Invoiced') {
|
|
200
|
+
return await this._request('PUT', endpoint, {
|
|
201
|
+
lines,
|
|
202
|
+
status: 'Invoiced',
|
|
203
|
+
invoiceNumber: params.invoiceNumber
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
return { success: false, error: 'GeΓ§ersiz durum' };
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
async shipOrder(shipmentPackageId, trackingNumber, cargoKey = 'YURTICI') {
|
|
211
|
+
return await this._request('PUT',
|
|
212
|
+
`/order/sellers/${this.supplierId}/shipment-packages/${shipmentPackageId}`,
|
|
213
|
+
{
|
|
214
|
+
trackingNumber,
|
|
215
|
+
cargoProviderCode: cargoKey,
|
|
216
|
+
status: 'Shipped'
|
|
217
|
+
}
|
|
218
|
+
);
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
async getShipmentProviders() {
|
|
222
|
+
return await this._request('GET', '/shipment-providers');
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
226
|
+
// KATEGORΔ° & MARKA
|
|
227
|
+
// Prefix: /product/...
|
|
228
|
+
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
229
|
+
|
|
230
|
+
async getCategories() {
|
|
231
|
+
return await this._request('GET', '/product/product-categories');
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
async getCategoryAttributes(categoryId) {
|
|
235
|
+
return await this._request('GET', `/product/product-categories/${categoryId}/attributes`);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
async searchBrands(name) {
|
|
239
|
+
return await this._request('GET', '/product/brands', null, { name });
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
async getBrandsByCategory(categoryId) {
|
|
243
|
+
return await this._request('GET', `/product/product-categories/${categoryId}/brands`);
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
247
|
+
// ADRES BΔ°LGΔ°LERΔ°
|
|
248
|
+
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
249
|
+
|
|
250
|
+
async getAddresses() {
|
|
251
|
+
return await this._request('GET', `/sellers/${this.supplierId}/addresses`);
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
255
|
+
// RAKΔ°P ANALΔ°ZΔ°
|
|
256
|
+
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
257
|
+
|
|
258
|
+
async getCompetitorPrices(barcode) {
|
|
259
|
+
try {
|
|
260
|
+
return {
|
|
261
|
+
success: true,
|
|
262
|
+
competitors: [],
|
|
263
|
+
message: 'Rakip analizi iΓ§in web_search tool kullanΔ±n'
|
|
264
|
+
};
|
|
265
|
+
} catch (error) {
|
|
266
|
+
return { success: false, error: error.message };
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
271
|
+
// SORU & CEVAP
|
|
272
|
+
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
273
|
+
|
|
274
|
+
async getQuestions(params = {}) {
|
|
275
|
+
const { status = 'WAITING_FOR_ANSWER', page = 0, size = 50 } = params;
|
|
276
|
+
return await this._request('GET', `/order/sellers/${this.supplierId}/questions/filter`, null, {
|
|
277
|
+
status, page, size
|
|
278
|
+
});
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
async answerQuestion(questionId, answer) {
|
|
282
|
+
return await this._request('POST', `/order/sellers/${this.supplierId}/questions/${questionId}/answers`, {
|
|
283
|
+
text: answer
|
|
284
|
+
});
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
288
|
+
// YARDIMCI METODLAR
|
|
289
|
+
// βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
290
|
+
|
|
291
|
+
async testConnection() {
|
|
292
|
+
const result = await this.getProducts({ page: 0, size: 1 });
|
|
293
|
+
return result.success;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
isConnected() {
|
|
297
|
+
return !!(this.supplierId && this.apiKey && this.apiSecret);
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
formatProduct(raw) {
|
|
301
|
+
return {
|
|
302
|
+
id: raw.id,
|
|
303
|
+
barcode: raw.barcode,
|
|
304
|
+
title: raw.title,
|
|
305
|
+
brand: raw.brand,
|
|
306
|
+
category: raw.categoryName,
|
|
307
|
+
price: raw.salePrice,
|
|
308
|
+
listPrice: raw.listPrice,
|
|
309
|
+
stock: raw.quantity,
|
|
310
|
+
images: raw.images?.map(i => i.url) || [],
|
|
311
|
+
approved: raw.approved,
|
|
312
|
+
onSale: raw.onSale,
|
|
313
|
+
url: `https://www.trendyol.com/p/-p-${raw.id}`
|
|
314
|
+
};
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
// Singleton instance
|
|
319
|
+
let instance = null;
|
|
320
|
+
|
|
321
|
+
export const trendyolApi = {
|
|
322
|
+
init(config) {
|
|
323
|
+
instance = new TrendyolAPI(config);
|
|
324
|
+
return instance;
|
|
325
|
+
},
|
|
326
|
+
|
|
327
|
+
getInstance() {
|
|
328
|
+
return instance;
|
|
329
|
+
},
|
|
330
|
+
|
|
331
|
+
isConnected() {
|
|
332
|
+
return instance?.isConnected() || false;
|
|
333
|
+
},
|
|
334
|
+
|
|
335
|
+
// Proxy methods
|
|
336
|
+
async getProducts(params) { return instance?.getProducts(params); },
|
|
337
|
+
async updatePrice(barcode, price) { return instance?.updatePrice(barcode, price); },
|
|
338
|
+
async updateStock(barcode, qty) { return instance?.updateStock(barcode, qty); },
|
|
339
|
+
async getOrders(params) { return instance?.getOrders(params); },
|
|
340
|
+
async getCompetitors(barcode) { return instance?.getCompetitorPrices(barcode); },
|
|
341
|
+
async testConnection() { return instance?.testConnection(); }
|
|
342
|
+
};
|