Pass API Documentation

Overview

Pass API предоставляет возможности для управления пропусками прибытия и доступом к складу OZON. API включает 7 методов для создания, обновления и удаления пропусков как для доставки товаров, так и для их возврата.

Key Features

  • 🚛 Управление пропусками перевозки - создание, обновление и удаление пропусков для доставки товаров
  • 📋 Список пропусков - получение списка всех пропусков с фильтрацией
  • 🔄 Пропуски для возврата - управление пропусками для возврата товаров
  • 👤 Информация о водителях - данные о водителях и транспортных средствах
  • 📅 Планирование прибытия - указание даты и времени прибытия на склад
  • 💬 Комментарии - добавление комментариев к пропускам
  • 📄 Интеграция с отправлениями - связь пропусков с posting_number

Available Methods

Carriage Pass Methods

createCarriagePass()

Создает пропуск для перевозки товаров на склад OZON.

const carriagePass = await passApi.createCarriagePass({
  carriage_id: 12345,
  arrival_passes: [{
    vehicle_number: 'А123БВ777',
    driver_name: 'Иванов Иван Иванович',
    driver_license: '12 34 567890',
    arrival_date: '2024-01-15T09:00:00Z',
    comment: 'Плановая поставка товаров'
  }]
});

console.log(`Создано пропусков: ${carriagePass.arrival_pass_ids?.length}`);

updateCarriagePass()

Обновляет существующие пропуски для перевозки.

await passApi.updateCarriagePass({
  carriage_id: 12345,
  arrival_passes: [{
    arrival_pass_id: '67890',
    vehicle_number: 'В789ДЕ999',
    driver_name: 'Сидоров Сидор Сидорович',
    driver_license: '11 22 334455',
    arrival_date: '2024-01-16T10:00:00Z',
    comment: 'Изменено время прибытия'
  }]
});

deleteCarriagePass()

Удаляет пропуски для перевозки.

await passApi.deleteCarriagePass({
  carriage_id: 12345,
  arrival_pass_ids: ['67890', '54321']
});

Return Pass Methods

createReturnPass()

Создает пропуск для возврата товаров.

const returnPass = await passApi.createReturnPass({
  arrival_passes: [{
    vehicle_number: 'С123ЖЗ111',
    driver_name: 'Федоров Федор Федорович',
    driver_license: '55 66 778899',
    arrival_date: '2024-01-20T11:00:00Z',
    posting_number: '12345-0001-1',
    comment: 'Возврат бракованных товаров'
  }]
});

updateReturnPass()

Обновляет пропуски для возврата.

await passApi.updateReturnPass({
  arrival_passes: [{
    arrival_pass_id: '11111',
    vehicle_number: 'Т456УФ222',
    driver_name: 'Николаев Николай Николаевич',
    driver_license: '33 44 556677',
    arrival_date: '2024-01-21T15:00:00Z',
    posting_number: '12345-0002-1',
    comment: 'Обновлено время прибытия для возврата'
  }]
});

deleteReturnPass()

Удаляет пропуски для возврата.

await passApi.deleteReturnPass({
  arrival_pass_ids: ['11111', '22222']
});

List Method

getPassList()

Получает список пропусков с возможностью фильтрации.

const passList = await passApi.getPassList({
  limit: 50,
  filter: {
    carriage_id: 12345,
    status: 'ACTIVE',
    date_from: '2024-01-01',
    date_to: '2024-01-31'
  }
});

passList.arrival_passes?.forEach(pass => {
  console.log(`Пропуск ${pass.arrival_pass_id}:`);
  console.log(`  Автомобиль: ${pass.vehicle_number}`);
  console.log(`  Водитель: ${pass.driver_name}`);
  console.log(`  Прибытие: ${pass.arrival_date}`);
  console.log(`  Статус: ${pass.status}`);
});

TypeScript Interfaces

Request Types

interface PassCreateCarriagePassRequest {
  carriage_id: number;
  arrival_passes: ArrivalPassInfo[];
}

interface PassCreateReturnPassRequest {
  arrival_passes: ReturnPassInfo[];
}

interface PassUpdateCarriagePassRequest {
  carriage_id: number;
  arrival_passes: UpdateArrivalPassInfo[];
}

interface PassUpdateReturnPassRequest {
  arrival_passes: UpdateReturnPassInfo[];
}

interface PassDeleteCarriagePassRequest {
  carriage_id: number;
  arrival_pass_ids: string[];
}

