πŸ“‹ 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.