vantuz 3.1.3 → 3.1.5

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vantuz",
3
- "version": "3.1.3",
3
+ "version": "3.1.5",
4
4
  "description": "Yapay Zeka Destekli E-Ticaret Yönetim Platformu - 7 Pazaryeri + WhatsApp/Telegram",
5
5
  "type": "module",
6
6
  "main": "cli.js",
@@ -10,6 +10,7 @@
10
10
  */
11
11
 
12
12
  import axios from 'axios';
13
+ import { log } from '../../../core/ai-provider.js';
13
14
 
14
15
  const BASE_URL = 'https://api.trendyol.com/sapigw';
15
16
  const STAGE_URL = 'https://stageapi.trendyol.com/stagesapigw'; // Test ortamı
@@ -42,254 +43,253 @@ export class TrendyolAPI {
42
43
  data,
43
44
  params
44
45
  });
45
- });
46
- return { success: true, data: response.data };
47
- } catch(error) {
48
- const errorMsg = error.response?.data?.errors?.[0]?.message || error.message;
49
- const statusCode = error.response?.status;
50
-
51
- console.error(`[Trendyol] API Hatası (${statusCode}): ${errorMsg}`);
52
- if (error.response?.data) {
53
- try {
54
- console.error('[Trendyol] Hata Detayı:', JSON.stringify(error.response.data));
55
- } catch (e) { }
46
+ return { success: true, data: response.data };
47
+ } catch (error) {
48
+ const errorMsg = error.response?.data?.errors?.[0]?.message || error.message;
49
+ const statusCode = error.response?.status;
50
+
51
+ console.error(`[Trendyol] API Hatası (${statusCode}): ${errorMsg}`);
52
+ if (error.response?.data) {
53
+ try {
54
+ console.error('[Trendyol] Hata Detayı:', JSON.stringify(error.response.data));
55
+ } catch (e) { }
56
+ }
57
+
58
+ return {
59
+ success: false,
60
+ error: errorMsg,
61
+ status: statusCode
62
+ };
56
63
  }
57
-
58
- return {
59
- success: false,
60
- error: errorMsg,
61
- status: statusCode
62
- };
63
64
  }
64
- }
65
65
 
66
66
  // ═══════════════════════════════════════════════════════════════════════════
67
67
  // ÜRÜN İŞLEMLERİ
68
68
  // ═══════════════════════════════════════════════════════════════════════════
69
69
 
70
70
  async getProducts(params = {}) {
71
- const { page = 0, size = 50, barcode, approved, onSale } = params;
72
- return await this._request('GET', `/suppliers/${this.supplierId}/products`, null, {
73
- page, size, barcode, approved, onSale
74
- });
75
- }
71
+ const { page = 0, size = 50, barcode, approved, onSale } = params;
72
+ return await this._request('GET', `/suppliers/${this.supplierId}/products`, null, {
73
+ page, size, barcode, approved, onSale
74
+ });
75
+ }
76
76
 
77
77
  async getProductByBarcode(barcode) {
78
- const result = await this.getProducts({ barcode });
79
- if (result.success && result.data.content?.length > 0) {
80
- return { success: true, data: result.data.content[0] };
78
+ const result = await this.getProducts({ barcode });
79
+ if (result.success && result.data.content?.length > 0) {
80
+ return { success: true, data: result.data.content[0] };
81
+ }
82
+ return { success: false, error: 'Ürün bulunamadı' };
81
83
  }
82
- return { success: false, error: 'Ürün bulunamadı' };
83
- }
84
84
 
85
85
  async createProducts(products) {
86
- // items: [{ barcode, title, productMainId, brandId, categoryId, ... }]
87
- return await this._request('POST', `/suppliers/${this.supplierId}/v2/products`, { items: products });
88
- }
86
+ // items: [{ barcode, title, productMainId, brandId, categoryId, ... }]
87
+ return await this._request('POST', `/suppliers/${this.supplierId}/v2/products`, { items: products });
88
+ }
89
89
 
90
90
  async updateProducts(products) {
91
- return await this._request('PUT', `/suppliers/${this.supplierId}/v2/products`, { items: products });
92
- }
91
+ return await this._request('PUT', `/suppliers/${this.supplierId}/v2/products`, { items: products });
92
+ }
93
93
 
94
94
  async deleteProducts(barcodes) {
95
- const items = barcodes.map(barcode => ({ barcode }));
96
- return await this._request('DELETE', `/suppliers/${this.supplierId}/products`, { items });
97
- }
95
+ const items = barcodes.map(barcode => ({ barcode }));
96
+ return await this._request('DELETE', `/suppliers/${this.supplierId}/products`, { items });
97
+ }
98
98
 