interface PassDeleteReturnPassRequest {
  arrival_pass_ids: string[];
}

interface PassListRequest {
  limit?: number;
  cursor?: string;
  filter?: {
    carriage_id?: number;
    status?: 'ACTIVE' | 'EXPIRED' | 'CANCELLED';
    date_from?: string;
    date_to?: string;
  };
}

interface ArrivalPassInfo {
  vehicle_number: string;
  driver_name: string;
  driver_license: string;
  arrival_date: string;
  comment?: string;
}

interface ReturnPassInfo extends ArrivalPassInfo {
  posting_number: string;
}

interface UpdateArrivalPassInfo extends ArrivalPassInfo {
  arrival_pass_id: string;
}

interface UpdateReturnPassInfo extends ReturnPassInfo {
  arrival_pass_id: string;
}

Response Types

interface PassCreateCarriagePassResponse {
  arrival_pass_ids?: string[];
}

interface PassCreateReturnPassResponse {
  arrival_pass_ids?: string[];
}

interface PassListResponse {
  arrival_passes?: PassInfo[];
  cursor?: string;
  has_next?: boolean;
}

interface PassInfo {
  arrival_pass_id: string;
  carriage_id?: number;
  vehicle_number: string;
  driver_name: string;
  driver_license: string;
  arrival_date: string;
  status: 'ACTIVE' | 'EXPIRED' | 'CANCELLED' | 'USED';
  comment?: string;
  posting_number?: string;
  created_at: string;
  updated_at?: string;
}

Usage Examples

Basic Pass Management

import { OzonApi } from 'bmad-ozon-seller-api';

const ozonApi = new OzonApi({
  clientId: 'your-client-id',
  apiKey: 'your-api-key'
});

// Создание пропуска для доставки
async function createDeliveryPass() {
  try {
    const result = await ozonApi.pass.createCarriagePass({
      carriage_id: 12345,
      arrival_passes: [{
        vehicle_number: 'А123БВ777',
        driver_name: 'Иванов Иван Иванович',
        driver_license: '12 34 567890',
        arrival_date: '2024-01-15T09:00:00Z',
        comment: 'Доставка товаров партнера'
      }]
    });
    
    console.log('Пропуск создан:', result.arrival_pass_ids);
    return result.arrival_pass_ids;
  } catch (error) {
    console.error('Ошибка создания пропуска:', error);
  }
}

// Создание пропуска для возврата
async function createReturnPass() {
  try {
    const result = await ozonApi.pass.createReturnPass({
      arrival_passes: [{
        vehicle_number: 'Б456ГД888',
        driver_name: 'Петров Петр Петрович',
        driver_license: '98 76 543210',
        arrival_date: '2024-01-20T14:00:00Z',
        posting_number: '12345-0001-1',
        comment: 'Возврат поврежденных товаров'
      }]
    });
    
    console.log('Пропуск для возврата создан:', result.arrival_pass_ids);
    return result.arrival_pass_ids;
  } catch (error) {
    console.error('Ошибка создания пропуска для возврата:', error);
  }
}

Advanced Pass Filtering

// Получение списка активных пропусков за период
async function getActivePassesForPeriod(carriageId: number, dateFrom: string, dateTo: string) {
  try {
    let allPasses: PassInfo[] = [];
    let cursor: string | undefined;
    
    do {
      const response = await ozonApi.pass.getPassList({
        limit: 100,
        cursor,
        filter: {
          carriage_id: carriageId,
          status: 'ACTIVE',
          date_from: dateFrom,
          date_to: dateTo
        }
      });
      
      if (response.arrival_passes) {
        allPasses = allPasses.concat(response.arrival_passes);
      }
      
      cursor = response.has_next ? response.cursor : undefined;
    } while (cursor);
    
    return allPasses;
  } catch (error) {
    console.error('Ошибка получения списка пропусков:', error);
    return [];
  }
}

// Использование
const activePasses = await getActivePassesForPeriod(
  12345, 
  '2024-01-01', 
  '2024-01-31'
);

console.log(`Найдено активных пропусков: ${activePasses.length}`);
activePasses.forEach(pass => {
  console.log(`${pass.arrival_pass_id}: ${pass.vehicle_number} - ${pass.arrival_date}`);
});

Complex Scenarios

Pass Management System

Класс для комплексного управления пропусками:

class PassManagementSystem {
  constructor(private ozonApi: OzonApi) {}
  
