vantuz 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,136 @@
1
+ /**
2
+ * ๐Ÿ“ฎ PTTavm API Entegrasyonu
3
+ * pttavm.com/entegrasyon
4
+ */
5
+
6
+ import axios from 'axios';
7
+
8
+ const BASE_URL = 'https://api.pttavm.com/v1';
9
+
10
+ export class PttavmAPI {
11
+ constructor(config) {
12
+ this.apiKey = config.apiKey;
13
+ this.token = config.token;
14
+ this.shopId = config.shopId;
15
+ }
16
+
17
+ _headers() {
18
+ return {
19
+ 'Authorization': `Bearer ${this.token}`,
20
+ 'X-API-Key': this.apiKey,
21
+ 'Content-Type': 'application/json'
22
+ };
23
+ }
24
+
25
+ async _request(method, endpoint, data = null, params = null) {
26
+ try {
27
+ const response = await axios({
28
+ method,
29
+ url: `${BASE_URL}${endpoint}`,
30
+ headers: this._headers(),
31
+ data,
32
+ params
33
+ });
34
+ return { success: true, data: response.data };
35
+ } catch (error) {
36
+ return {
37
+ success: false,
38
+ error: error.response?.data || error.message
39
+ };
40
+ }
41
+ }
42
+
43
+ // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
44
+ // รœRรœN ฤฐลžLEMLERฤฐ
45
+ // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
46
+
47
+ async getProducts(params = {}) {
48
+ const { page = 1, limit = 100, barcode } = params;
49
+ return await this._request('GET', '/products', null, {
50
+ page, limit, barcode
51
+ });
52
+ }
53
+
54
+ async createProduct(product) {
55
+ return await this._request('POST', '/products', product);
56
+ }
57
+
58
+ async updateProduct(productId, updates) {
59
+ return await this._request('PUT', `/products/${productId}`, updates);
60
+ }
61
+
62
+ async updatePrice(barcode, price) {
63
+ return await this._request('PUT', '/products/price', {
64
+ items: [{ barcode, salePrice: price }]
65
+ });
66
+ }
67
+
68
+ async updateStock(barcode, quantity) {
69
+ return await this._request('PUT', '/products/stock', {
70
+ items: [{ barcode, quantity }]
71
+ });
72
+ }
73
+
74
+ // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
75
+ // SฤฐPARฤฐลž ฤฐลžLEMLERฤฐ
76
+ // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
77
+
78
+ async getOrders(params = {}) {
79
+ const { status, startDate, endDate, page = 1, limit = 100 } = params;
80
+ return await this._request('GET', '/orders', null, {
81
+ status, startDate, endDate, page, limit
82
+ });
83
+ }
84
+
85
+ async getOrderDetail(orderId) {
86
+ return await this._request('GET', `/orders/${orderId}`);
87
+ }
88
+
89
+ async updateOrderStatus(orderId, status) {
90
+ return await this._request('PUT', `/orders/${orderId}/status`, { status });
91
+ }
92
+
93
+ async shipOrder(orderId, trackingNumber) {
94
+ return await this._request('PUT', `/orders/${orderId}/ship`, {
95
+ trackingNumber,
96
+ cargoCompany: 'PTT'
97
+ });
98
+ }
99
+
100
+ // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
101
+ // KATEGORฤฐ
102
+ // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
103
+
104
+ async getCategories() {
105
+ return await this._request('GET', '/categories');
106
+ }
107
+
108
+ // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
109
+ // HELPER
110
+ // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
111
+
112
+ async testConnection() {
113
+ const result = await this.getProducts({ page: 1, limit: 1 });
114
+ return result.success;
115
+ }
116
+
117
+ isConnected() {
118
+ return !!(this.apiKey && this.token);
119
+ }
120
+ }
121
+
122
+ let instance = null;
123
+
124
+ export const pttavmApi = {
125
+ init(config) {
126
+ instance = new PttavmAPI(config);
127
+ return instance;
128
+ },
129
+ getInstance() { return instance; },
130
+ isConnected() { return instance?.isConnected() || false; },
131
+
132
+ async getProducts(params) { return instance?.getProducts(params); },
133
+ async updatePrice(code, price) { return instance?.updatePrice(code, price); },
134
+ async updateStock(code, qty) { return instance?.updateStock(code, qty); },
135
+ async getOrders(params) { return instance?.getOrders(params); }
136
+ };
@@ -0,0 +1,307 @@
1
+ /**
2
+ * ๐ŸŸ  TRENDYOL API Entegrasyonu
3
+ * developers.trendyol.com
4
+ *
5
+ * ร–zellikler:
6
+ * - รœrรผn listeleme/gรผncelleme
7
+ * - Fiyat/stok yรถnetimi
8
+ * - SipariลŸ yรถnetimi
9
+ * - Rakip fiyat รงekme
10
+ */
11
+
12
+ import axios from 'axios';
13
+
14
+ const BASE_URL = 'https://api.trendyol.com/sapigw';
15
+ const STAGE_URL = 'https://stageapi.trendyol.com/stagesapigw'; // Test ortamฤฑ
16
+
17
+ export class TrendyolAPI {
18
+ constructor(config) {
19
+ this.supplierId = config.supplierId;
20
+ this.apiKey = config.apiKey;
21
+ this.apiSecret = config.apiSecret;
22
+ this.isStage = config.isStage || false;
23
+
24
+ this.baseUrl = this.isStage ? STAGE_URL : BASE_URL;
25
+ this.auth = Buffer.from(`${this.apiKey}:${this.apiSecret}`).toString('base64');
26
+ }
27
+
28
+ _headers() {
29
+ return {
30
+ 'Authorization': `Basic ${this.auth}`,
31
+ 'Content-Type': 'application/json',
32
+ 'User-Agent': `${this.supplierId} - VantuzAI`
33
+ };
34
+ }
35
+
36
+ async _request(method, endpoint, data = null, params = null) {
37
+ try {
38
+ const response = await axios({
39
+ method,
40
+ url: `${this.baseUrl}${endpoint}`,
41
+ headers: this._headers(),
42
+ data,
43
+ params
44
+ });
45
+ return { success: true, data: response.data };
46
+ } catch (error) {
47
+ return {
48
+ success: false,
49
+ error: error.response?.data?.errors || error.message,
50
+ status: error.response?.status
51
+ };
52
+ }
53
+ }
54
+
55
+ // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
56
+ // รœRรœN ฤฐลžLEMLERฤฐ
57
+ // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
58
+
59
+ async getProducts(params = {}) {
60
+ const { page = 0, size = 50, barcode, approved, onSale } = params;
61
+ return await this._request('GET', `/suppliers/${this.supplierId}/products`, null, {
62
+ page, size, barcode, approved, onSale
63
+ });
64
+ }
65
+
66
+ async getProductByBarcode(barcode) {
67
+ const result = await this.getProducts({ barcode });
68
+ if (result.success && result.data.content?.length > 0) {
69
+ return { success: true, data: result.data.content[0] };
70
+ }
71
+ return { success: false, error: 'รœrรผn bulunamadฤฑ' };
72
+ }
73
+
74
+ async createProducts(products) {
75
+ // items: [{ barcode, title, productMainId, brandId, categoryId, ... }]
76
+ return await this._request('POST', `/suppliers/${this.supplierId}/v2/products`, { items: products });
77
+ }
78
+
79
+ async updateProducts(products) {
80
+ return await this._request('PUT', `/suppliers/${this.supplierId}/v2/products`, { items: products });
81
+ }
82
+
83
+ async deleteProducts(barcodes) {
84
+ const items = barcodes.map(barcode => ({ barcode }));
85
+ return await this._request('DELETE', `/suppliers/${this.supplierId}/products`, { items });
86
+ }
87
+
88
+ // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
89
+ // FฤฐYAT & STOK
90
+ // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
91
+
92
+ async updatePriceAndStock(items) {
93
+ // items: [{ barcode, quantity, salePrice, listPrice }]
94
+ return await this._request('POST', `/suppliers/${this.supplierId}/products/price-and-inventory`, { items });
95
+ }
96
+
97
+ async updatePrice(barcode, salePrice, listPrice = null) {
98
+ return await this.updatePriceAndStock([{
99
+ barcode,
100
+ salePrice,
101
+ listPrice: listPrice || salePrice
102
+ }]);
103
+ }
104
+
105
+ async updateStock(barcode, quantity) {
106
+ return await this.updatePriceAndStock([{ barcode, quantity }]);
107
+ }
108
+
109
+ async bulkPriceUpdate(updates) {
110
+ // updates: [{ barcode, price, listPrice? }]
111
+ const items = updates.map(u => ({
112
+ barcode: u.barcode,
113
+ salePrice: u.price,
114
+ listPrice: u.listPrice || u.price
115
+ }));
116
+ return await this.updatePriceAndStock(items);
117
+ }
118
+
119
+ // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
120
+ // SฤฐPARฤฐลž ฤฐลžLEMLERฤฐ
121
+ // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
122
+
123
+ async getOrders(params = {}) {
124
+ const {
125
+ status, // Created, Picking, Invoiced, Shipped, Cancelled, Delivered
126
+ startDate,
127
+ endDate,
128
+ page = 0,
129
+ size = 50,
130
+ orderNumber
131
+ } = params;
132
+
133
+ return await this._request('GET', `/suppliers/${this.supplierId}/orders`, null, {
134
+ status, startDate, endDate, page, size, orderNumber
135
+ });
136
+ }
137
+
138
+ async getOrderByNumber(orderNumber) {
139
+ const result = await this.getOrders({ orderNumber });
140
+ if (result.success && result.data.content?.length > 0) {
141
+ return { success: true, data: result.data.content[0] };
142
+ }
143
+ return { success: false, error: 'SipariลŸ bulunamadฤฑ' };
144
+ }
145
+
146
+ async updateOrderStatus(lines, status, params = {}) {
147
+ // lines: [{ lineId, quantity }]
148
+ // status: Picking, Invoiced, UnSupplied
149
+ const endpoint = `/suppliers/${this.supplierId}/shipment-packages`;
150
+
151
+ if (status === 'Picking') {
152
+ return await this._request('PUT', endpoint, { lines, status: 'Picking' });
153
+ } else if (status === 'Invoiced') {
154
+ return await this._request('PUT', endpoint, {
155
+ lines,
156
+ status: 'Invoiced',
157
+ invoiceNumber: params.invoiceNumber
158
+ });
159
+ }
160
+
161
+ return { success: false, error: 'Geรงersiz durum' };
162
+ }
163
+
164
+ async shipOrder(shipmentPackageId, trackingNumber, cargoKey = 'YURTICI') {
165
+ // cargoKey: YURTICI, MNG, ARAS, PTT, SURAT, UPS, HOROZ, CEVA, SENDEO
166
+ return await this._request('PUT',
167
+ `/suppliers/${this.supplierId}/shipment-packages/${shipmentPackageId}`,
168
+ {
169
+ trackingNumber,
170
+ cargoProviderCode: cargoKey,
171
+ status: 'Shipped'
172
+ }
173
+ );
174
+ }
175
+
176
+ async getShipmentProviders() {
177
+ return await this._request('GET', '/shipment-providers');
178
+ }
179
+
180
+ // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
181
+ // KATEGORฤฐ & MARKA
182
+ // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
183
+
184
+ async getCategories() {
185
+ return await this._request('GET', '/product-categories');
186
+ }
187
+
188
+ async getCategoryAttributes(categoryId) {
189
+ return await this._request('GET', `/product-categories/${categoryId}/attributes`);
190
+ }
191
+
192
+ async searchBrands(name) {
193
+ return await this._request('GET', '/brands', null, { name });
194
+ }
195
+
196
+ async getBrandsByCategory(categoryId) {
197
+ return await this._request('GET', `/product-categories/${categoryId}/brands`);
198
+ }
199
+
200
+ // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
201
+ // RAKฤฐP ANALฤฐZฤฐ (Scraping - Dikkat: Rate limit)
202
+ // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
203
+
204
+ async getCompetitorPrices(barcode) {
205
+ // Bu endpoint resmi API'de yok, web scraping gerekir
206
+ // Alternatif: Brave Search API ile rakip aramasฤฑ
207
+ try {
208
+ // Trendyol'da aynฤฑ รผrรผnรผ satan diฤŸer satฤฑcฤฑlarฤฑ bul
209
+ const searchUrl = `https://www.trendyol.com/sr?q=${barcode}`;
210
+ // Not: Bu gerรงek scraping gerektirir, burada placeholder
211
+ return {
212
+ success: true,
213
+ competitors: [],
214
+ message: 'Rakip analizi iรงin web_search tool kullanฤฑn'
215
+ };
216
+ } catch (error) {
217
+ return { success: false, error: error.message };
218
+ }
219
+ }
220
+
221
+ // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
222
+ // SORU & CEVAP
223
+ // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
224
+
225
+ async getQuestions(params = {}) {
226
+ const { status = 'WAITING_FOR_ANSWER', page = 0, size = 50 } = params;
227
+ return await this._request('GET', `/suppliers/${this.supplierId}/questions/filter`, null, {
228
+ status, page, size
229
+ });
230
+ }
231
+
232
+ async answerQuestion(questionId, answer) {
233
+ return await this._request('POST', `/suppliers/${this.supplierId}/questions/${questionId}/answers`, {
234
+ text: answer
235
+ });
236
+ }
237
+
238
+ // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
239
+ // WEBHOOK
240
+ // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
241
+
242
+ async getWebhooks() {
243
+ return await this._request('GET', `/suppliers/${this.supplierId}/webhooks`);
244
+ }
245
+
246
+ async createWebhook(url, events = ['order.created', 'order.shipped']) {
247
+ return await this._request('POST', `/suppliers/${this.supplierId}/webhooks`, {
248
+ url,
249
+ events
250
+ });
251
+ }
252
+
253
+ // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
254
+ // YARDIMCI METODLAR
255
+ // โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
256
+
257
+ async testConnection() {
258
+ const result = await this.getProducts({ page: 0, size: 1 });
259
+ return result.success;
260
+ }
261
+
262
+ isConnected() {
263
+ return !!(this.supplierId && this.apiKey && this.apiSecret);
264
+ }
265
+
266
+ formatProduct(raw) {
267
+ return {
268
+ id: raw.id,
269
+ barcode: raw.barcode,
270
+ title: raw.title,
271
+ brand: raw.brand,
272
+ category: raw.categoryName,
273
+ price: raw.salePrice,
274
+ listPrice: raw.listPrice,
275
+ stock: raw.quantity,
276
+ images: raw.images?.map(i => i.url) || [],
277
+ approved: raw.approved,
278
+ onSale: raw.onSale,
279
+ url: `https://www.trendyol.com/p/-p-${raw.id}`
280
+ };
281
+ }
282
+ }
283
+
284
+ // Singleton instance
285
+ let instance = null;
286
+
287
+ export const trendyolApi = {
288
+ init(config) {
289
+ instance = new TrendyolAPI(config);
290
+ return instance;
291
+ },
292
+
293
+ getInstance() {
294
+ return instance;
295
+ },
296
+
297
+ isConnected() {
298
+ return instance?.isConnected() || false;
299
+ },
300
+
301
+ // Proxy methods
302
+ async getProducts(params) { return instance?.getProducts(params); },
303
+ async updatePrice(barcode, price) { return instance?.updatePrice(barcode, price); },
304
+ async updateStock(barcode, qty) { return instance?.updateStock(barcode, qty); },
305
+ async getOrders(params) { return instance?.getOrders(params); },
306
+ async getCompetitors(barcode) { return instance?.getCompetitorPrices(barcode); }
307
+ };
@@ -0,0 +1,253 @@
1
+ /**
2
+ * ๐Ÿ”” AKILLI UYARI SฤฐSTEMฤฐ
3
+ * Stok, fiyat ve sipariลŸ uyarฤฑlarฤฑ
4
+ */
5
+
6
+ const DEFAULT_THRESHOLDS = {
7
+ criticalStock: 5, // Kritik stok seviyesi
8
+ lowStock: 20, // DรผลŸรผk stok uyarฤฑsฤฑ
9
+ priceDropPercent: 10, // Rakip fiyat dรผลŸรผลŸรผ uyarฤฑsฤฑ
10
+ orderDelay: 24, // SipariลŸ gecikme saati
11
+ reviewNegative: 3 // Negatif yorum eลŸiฤŸi
12
+ };
13
+
14
+ export class AlertService {
15
+ constructor(config = {}) {
16
+ this.thresholds = { ...DEFAULT_THRESHOLDS, ...config.thresholds };
17
+ this.subscribers = [];
18
+ this.alerts = [];
19
+ this.notifiedToday = new Set(); // Aynฤฑ uyarฤฑyฤฑ tekrar gรถnderme
20
+ }
21
+
22
+ /**
23
+ * Uyarฤฑ ekle
24
+ */
25
+ addAlert(alert) {
26
+ const key = `${alert.type}-${alert.productId || alert.orderId || 'general'}`;
27
+
28
+ // Bugรผn zaten bildirildi mi?
29
+ if (this.notifiedToday.has(key)) {
30
+ return false;
31
+ }
32
+
33
+ this.alerts.push({
34
+ ...alert,
35
+ id: `alert-${Date.now()}`,
36
+ timestamp: new Date().toISOString(),
37
+ read: false
38
+ });
39
+
40
+ this.notifiedToday.add(key);
41
+ return true;
42
+ }
43
+
44
+ /**
45
+ * Stok kontrolรผ
46
+ */
47
+ async checkStock(products, platform) {
48
+ const alerts = [];
49
+
50
+ for (const product of products) {
51
+ const stock = product.quantity || product.stock || product.availableStock || 0;
52
+ const name = product.title || product.name || product.barcode;
53
+
54
+ if (stock <= 0) {
55
+ alerts.push({
56
+ type: 'stock_out',
57
+ severity: 'critical',
58
+ icon: '๐Ÿ”ด',
59
+ message: `Stok bitti: ${name}`,
60
+ productId: product.barcode || product.id,
61
+ platform,
62
+ value: stock
63
+ });
64
+ } else if (stock <= this.thresholds.criticalStock) {
65
+ alerts.push({
66
+ type: 'stock_critical',
67
+ severity: 'high',
68
+ icon: '๐ŸŸ ',
69
+ message: `Kritik stok (${stock}): ${name}`,
70
+ productId: product.barcode || product.id,
71
+ platform,
72
+ value: stock
73
+ });
74
+ } else if (stock <= this.thresholds.lowStock) {
75
+ alerts.push({
76
+ type: 'stock_low',
77
+ severity: 'medium',
78
+ icon: '๐ŸŸก',
79
+ message: `DรผลŸรผk stok (${stock}): ${name}`,
80
+ productId: product.barcode || product.id,
81
+ platform,
82
+ value: stock
83
+ });
84
+ }
85
+ }
86
+
87
+ alerts.forEach(a => this.addAlert(a));
88
+ return alerts;
89
+ }
90
+
91
+ /**
92
+ * Rakip fiyat kontrolรผ
93
+ */
94
+ async checkCompetitorPrices(comparisons) {
95
+ const alerts = [];
96
+
97
+ for (const comp of comparisons) {
98
+ const { product, ourPrice, lowestCompetitor, competitorName } = comp;
99
+ const diff = ((ourPrice - lowestCompetitor) / ourPrice) * 100;
100
+
101
+ if (lowestCompetitor < ourPrice && diff > this.thresholds.priceDropPercent) {
102
+ alerts.push({
103
+ type: 'competitor_undercut',
104
+ severity: 'high',
105
+ icon: '๐Ÿ’ธ',
106
+ message: `Rakip ${Math.round(diff)}% ucuz: ${product.name || product.barcode}`,
107
+ productId: product.barcode,
108
+ competitor: competitorName,
109
+ ourPrice,
110
+ competitorPrice: lowestCompetitor,
111
+ suggestion: `Fiyatฤฑ ${lowestCompetitor * 0.99}โ‚บ'ye dรผลŸรผrmeyi dรผลŸรผnรผn`
112
+ });
113
+ }
114
+ }
115
+
116
+ alerts.forEach(a => this.addAlert(a));
117
+ return alerts;
118
+ }
119
+
120
+ /**
121
+ * SipariลŸ gecikme kontrolรผ
122
+ */
123
+ async checkOrderDelays(orders) {
124
+ const alerts = [];
125
+ const now = Date.now();
126
+
127
+ for (const order of orders) {
128
+ const createdAt = new Date(order.createdDate || order.orderDate).getTime();
129
+ const hoursAgo = (now - createdAt) / (1000 * 60 * 60);
130
+
131
+ const status = order.status?.toLowerCase();
132
+ const isPending = ['created', 'new', 'pending', 'yeni'].some(s => status?.includes(s));
133
+
134
+ if (isPending && hoursAgo > this.thresholds.orderDelay) {
135
+ alerts.push({
136
+ type: 'order_delayed',
137
+ severity: 'high',
138
+ icon: 'โฐ',
139
+ message: `${Math.round(hoursAgo)} saat bekleyen sipariลŸ: #${order.orderNumber || order.id}`,
140
+ orderId: order.id,
141
+ hoursDelayed: Math.round(hoursAgo),
142
+ suggestion: 'SipariลŸi hazฤฑrlayฤฑn veya iptal edin'
143
+ });
144
+ }
145
+ }
146
+
147
+ alerts.forEach(a => this.addAlert(a));
148
+ return alerts;
149
+ }
150
+
151
+ /**
152
+ * Tรผm uyarฤฑlarฤฑ formatla
153
+ */
154
+ formatAlerts(alerts) {
155
+ if (alerts.length === 0) {
156
+ return 'โœ… Herhangi bir uyarฤฑ yok!';
157
+ }
158
+
159
+ const grouped = {
160
+ critical: alerts.filter(a => a.severity === 'critical'),
161
+ high: alerts.filter(a => a.severity === 'high'),
162
+ medium: alerts.filter(a => a.severity === 'medium'),
163
+ low: alerts.filter(a => a.severity === 'low')
164
+ };
165
+
166
+ let message = '๐Ÿ“‹ **Uyarฤฑ ร–zeti**\n\n';
167
+
168
+ if (grouped.critical.length > 0) {
169
+ message += `๐Ÿ”ด **Kritik (${grouped.critical.length})**\n`;
170
+ grouped.critical.forEach(a => {
171
+ message += ` โ€ข ${a.message}\n`;
172
+ });
173
+ message += '\n';
174
+ }
175
+
176
+ if (grouped.high.length > 0) {
177
+ message += `๐ŸŸ  **Yรผksek (${grouped.high.length})**\n`;
178
+ grouped.high.slice(0, 5).forEach(a => {
179
+ message += ` โ€ข ${a.message}\n`;
180
+ });
181
+ if (grouped.high.length > 5) {
182
+ message += ` ... ve ${grouped.high.length - 5} uyarฤฑ daha\n`;
183
+ }
184
+ message += '\n';
185
+ }
186
+
187
+ if (grouped.medium.length > 0) {
188
+ message += `๐ŸŸก **Orta (${grouped.medium.length})**\n`;
189
+ grouped.medium.slice(0, 3).forEach(a => {
190
+ message += ` โ€ข ${a.message}\n`;
191
+ });
192
+ if (grouped.medium.length > 3) {
193
+ message += ` ... ve ${grouped.medium.length - 3} uyarฤฑ daha\n`;
194
+ }
195
+ }
196
+
197
+ return message;
198
+ }
199
+
200
+ /**
201
+ * OkunmamฤฑลŸ uyarฤฑ sayฤฑsฤฑ
202
+ */
203
+ getUnreadCount() {
204
+ return this.alerts.filter(a => !a.read).length;
205
+ }
206
+
207
+ /**
208
+ * Uyarฤฑlarฤฑ okundu iลŸaretle
209
+ */
210
+ markAllRead() {
211
+ this.alerts.forEach(a => a.read = true);
212
+ }
213
+
214
+ /**
215
+ * Gรผnlรผk cache'i temizle
216
+ */
217
+ resetDaily() {
218
+ this.notifiedToday.clear();
219
+ }
220
+ }
221
+
222
+ export const alertTool = {
223
+ name: 'alert',
224
+
225
+ async execute(params, context) {
226
+ const { action, type } = params;
227
+ const alertService = new AlertService();
228
+
229
+ switch (action) {
230
+ case 'check':
231
+ // Tรผm kontrolleri yap ve uyarฤฑlarฤฑ topla
232
+ const allAlerts = [];
233
+ // TODO: Platform API'lerinden veri รงek ve kontrol et
234
+ return { success: true, alerts: allAlerts };
235
+
236
+ case 'list':
237
+ return {
238
+ success: true,
239
+ alerts: alertService.alerts,
240
+ unread: alertService.getUnreadCount()
241
+ };
242
+
243
+ case 'clear':
244
+ alertService.markAllRead();
245
+ return { success: true };
246
+
247
+ default:
248
+ return { success: false, error: 'Geรงersiz action' };
249
+ }
250
+ }
251
+ };
252
+
253
+ export default AlertService;