99
99
  // ═══════════════════════════════════════════════════════════════════════════
100
100
  // FİYAT & STOK
101
101
  // ═══════════════════════════════════════════════════════════════════════════
102
102
 
103
103
  async updatePriceAndStock(items) {
104
- // items: [{ barcode, quantity, salePrice, listPrice }]
105
- return await this._request('POST', `/suppliers/${this.supplierId}/products/price-and-inventory`, { items });
106
- }
104
+ // items: [{ barcode, quantity, salePrice, listPrice }]
105
+ return await this._request('POST', `/suppliers/${this.supplierId}/products/price-and-inventory`, { items });
106
+ }
107
107
 
108
108
  async updatePrice(barcode, salePrice, listPrice = null) {
109
- return await this.updatePriceAndStock([{
110
- barcode,
111
- salePrice,
112
- listPrice: listPrice || salePrice
113
- }]);
114
- }
109
+ return await this.updatePriceAndStock([{
110
+ barcode,
111
+ salePrice,
112
+ listPrice: listPrice || salePrice
113
+ }]);
114
+ }
115
115
 
116
116
  async updateStock(barcode, quantity) {
117
- return await this.updatePriceAndStock([{ barcode, quantity }]);
118
- }
117
+ return await this.updatePriceAndStock([{ barcode, quantity }]);
118
+ }
119
119
 
120
120
  async bulkPriceUpdate(updates) {
121
- // updates: [{ barcode, price, listPrice? }]
122
- const items = updates.map(u => ({
123
- barcode: u.barcode,
124
- salePrice: u.price,
125
- listPrice: u.listPrice || u.price
126
- }));
127
- return await this.updatePriceAndStock(items);
128
- }
121
+ // updates: [{ barcode, price, listPrice? }]
122
+ const items = updates.map(u => ({
123
+ barcode: u.barcode,
124
+ salePrice: u.price,
125
+ listPrice: u.listPrice || u.price
126
+ }));
127
+ return await this.updatePriceAndStock(items);
128
+ }
129
129
 
130
130
  // ═══════════════════════════════════════════════════════════════════════════
131
131
  // SİPARİŞ İŞLEMLERİ
132
132
  // ═══════════════════════════════════════════════════════════════════════════
133
133
 
134
134
  async getOrders(params = {}) {
135
- const {
136
- status,
137
- startDate = new Date(Date.now() - 30 * 24 * 60 * 60 * 1000).getTime(), // Son 30 gün
138
- endDate = Date.now(),
139
- page = 0,
140
- size = 50,
141
- orderNumber
142
- } = params;
143
-
144
- return await this._request('GET', `/suppliers/${this.supplierId}/orders`, null, {
145
- status, startDate, endDate, page, size, orderNumber, orderByDirection: 'DESC', orderByField: 'PackageLastModifiedDate'
146
- });
147
- }
135
+ const {
136
+ status,
137
+ startDate = new Date(Date.now() - 30 * 24 * 60 * 60 * 1000).getTime(), // Son 30 gün
138
+ endDate = Date.now(),
139
+ page = 0,
140
+ size = 50,
141
+ orderNumber
142
+ } = params;
143
+
144
+ return await this._request('GET', `/suppliers/${this.supplierId}/orders`, null, {
145
+ status, startDate, endDate, page, size, orderNumber, orderByDirection: 'DESC', orderByField: 'PackageLastModifiedDate'
146
+ });
147
+ }
148
148
 
149
149
  async getOrderByNumber(orderNumber) {
150
- const result = await this.getOrders({ orderNumber });
151
- if (result.success && result.data.content?.length > 0) {
152
- return { success: true, data: result.data.content[0] };
150
+ const result = await this.getOrders({ orderNumber });
151
+ if (result.success && result.data.content?.length > 0) {
152
+ return { success: true, data: result.data.content[0] };
153
+ }
154
+ return { success: false, error: 'Sipariş bulunamadı' };
153
155
  }
154
- return { success: false, error: 'Sipariş bulunamadı' };
155
- }
156
156
 