  /**
   * Планирование доставок на несколько дней
   */
  async planDeliveries(carriageId: number, deliveries: DeliveryPlan[]) {
    const results = [];
    
    for (const delivery of deliveries) {
      try {
        const pass = await this.ozonApi.pass.createCarriagePass({
          carriage_id: carriageId,
          arrival_passes: [{
            vehicle_number: delivery.vehicleNumber,
            driver_name: delivery.driverName,
            driver_license: delivery.driverLicense,
            arrival_date: delivery.arrivalDate,
            comment: delivery.comment
          }]
        });
        
        results.push({
          delivery,
          passIds: pass.arrival_pass_ids,
          status: 'success'
        });
        
        console.log(`✅ Пропуск создан для ${delivery.vehicleNumber}`);
      } catch (error) {
        results.push({
          delivery,
          error: error.message,
          status: 'failed'
        });
        
        console.error(`❌ Ошибка создания пропуска для ${delivery.vehicleNumber}:`, error);
      }
      
      // Небольшая задержка между запросами
      await new Promise(resolve => setTimeout(resolve, 100));
    }
    
    return results;
  }
  
  /**
   * Обновление времени прибытия для нескольких пропусков
   */
  async updateArrivalTimes(updates: PassTimeUpdate[]) {
    const results = [];
    
    for (const update of updates) {
      try {
        if (update.type === 'carriage') {
          await this.ozonApi.pass.updateCarriagePass({
            carriage_id: update.carriageId!,
            arrival_passes: [{
              arrival_pass_id: update.passId,
              vehicle_number: update.vehicleNumber,
              driver_name: update.driverName,
              driver_license: update.driverLicense,
              arrival_date: update.newArrivalDate,
              comment: update.comment
            }]
          });
        } else {
          await this.ozonApi.pass.updateReturnPass({
            arrival_passes: [{
              arrival_pass_id: update.passId,
              vehicle_number: update.vehicleNumber,
              driver_name: update.driverName,
              driver_license: update.driverLicense,
              arrival_date: update.newArrivalDate,
              posting_number: update.postingNumber!,
              comment: update.comment
            }]
          });
        }
        
        results.push({
          passId: update.passId,
          status: 'updated'
        });
        
        console.log(`✅ Пропуск ${update.passId} обновлен`);
      } catch (error) {
        results.push({
          passId: update.passId,
          status: 'failed',
          error: error.message
        });
        
        console.error(`❌ Ошибка обновления пропуска ${update.passId}:`, error);
      }
    }
    
    return results;
  }
  
  /**
   * Получение статистики по пропускам
   */
  async getPassStatistics(carriageId?: number, dateFrom?: string, dateTo?: string) {
    try {
      const passes = await this.getAllPasses(carriageId, dateFrom, dateTo);
      
      const stats = passes.reduce((acc, pass) => {
        acc.total++;
        acc.byStatus[pass.status] = (acc.byStatus[pass.status] || 0) + 1;
        
        if (pass.posting_number) {
          acc.returnPasses++;
        } else {
          acc.deliveryPasses++;
        }
        
        return acc;
      }, {
        total: 0,
        byStatus: {} as Record<string, number>,
        deliveryPasses: 0,
        returnPasses: 0
      });
      
      return stats;
    } catch (error) {
      console.error('Ошибка получения статистики:', error);
      throw error;
    }
  }
  
  private async getAllPasses(carriageId?: number, dateFrom?: string, dateTo?: string) {
    let allPasses: PassInfo[] = [];
    let cursor: string | undefined;
    
    do {
      const response = await this.ozonApi.pass.getPassList({
        limit: 1000,
        cursor,
        filter: {
          carriage_id: carriageId,
          date_from: dateFrom,
          date_to: dateTo
        }
      });
      
      if (response.arrival_passes) {
        allPasses = allPasses.concat(response.arrival_passes);
      }
      
      cursor = response.has_next ? response.cursor : undefined;
    } while (cursor);
    
    return allPasses;
  }
}

// Интерфейсы для системы управления
interface DeliveryPlan {
  vehicleNumber: string;
  driverName: string;
  driverLicense: string;
  arrivalDate: string;
  comment?: string;
}

interface PassTimeUpdate {
  passId: string;
  type: 'carriage' | 'return';
  carriageId?: number;
  postingNumber?: string;
  vehicleNumber: string;
  driverName: string;
  driverLicense: string;
  newArrivalDate: string;
  comment?: string;
}

// Использование системы управления пропусками
const passManager = new PassManagementSystem(ozonApi);

