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.
- package/LICENSE +45 -0
- package/README.md +44 -0
- package/cli.js +420 -0
- package/core/ai-analyst.js +46 -0
- package/core/database.js +74 -0
- package/core/license-manager.js +50 -0
- package/core/product-manager.js +134 -0
- package/package.json +72 -0
- package/plugins/vantuz/index.js +480 -0
- package/plugins/vantuz/memory/hippocampus.js +464 -0
- package/plugins/vantuz/package.json +21 -0
- package/plugins/vantuz/platforms/amazon.js +239 -0
- package/plugins/vantuz/platforms/ciceksepeti.js +175 -0
- package/plugins/vantuz/platforms/hepsiburada.js +189 -0
- package/plugins/vantuz/platforms/index.js +215 -0
- package/plugins/vantuz/platforms/n11.js +263 -0
- package/plugins/vantuz/platforms/pazarama.js +171 -0
- package/plugins/vantuz/platforms/pttavm.js +136 -0
- package/plugins/vantuz/platforms/trendyol.js +307 -0
- package/plugins/vantuz/services/alerts.js +253 -0
- package/plugins/vantuz/services/license.js +237 -0
- package/plugins/vantuz/services/scheduler.js +232 -0
- package/plugins/vantuz/tools/analytics.js +152 -0
- package/plugins/vantuz/tools/crossborder.js +187 -0
- package/plugins/vantuz/tools/nl-parser.js +211 -0
- package/plugins/vantuz/tools/product.js +110 -0
- package/plugins/vantuz/tools/quick-report.js +175 -0
- package/plugins/vantuz/tools/repricer.js +314 -0
- package/plugins/vantuz/tools/sentiment.js +115 -0
- package/plugins/vantuz/tools/vision.js +257 -0
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 🏪 Platform API Hub
|
|
3
|
+
* Tüm pazaryeri API'lerini tek noktadan yönet
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { trendyolApi, TrendyolAPI } from './trendyol.js';
|
|
7
|
+
import { hepsiburadaApi, HepsiburadaAPI } from './hepsiburada.js';
|
|
8
|
+
import { n11Api, N11API } from './n11.js';
|
|
9
|
+
import { amazonApi, AmazonAPI } from './amazon.js';
|
|
10
|
+
import { ciceksepetiApi, CiceksepetiAPI } from './ciceksepeti.js';
|
|
11
|
+
import { pttavmApi, PttavmAPI } from './pttavm.js';
|
|
12
|
+
import { pazaramaApi, PazaramaAPI } from './pazarama.js';
|
|
13
|
+
|
|
14
|
+
// Platform aliases
|
|
15
|
+
const PLATFORM_ALIASES = {
|
|
16
|
+
ty: 'trendyol',
|
|
17
|
+
trendyol: 'trendyol',
|
|
18
|
+
hb: 'hepsiburada',
|
|
19
|
+
hepsiburada: 'hepsiburada',
|
|
20
|
+
n11: 'n11',
|
|
21
|
+
amazon: 'amazon',
|
|
22
|
+
amz: 'amazon',
|
|
23
|
+
cs: 'ciceksepeti',
|
|
24
|
+
ciceksepeti: 'ciceksepeti',
|
|
25
|
+
çiçeksepeti: 'ciceksepeti',
|
|
26
|
+
ptt: 'pttavm',
|
|
27
|
+
pttavm: 'pttavm',
|
|
28
|
+
pazarama: 'pazarama',
|
|
29
|
+
pzr: 'pazarama'
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
const platforms = {
|
|
33
|
+
trendyol: trendyolApi,
|
|
34
|
+
hepsiburada: hepsiburadaApi,
|
|
35
|
+
n11: n11Api,
|
|
36
|
+
amazon: amazonApi,
|
|
37
|
+
ciceksepeti: ciceksepetiApi,
|
|
38
|
+
pttavm: pttavmApi,
|
|
39
|
+
pazarama: pazaramaApi
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
43
|
+
// PLATFORM HUB
|
|
44
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
45
|
+
|
|
46
|
+
export const platformHub = {
|
|
47
|
+
/**
|
|
48
|
+
* Platform'u alias ile bul
|
|
49
|
+
*/
|
|
50
|
+
resolve(alias) {
|
|
51
|
+
const normalized = alias?.toLowerCase().trim();
|
|
52
|
+
const name = PLATFORM_ALIASES[normalized];
|
|
53
|
+
return name ? platforms[name] : null;
|
|
54
|
+
},
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Tüm platformları başlat
|
|
58
|
+
*/
|
|
59
|
+
async initAll(config) {
|
|
60
|
+
const results = {};
|
|
61
|
+
|
|
62
|
+
if (config.trendyol) {
|
|
63
|
+
results.trendyol = trendyolApi.init(config.trendyol);
|
|
64
|
+
}
|
|
65
|
+
if (config.hepsiburada) {
|
|
66
|
+
results.hepsiburada = hepsiburadaApi.init(config.hepsiburada);
|
|
67
|
+
}
|
|
68
|
+
if (config.n11) {
|
|
69
|
+
results.n11 = n11Api.init(config.n11);
|
|
70
|
+
}
|
|
71
|
+
if (config.amazon) {
|
|
72
|
+
results.amazon = amazonApi.init(config.amazon.eu, 'eu');
|
|
73
|
+
if (config.amazon.us) {
|
|
74
|
+
amazonApi.init(config.amazon.us, 'na');
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
if (config.ciceksepeti) {
|
|
78
|
+
results.ciceksepeti = ciceksepetiApi.init(config.ciceksepeti);
|
|
79
|
+
}
|
|
80
|
+
if (config.pttavm) {
|
|
81
|
+
results.pttavm = pttavmApi.init(config.pttavm);
|
|
82
|
+
}
|
|
83
|
+
if (config.pazarama) {
|
|
84
|
+
results.pazarama = pazaramaApi.init(config.pazarama);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
return results;
|
|
88
|
+
},
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Bağlı platformları listele
|
|
92
|
+
*/
|
|
93
|
+
getConnected() {
|
|
94
|
+
const connected = [];
|
|
95
|
+
for (const [name, api] of Object.entries(platforms)) {
|
|
96
|
+
if (api.isConnected()) {
|
|
97
|
+
connected.push(name);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
return connected;
|
|
101
|
+
},
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Durum özeti
|
|
105
|
+
*/
|
|
106
|
+
getStatus() {
|
|
107
|
+
const status = {};
|
|
108
|
+
for (const [name, api] of Object.entries(platforms)) {
|
|
109
|
+
status[name] = {
|
|
110
|
+
connected: api.isConnected(),
|
|
111
|
+
icon: this.getIcon(name)
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
return status;
|
|
115
|
+
},
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Platform ikonu
|
|
119
|
+
*/
|
|
120
|
+
getIcon(platform) {
|
|
121
|
+
const icons = {
|
|
122
|
+
trendyol: '🟠',
|
|
123
|
+
hepsiburada: '🟣',
|
|
124
|
+
n11: '🔵',
|
|
125
|
+
amazon: '🟡',
|
|
126
|
+
ciceksepeti: '🌸',
|
|
127
|
+
pttavm: '📮',
|
|
128
|
+
pazarama: '🛒'
|
|
129
|
+
};
|
|
130
|
+
return icons[platform] || '📦';
|
|
131
|
+
},
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Çoklu platform fiyat güncelle
|
|
135
|
+
*/
|
|
136
|
+
async updatePriceMulti(barcode, price, targetPlatforms = 'all') {
|
|
137
|
+
const targets = targetPlatforms === 'all'
|
|
138
|
+
? this.getConnected()
|
|
139
|
+
: targetPlatforms.split(',').map(p => PLATFORM_ALIASES[p.trim()]).filter(Boolean);
|
|
140
|
+
|
|
141
|
+
const results = {};
|
|
142
|
+
for (const platform of targets) {
|
|
143
|
+
const api = platforms[platform];
|
|
144
|
+
if (api?.isConnected()) {
|
|
145
|
+
results[platform] = await api.updatePrice(barcode, price);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
return results;
|
|
149
|
+
},
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Çoklu platform stok güncelle
|
|
153
|
+
*/
|
|
154
|
+
async updateStockMulti(barcode, quantity, targetPlatforms = 'all') {
|
|
155
|
+
const targets = targetPlatforms === 'all'
|
|
156
|
+
? this.getConnected()
|
|
157
|
+
: targetPlatforms.split(',').map(p => PLATFORM_ALIASES[p.trim()]).filter(Boolean);
|
|
158
|
+
|
|
159
|
+
const results = {};
|
|
160
|
+
for (const platform of targets) {
|
|
161
|
+
const api = platforms[platform];
|
|
162
|
+
if (api?.isConnected()) {
|
|
163
|
+
results[platform] = await api.updateStock(barcode, quantity);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
return results;
|
|
167
|
+
},
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Tüm platformlardan sipariş çek
|
|
171
|
+
*/
|
|
172
|
+
async getAllOrders(params = {}) {
|
|
173
|
+
const connected = this.getConnected();
|
|
174
|
+
const allOrders = [];
|
|
175
|
+
|
|
176
|
+
for (const platform of connected) {
|
|
177
|
+
const api = platforms[platform];
|
|
178
|
+
const result = await api.getOrders(params);
|
|
179
|
+
if (result.success) {
|
|
180
|
+
const orders = result.data.content || result.data.orders || result.data || [];
|
|
181
|
+
orders.forEach(order => {
|
|
182
|
+
allOrders.push({
|
|
183
|
+
...order,
|
|
184
|
+
_platform: platform,
|
|
185
|
+
_icon: this.getIcon(platform)
|
|
186
|
+
});
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// Tarihe göre sırala
|
|
192
|
+
allOrders.sort((a, b) => new Date(b.createdDate || b.orderDate) - new Date(a.createdDate || a.orderDate));
|
|
193
|
+
return allOrders;
|
|
194
|
+
}
|
|
195
|
+
};
|
|
196
|
+
|
|
197
|
+
// Export individual APIs
|
|
198
|
+
export {
|
|
199
|
+
trendyolApi,
|
|
200
|
+
hepsiburadaApi,
|
|
201
|
+
n11Api,
|
|
202
|
+
amazonApi,
|
|
203
|
+
ciceksepetiApi,
|
|
204
|
+
pttavmApi,
|
|
205
|
+
pazaramaApi,
|
|
206
|
+
TrendyolAPI,
|
|
207
|
+
HepsiburadaAPI,
|
|
208
|
+
N11API,
|
|
209
|
+
AmazonAPI,
|
|
210
|
+
CiceksepetiAPI,
|
|
211
|
+
PttavmAPI,
|
|
212
|
+
PazaramaAPI
|
|
213
|
+
};
|
|
214
|
+
|
|
215
|
+
export default platformHub;
|
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 🔵 N11 SOAP API Entegrasyonu
|
|
3
|
+
* api.n11.com/ws/*.wsdl
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import axios from 'axios';
|
|
7
|
+
import { parseStringPromise, Builder } from 'xml2js';
|
|
8
|
+
|
|
9
|
+
const WSDL_URLS = {
|
|
10
|
+
product: 'https://api.n11.com/ws/ProductService.wsdl',
|
|
11
|
+
order: 'https://api.n11.com/ws/OrderService.wsdl',
|
|
12
|
+
shipment: 'https://api.n11.com/ws/ShipmentService.wsdl',
|
|
13
|
+
category: 'https://api.n11.com/ws/CategoryService.wsdl',
|
|
14
|
+
city: 'https://api.n11.com/ws/CityService.wsdl'
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
const SOAP_ENDPOINTS = {
|
|
18
|
+
product: 'https://api.n11.com/ws/ProductService',
|
|
19
|
+
order: 'https://api.n11.com/ws/OrderService',
|
|
20
|
+
shipment: 'https://api.n11.com/ws/ShipmentService',
|
|
21
|
+
category: 'https://api.n11.com/ws/CategoryService'
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export class N11API {
|
|
25
|
+
constructor(config) {
|
|
26
|
+
this.apiKey = config.apiKey;
|
|
27
|
+
this.apiSecret = config.apiSecret;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
_buildSoapEnvelope(service, method, body) {
|
|
31
|
+
const auth = `
|
|
32
|
+
<auth>
|
|
33
|
+
<appKey>${this.apiKey}</appKey>
|
|
34
|
+
<appSecret>${this.apiSecret}</appSecret>
|
|
35
|
+
</auth>
|
|
36
|
+
`;
|
|
37
|
+
|
|
38
|
+
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
39
|
+
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
|
|
40
|
+
xmlns:ns1="http://www.n11.com/ws/schemas">
|
|
41
|
+
<SOAP-ENV:Body>
|
|
42
|
+
<ns1:${method}Request>
|
|
43
|
+
${auth}
|
|
44
|
+
${body}
|
|
45
|
+
</ns1:${method}Request>
|
|
46
|
+
</SOAP-ENV:Body>
|
|
47
|
+
</SOAP-ENV:Envelope>`;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
async _soapRequest(service, method, body = '') {
|
|
51
|
+
try {
|
|
52
|
+
const envelope = this._buildSoapEnvelope(service, method, body);
|
|
53
|
+
const response = await axios.post(SOAP_ENDPOINTS[service], envelope, {
|
|
54
|
+
headers: {
|
|
55
|
+
'Content-Type': 'text/xml; charset=utf-8',
|
|
56
|
+
'SOAPAction': `${method}`
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
const result = await parseStringPromise(response.data, { explicitArray: false });
|
|
61
|
+
const bodyKey = Object.keys(result['SOAP-ENV:Envelope']['SOAP-ENV:Body'])[0];
|
|
62
|
+
return {
|
|
63
|
+
success: true,
|
|
64
|
+
data: result['SOAP-ENV:Envelope']['SOAP-ENV:Body'][bodyKey]
|
|
65
|
+
};
|
|
66
|
+
} catch (error) {
|
|
67
|
+
return {
|
|
68
|
+
success: false,
|
|
69
|
+
error: error.response?.data || error.message
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
75
|
+
// ÜRÜN İŞLEMLERİ
|
|
76
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
77
|
+
|
|
78
|
+
async getProducts(params = {}) {
|
|
79
|
+
const { page = 0, size = 100 } = params;
|
|
80
|
+
return await this._soapRequest('product', 'GetProductList', `
|
|
81
|
+
<pagingData>
|
|
82
|
+
<currentPage>${page}</currentPage>
|
|
83
|
+
<pageSize>${size}</pageSize>
|
|
84
|
+
</pagingData>
|
|
85
|
+
`);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
async getProductByCode(productSellerCode) {
|
|
89
|
+
return await this._soapRequest('product', 'GetProductBySellerCode', `
|
|
90
|
+
<productSellerCode>${productSellerCode}</productSellerCode>
|
|
91
|
+
`);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
async createProduct(product) {
|
|
95
|
+
const {
|
|
96
|
+
productSellerCode, title, subtitle, description,
|
|
97
|
+
domesticPrice, currencyType = 1, categoryId,
|
|
98
|
+
preparingDay = 3, shipmentTemplate, images, attributes
|
|
99
|
+
} = product;
|
|
100
|
+
|
|
101
|
+
const imageXml = images.map((url, i) =>
|
|
102
|
+
`<image><url>${url}</url><order>${i + 1}</order></image>`
|
|
103
|
+
).join('');
|
|
104
|
+
|
|
105
|
+
const attrXml = attributes?.map(a =>
|
|
106
|
+
`<productAttribute>
|
|
107
|
+
<name>${a.name}</name>
|
|
108
|
+
<value>${a.value}</value>
|
|
109
|
+
</productAttribute>`
|
|
110
|
+
).join('') || '';
|
|
111
|
+
|
|
112
|
+
return await this._soapRequest('product', 'SaveProduct', `
|
|
113
|
+
<product>
|
|
114
|
+
<productSellerCode>${productSellerCode}</productSellerCode>
|
|
115
|
+
<title>${title}</title>
|
|
116
|
+
<subtitle>${subtitle || ''}</subtitle>
|
|
117
|
+
<description><![CDATA[${description}]]></description>
|
|
118
|
+
<category><id>${categoryId}</id></category>
|
|
119
|
+
<price>${domesticPrice}</price>
|
|
120
|
+
<currencyType>${currencyType}</currencyType>
|
|
121
|
+
<preparingDay>${preparingDay}</preparingDay>
|
|
122
|
+
<shipmentTemplate>${shipmentTemplate}</shipmentTemplate>
|
|
123
|
+
<images>${imageXml}</images>
|
|
124
|
+
<attributes>${attrXml}</attributes>
|
|
125
|
+
<stockItems>
|
|
126
|
+
<stockItem>
|
|
127
|
+
<quantity>0</quantity>
|
|
128
|
+
<sellerStockCode>${productSellerCode}</sellerStockCode>
|
|
129
|
+
</stockItem>
|
|
130
|
+
</stockItems>
|
|
131
|
+
</product>
|
|
132
|
+
`);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
async updatePrice(productSellerCode, price) {
|
|
136
|
+
return await this._soapRequest('product', 'UpdateProductPriceBySellerCode', `
|
|
137
|
+
<productSellerCode>${productSellerCode}</productSellerCode>
|
|
138
|
+
<price>${price}</price>
|
|
139
|
+
<currencyType>1</currencyType>
|
|
140
|
+
`);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
async updateStock(productSellerCode, quantity) {
|
|
144
|
+
return await this._soapRequest('product', 'UpdateStockByStockSellerCode', `
|
|
145
|
+
<stockItems>
|
|
146
|
+
<stockItem>
|
|
147
|
+
<sellerStockCode>${productSellerCode}</sellerStockCode>
|
|
148
|
+
<quantity>${quantity}</quantity>
|
|
149
|
+
</stockItem>
|
|
150
|
+
</stockItems>
|
|
151
|
+
`);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
async deleteProduct(productSellerCode) {
|
|
155
|
+
return await this._soapRequest('product', 'DeleteProductBySellerCode', `
|
|
156
|
+
<productSellerCode>${productSellerCode}</productSellerCode>
|
|
157
|
+
`);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
161
|
+
// SİPARİŞ İŞLEMLERİ
|
|
162
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
163
|
+
|
|
164
|
+
async getOrders(params = {}) {
|
|
165
|
+
const { status, startDate, endDate, page = 0, size = 100 } = params;
|
|
166
|
+
|
|
167
|
+
let searchData = '';
|
|
168
|
+
if (status) searchData += `<status>${status}</status>`;
|
|
169
|
+
if (startDate) searchData += `<period><startDate>${startDate}</startDate>`;
|
|
170
|
+
if (endDate) searchData += `<endDate>${endDate}</endDate></period>`;
|
|
171
|
+
|
|
172
|
+
return await this._soapRequest('order', 'DetailedOrderList', `
|
|
173
|
+
<searchData>${searchData}</searchData>
|
|
174
|
+
<pagingData>
|
|
175
|
+
<currentPage>${page}</currentPage>
|
|
176
|
+
<pageSize>${size}</pageSize>
|
|
177
|
+
</pagingData>
|
|
178
|
+
`);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
async getOrderDetail(orderId) {
|
|
182
|
+
return await this._soapRequest('order', 'OrderDetail', `
|
|
183
|
+
<orderRequest>
|
|
184
|
+
<id>${orderId}</id>
|
|
185
|
+
</orderRequest>
|
|
186
|
+
`);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
async shipOrder(orderItemList, shipmentCompanyCode, trackingNumber) {
|
|
190
|
+
// orderItemList: [{ id, quantity }]
|
|
191
|
+
const itemsXml = orderItemList.map(item =>
|
|
192
|
+
`<orderItem>
|
|
193
|
+
<id>${item.id}</id>
|
|
194
|
+
<quantity>${item.quantity}</quantity>
|
|
195
|
+
</orderItem>`
|
|
196
|
+
).join('');
|
|
197
|
+
|
|
198
|
+
return await this._soapRequest('order', 'MakeOrderItemShipment', `
|
|
199
|
+
<orderItemList>${itemsXml}</orderItemList>
|
|
200
|
+
<shipmentInfo>
|
|
201
|
+
<shipmentCompany><id>${shipmentCompanyCode}</id></shipmentCompany>
|
|
202
|
+
<trackingNumber>${trackingNumber}</trackingNumber>
|
|
203
|
+
</shipmentInfo>
|
|
204
|
+
`);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
208
|
+
// KATEGORİ
|
|
209
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
210
|
+
|
|
211
|
+
async getTopCategories() {
|
|
212
|
+
return await this._soapRequest('category', 'GetTopLevelCategories', '');
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
async getSubCategories(categoryId) {
|
|
216
|
+
return await this._soapRequest('category', 'GetSubCategories', `
|
|
217
|
+
<categoryId>${categoryId}</categoryId>
|
|
218
|
+
<pagingData>
|
|
219
|
+
<currentPage>0</currentPage>
|
|
220
|
+
<pageSize>100</pageSize>
|
|
221
|
+
</pagingData>
|
|
222
|
+
`);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
async getCategoryAttributes(categoryId) {
|
|
226
|
+
return await this._soapRequest('category', 'GetCategoryAttributes', `
|
|
227
|
+
<categoryId>${categoryId}</categoryId>
|
|
228
|
+
<pagingData>
|
|
229
|
+
<currentPage>0</currentPage>
|
|
230
|
+
<pageSize>100</pageSize>
|
|
231
|
+
</pagingData>
|
|
232
|
+
`);
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
236
|
+
// HELPER
|
|
237
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
238
|
+
|
|
239
|
+
async testConnection() {
|
|
240
|
+
const result = await this.getProducts({ page: 0, size: 1 });
|
|
241
|
+
return result.success;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
isConnected() {
|
|
245
|
+
return !!(this.apiKey && this.apiSecret);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
let instance = null;
|
|
250
|
+
|
|
251
|
+
export const n11Api = {
|
|
252
|
+
init(config) {
|
|
253
|
+
instance = new N11API(config);
|
|
254
|
+
return instance;
|
|
255
|
+
},
|
|
256
|
+
getInstance() { return instance; },
|
|
257
|
+
isConnected() { return instance?.isConnected() || false; },
|
|
258
|
+
|
|
259
|
+
async getProducts(params) { return instance?.getProducts(params); },
|
|
260
|
+
async updatePrice(code, price) { return instance?.updatePrice(code, price); },
|
|
261
|
+
async updateStock(code, qty) { return instance?.updateStock(code, qty); },
|
|
262
|
+
async getOrders(params) { return instance?.getOrders(params); }
|
|
263
|
+
};
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 🛒 PAZARAMA API Entegrasyonu
|
|
3
|
+
* sellers.pazarama.com
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import axios from 'axios';
|
|
7
|
+
|
|
8
|
+
const BASE_URL = 'https://isortagimapi.pazarama.com/api';
|
|
9
|
+
const AUTH_URL = 'https://isortagimapi.pazarama.com/oauth/token';
|
|
10
|
+
|
|
11
|
+
export class PazaramaAPI {
|
|
12
|
+
constructor(config) {
|
|
13
|
+
this.clientId = config.clientId;
|
|
14
|
+
this.clientSecret = config.clientSecret;
|
|
15
|
+
this.accessToken = null;
|
|
16
|
+
this.tokenExpiry = null;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
async _getAccessToken() {
|
|
20
|
+
if (this.accessToken && this.tokenExpiry > Date.now()) {
|
|
21
|
+
return this.accessToken;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
try {
|
|
25
|
+
const response = await axios.post(AUTH_URL, {
|
|
26
|
+
grant_type: 'client_credentials',
|
|
27
|
+
client_id: this.clientId,
|
|
28
|
+
client_secret: this.clientSecret
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
this.accessToken = response.data.access_token;
|
|
32
|
+
this.tokenExpiry = Date.now() + (response.data.expires_in * 1000) - 60000;
|
|
33
|
+
return this.accessToken;
|
|
34
|
+
} catch (error) {
|
|
35
|
+
throw new Error('Pazarama token alınamadı: ' + error.message);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
async _request(method, endpoint, data = null, params = null) {
|
|
40
|
+
try {
|
|
41
|
+
const token = await this._getAccessToken();
|
|
42
|
+
const response = await axios({
|
|
43
|
+
method,
|
|
44
|
+
url: `${BASE_URL}${endpoint}`,
|
|
45
|
+
headers: {
|
|
46
|
+
'Authorization': `Bearer ${token}`,
|
|
47
|
+
'Content-Type': 'application/json'
|
|
48
|
+
},
|
|
49
|
+
data,
|
|
50
|
+
params
|
|
51
|
+
});
|
|
52
|
+
return { success: true, data: response.data };
|
|
53
|
+
} catch (error) {
|
|
54
|
+
return {
|
|
55
|
+
success: false,
|
|
56
|
+
error: error.response?.data || error.message
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
62
|
+
// ÜRÜN İŞLEMLERİ
|
|
63
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
64
|
+
|
|
65
|
+
async getProducts(params = {}) {
|
|
66
|
+
const { page = 0, size = 100, code } = params;
|
|
67
|
+
return await this._request('GET', '/products', null, {
|
|
68
|
+
page, size, code
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
async createProduct(product) {
|
|
73
|
+
return await this._request('POST', '/products', product);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
async updateProduct(productCode, updates) {
|
|
77
|
+
return await this._request('PUT', `/products/${productCode}`, updates);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
async updatePrice(productCode, salePrice, listPrice = null) {
|
|
81
|
+
return await this._request('PUT', `/products/${productCode}/price`, {
|
|
82
|
+
salePrice,
|
|
83
|
+
listPrice: listPrice || salePrice
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
async updateStock(productCode, quantity) {
|
|
88
|
+
return await this._request('PUT', `/products/${productCode}/stock`, {
|
|
89
|
+
quantity
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
94
|
+
// SİPARİŞ İŞLEMLERİ
|
|
95
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
96
|
+
|
|
97
|
+
async getOrders(params = {}) {
|
|
98
|
+
const { status, startDate, endDate, page = 0, size = 100 } = params;
|
|
99
|
+
return await this._request('GET', '/orders', null, {
|
|
100
|
+
status, startDate, endDate, page, size
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
async getOrderDetail(orderId) {
|
|
105
|
+
return await this._request('GET', `/orders/${orderId}`);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
async approveOrder(orderId) {
|
|
109
|
+
return await this._request('PUT', `/orders/${orderId}/approve`);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
async shipOrder(orderId, trackingNumber, cargoCompany) {
|
|
113
|
+
return await this._request('PUT', `/orders/${orderId}/ship`, {
|
|
114
|
+
trackingNumber,
|
|
115
|
+
cargoCompany
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
async cancelOrder(orderId, reason) {
|
|
120
|
+
return await this._request('PUT', `/orders/${orderId}/cancel`, { reason });
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
124
|
+
// KATEGORİ & MARKA
|
|
125
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
126
|
+
|
|
127
|
+
async getCategories() {
|
|
128
|
+
return await this._request('GET', '/categories');
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
async getCategoryAttributes(categoryId) {
|
|
132
|
+
return await this._request('GET', `/categories/${categoryId}/attributes`);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
async getBrands() {
|
|
136
|
+
return await this._request('GET', '/brands');
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
140
|
+
// HELPER
|
|
141
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
142
|
+
|
|
143
|
+
async testConnection() {
|
|
144
|
+
try {
|
|
145
|
+
await this._getAccessToken();
|
|
146
|
+
return true;
|
|
147
|
+
} catch {
|
|
148
|
+
return false;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
isConnected() {
|
|
153
|
+
return !!(this.clientId && this.clientSecret);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
let instance = null;
|
|
158
|
+
|
|
159
|
+
export const pazaramaApi = {
|
|
160
|
+
init(config) {
|
|
161
|
+
instance = new PazaramaAPI(config);
|
|
162
|
+
return instance;
|
|
163
|
+
},
|
|
164
|
+
getInstance() { return instance; },
|
|
165
|
+
isConnected() { return instance?.isConnected() || false; },
|
|
166
|
+
|
|
167
|
+
async getProducts(params) { return instance?.getProducts(params); },
|
|
168
|
+
async updatePrice(code, price) { return instance?.updatePrice(code, price); },
|
|
169
|
+
async updateStock(code, qty) { return instance?.updateStock(code, qty); },
|
|
170
|
+
async getOrders(params) { return instance?.getOrders(params); }
|
|
171
|
+
};
|