157
157
  async updateOrderStatus(lines, status, params = {}) {
158
- // lines: [{ lineId, quantity }]
159
- // status: Picking, Invoiced, UnSupplied
160
- const endpoint = `/suppliers/${this.supplierId}/shipment-packages`;
161
-
162
- if (status === 'Picking') {
163
- return await this._request('PUT', endpoint, { lines, status: 'Picking' });
164
- } else if (status === 'Invoiced') {
165
- return await this._request('PUT', endpoint, {
166
- lines,
167
- status: 'Invoiced',
168
- invoiceNumber: params.invoiceNumber
169
- });
170
- }
158
+ // lines: [{ lineId, quantity }]
159
+ // status: Picking, Invoiced, UnSupplied
160
+ const endpoint = `/suppliers/${this.supplierId}/shipment-packages`;
161
+
162
+ if (status === 'Picking') {
163
+ return await this._request('PUT', endpoint, { lines, status: 'Picking' });
164
+ } else if (status === 'Invoiced') {
165
+ return await this._request('PUT', endpoint, {
166
+ lines,
167
+ status: 'Invoiced',
168
+ invoiceNumber: params.invoiceNumber
169
+ });
170
+ }
171
171
 
172
- return { success: false, error: 'Geçersiz durum' };
173
- }
172
+ return { success: false, error: 'Geçersiz durum' };
173
+ }
174
174
 
175
175
  async shipOrder(shipmentPackageId, trackingNumber, cargoKey = 'YURTICI') {
176
- // cargoKey: YURTICI, MNG, ARAS, PTT, SURAT, UPS, HOROZ, CEVA, SENDEO
177
- return await this._request('PUT',
178
- `/suppliers/${this.supplierId}/shipment-packages/${shipmentPackageId}`,
179
- {
180
- trackingNumber,
181
- cargoProviderCode: cargoKey,
182
- status: 'Shipped'
183
- }
184
- );
185
- }
176
+ // cargoKey: YURTICI, MNG, ARAS, PTT, SURAT, UPS, HOROZ, CEVA, SENDEO
177
+ return await this._request('PUT',
178
+ `/suppliers/${this.supplierId}/shipment-packages/${shipmentPackageId}`,
179
+ {
180
+ trackingNumber,
181
+ cargoProviderCode: cargoKey,
182
+ status: 'Shipped'
183
+ }
184
+ );
185
+ }
186
186
 
187
187
  async getShipmentProviders() {
188
- return await this._request('GET', '/shipment-providers');
189
- }
188
+ return await this._request('GET', '/shipment-providers');
189
+ }
190
190
 
191
191
  // ═══════════════════════════════════════════════════════════════════════════
192
192
  // KATEGORİ & MARKA
193
193
  // ═══════════════════════════════════════════════════════════════════════════
194
194
 
195
195
  async getCategories() {
196
- return await this._request('GET', '/product-categories');
197
- }
196
+ return await this._request('GET', '/product-categories');
197
+ }
198
198
 
199
199
  async getCategoryAttributes(categoryId) {
200
- return await this._request('GET', `/product-categories/${categoryId}/attributes`);
201
- }
200
+ return await this._request('GET', `/product-categories/${categoryId}/attributes`);
201
+ }
202
202
 
203
203
  async searchBrands(name) {
204
- return await this._request('GET', '/brands', null, { name });
205
- }
204
+ return await this._request('GET', '/brands', null, { name });
205
+ }
206
206
 
207
207
  async getBrandsByCategory(categoryId) {
208
- return await this._request('GET', `/product-categories/${categoryId}/brands`);
209
- }
208
+ return await this._request('GET', `/product-categories/${categoryId}/brands`);
209
+ }
210
210
 
211
211
  // ═══════════════════════════════════════════════════════════════════════════
212
212
  // RAKİP ANALİZİ (Scraping - Dikkat: Rate limit)
213
213
  // ═══════════════════════════════════════════════════════════════════════════
214
214
 
215
215
  async getCompetitorPrices(barcode) {
216
- // Bu endpoint resmi API'de yok, web scraping gerekir
217
- // Alternatif: Brave Search API ile rakip araması
218
- try {
219
- // Trendyol'da aynı ürünü satan diğer satıcıları bul
220
- const searchUrl = `https://www.trendyol.com/sr?q=${barcode}`;
221
- // Not: Bu gerçek scraping gerektirir, burada placeholder
222
- return {
223
- success: true,
224
- competitors: [],
225
- message: 'Rakip analizi için web_search tool kullanın'
226
- };
227
- } catch (error) {
228
- return { success: false, error: error.message };
216
+ // Bu endpoint resmi API'de yok, web scraping gerekir
217
+ // Alternatif: Brave Search API ile rakip araması
218
+ try {
219
+ // Trendyol'da aynı ürünü satan diğer satıcıları bul
220
+ const searchUrl = `https://www.trendyol.com/sr?q=${barcode}`;
221
+ // Not: Bu gerçek scraping gerektirir, burada placeholder
222
+ return {
223
+ success: true,
224
+ competitors: [],
225
+ message: 'Rakip analizi için web_search tool kullanın'
226
+ };
227
+ } catch (error) {
228
+ return { success: false, error: error.message };
229
+ }
229
230
  }
230
- }
231
231
 