// Планирование доставок
const deliveryPlans: DeliveryPlan[] = [
  {
    vehicleNumber: 'А111БВ222',
    driverName: 'Иванов И.И.',
    driverLicense: '12 34 567890',
    arrivalDate: '2024-01-15T09:00:00Z',
    comment: 'Утренняя доставка'
  },
  {
    vehicleNumber: 'Г333ДЕ444',
    driverName: 'Петров П.П.',
    driverLicense: '98 76 543210',
    arrivalDate: '2024-01-15T14:00:00Z',
    comment: 'Дневная доставка'
  }
];

const deliveryResults = await passManager.planDeliveries(12345, deliveryPlans);
console.log('Результаты планирования:', deliveryResults);

// Получение статистики
const stats = await passManager.getPassStatistics(12345, '2024-01-01', '2024-01-31');
console.log('Статистика пропусков:', stats);

Pass Monitoring Dashboard

Система мониторинга пропусков:

class PassMonitoringDashboard {
  constructor(private ozonApi: OzonApi) {}
  
  /**
   * Мониторинг просроченных пропусков
   */
  async monitorExpiredPasses() {
    try {
      const passes = await this.getAllActivePasses();
      const now = new Date();
      const expiredPasses = passes.filter(pass => {
        const arrivalDate = new Date(pass.arrival_date);
        return arrivalDate < now && pass.status === 'ACTIVE';
      });
      
      if (expiredPasses.length > 0) {
        console.warn(`⚠️ Найдено ${expiredPasses.length} просроченных пропусков:`);
        expiredPasses.forEach(pass => {
          console.warn(`  - ${pass.arrival_pass_id}: ${pass.vehicle_number} (${pass.arrival_date})`);
        });
        
        return expiredPasses;
      }
      
      console.log('✅ Просроченных пропусков не найдено');
      return [];
    } catch (error) {
      console.error('Ошибка мониторинга просроченных пропусков:', error);
      throw error;
    }
  }
  
  /**
   * Отчет о пропусках за день
   */
  async generateDailyReport(date: string) {
    try {
      const dateStart = `${date}T00:00:00Z`;
      const dateEnd = `${date}T23:59:59Z`;
      
      const passes = await this.getPassesForPeriod(dateStart, dateEnd);
      
      const report = {
        date,
        totalPasses: passes.length,
        deliveryPasses: passes.filter(p => !p.posting_number).length,
        returnPasses: passes.filter(p => p.posting_number).length,
        statusBreakdown: this.getStatusBreakdown(passes),
        hourlyDistribution: this.getHourlyDistribution(passes),
        topDrivers: this.getTopDrivers(passes, 5)
      };
      
      console.log('📊 Отчет о пропусках за', date);
      console.log('Всего пропусков:', report.totalPasses);
      console.log('Доставки:', report.deliveryPasses);
      console.log('Возвраты:', report.returnPasses);
      console.log('Статусы:', report.statusBreakdown);
      
      return report;
    } catch (error) {
      console.error('Ошибка создания отчета:', error);
      throw error;
    }
  }
  
  private async getAllActivePasses() {
    return this.getPassesForPeriod();
  }
  
  private async getPassesForPeriod(dateFrom?: string, dateTo?: string) {
    let allPasses: PassInfo[] = [];
    let cursor: string | undefined;
    
    do {
      const response = await this.ozonApi.pass.getPassList({
        limit: 1000,
        cursor,
        filter: {
          date_from: dateFrom,
          date_to: dateTo
        }
      });
      
      if (response.arrival_passes) {
        allPasses = allPasses.concat(response.arrival_passes);
      }
      
      cursor = response.has_next ? response.cursor : undefined;
    } while (cursor);
    
    return allPasses;
  }
  
  private getStatusBreakdown(passes: PassInfo[]) {
    return passes.reduce((acc, pass) => {
      acc[pass.status] = (acc[pass.status] || 0) + 1;
      return acc;
    }, {} as Record<string, number>);
  }
  
  private getHourlyDistribution(passes: PassInfo[]) {
    const distribution: Record<number, number> = {};
    
    passes.forEach(pass => {
      const hour = new Date(pass.arrival_date).getHours();
      distribution[hour] = (distribution[hour] || 0) + 1;
    });
    
    return distribution;
  }
  
  private getTopDrivers(passes: PassInfo[], limit: number) {
    const driverCounts = passes.reduce((acc, pass) => {
      acc[pass.driver_name] = (acc[pass.driver_name] || 0) + 1;
      return acc;
    }, {} as Record<string, number>);
    
    return Object.entries(driverCounts)
      .sort(([,a], [,b]) => b - a)
      .slice(0, limit)
      .map(([name, count]) => ({ name, count }));
  }
}

