π FBS API - Π£ΠΏΡΠ°Π²Π»Π΅Π½ΠΈΠ΅ ΠΎΡΠΏΡΠ°Π²Π»Π΅Π½ΠΈΡΠΌΠΈ
π FBS API - Π£ΠΏΡΠ°Π²Π»Π΅Π½ΠΈΠ΅ ΠΎΡΠΏΡΠ°Π²Π»Π΅Π½ΠΈΡΠΌΠΈ
ΠΠ΅ΡΠ°Π»ΡΠ½ΠΎΠ΅ ΡΡΠΊΠΎΠ²ΠΎΠ΄ΡΡΠ²ΠΎ ΠΏΠΎ ΡΠ°Π±ΠΎΡΠ΅ Ρ ΠΎΡΠΏΡΠ°Π²Π»Π΅Π½ΠΈΡΠΌΠΈ FBS β ΠΏΠΎΠ»ΡΡΠ΅Π½ΠΈΠ΅ ΡΠΏΠΈΡΠΊΠΎΠ², ΠΏΠΎΠΈΡΠΊ, ΡΠΈΠ»ΡΡΡΠ°ΡΠΈΡ ΠΈ ΡΠΏΡΠ°Π²Π»Π΅Π½ΠΈΠ΅ ΠΆΠΈΠ·Π½Π΅Π½Π½ΡΠΌ ΡΠΈΠΊΠ»ΠΎΠΌ Π·Π°ΠΊΠ°Π·ΠΎΠ².
π― ΠΠ±Π·ΠΎΡ ΠΌΠ΅ΡΠΎΠ΄ΠΎΠ² ΡΠΏΡΠ°Π²Π»Π΅Π½ΠΈΡ ΠΎΡΠΏΡΠ°Π²Π»Π΅Π½ΠΈΡΠΌΠΈ
| ΠΠ΅ΡΠΎΠ΄ | Endpoint | ΠΠ΅ΡΡΠΈΡ | ΠΠ°Π·Π½Π°ΡΠ΅Π½ΠΈΠ΅ |
|---|---|---|---|
getPostingListV3 |
/v3/posting/fbs/list |
v3 | Π‘ΠΏΠΈΡΠΎΠΊ ΠΎΡΠΏΡΠ°Π²Π»Π΅Π½ΠΈΠΉ Ρ ΡΠ°ΡΡΠΈΡΠ΅Π½Π½ΠΎΠΉ ΡΠΈΠ»ΡΡΡΠ°ΡΠΈΠ΅ΠΉ |
getUnfulfilledListV3 |
/v3/posting/fbs/unfulfilled/list |
v3 | ΠΠ΅ΠΎΠ±ΡΠ°Π±ΠΎΡΠ°Π½Π½ΡΠ΅ ΠΎΡΠΏΡΠ°Π²Π»Π΅Π½ΠΈΡ |
getPostingV3 |
/v3/posting/fbs/get |
v3 | ΠΠ΅ΡΠ°Π»ΡΠ½Π°Ρ ΠΈΠ½ΡΠΎΡΠΌΠ°ΡΠΈΡ ΠΎΠ± ΠΎΡΠΏΡΠ°Π²Π»Π΅Π½ΠΈΠΈ |
getPostingByBarcode |
/v2/posting/fbs/get-by-barcode |
v2 | ΠΠΎΠΈΡΠΊ ΠΎΡΠΏΡΠ°Π²Π»Π΅Π½ΠΈΡ ΠΏΠΎ ΡΡΡΠΈΡ ΠΊΠΎΠ΄Ρ |
cancelPosting |
/v2/posting/fbs/cancel |
v2 | ΠΡΠΌΠ΅Π½Π° ΠΎΡΠΏΡΠ°Π²Π»Π΅Π½ΠΈΡ |
moveToAwaitingDelivery |
/v2/posting/fbs/awaiting-delivery |
v2 | ΠΠ΅ΡΠ΅Π΄Π°ΡΠ° ΠΊ ΠΎΡΠ³ΡΡΠ·ΠΊΠ΅ |
π 1. ΠΠΎΠ»ΡΡΠ΅Π½ΠΈΠ΅ ΡΠΏΠΈΡΠΊΠ° ΠΎΡΠΏΡΠ°Π²Π»Π΅Π½ΠΈΠΉ
getPostingListV3() - ΠΡΠ½ΠΎΠ²Π½ΠΎΠΉ ΠΌΠ΅ΡΠΎΠ΄ ΡΠΏΠΈΡΠΊΠ°
// ΠΠ°Π·ΠΎΠ²ΡΠΉ Π·Π°ΠΏΡΠΎΡ ΠΎΡΠΏΡΠ°Π²Π»Π΅Π½ΠΈΠΉ
const postings = await client.fbs.getPostingListV3({
filter: {
since: '2024-01-01T00:00:00Z',
to: '2024-01-31T23:59:59Z',
status: 'awaiting_packaging' // ΠΠΎΠ½ΠΊΡΠ΅ΡΠ½ΡΠΉ ΡΡΠ°ΡΡΡ
},
limit: 100,
offset: 0
});
console.log(`π¦ ΠΠ°ΠΉΠ΄Π΅Π½ΠΎ ΠΎΡΠΏΡΠ°Π²Π»Π΅Π½ΠΈΠΉ: ${postings.result?.postings?.length}`);
console.log(`π ΠΡΡΡ Π΅ΡΠ΅ ΡΡΡΠ°Π½ΠΈΡΡ: ${postings.result?.has_next}`);
// ΠΠ±ΡΠ°Π±ΠΎΡΠΊΠ° ΡΠ΅Π·ΡΠ»ΡΡΠ°ΡΠΎΠ²
postings.result?.postings?.forEach(posting => {
console.log(`\nπ ΠΡΠΏΡΠ°Π²Π»Π΅Π½ΠΈΠ΅: ${posting.posting_number}`);
console.log(` Π‘ΡΠ°ΡΡΡ: ${posting.status}`);
console.log(` ΠΠ°ΡΠ° ΡΠΎΠ·Π΄Π°Π½ΠΈΡ: ${posting.created_at}`);
console.log(` ΠΠ°ΡΠ° ΠΎΡΠ³ΡΡΠ·ΠΊΠΈ: ${posting.shipment_date}`);
console.log(` Π’ΠΎΠ²Π°ΡΠΎΠ² Π² Π·Π°ΠΊΠ°Π·Π΅: ${posting.products?.length}`);
// ΠΠ½ΡΠΎΡΠΌΠ°ΡΠΈΡ ΠΎ ΡΠΎΠ²Π°ΡΠ°Ρ
posting.products?.forEach((product, index) => {
console.log(` ${index + 1}. ${product.name} (SKU: ${product.sku})`);
console.log(` ΠΠΎΠ»ΠΈΡΠ΅ΡΡΠ²ΠΎ: ${product.quantity} ΡΡ.`);
console.log(` Π¦Π΅Π½Π°: ${product.price}β½`);
});
});
Π Π°ΡΡΠΈΡΠ΅Π½Π½Π°Ρ ΡΠΈΠ»ΡΡΡΠ°ΡΠΈΡ
// Π€ΠΈΠ»ΡΡΡΠ°ΡΠΈΡ ΠΏΠΎ ΠΌΠ½ΠΎΠΆΠ΅ΡΡΠ²Π΅Π½Π½ΡΠΌ ΠΊΡΠΈΡΠ΅ΡΠΈΡΠΌ
const advancedFilter = await client.fbs.getPostingListV3({
filter: {
since: '2024-01-01T00:00:00Z',
to: '2024-01-31T23:59:59Z',
status: ['awaiting_packaging', 'awaiting_deliver'], // ΠΠ½ΠΎΠΆΠ΅ΡΡΠ²Π΅Π½Π½ΡΠ΅ ΡΡΠ°ΡΡΡΡ
delivery_method_id: [1, 2], // ΠΠΎΠ½ΠΊΡΠ΅ΡΠ½ΡΠ΅ ΠΌΠ΅ΡΠΎΠ΄Ρ Π΄ΠΎΡΡΠ°Π²ΠΊΠΈ
provider_id: [3, 4], // ΠΠΏΡΠ΅Π΄Π΅Π»Π΅Π½Π½ΡΠ΅ ΠΏΡΠΎΠ²Π°ΠΉΠ΄Π΅ΡΡ
warehouse_id: [12345] // ΠΠΎΠ½ΠΊΡΠ΅ΡΠ½ΡΠΉ ΡΠΊΠ»Π°Π΄
},
limit: 50,
offset: 0,
with: {
analytics_data: true, // ΠΠΊΠ»ΡΡΠΈΡΡ Π°Π½Π°Π»ΠΈΡΠΈΡΠ΅ΡΠΊΠΈΠ΅ Π΄Π°Π½Π½ΡΠ΅
financial_data: true, // ΠΠΊΠ»ΡΡΠΈΡΡ ΡΠΈΠ½Π°Π½ΡΠΎΠ²ΡΡ ΠΈΠ½ΡΠΎΡΠΌΠ°ΡΠΈΡ
translit: false // ΠΠ΅ ΡΡΠ°Π½ΡΠ»ΠΈΡΠ΅ΡΠΈΡΠΎΠ²Π°ΡΡ Π½Π°Π·Π²Π°Π½ΠΈΡ
}
});
// ΠΠ°Π³ΠΈΠ½Π°ΡΠΈΡ Π΄Π»Ρ Π±ΠΎΠ»ΡΡΠΈΡ
ΠΎΠ±ΡΠ΅ΠΌΠΎΠ²
const getAllPostings = async (filter: any) => {
const allPostings: any[] = [];
let offset = 0;
const limit = 100;
let hasNext = true;
while (hasNext) {
const response = await client.fbs.getPostingListV3({
filter,
limit,
offset,
with: { analytics_data: true }
});
const postings = response.result?.postings || [];
allPostings.push(...postings);
hasNext = response.result?.has_next || false;
offset += limit;
console.log(`π ΠΠ°Π³ΡΡΠΆΠ΅Π½ΠΎ ΠΎΡΠΏΡΠ°Π²Π»Π΅Π½ΠΈΠΉ: ${allPostings.length}`);
// ΠΠ°ΡΠ·Π° ΠΌΠ΅ΠΆΠ΄Ρ Π·Π°ΠΏΡΠΎΡΠ°ΠΌΠΈ Π΄Π»Ρ ΠΈΠ·Π±Π΅ΠΆΠ°Π½ΠΈΡ Π»ΠΈΠΌΠΈΡΠΎΠ²
if (hasNext) {
await new Promise(resolve => setTimeout(resolve, 1000));
}
}
return allPostings;
};
β³ 2. ΠΠ΅ΠΎΠ±ΡΠ°Π±ΠΎΡΠ°Π½Π½ΡΠ΅ ΠΎΡΠΏΡΠ°Π²Π»Π΅Π½ΠΈΡ
getUnfulfilledListV3() - ΠΡΠΈΠΎΡΠΈΡΠ΅ΡΠ½ΡΠ΅ Π·Π°ΠΊΠ°Π·Ρ
// ΠΠΎΠ»ΡΡΠΈΡΡ Π²ΡΠ΅ Π½Π΅ΠΎΠ±ΡΠ°Π±ΠΎΡΠ°Π½Π½ΡΠ΅ ΠΎΡΠΏΡΠ°Π²Π»Π΅Π½ΠΈΡ
const unfulfilledPostings = await client.fbs.getUnfulfilledListV3({
limit: 100,
offset: 0
});
console.log(`β³ ΠΠ΅ΠΎΠ±ΡΠ°Π±ΠΎΡΠ°Π½Π½ΡΡ
ΠΎΡΠΏΡΠ°Π²Π»Π΅Π½ΠΈΠΉ: ${unfulfilledPostings.result?.postings?.length}`);
// ΠΡΡΠΏΠΏΠΈΡΠΎΠ²ΠΊΠ° ΠΏΠΎ ΡΡΠ°ΡΡΡΠ°ΠΌ Π΄Π»Ρ ΠΏΡΠΈΠΎΡΠΈΡΠΈΠ·Π°ΡΠΈΠΈ
const groupByStatus = (postings: any[]) => {
const grouped: { [key: string]: any[] } = {};
postings.forEach(posting => {
const status = posting.status || 'unknown';
if (!grouped[status]) {
grouped[status] = [];
}
grouped[status].push(posting);
});
return grouped;
};
const groupedPostings = groupByStatus(unfulfilledPostings.result?.postings || []);
// ΠΡΠ²ΠΎΠ΄ ΠΏΡΠΈΠΎΡΠΈΡΠ΅ΡΠΎΠ²
const statusPriority = [
'awaiting_packaging', // ΠΡΡΡΠΈΠΉ ΠΏΡΠΈΠΎΡΠΈΡΠ΅Ρ
'awaiting_approve',
'awaiting_deliver',
'acceptance_in_progress',
'arbitration' // Π’ΡΠ΅Π±ΡΠ΅Ρ ΠΎΡΠΎΠ±ΠΎΠ³ΠΎ Π²Π½ΠΈΠΌΠ°Π½ΠΈΡ
];
console.log('\nπ ΠΠ΅ΠΎΠ±ΡΠ°Π±ΠΎΡΠ°Π½Π½ΡΠ΅ ΠΎΡΠΏΡΠ°Π²Π»Π΅Π½ΠΈΡ ΠΏΠΎ ΡΡΠ°ΡΡΡΠ°ΠΌ:');
statusPriority.forEach(status => {
const count = groupedPostings[status]?.length || 0;
if (count > 0) {
console.log(` ${status}: ${count} ΠΎΡΠΏΡΠ°Π²Π»Π΅Π½ΠΈΠΉ`);
// ΠΠΎΠΊΠ°Π·Π°ΡΡ ΠΏΠ΅ΡΠ²ΡΠ΅ Π½Π΅ΡΠΊΠΎΠ»ΡΠΊΠΎ Π΄Π»Ρ ΠΊΠΎΠ½ΡΠ΅ΠΊΡΡΠ°
groupedPostings[status].slice(0, 3).forEach(posting => {
console.log(` - ${posting.posting_number} (${posting.shipment_date})`);
});
}
});
π 3. ΠΠΎΠΈΡΠΊ ΠΈ ΠΏΠΎΠ»ΡΡΠ΅Π½ΠΈΠ΅ ΠΊΠΎΠ½ΠΊΡΠ΅ΡΠ½ΠΎΠ³ΠΎ ΠΎΡΠΏΡΠ°Π²Π»Π΅Π½ΠΈΡ
getPostingV3() - ΠΠΎ ΠΈΠ΄Π΅Π½ΡΠΈΡΠΈΠΊΠ°ΡΠΎΡΡ
// ΠΠΎΠ»ΡΡΠΈΡΡ Π΄Π΅ΡΠ°Π»ΡΠ½ΡΡ ΠΈΠ½ΡΠΎΡΠΌΠ°ΡΠΈΡ ΠΎΠ± ΠΎΡΠΏΡΠ°Π²Π»Π΅Π½ΠΈΠΈ
const postingDetails = await client.fbs.getPostingV3({
posting_number: '12345-0001-1',
with: {
analytics_data: true,
financial_data: true
}
});
const posting = postingDetails.result;
if (posting) {
console.log(`\nπ ΠΠ΅ΡΠ°Π»ΠΈ ΠΎΡΠΏΡΠ°Π²Π»Π΅Π½ΠΈΡ: ${posting.posting_number}`);
console.log(` Π‘ΡΠ°ΡΡΡ: ${posting.status}`);
console.log(` ΠΠ°ΡΠ° ΡΠΎΠ·Π΄Π°Π½ΠΈΡ: ${posting.created_at}`);
console.log(` ΠΠ°ΡΠ° ΠΎΡΠ³ΡΡΠ·ΠΊΠΈ: ${posting.shipment_date}`);
console.log(` ΠΠ΄ΡΠ΅Ρ Π΄ΠΎΡΡΠ°Π²ΠΊΠΈ: ${posting.delivery_method?.address}`);
console.log(` Π‘ΡΠΎΠΈΠΌΠΎΡΡΡ Π΄ΠΎΡΡΠ°Π²ΠΊΠΈ: ${posting.delivery_price}β½`);
// Π€ΠΈΠ½Π°Π½ΡΠΎΠ²Π°Ρ ΠΈΠ½ΡΠΎΡΠΌΠ°ΡΠΈΡ
if (posting.financial_data) {
console.log(` π° ΠΡΡΡΡΠΊΠ°: ${posting.financial_data.posting_services?.marketplace_service_item_fulfillment}β½`);
console.log(` πΈ ΠΠΎΠΌΠΈΡΡΠΈΡ: ${posting.financial_data.posting_services?.marketplace_service_item_pickup}β½`);
}
// ΠΠ½Π°Π»ΠΈΡΠΈΡΠ΅ΡΠΊΠΈΠ΅ Π΄Π°Π½Π½ΡΠ΅
if (posting.analytics_data) {
console.log(` π Π Π΅Π³ΠΈΠΎΠ½ Π΄ΠΎΡΡΠ°Π²ΠΊΠΈ: ${posting.analytics_data.region}`);
console.log(` π ΠΠΎΡΠΎΠ΄: ${posting.analytics_data.city}`);
}
}
getPostingByBarcode() - ΠΠΎ ΡΡΡΠΈΡ
ΠΊΠΎΠ΄Ρ
// ΠΠΎΠΈΡΠΊ ΠΎΡΠΏΡΠ°Π²Π»Π΅Π½ΠΈΡ ΠΏΠΎ ΡΡΡΠΈΡ
ΠΊΠΎΠ΄Ρ (ΡΠ΄ΠΎΠ±Π½ΠΎ Π΄Π»Ρ ΡΠΊΠ°Π½ΠΈΡΠΎΠ²Π°Π½ΠΈΡ)
const findByBarcode = async (barcode: string) => {
try {
const result = await client.fbs.getPostingByBarcode({
barcode: barcode
});
if (result.result) {
console.log(`β
ΠΠ°ΠΉΠ΄Π΅Π½ΠΎ ΠΎΡΠΏΡΠ°Π²Π»Π΅Π½ΠΈΠ΅: ${result.result.posting_number}`);
console.log(` Π‘ΡΠ°ΡΡΡ: ${result.result.status}`);
console.log(` Π’ΠΎΠ²Π°ΡΠΎΠ²: ${result.result.products?.length}`);
return result.result;
}
} catch (error) {
console.error(`β ΠΡΠΏΡΠ°Π²Π»Π΅Π½ΠΈΠ΅ Ρ ΡΡΡΠΈΡ
ΠΊΠΎΠ΄ΠΎΠΌ ${barcode} Π½Π΅ Π½Π°ΠΉΠ΄Π΅Π½ΠΎ:`, error.message);
return null;
}
};
// ΠΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°Π½ΠΈΠ΅ Π΄Π»Ρ ΡΠΊΠ°Π½ΠΈΡΠΎΠ²Π°Π½ΠΈΡ Π½Π° ΡΠΊΠ»Π°Π΄Π΅
const processScannedBarcode = async (scannedBarcode: string) => {
const posting = await findByBarcode(scannedBarcode);
if (posting) {
if (posting.status === 'awaiting_packaging') {
console.log('π¦ ΠΡΠΏΡΠ°Π²Π»Π΅Π½ΠΈΠ΅ Π³ΠΎΡΠΎΠ²ΠΎ ΠΊ ΡΠΏΠ°ΠΊΠΎΠ²ΠΊΠ΅');
// ΠΠΎΠ³ΠΈΠΊΠ° ΡΠΏΠ°ΠΊΠΎΠ²ΠΊΠΈ
} else if (posting.status === 'awaiting_deliver') {
console.log('π ΠΡΠΏΡΠ°Π²Π»Π΅Π½ΠΈΠ΅ Π³ΠΎΡΠΎΠ²ΠΎ ΠΊ ΠΎΡΠ³ΡΡΠ·ΠΊΠ΅');
// ΠΠΎΠ³ΠΈΠΊΠ° ΠΎΡΠ³ΡΡΠ·ΠΊΠΈ
} else {
console.log(`β οΈ ΠΠ΅ΠΎΠΆΠΈΠ΄Π°Π½Π½ΡΠΉ ΡΡΠ°ΡΡΡ: ${posting.status}`);
}
}
};
β 4. ΠΡΠΌΠ΅Π½Π° ΠΎΡΠΏΡΠ°Π²Π»Π΅Π½ΠΈΡ
cancelPosting() - Π‘ ΡΠΊΠ°Π·Π°Π½ΠΈΠ΅ΠΌ ΠΏΡΠΈΡΠΈΠ½Ρ
// ΠΠΎΠ»ΡΡΠΈΡΡ ΡΠΏΠΈΡΠΎΠΊ Π΄ΠΎΡΡΡΠΏΠ½ΡΡ
ΠΏΡΠΈΡΠΈΠ½ ΠΎΡΠΌΠ΅Π½Ρ
const cancelReasons = await client.fbs.getCancelReasonList();
console.log('π ΠΠΎΡΡΡΠΏΠ½ΡΠ΅ ΠΏΡΠΈΡΠΈΠ½Ρ ΠΎΡΠΌΠ΅Π½Ρ:');
cancelReasons.result?.forEach(reason => {
console.log(` ${reason.id}: ${reason.name}`);
});
// ΠΡΠΌΠ΅Π½ΠΈΡΡ ΠΎΡΠΏΡΠ°Π²Π»Π΅Π½ΠΈΠ΅ Ρ ΠΊΠΎΠ½ΠΊΡΠ΅ΡΠ½ΠΎΠΉ ΠΏΡΠΈΡΠΈΠ½ΠΎΠΉ
const cancelPostingWithReason = async (postingNumber: string, reasonId: number, customMessage?: string) => {
try {
const cancelRequest: any = {
posting_number: postingNumber,
cancel_reason_id: reasonId
};
// ΠΡΠ»ΠΈ ΠΏΡΠΈΡΠΈΠ½Π° 402, ΡΡΠ΅Π±ΡΠ΅ΡΡΡ Π΄ΠΎΠΏΠΎΠ»Π½ΠΈΡΠ΅Π»ΡΠ½ΠΎΠ΅ ΡΠΎΠΎΠ±ΡΠ΅Π½ΠΈΠ΅
if (reasonId === 402 && customMessage) {
cancelRequest.cancel_reason_message = customMessage;
}
const result = await client.fbs.cancelPosting(cancelRequest);
if (result.result) {
console.log(`β
ΠΡΠΏΡΠ°Π²Π»Π΅Π½ΠΈΠ΅ ${postingNumber} ΠΎΡΠΌΠ΅Π½Π΅Π½ΠΎ`);
console.log(` ΠΡΠΈΡΠΈΠ½Π°: ${reasonId}`);
if (customMessage) {
console.log(` Π‘ΠΎΠΎΠ±ΡΠ΅Π½ΠΈΠ΅: ${customMessage}`);
}
}
return result;
} catch (error) {
console.error(`β ΠΡΠΈΠ±ΠΊΠ° ΠΎΡΠΌΠ΅Π½Ρ ΠΎΡΠΏΡΠ°Π²Π»Π΅Π½ΠΈΡ ${postingNumber}:`, error.message);
throw error;
}
};
// ΠΠ°ΡΡΠΎΠ²Π°Ρ ΠΎΡΠΌΠ΅Π½Π° Ρ ΠΎΠ΄ΠΈΠ½Π°ΠΊΠΎΠ²ΠΎΠΉ ΠΏΡΠΈΡΠΈΠ½ΠΎΠΉ
const bulkCancelPostings = async (postingNumbers: string[], reasonId: number) => {
const results = [];
for (const postingNumber of postingNumbers) {
try {
const result = await cancelPostingWithReason(postingNumber, reasonId);
results.push({ postingNumber, success: true, result });
// ΠΠ°ΡΠ·Π° ΠΌΠ΅ΠΆΠ΄Ρ Π·Π°ΠΏΡΠΎΡΠ°ΠΌΠΈ
await new Promise(resolve => setTimeout(resolve, 500));
} catch (error) {
results.push({ postingNumber, success: false, error: error.message });
}
}
console.log(`\nπ Π Π΅Π·ΡΠ»ΡΡΠ°ΡΡ ΠΌΠ°ΡΡΠΎΠ²ΠΎΠΉ ΠΎΡΠΌΠ΅Π½Ρ:`);
console.log(`β
Π£ΡΠΏΠ΅ΡΠ½ΠΎ: ${results.filter(r => r.success).length}`);
console.log(`β ΠΡΠΈΠ±ΠΎΠΊ: ${results.filter(r => !r.success).length}`);
return results;
};
π 5. ΠΠ΅ΡΠ΅Π΄Π°ΡΠ° ΠΊ ΠΎΡΠ³ΡΡΠ·ΠΊΠ΅
moveToAwaitingDelivery() - Π Π΅ΡΠ΅Π½ΠΈΠ΅ ΡΠΏΠΎΡΠ½ΡΡ
ΡΠΈΡΡΠ°ΡΠΈΠΉ
// ΠΠ΅ΡΠ΅Π΄Π°ΡΡ ΡΠΏΠΎΡΠ½ΠΎΠ΅ ΠΎΡΠΏΡΠ°Π²Π»Π΅Π½ΠΈΠ΅ ΠΊ ΠΎΡΠ³ΡΡΠ·ΠΊΠ΅
const movePostingToDelivery = async (postingNumber: string) => {
try {
const result = await client.fbs.moveToAwaitingDelivery({
posting_number: postingNumber
});
if (result.result) {
console.log(`β
ΠΡΠΏΡΠ°Π²Π»Π΅Π½ΠΈΠ΅ ${postingNumber} ΠΏΠ΅ΡΠ΅Π΄Π°Π½ΠΎ ΠΊ ΠΎΡΠ³ΡΡΠ·ΠΊΠ΅`);
console.log(` ΠΠΎΠ²ΡΠΉ ΡΡΠ°ΡΡΡ: awaiting_deliver`);
}
return result;
} catch (error) {
console.error(`β ΠΡΠΈΠ±ΠΊΠ° ΠΏΠ΅ΡΠ΅Π΄Π°ΡΠΈ ΠΊ ΠΎΡΠ³ΡΡΠ·ΠΊΠ΅ ${postingNumber}:`, error.message);
throw error;
}
};
// ΠΠ°ΠΊΠ΅ΡΠ½ΠΎΠ΅ ΡΠ΅ΡΠ΅Π½ΠΈΠ΅ Π°ΡΠ±ΠΈΡΡΠ°ΠΆΠ½ΡΡ
ΡΠΏΠΎΡΠΎΠ²
const resolveArbitrationPostings = async () => {
// ΠΠ°ΠΉΡΠΈ Π²ΡΠ΅ ΠΎΡΠΏΡΠ°Π²Π»Π΅Π½ΠΈΡ Π² Π°ΡΠ±ΠΈΡΡΠ°ΠΆΠ΅
const arbitrationPostings = await client.fbs.getPostingListV3({
filter: {
since: '2024-01-01T00:00:00Z',
to: new Date().toISOString(),
status: 'arbitration'
},
limit: 100
});
console.log(`βοΈ ΠΡΠΏΡΠ°Π²Π»Π΅Π½ΠΈΠΉ Π² Π°ΡΠ±ΠΈΡΡΠ°ΠΆΠ΅: ${arbitrationPostings.result?.postings?.length || 0}`);
// ΠΠ±ΡΠ°Π±ΠΎΡΠ°ΡΡ ΠΊΠ°ΠΆΠ΄ΠΎΠ΅ Π°ΡΠ±ΠΈΡΡΠ°ΠΆΠ½ΠΎΠ΅ ΠΎΡΠΏΡΠ°Π²Π»Π΅Π½ΠΈΠ΅
for (const posting of arbitrationPostings.result?.postings || []) {
try {
console.log(`\nπ Π Π΅ΡΠ΅Π½ΠΈΠ΅ Π°ΡΠ±ΠΈΡΡΠ°ΠΆΠ°: ${posting.posting_number}`);
// ΠΠ½Π°Π»ΠΈΠ· ΠΏΡΠΈΡΠΈΠ½Ρ Π°ΡΠ±ΠΈΡΡΠ°ΠΆΠ° (Π»ΠΎΠ³ΠΈΠΊΠ° Π·Π°Π²ΠΈΡΠΈΡ ΠΎΡ Π±ΠΈΠ·Π½Π΅Ρ-ΠΏΡΠ°Π²ΠΈΠ»)
const shouldDeliver = await analyzeArbitrationCase(posting);
if (shouldDeliver) {
await movePostingToDelivery(posting.posting_number);
console.log(` β
ΠΠ΅ΡΠ΅Π΄Π°Π½ΠΎ ΠΊ ΠΎΡΠ³ΡΡΠ·ΠΊΠ΅`);
} else {
await cancelPostingWithReason(posting.posting_number, 352); // ΠΡΠΈΡΠΈΠ½Π° ΠΎΡΠΌΠ΅Π½Ρ ΠΏΠΎ Π°ΡΠ±ΠΈΡΡΠ°ΠΆΡ
console.log(` β ΠΡΠΌΠ΅Π½Π΅Π½ΠΎ`);
}
// ΠΠ°ΡΠ·Π° ΠΌΠ΅ΠΆΠ΄Ρ ΠΎΠ±ΡΠ°Π±ΠΎΡΠΊΠΎΠΉ
await new Promise(resolve => setTimeout(resolve, 1000));
} catch (error) {
console.error(` β ΠΡΠΈΠ±ΠΊΠ° ΠΎΠ±ΡΠ°Π±ΠΎΡΠΊΠΈ ${posting.posting_number}:`, error.message);
}
}
};
// ΠΡΠΈΠΌΠ΅Ρ Π°Π½Π°Π»ΠΈΠ·Π° Π°ΡΠ±ΠΈΡΡΠ°ΠΆΠ½ΠΎΠ³ΠΎ ΡΠ»ΡΡΠ°Ρ
const analyzeArbitrationCase = async (posting: any): Promise<boolean> => {
// ΠΡΠΈΠΌΠ΅ΡΠ½Π°Ρ Π»ΠΎΠ³ΠΈΠΊΠ° Π°Π½Π°Π»ΠΈΠ·Π°
const criteria = {
daysInArbitration: calculateDaysInStatus(posting, 'arbitration'),
totalValue: posting.products?.reduce((sum: number, p: any) => sum + parseFloat(p.price || '0'), 0) || 0,
productCount: posting.products?.length || 0
};
// ΠΡΠΎΡΡΡΠ΅ ΠΏΡΠ°Π²ΠΈΠ»Π° ΠΏΡΠΈΠ½ΡΡΠΈΡ ΡΠ΅ΡΠ΅Π½ΠΈΡ
if (criteria.daysInArbitration > 7) {
return false; // Π‘Π»ΠΈΡΠΊΠΎΠΌ Π΄ΠΎΠ»Π³ΠΎ Π² Π°ΡΠ±ΠΈΡΡΠ°ΠΆΠ΅ - ΠΎΡΠΌΠ΅Π½ΠΈΡΡ
}
if (criteria.totalValue > 10000) {
return true; // ΠΠΎΡΠΎΠ³ΠΎΠΉ Π·Π°ΠΊΠ°Π· - ΠΏΠΎΠΏΡΡΠ°ΡΡΡΡ Π΄ΠΎΡΡΠ°Π²ΠΈΡΡ
}
return criteria.productCount <= 3; // ΠΡΠΎΡΡΡΠ΅ Π·Π°ΠΊΠ°Π·Ρ - Π΄ΠΎΡΡΠ°Π²ΠΈΡΡ
};
const calculateDaysInStatus = (posting: any, status: string): number => {
// ΠΠΎΠ³ΠΈΠΊΠ° ΡΠ°ΡΡΠ΅ΡΠ° Π΄Π½Π΅ΠΉ Π² ΡΡΠ°ΡΡΡΠ΅ Π½Π° ΠΎΡΠ½ΠΎΠ²Π΅ ΠΈΡΡΠΎΡΠΈΠΈ
const statusDate = new Date(posting.updated_at || posting.created_at);
const now = new Date();
return Math.floor((now.getTime() - statusDate.getTime()) / (1000 * 60 * 60 * 24));
};
π 6. ΠΠΎΠ½ΠΈΡΠΎΡΠΈΠ½Π³ ΠΈ Π°Π²ΡΠΎΠΌΠ°ΡΠΈΠ·Π°ΡΠΈΡ
ΠΠ²ΡΠΎΠΌΠ°ΡΠΈΡΠ΅ΡΠΊΠΈΠΉ ΠΎΠ±ΡΠ°Π±ΠΎΡΡΠΈΠΊ ΠΎΡΠΏΡΠ°Π²Π»Π΅Π½ΠΈΠΉ
class FbsPostingManager {
constructor(private client: OzonSellerAPI) {}
async processAllPendingPostings() {
console.log('π ΠΠ°ΠΏΡΡΠΊ ΠΎΠ±ΡΠ°Π±ΠΎΡΠΊΠΈ ΠΎΡΠΏΡΠ°Π²Π»Π΅Π½ΠΈΠΉ...');
try {
// 1. ΠΠ±ΡΠ°Π±ΠΎΡΠ°ΡΡ Π½ΠΎΠ²ΡΠ΅ ΠΎΡΠΏΡΠ°Π²Π»Π΅Π½ΠΈΡ (ΡΠΏΠ°ΠΊΠΎΠ²ΠΊΠ°)
await this.processPackaging();
// 2. ΠΠ±ΡΠ°Π±ΠΎΡΠ°ΡΡ Π³ΠΎΡΠΎΠ²ΡΠ΅ ΠΊ ΠΎΡΠ³ΡΡΠ·ΠΊΠ΅
await this.processDelivery();
// 3. Π Π΅ΡΠΈΡΡ Π°ΡΠ±ΠΈΡΡΠ°ΠΆΠ½ΡΠ΅ ΡΠΏΠΎΡΡ
await this.processArbitration();
// 4. ΠΡΠΎΠ²Π΅ΡΠΈΡΡ ΠΏΡΠΎΡΡΠΎΡΠ΅Π½Π½ΡΠ΅ ΠΎΡΠΏΡΠ°Π²Π»Π΅Π½ΠΈΡ
await this.checkOverduePostings();
console.log('β
ΠΠ±ΡΠ°Π±ΠΎΡΠΊΠ° Π·Π°Π²Π΅ΡΡΠ΅Π½Π°');
} catch (error) {
console.error('β ΠΡΠΈΠ±ΠΊΠ° ΠΎΠ±ΡΠ°Π±ΠΎΡΠΊΠΈ:', error);
}
}
private async processPackaging() {
const packagingPostings = await this.client.fbs.getPostingListV3({
filter: {
since: this.getDateDaysAgo(30),
to: new Date().toISOString(),
status: 'awaiting_packaging'
},
limit: 50
});
console.log(`π¦ Π ΡΠΏΠ°ΠΊΠΎΠ²ΠΊΠ΅: ${packagingPostings.result?.postings?.length || 0}`);
// Π£Π²Π΅Π΄ΠΎΠΌΠΈΡΡ ΡΠΊΠ»Π°Π΄ ΠΎ Π½Π΅ΠΎΠ±Ρ
ΠΎΠ΄ΠΈΠΌΠΎΡΡΠΈ ΡΠΏΠ°ΠΊΠΎΠ²ΠΊΠΈ
for (const posting of packagingPostings.result?.postings || []) {
await this.notifyWarehouseForPackaging(posting);
}
}
private async processDelivery() {
const deliveryPostings = await this.client.fbs.getPostingListV3({
filter: {
since: this.getDateDaysAgo(7),
to: new Date().toISOString(),
status: 'awaiting_deliver'
},
limit: 50
});
console.log(`π Π ΠΎΡΠ³ΡΡΠ·ΠΊΠ΅: ${deliveryPostings.result?.postings?.length || 0}`);
// Π‘ΠΎΠ·Π΄Π°ΡΡ ΡΡΠΈΠΊΠ΅ΡΠΊΠΈ Π΄Π»Ρ ΠΎΡΠ³ΡΡΠ·ΠΊΠΈ (ΡΡΠΎ Π±ΡΠ΄Π΅Ρ Π² ΡΠ»Π΅Π΄ΡΡΡΠ΅ΠΌ ΡΠ°Π·Π΄Π΅Π»Π΅)
for (const posting of deliveryPostings.result?.postings || []) {
await this.prepareForDelivery(posting);
}
}
private getDateDaysAgo(days: number): string {
const date = new Date();
date.setDate(date.getDate() - days);
return date.toISOString();
}
private async notifyWarehouseForPackaging(posting: any) {
// ΠΠΎΠ³ΠΈΠΊΠ° ΡΠ²Π΅Π΄ΠΎΠΌΠ»Π΅Π½ΠΈΡ ΡΠΊΠ»Π°Π΄Π°
console.log(`π§ Π£Π²Π΅Π΄ΠΎΠΌΠ»Π΅Π½ΠΈΠ΅ ΡΠΊΠ»Π°Π΄Π°: ${posting.posting_number}`);
}
private async prepareForDelivery(posting: any) {
// ΠΠΎΠ΄Π³ΠΎΡΠΎΠ²ΠΊΠ° ΠΊ ΠΎΡΠ³ΡΡΠ·ΠΊΠ΅ (ΡΠΎΠ·Π΄Π°Π½ΠΈΠ΅ ΡΡΠΈΠΊΠ΅ΡΠΎΠΊ ΠΈ Ρ.Π΄.)
console.log(`π·οΈ ΠΠΎΠ΄Π³ΠΎΡΠΎΠ²ΠΊΠ° ΡΡΠΈΠΊΠ΅ΡΠΊΠΈ: ${posting.posting_number}`);
}
}
// ΠΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°Π½ΠΈΠ΅
const postingManager = new FbsPostingManager(client);
await postingManager.processAllPendingPostings();
β οΈ ΠΠ°ΠΆΠ½ΡΠ΅ ΠΎΡΠΎΠ±Π΅Π½Π½ΠΎΡΡΠΈ
ΠΡΠ΅ΠΌΠ΅Π½Π½ΡΠ΅ ΠΎΠ³ΡΠ°Π½ΠΈΡΠ΅Π½ΠΈΡ
- Π€ΠΈΠ»ΡΡΡ ΠΏΠΎ Π²ΡΠ΅ΠΌΠ΅Π½ΠΈ: ΠΌΠ°ΠΊΡΠΈΠΌΡΠΌ 1 Π³ΠΎΠ΄ ΠΌΠ΅ΠΆΠ΄Ρ
sinceΠΈto - ΠΠΊΡΡΠ°Π»ΡΠ½ΠΎΡΡΡ Π΄Π°Π½Π½ΡΡ : ΡΠ΅Π³ΡΠ»ΡΡΠ½ΠΎ ΠΎΠ±Π½ΠΎΠ²Π»ΡΠΉΡΠ΅ ΠΈΠ½ΡΠΎΡΠΌΠ°ΡΠΈΡ ΠΈΠ»ΠΈ ΠΈΡΠΏΠΎΠ»ΡΠ·ΡΠΉΡΠ΅ push-ΡΠ²Π΅Π΄ΠΎΠΌΠ»Π΅Π½ΠΈΡ
- Π‘ΡΠ°ΡΡΡ ΠΈΠ·ΠΌΠ΅Π½Π΅Π½ΠΈΡ: ΠΌΠΎΠ³ΡΡ ΠΏΡΠΎΠΈΡΡ ΠΎΠ΄ΠΈΡΡ Π°Π²ΡΠΎΠΌΠ°ΡΠΈΡΠ΅ΡΠΊΠΈ ΡΠΈΡΡΠ΅ΠΌΠΎΠΉ OZON
ΠΠ±ΡΠ°Π±ΠΎΡΠΊΠ° ΠΎΡΠΈΠ±ΠΎΠΊ
const safeGetPostings = async (filter: any) => {
try {
return await client.fbs.getPostingListV3(filter);
} catch (error) {
if (error.message.includes('time range too large')) {
console.warn('β οΈ Π‘Π»ΠΈΡΠΊΠΎΠΌ Π±ΠΎΠ»ΡΡΠΎΠΉ Π²ΡΠ΅ΠΌΠ΅Π½Π½ΠΎΠΉ Π΄ΠΈΠ°ΠΏΠ°Π·ΠΎΠ½, ΡΠ°Π·Π±ΠΈΠ²Π°Π΅ΠΌ Π½Π° ΡΠ°ΡΡΠΈ...');
return await getPostingsInBatches(filter);
}
throw error;
}
};
const getPostingsInBatches = async (filter: any) => {
// Π Π°Π·Π±ΠΈΡΡ Π±ΠΎΠ»ΡΡΠΎΠΉ ΠΏΠ΅ΡΠΈΠΎΠ΄ Π½Π° ΠΌΠ΅ΡΡΡΠ½ΡΠ΅ Π±Π°ΡΡΠΈ
const start = new Date(filter.since);
const end = new Date(filter.to);
const results = [];
while (start < end) {
const batchEnd = new Date(start);
batchEnd.setMonth(batchEnd.getMonth() + 1);
if (batchEnd > end) batchEnd.setTime(end.getTime());
const batchFilter = {
...filter,
since: start.toISOString(),
to: batchEnd.toISOString()
};
const batch = await client.fbs.getPostingListV3(batchFilter);
results.push(...(batch.result?.postings || []));
start.setTime(batchEnd.getTime());
await new Promise(resolve => setTimeout(resolve, 1000));
}
return { result: { postings: results } };
};
π‘ Π‘Π»Π΅Π΄ΡΡΡΠΈΠΉ ΡΠ°Π·Π΄Π΅Π»: ΠΡΠΈΠΊΠ΅ΡΠΊΠΈ ΠΈ ΠΏΠ΅ΡΠ°ΡΡ (fbs-labels.md) β ΠΏΠΎΠ΄ΡΠΎΠ±Π½ΠΎΠ΅ ΡΡΠΊΠΎΠ²ΠΎΠ΄ΡΡΠ²ΠΎ ΠΏΠΎ ΡΠΎΠ·Π΄Π°Π½ΠΈΡ ΠΈ ΠΏΠ΅ΡΠ°ΡΠΈ ΡΡΠΈΠΊΠ΅ΡΠΎΠΊ Π΄Π»Ρ ΠΎΡΠΏΡΠ°Π²Π»Π΅Π½ΠΈΠΉ FBS.