232
232
  // ═══════════════════════════════════════════════════════════════════════════
233
233
  // SORU & CEVAP
234
234
  // ═══════════════════════════════════════════════════════════════════════════
235
235
 
236
236
  async getQuestions(params = {}) {
237
- const { status = 'WAITING_FOR_ANSWER', page = 0, size = 50 } = params;
238
- return await this._request('GET', `/suppliers/${this.supplierId}/questions/filter`, null, {
239
- status, page, size
240
- });
241
- }
237
+ const { status = 'WAITING_FOR_ANSWER', page = 0, size = 50 } = params;
238
+ return await this._request('GET', `/suppliers/${this.supplierId}/questions/filter`, null, {
239
+ status, page, size
240
+ });
241
+ }
242
242
 
243
243
  async answerQuestion(questionId, answer) {
244
- return await this._request('POST', `/suppliers/${this.supplierId}/questions/${questionId}/answers`, {
245
- text: answer
246
- });
247
- }
244
+ return await this._request('POST', `/suppliers/${this.supplierId}/questions/${questionId}/answers`, {
245
+ text: answer
246
+ });
247
+ }
248
248
 
249
249
  // ═══════════════════════════════════════════════════════════════════════════
250
250
  // WEBHOOK
251
251
  // ═══════════════════════════════════════════════════════════════════════════
252
252
 
253
253
  async getWebhooks() {
254
- return await this._request('GET', `/suppliers/${this.supplierId}/webhooks`);
255
- }
254
+ return await this._request('GET', `/suppliers/${this.supplierId}/webhooks`);
255
+ }
256
256
 
257
257
  async createWebhook(url, events = ['order.created', 'order.shipped']) {
258
- return await this._request('POST', `/suppliers/${this.supplierId}/webhooks`, {
259
- url,
260
- events
261
- });
262
- }
258
+ return await this._request('POST', `/suppliers/${this.supplierId}/webhooks`, {
259
+ url,
260
+ events
261
+ });
262
+ }
263
263
 
264
264
  // ═══════════════════════════════════════════════════════════════════════════
265
265
  // YARDIMCI METODLAR
266
266
  // ═══════════════════════════════════════════════════════════════════════════
267
267
 
268
268
  async testConnection() {
269
- const result = await this.getProducts({ page: 0, size: 1 });
270
- return result.success;
271
- }
269
+ const result = await this.getProducts({ page: 0, size: 1 });
270
+ return result.success;
271
+ }
272
272
 
273
- isConnected() {
274
- return !!(this.supplierId && this.apiKey && this.apiSecret);
275
- }
273
+ isConnected() {
274
+ return !!(this.supplierId && this.apiKey && this.apiSecret);
275
+ }
276
276
 
277
- formatProduct(raw) {
278
- return {
279
- id: raw.id,
280
- barcode: raw.barcode,
281
- title: raw.title,
282
- brand: raw.brand,
283
- category: raw.categoryName,
284
- price: raw.salePrice,
285
- listPrice: raw.listPrice,
286
- stock: raw.quantity,
287
- images: raw.images?.map(i => i.url) || [],
288
- approved: raw.approved,
289
- onSale: raw.onSale,
290
- url: `https://www.trendyol.com/p/-p-${raw.id}`
291
- };
292
- }
277
+ formatProduct(raw) {
278
+ return {
279
+ id: raw.id,
280
+ barcode: raw.barcode,
281
+ title: raw.title,
282
+ brand: raw.brand,
283
+ category: raw.categoryName,
284
+ price: raw.salePrice,
285
+ listPrice: raw.listPrice,
286
+ stock: raw.quantity,
287
+ images: raw.images?.map(i => i.url) || [],
288
+ approved: raw.approved,
289
+ onSale: raw.onSale,
290
+ url: `https://www.trendyol.com/p/-p-${raw.id}`
291
+ };
292
+ }
293
293
  }
294
294
 
295
295
  // Singleton instance