// Использование системы мониторинга
const dashboard = new PassMonitoringDashboard(ozonApi);

// Мониторинг просроченных пропусков
const expiredPasses = await dashboard.monitorExpiredPasses();

// Ежедневный отчет
const dailyReport = await dashboard.generateDailyReport('2024-01-15');

Error Handling

// Обработка ошибок при работе с пропусками
async function safePassOperation() {
  try {
    const result = await ozonApi.pass.createCarriagePass({
      carriage_id: 12345,
      arrival_passes: [{
        vehicle_number: 'А123БВ777',
        driver_name: 'Иванов И.И.',
        driver_license: '12 34 567890',
        arrival_date: '2024-01-15T09:00:00Z'
      }]
    });
    
    return result;
  } catch (error) {
    if (error.code === 'INVALID_PARAMETER') {
      console.error('Неверные параметры пропуска:', error.message);
    } else if (error.code === 'CARRIAGE_NOT_FOUND') {
      console.error('Перевозка не найдена:', error.message);
    } else if (error.code === 'ACCESS_DENIED') {
      console.error('Недостаточно прав для создания пропуска:', error.message);
    } else {
      console.error('Неожиданная ошибка:', error);
    }
    
    throw error;
  }
}

Best Practices

1. Валидация данных водителей

function validateDriverInfo(driverInfo: ArrivalPassInfo): boolean {
  // Проверка номера автомобиля (российский формат)
  const vehicleRegex = /^[АВЕКМНОРСТУХ]\d{3}[АВЕКМНОРСТУХ]{2}\d{2,3}$/;
  if (!vehicleRegex.test(driverInfo.vehicle_number)) {
    throw new Error('Неверный формат номера автомобиля');
  }
  
  // Проверка водительских прав
  const licenseRegex = /^\d{2}\s\d{2}\s\d{6}$/;
  if (!licenseRegex.test(driverInfo.driver_license)) {
    throw new Error('Неверный формат водительских прав');
  }
  
  // Проверка даты прибытия
  const arrivalDate = new Date(driverInfo.arrival_date);
  const now = new Date();
  if (arrivalDate <= now) {
    throw new Error('Дата прибытия должна быть в будущем');
  }
  
  return true;
}

2. Оптимизация работы с большим количеством пропусков

async function processManyPasses(passes: ArrivalPassInfo[], batchSize = 10) {
  const results = [];
  
  for (let i = 0; i < passes.length; i += batchSize) {
    const batch = passes.slice(i, i + batchSize);
    const batchPromises = batch.map(pass => 
      ozonApi.pass.createCarriagePass({
        carriage_id: pass.carriage_id,
        arrival_passes: [pass]
      }).catch(error => ({ error, pass }))
    );
    
    const batchResults = await Promise.all(batchPromises);
    results.push(...batchResults);
    
    // Задержка между батчами
    if (i + batchSize < passes.length) {
      await new Promise(resolve => setTimeout(resolve, 1000));
    }
  }
  
  return results;
}

3. Кэширование списка пропусков

class PassCache {
  private cache = new Map<string, { data: PassListResponse; timestamp: number }>();
  private readonly ttl = 5 * 60 * 1000; // 5 минут
  
  async getPassList(request: PassListRequest): Promise<PassListResponse> {
    const key = JSON.stringify(request);
    const cached = this.cache.get(key);
    
    if (cached && Date.now() - cached.timestamp < this.ttl) {
      return cached.data;
    }
    
    const data = await ozonApi.pass.getPassList(request);
    this.cache.set(key, { data, timestamp: Date.now() });
    
    return data;
  }
  
  clearCache() {
    this.cache.clear();
  }
}

Integration Notes

  • Время прибытия: Указывайте время в UTC формате ISO 8601
  • Номера автомобилей: Используйте российский формат номерных знаков
  • Водительские права: Формат “XX XX XXXXXX” (серия и номер)
  • Комментарии: Ограничение длины - 500 символов
  • Rate Limiting: Максимум 100 запросов в минуту
  • Carriage ID: Обязательно для пропусков доставки
  • Posting Number: Обязательно для пропусков возврата

Pass API обеспечивает полный контроль над процессом управления пропусками на склады OZON, позволяя эффективно планировать и отслеживать все поставки и возвраты товаров.