Warehouse API
Warehouse API
API для управления складами и методами доставки.
Обзор
Warehouse API предоставляет инструменты для управления складской системой и настройки методов доставки. API позволяет получать информацию о доступных складах, их характеристиках и поддерживаемых способах доставки товаров.
Ключевые возможности:
- Получение списка доступных складов
- Просмотр информации о складах (адреса, режим работы, статус)
- Управление методами доставки для каждого склада
- Настройка параметров логистики и стоимости доставки
Методы API
getWarehousesList()
Получить список всех доступных складов с детальной информацией.
import { OzonSellerAPI } from 'bmad-ozon-seller-api';
const api = new OzonSellerAPI({
clientId: 'your-client-id',
apiKey: 'your-api-key'
});
// Получение полного списка складов
const warehouses = await api.warehouse.getWarehousesList();
console.log('Total warehouses:', warehouses.total);
warehouses.warehouses?.forEach(warehouse => {
console.log(`\n📦 Склад: ${warehouse.name} (ID: ${warehouse.warehouse_id})`);
console.log(`Тип: ${warehouse.type}`);
console.log(`Адрес: ${warehouse.address}, ${warehouse.city}`);
console.log(`Регион: ${warehouse.region}`);
console.log(`Активен: ${warehouse.is_active ? '✅' : '❌'}`);
// Информация о координатах
if (warehouse.coordinates) {
console.log(`Координаты: ${warehouse.coordinates.latitude}, ${warehouse.coordinates.longitude}`);
}
// Режим работы
if (warehouse.working_hours) {
console.log('Режим работы:');
warehouse.working_hours.forEach(hours => {
if (hours.is_day_off) {
console.log(` ${hours.day}: Выходной`);
} else {
console.log(` ${hours.day}: ${hours.open_time} - ${hours.close_time}`);
}
});
}
// Контактная информация
if (warehouse.contact_info) {
console.log('Контакты:');
if (warehouse.contact_info.phone) {
console.log(` Телефон: ${warehouse.contact_info.phone}`);
}
if (warehouse.contact_info.email) {
console.log(` Email: ${warehouse.contact_info.email}`);
}
}
// Дополнительные сервисы
if (warehouse.services && warehouse.services.length > 0) {
console.log('Доступные сервисы:', warehouse.services.join(', '));
}
// Ограничения
if (warehouse.restrictions) {
console.log('Ограничения:');
if (warehouse.restrictions.max_weight) {
console.log(` Максимальный вес: ${warehouse.restrictions.max_weight} кг`);
}
if (warehouse.restrictions.max_dimensions) {
console.log(` Максимальные размеры: ${warehouse.restrictions.max_dimensions.length}x${warehouse.restrictions.max_dimensions.width}x${warehouse.restrictions.max_dimensions.height} см`);
}
if (warehouse.restrictions.prohibited_categories) {
console.log(` Запрещенные категории: ${warehouse.restrictions.prohibited_categories.join(', ')}`);
}
}
});
// Фильтрация активных складов
const activeWarehouses = warehouses.warehouses?.filter(w => w.is_active) || [];
console.log(`\n✅ Активных складов: ${activeWarehouses.length}`);
// Группировка по типам
const warehousesByType = warehouses.warehouses?.reduce((acc, warehouse) => {
const type = warehouse.type || 'unknown';
if (!acc[type]) {
acc[type] = [];
}
acc[type].push(warehouse);
return acc;
}, {} as Record<string, any[]>);
console.log('\n📊 Склады по типам:');
Object.entries(warehousesByType || {}).forEach(([type, items]) => {
console.log(` ${type}: ${items.length} складов`);
});
getDeliveryMethods()
Получить список доступных методов доставки для конкретного склада.
// Получение методов доставки для конкретного склада
const deliveryMethods = await api.warehouse.getDeliveryMethods({
warehouse_id: 123,
delivery_type: 'courier'
});
console.log(`Найдено ${deliveryMethods.delivery_methods?.length} методов доставки`);
deliveryMethods.delivery_methods?.forEach(method => {
console.log(`\n🚚 Метод доставки: ${method.name}`);
console.log(`ID: ${method.delivery_method_id}`);
console.log(`Тип: ${method.type}`);
console.log(`Стоимость: ${method.cost} ${method.currency}`);
console.log(`Время доставки: ${method.delivery_days} дней`);
console.log(`Активен: ${method.is_active ? '✅' : '❌'}`);
// Зоны доставки
if (method.delivery_zones && method.delivery_zones.length > 0) {
console.log('Зоны доставки:');
method.delivery_zones.forEach(zone => {
console.log(` 📍 ${zone.name}: ${zone.description || 'нет описания'}`);
if (zone.cities && zone.cities.length > 0) {
console.log(` Города: ${zone.cities.slice(0, 5).join(', ')}${zone.cities.length > 5 ? '...' : ''}`);
}
if (zone.additional_cost > 0) {
console.log(` Доплата: ${zone.additional_cost} ${method.currency}`);
}
});
}
// Ограничения по весу и размерам
if (method.weight_limits) {
console.log('Ограничения по весу:');
console.log(` Минимум: ${method.weight_limits.min_weight || 0} кг`);
console.log(` Максимум: ${method.weight_limits.max_weight} кг`);
}
if (method.size_limits) {
console.log('Ограничения по размерам:');
console.log(` Максимальные: ${method.size_limits.max_length}x${method.size_limits.max_width}x${method.size_limits.max_height} см`);
}
// Дополнительные услуги
if (method.additional_services && method.additional_services.length > 0) {
console.log('Дополнительные услуги:');
method.additional_services.forEach(service => {
console.log(` ✨ ${service.name}: ${service.cost} ${method.currency}`);
if (service.description) {
console.log(` ${service.description}`);
}
});
}
// Расписание доставки
if (method.delivery_schedule) {
console.log('Расписание доставки:');
method.delivery_schedule.forEach(schedule => {
console.log(` ${schedule.day}: ${schedule.time_slots.join(', ')}`);
});
}
});
// Фильтрация по различным критериям
const courierMethods = await api.warehouse.getDeliveryMethods({
warehouse_id: 123,
delivery_type: 'courier'
});
const pickupMethods = await api.warehouse.getDeliveryMethods({
warehouse_id: 123,
delivery_type: 'pickup'
});
const postalMethods = await api.warehouse.getDeliveryMethods({
warehouse_id: 123,
delivery_type: 'postal'
});
console.log('\n📈 Статистика методов доставки:');
console.log(`Курьерская доставка: ${courierMethods.delivery_methods?.length || 0}`);
console.log(`Самовывоз: ${pickupMethods.delivery_methods?.length || 0}`);
console.log(`Почтовая доставка: ${postalMethods.delivery_methods?.length || 0}`);
TypeScript Interfaces
Request Types
interface WarehouseListRequest {
/** Фильтр по статусу активности склада */
is_active?: boolean;
/** Фильтр по типу склада */
warehouse_type?: 'fbo' | 'fbs' | 'crossdock' | 'fulfillment';
/** Фильтр по городу */
city?: string;
/** Фильтр по региону */
region?: string;
/** Лимит количества записей */
limit?: number;
/** Смещение для пагинации */
offset?: number;
}
interface WarehouseDeliveryMethodListRequest {
/** ID склада */
warehouse_id: number;
/** Тип доставки */
delivery_type?: 'courier' | 'pickup' | 'postal' | 'express';
/** Фильтр по активным методам */
is_active?: boolean;
/** Фильтр по городу доставки */
delivery_city?: string;
/** Максимальная стоимость доставки */
max_cost?: number;
/** Максимальное время доставки в днях */
max_delivery_days?: number;
}
Response Types
interface WarehouseListResponse {
/** Список складов */
warehouses?: Warehouse[];
/** Общее количество складов */
total: number;
/** Есть ли следующая страница */
has_next: boolean;
}
interface Warehouse {
/** ID склада */
warehouse_id: number;
/** Название склада */
name: string;
/** Тип склада */
type: 'fbo' | 'fbs' | 'crossdock' | 'fulfillment';
/** Активность склада */
is_active: boolean;
/** Адрес склада */
address: string;
/** Город */
city: string;
/** Регион */
region: string;
/** Почтовый индекс */
postal_code?: string;
/** Координаты */
coordinates?: WarehouseCoordinates;
/** Режим работы */
working_hours?: WorkingHours[];
/** Контактная информация */
contact_info?: ContactInfo;
/** Доступные сервисы */
services?: string[];
/** Ограничения склада */
restrictions?: WarehouseRestrictions;
/** Дата создания */
created_at: string;
/** Дата последнего обновления */
updated_at: string;
}
interface WarehouseCoordinates {
/** Широта */
latitude: number;
/** Долгота */
longitude: number;
}
interface WorkingHours {
/** День недели */
day: 'monday' | 'tuesday' | 'wednesday' | 'thursday' | 'friday' | 'saturday' | 'sunday';
/** Выходной день */
is_day_off: boolean;
/** Время открытия */
open_time?: string;
/** Время закрытия */
close_time?: string;
/** Обеденный перерыв */
lunch_break?: {
start_time: string;
end_time: string;
};
}
interface ContactInfo {
/** Номер телефона */
phone?: string;
/** Email адрес */
email?: string;
/** Контактное лицо */
contact_person?: string;
/** Дополнительная информация */
notes?: string;
}
interface WarehouseRestrictions {
/** Максимальный вес товара в кг */
max_weight?: number;
/** Максимальные размеры */
max_dimensions?: {
length: number;
width: number;
height: number;
};
/** Запрещенные категории товаров */
prohibited_categories?: string[];
/** Требования к упаковке */
packaging_requirements?: string[];
/** Минимальная температура хранения */
min_temperature?: number;
/** Максимальная температура хранения */
max_temperature?: number;
}
interface WarehouseDeliveryMethodListResponse {
/** Список методов доставки */
delivery_methods?: DeliveryMethod[];
/** Общее количество методов */
total: number;
}
interface DeliveryMethod {
/** ID метода доставки */
delivery_method_id: number;
/** Название метода */
name: string;
/** Тип доставки */
type: 'courier' | 'pickup' | 'postal' | 'express';
/** Стоимость доставки */
cost: number;
/** Валюта */
currency: 'RUB' | 'USD' | 'EUR';
/** Время доставки в днях */
delivery_days: number;
/** Активность метода */
is_active: boolean;
/** Зоны доставки */
delivery_zones?: DeliveryZone[];
/** Ограничения по весу */
weight_limits?: WeightLimits;
/** Ограничения по размерам */
size_limits?: SizeLimits;
/** Дополнительные услуги */
additional_services?: AdditionalService[];
/** Расписание доставки */
delivery_schedule?: DeliverySchedule[];
/** Описание метода */
description?: string;
}
interface DeliveryZone {
/** ID зоны */
zone_id: number;
/** Название зоны */
name: string;
/** Описание зоны */
description?: string;
/** Список городов в зоне */
cities?: string[];
/** Дополнительная стоимость */
additional_cost: number;
/** Дополнительное время доставки */
additional_days: number;
}
interface WeightLimits {
/** Минимальный вес в кг */
min_weight?: number;
/** Максимальный вес в кг */
max_weight: number;
/** Стоимость за каждый дополнительный кг */
cost_per_kg?: number;
}
interface SizeLimits {
/** Максимальная длина в см */
max_length: number;
/** Максимальная ширина в см */
max_width: number;
/** Максимальная высота в см */
max_height: number;
/** Максимальный объемный вес */
max_volume_weight?: number;
}
interface AdditionalService {
/** ID услуги */
service_id: number;
/** Название услуги */
name: string;
/** Описание услуги */
description?: string;
/** Стоимость услуги */
cost: number;
/** Валюта */
currency: string;
/** Обязательность услуги */
is_mandatory: boolean;
}
interface DeliverySchedule {
/** День недели */
day: 'monday' | 'tuesday' | 'wednesday' | 'thursday' | 'friday' | 'saturday' | 'sunday';
/** Временные слоты */
time_slots: string[];
/** Доступность в этот день */
is_available: boolean;
}
Примеры использования
Анализ складской сети
class WarehouseAnalyzer {
constructor(private api: OzonSellerAPI) {}
async analyzeWarehouseNetwork(): Promise<WarehouseAnalysis> {
const warehouses = await this.api.warehouse.getWarehousesList();
const analysis: WarehouseAnalysis = {
total_warehouses: warehouses.total,
active_warehouses: 0,
inactive_warehouses: 0,
by_type: {},
by_region: {},
coverage_analysis: {
cities_covered: new Set<string>(),
regions_covered: new Set<string>()
},
service_availability: {},
capacity_analysis: {
total_capacity: 0,
utilization: 0,
bottlenecks: []
}
};
// Анализ по складам
warehouses.warehouses?.forEach(warehouse => {
// Подсчет активных/неактивных
if (warehouse.is_active) {
analysis.active_warehouses++;
} else {
analysis.inactive_warehouses++;
}
// Группировка по типам
const type = warehouse.type || 'unknown';
analysis.by_type[type] = (analysis.by_type[type] || 0) + 1;
// Группировка по регионам
analysis.by_region[warehouse.region] = (analysis.by_region[warehouse.region] || 0) + 1;
// Покрытие
analysis.coverage_analysis.cities_covered.add(warehouse.city);
analysis.coverage_analysis.regions_covered.add(warehouse.region);
// Анализ сервисов
warehouse.services?.forEach(service => {
analysis.service_availability[service] = (analysis.service_availability[service] || 0) + 1;
});
// Анализ ограничений (потенциальные узкие места)
if (warehouse.restrictions) {
if (warehouse.restrictions.max_weight && warehouse.restrictions.max_weight < 50) {
analysis.capacity_analysis.bottlenecks.push({
warehouse_id: warehouse.warehouse_id,
warehouse_name: warehouse.name,
issue: 'low_weight_limit',
value: warehouse.restrictions.max_weight
});
}
}
});
// Преобразуем Set в числа для финального анализа
analysis.coverage_analysis.cities_count = analysis.coverage_analysis.cities_covered.size;
analysis.coverage_analysis.regions_count = analysis.coverage_analysis.regions_covered.size;
return analysis;
}
async generateRecommendations(analysis: WarehouseAnalysis): Promise<WarehouseRecommendation[]> {
const recommendations: WarehouseRecommendation[] = [];
// Рекомендации по покрытию
if (analysis.coverage_analysis.regions_count < 5) {
recommendations.push({
type: 'coverage',
priority: 'high',
title: 'Расширить географическое покрытие',
description: 'Недостаточное покрытие регионов. Рекомендуется открыть склады в новых регионах.',
action: 'Рассмотреть возможность открытия складов в крупных городах без покрытия'
});
}
// Рекомендации по активности
const inactivePercentage = (analysis.inactive_warehouses / analysis.total_warehouses) * 100;
if (inactivePercentage > 20) {
recommendations.push({
type: 'efficiency',
priority: 'medium',
title: 'Оптимизировать использование складов',
description: `${inactivePercentage.toFixed(1)}% складов неактивны`,
action: 'Проанализировать причины неактивности и активировать или закрыть неэффективные склады'
});
}
// Рекомендации по узким местам
if (analysis.capacity_analysis.bottlenecks.length > 0) {
recommendations.push({
type: 'capacity',
priority: 'high',
title: 'Устранить ограничения по весу',
description: `${analysis.capacity_analysis.bottlenecks.length} складов имеют низкие лимиты веса`,
action: 'Увеличить допустимые лимиты веса или обновить оборудование'
});
}
return recommendations;
}
async findOptimalWarehouses(criteria: OptimalWarehouseCriteria): Promise<Warehouse[]> {
const warehouses = await this.api.warehouse.getWarehousesList();
return warehouses.warehouses?.filter(warehouse => {
// Проверяем активность
if (criteria.must_be_active && !warehouse.is_active) {
return false;
}
// Проверяем тип
if (criteria.warehouse_types && !criteria.warehouse_types.includes(warehouse.type)) {
return false;
}
// Проверяем регион
if (criteria.regions && !criteria.regions.includes(warehouse.region)) {
return false;
}
// Проверяем наличие требуемых сервисов
if (criteria.required_services) {
const hasAllServices = criteria.required_services.every(service =>
warehouse.services?.includes(service)
);
if (!hasAllServices) {
return false;
}
}
// Проверяем ограничения по весу
if (criteria.min_weight_capacity && warehouse.restrictions?.max_weight) {
if (warehouse.restrictions.max_weight < criteria.min_weight_capacity) {
return false;
}
}
return true;
}) || [];
}
}
interface WarehouseAnalysis {
total_warehouses: number;
active_warehouses: number;
inactive_warehouses: number;
by_type: Record<string, number>;
by_region: Record<string, number>;
coverage_analysis: {
cities_covered: Set<string>;
regions_covered: Set<string>;
cities_count?: number;
regions_count?: number;
};
service_availability: Record<string, number>;
capacity_analysis: {
total_capacity: number;
utilization: number;
bottlenecks: CapacityBottleneck[];
};
}
interface CapacityBottleneck {
warehouse_id: number;
warehouse_name: string;
issue: 'low_weight_limit' | 'size_constraints' | 'service_limitations';
value: number;
}
interface WarehouseRecommendation {
type: 'coverage' | 'efficiency' | 'capacity' | 'cost';
priority: 'low' | 'medium' | 'high';
title: string;
description: string;
action: string;
}
interface OptimalWarehouseCriteria {
must_be_active?: boolean;
warehouse_types?: ('fbo' | 'fbs' | 'crossdock' | 'fulfillment')[];
regions?: string[];
required_services?: string[];
min_weight_capacity?: number;
max_distance_km?: number;
target_city?: string;
}
// Использование анализатора
const analyzer = new WarehouseAnalyzer(api);
// Комплексный анализ складской сети
const analysis = await analyzer.analyzeWarehouseNetwork();
console.log('📊 АНАЛИЗ СКЛАДСКОЙ СЕТИ:');
console.log(`Всего складов: ${analysis.total_warehouses}`);
console.log(`Активных: ${analysis.active_warehouses}`);
console.log(`Неактивных: ${analysis.inactive_warehouses}`);
console.log('\n🏭 По типам складов:');
Object.entries(analysis.by_type).forEach(([type, count]) => {
console.log(` ${type}: ${count}`);
});
console.log('\n🗺️ Покрытие:');
console.log(`Городов: ${analysis.coverage_analysis.cities_count}`);
console.log(`Регионов: ${analysis.coverage_analysis.regions_count}`);
// Получение рекомендаций
const recommendations = await analyzer.generateRecommendations(analysis);
if (recommendations.length > 0) {
console.log('\n💡 РЕКОМЕНДАЦИИ:');
recommendations.forEach(rec => {
const priorityEmoji = rec.priority === 'high' ? '🔥' : rec.priority === 'medium' ? '⚠️' : 'ℹ️';
console.log(`${priorityEmoji} ${rec.title}`);
console.log(` ${rec.description}`);
console.log(` Действие: ${rec.action}\n`);
});
}
// Поиск оптимальных складов
const optimalWarehouses = await analyzer.findOptimalWarehouses({
must_be_active: true,
warehouse_types: ['fbo', 'fbs'],
required_services: ['packaging', 'quality_check'],
min_weight_capacity: 100
});
console.log(`\n🎯 Найдено ${optimalWarehouses.length} оптимальных складов`);
optimalWarehouses.forEach(warehouse => {
console.log(` • ${warehouse.name} (${warehouse.city})`);
});
Оптимизация доставки
class DeliveryOptimizer {
constructor(private api: OzonSellerAPI) {}
async optimizeDeliveryForOrder(order: DeliveryOrder): Promise<DeliveryOptimization> {
// Получаем список складов в регионе заказа
const warehouses = await this.api.warehouse.getWarehousesList({
region: order.delivery_region,
is_active: true
});
const optimizationResults: DeliveryOption[] = [];
// Анализируем каждый склад
for (const warehouse of warehouses.warehouses || []) {
// Проверяем совместимость склада с заказом
if (!this.isWarehouseCompatible(warehouse, order)) {
continue;
}
// Получаем методы доставки для склада
const deliveryMethods = await this.api.warehouse.getDeliveryMethods({
warehouse_id: warehouse.warehouse_id,
delivery_city: order.delivery_city,
max_cost: order.max_delivery_cost,
max_delivery_days: order.max_delivery_days
});
// Анализируем каждый метод доставки
for (const method of deliveryMethods.delivery_methods || []) {
if (!method.is_active) continue;
const option = this.calculateDeliveryOption(warehouse, method, order);
if (option) {
optimizationResults.push(option);
}
}
// Задержка для соблюдения лимитов API
await new Promise(resolve => setTimeout(resolve, 100));
}
// Сортируем варианты по оптимальности
const sortedOptions = this.rankDeliveryOptions(optimizationResults, order.preferences);
return {
order_id: order.order_id,
total_options: optimizationResults.length,
recommended_options: sortedOptions.slice(0, 3),
all_options: sortedOptions,
optimization_criteria: order.preferences,
analysis: this.generateOptimizationAnalysis(sortedOptions)
};
}
private isWarehouseCompatible(warehouse: Warehouse, order: DeliveryOrder): boolean {
// Проверяем вес
if (warehouse.restrictions?.max_weight && order.total_weight > warehouse.restrictions.max_weight) {
return false;
}
// Проверяем размеры
if (warehouse.restrictions?.max_dimensions) {
const { length, width, height } = warehouse.restrictions.max_dimensions;
if (order.dimensions.length > length ||
order.dimensions.width > width ||
order.dimensions.height > height) {
return false;
}
}
// Проверяем запрещенные категории
if (warehouse.restrictions?.prohibited_categories) {
const hasProhibited = order.product_categories.some(category =>
warehouse.restrictions!.prohibited_categories!.includes(category)
);
if (hasProhibited) {
return false;
}
}
return true;
}
private calculateDeliveryOption(
warehouse: Warehouse,
method: DeliveryMethod,
order: DeliveryOrder
): DeliveryOption | null {
// Базовая стоимость
let totalCost = method.cost;
let totalDays = method.delivery_days;
// Дополнительные расходы по зонам
if (method.delivery_zones) {
const zone = method.delivery_zones.find(z =>
z.cities?.includes(order.delivery_city)
);
if (zone) {
totalCost += zone.additional_cost;
totalDays += zone.additional_days;
}
}
// Дополнительные расходы по весу
if (method.weight_limits?.cost_per_kg && order.total_weight > 1) {
totalCost += (order.total_weight - 1) * method.weight_limits.cost_per_kg;
}
// Проверяем лимиты заказа
if (order.max_delivery_cost && totalCost > order.max_delivery_cost) {
return null;
}
if (order.max_delivery_days && totalDays > order.max_delivery_days) {
return null;
}
// Рассчитываем оценку оптимальности
const score = this.calculateOptimalityScore(
{ totalCost, totalDays, warehouse, method },
order.preferences
);
return {
warehouse_id: warehouse.warehouse_id,
warehouse_name: warehouse.name,
warehouse_city: warehouse.city,
delivery_method_id: method.delivery_method_id,
delivery_method_name: method.name,
delivery_type: method.type,
total_cost: totalCost,
currency: method.currency,
delivery_days: totalDays,
optimality_score: score,
features: this.extractDeliveryFeatures(method),
estimated_delivery_date: this.calculateDeliveryDate(totalDays)
};
}
private calculateOptimalityScore(
option: {
totalCost: number;
totalDays: number;
warehouse: Warehouse;
method: DeliveryMethod;
},
preferences: DeliveryPreferences
): number {
let score = 0;
// Весовые коэффициенты
const costWeight = preferences.cost_importance || 0.3;
const speedWeight = preferences.speed_importance || 0.4;
const reliabilityWeight = preferences.reliability_importance || 0.3;
// Нормализованная оценка стоимости (меньше = лучше)
const costScore = Math.max(0, 100 - (option.totalCost / 10));
// Нормализованная оценка скорости (меньше дней = лучше)
const speedScore = Math.max(0, 100 - (option.totalDays * 10));
// Оценка надежности (на основе типа доставки и склада)
let reliabilityScore = 70; // базовая оценка
if (option.method.type === 'express') reliabilityScore += 20;
if (option.method.type === 'courier') reliabilityScore += 10;
if (option.warehouse.type === 'fbo') reliabilityScore += 15;
// Итоговая оценка
score = (costScore * costWeight) + (speedScore * speedWeight) + (reliabilityScore * reliabilityWeight);
return Math.min(100, Math.max(0, score));
}
private rankDeliveryOptions(options: DeliveryOption[], preferences: DeliveryPreferences): DeliveryOption[] {
return options.sort((a, b) => {
// Основная сортировка по оценке оптимальности
if (b.optimality_score !== a.optimality_score) {
return b.optimality_score - a.optimality_score;
}
// Вторичная сортировка по предпочтениям
if (preferences.primary_criteria === 'cost') {
return a.total_cost - b.total_cost;
} else if (preferences.primary_criteria === 'speed') {
return a.delivery_days - b.delivery_days;
}
return 0;
});
}
private extractDeliveryFeatures(method: DeliveryMethod): string[] {
const features: string[] = [];
if (method.additional_services) {
features.push(...method.additional_services.map(s => s.name));
}
if (method.delivery_schedule && method.delivery_schedule.length > 0) {
features.push('Гибкое расписание');
}
if (method.type === 'express') {
features.push('Экспресс-доставка');
}
return features;
}
private calculateDeliveryDate(deliveryDays: number): string {
const date = new Date();
date.setDate(date.getDate() + deliveryDays);
return date.toISOString().split('T')[0];
}
private generateOptimizationAnalysis(options: DeliveryOption[]): OptimizationAnalysis {
if (options.length === 0) {
return {
best_option: null,
cost_range: { min: 0, max: 0 },
delivery_time_range: { min: 0, max: 0 },
recommendations: ['Нет доступных вариантов доставки для данного заказа']
};
}
const costs = options.map(o => o.total_cost);
const days = options.map(o => o.delivery_days);
return {
best_option: options[0],
cost_range: {
min: Math.min(...costs),
max: Math.max(...costs)
},
delivery_time_range: {
min: Math.min(...days),
max: Math.max(...days)
},
recommendations: this.generateRecommendations(options)
};
}
private generateRecommendations(options: DeliveryOption[]): string[] {
const recommendations: string[] = [];
const bestOption = options[0];
if (bestOption) {
recommendations.push(`Рекомендуем: ${bestOption.delivery_method_name} через ${bestOption.warehouse_name}`);
}
const budgetOption = options.reduce((min, option) =>
option.total_cost < min.total_cost ? option : min
);
if (budgetOption && budgetOption !== bestOption) {
recommendations.push(`Экономный вариант: ${budgetOption.delivery_method_name} (${budgetOption.total_cost} руб.)`);
}
const fastestOption = options.reduce((min, option) =>
option.delivery_days < min.delivery_days ? option : min
);
if (fastestOption && fastestOption !== bestOption && fastestOption !== budgetOption) {
recommendations.push(`Самый быстрый: ${fastestOption.delivery_method_name} (${fastestOption.delivery_days} дней)`);
}
return recommendations;
}
}
// Интерфейсы для оптимизатора доставки
interface DeliveryOrder {
order_id: string;
total_weight: number;
dimensions: {
length: number;
width: number;
height: number;
};
product_categories: string[];
delivery_city: string;
delivery_region: string;
max_delivery_cost?: number;
max_delivery_days?: number;
preferences: DeliveryPreferences;
}
interface DeliveryPreferences {
primary_criteria: 'cost' | 'speed' | 'reliability';
cost_importance?: number;
speed_importance?: number;
reliability_importance?: number;
}
interface DeliveryOption {
warehouse_id: number;
warehouse_name: string;
warehouse_city: string;
delivery_method_id: number;
delivery_method_name: string;
delivery_type: string;
total_cost: number;
currency: string;
delivery_days: number;
optimality_score: number;
features: string[];
estimated_delivery_date: string;
}
interface DeliveryOptimization {
order_id: string;
total_options: number;
recommended_options: DeliveryOption[];
all_options: DeliveryOption[];
optimization_criteria: DeliveryPreferences;
analysis: OptimizationAnalysis;
}
interface OptimizationAnalysis {
best_option: DeliveryOption | null;
cost_range: { min: number; max: number };
delivery_time_range: { min: number; max: number };
recommendations: string[];
}
// Использование оптимизатора доставки
const deliveryOptimizer = new DeliveryOptimizer(api);
// Пример заказа
const sampleOrder: DeliveryOrder = {
order_id: 'ORDER-2024-001',
total_weight: 2.5,
dimensions: {
length: 30,
width: 20,
height: 15
},
product_categories: ['electronics', 'accessories'],
delivery_city: 'Санкт-Петербург',
delivery_region: 'Ленинградская область',
max_delivery_cost: 500,
max_delivery_days: 7,
preferences: {
primary_criteria: 'speed',
cost_importance: 0.3,
speed_importance: 0.5,
reliability_importance: 0.2
}
};
// Оптимизация доставки
const optimization = await deliveryOptimizer.optimizeDeliveryForOrder(sampleOrder);
console.log('🚚 РЕЗУЛЬТАТЫ ОПТИМИЗАЦИИ ДОСТАВКИ:');
console.log(`Заказ: ${optimization.order_id}`);
console.log(`Найдено вариантов: ${optimization.total_options}`);
console.log('\n🏆 РЕКОМЕНДУЕМЫЕ ВАРИАНТЫ:');
optimization.recommended_options.forEach((option, index) => {
console.log(`\n${index + 1}. ${option.delivery_method_name}`);
console.log(` Склад: ${option.warehouse_name} (${option.warehouse_city})`);
console.log(` Стоимость: ${option.total_cost} ${option.currency}`);
console.log(` Время доставки: ${option.delivery_days} дней`);
console.log(` Оценка оптимальности: ${option.optimality_score.toFixed(1)}/100`);
console.log(` Дата доставки: ${option.estimated_delivery_date}`);
if (option.features.length > 0) {
console.log(` Особенности: ${option.features.join(', ')}`);
}
});
console.log('\n📊 АНАЛИЗ:');
console.log(`Диапазон стоимости: ${optimization.analysis.cost_range.min} - ${optimization.analysis.cost_range.max} руб.`);
console.log(`Диапазон времени: ${optimization.analysis.delivery_time_range.min} - ${optimization.analysis.delivery_time_range.max} дней`);
console.log('\n💡 РЕКОМЕНДАЦИИ:');
optimization.analysis.recommendations.forEach(rec => {
console.log(` • ${rec}`);
});
Комплексные сценарии
Система мониторинга складов
class WarehouseMonitoringSystem {
private api: OzonSellerAPI;
private monitoringConfig: MonitoringConfig;
private alerts: Alert[] = [];
constructor(api: OzonSellerAPI, config: MonitoringConfig) {
this.api = api;
this.monitoringConfig = config;
}
async runCompleteMonitoring(): Promise<MonitoringReport> {
console.log('🔍 Запуск комплексного мониторинга складов...');
const report: MonitoringReport = {
timestamp: new Date().toISOString(),
warehouse_status: [],
delivery_performance: [],
alerts: [],
recommendations: [],
kpis: {
warehouse_availability: 0,
average_delivery_cost: 0,
average_delivery_time: 0,
service_coverage: 0
}
};
try {
// 1. Мониторинг складов
const warehouseStatus = await this.monitorWarehouses();
report.warehouse_status = warehouseStatus;
// 2. Мониторинг доставки
const deliveryPerformance = await this.monitorDeliveryMethods();
report.delivery_performance = deliveryPerformance;
// 3. Расчет KPI
report.kpis = this.calculateKPIs(warehouseStatus, deliveryPerformance);
// 4. Генерация предупреждений
report.alerts = this.generateAlerts(warehouseStatus, deliveryPerformance);
// 5. Генерация рекомендаций
report.recommendations = this.generateRecommendations(report);
console.log('✅ Мониторинг завершен успешно');
} catch (error) {
console.error('❌ Ошибка при мониторинге:', error);
report.alerts.push({
type: 'system_error',
severity: 'high',
message: `Системная ошибка мониторинга: ${error.message}`,
timestamp: new Date().toISOString()
});
}
return report;
}
private async monitorWarehouses(): Promise<WarehouseStatus[]> {
const warehouses = await this.api.warehouse.getWarehousesList();
const statuses: WarehouseStatus[] = [];
for (const warehouse of warehouses.warehouses || []) {
const status: WarehouseStatus = {
warehouse_id: warehouse.warehouse_id,
warehouse_name: warehouse.name,
is_active: warehouse.is_active,
type: warehouse.type,
city: warehouse.city,
region: warehouse.region,
health_score: 100,
issues: [],
last_checked: new Date().toISOString()
};
// Проверка активности
if (!warehouse.is_active) {
status.health_score -= 50;
status.issues.push('Склад неактивен');
}
// Проверка ограничений
if (warehouse.restrictions) {
if (warehouse.restrictions.max_weight && warehouse.restrictions.max_weight < 10) {
status.health_score -= 20;
status.issues.push('Низкий лимит веса');
}
if (warehouse.restrictions.prohibited_categories &&
warehouse.restrictions.prohibited_categories.length > 10) {
status.health_score -= 15;
status.issues.push('Много запрещенных категорий');
}
}
// Проверка контактной информации
if (!warehouse.contact_info?.phone) {
status.health_score -= 10;
status.issues.push('Нет контактного телефона');
}
// Проверка режима работы
if (!warehouse.working_hours || warehouse.working_hours.length === 0) {
status.health_score -= 15;
status.issues.push('Не указан режим работы');
} else {
const workingDays = warehouse.working_hours.filter(h => !h.is_day_off).length;
if (workingDays < 5) {
status.health_score -= 10;
status.issues.push('Мало рабочих дней');
}
}
statuses.push(status);
}
return statuses;
}
private async monitorDeliveryMethods(): Promise<DeliveryPerformance[]> {
const warehouses = await this.api.warehouse.getWarehousesList({ is_active: true });
const performances: DeliveryPerformance[] = [];
for (const warehouse of warehouses.warehouses || []) {
const deliveryMethods = await this.api.warehouse.getDeliveryMethods({
warehouse_id: warehouse.warehouse_id
});
for (const method of deliveryMethods.delivery_methods || []) {
const performance: DeliveryPerformance = {
warehouse_id: warehouse.warehouse_id,
warehouse_name: warehouse.name,
delivery_method_id: method.delivery_method_id,
method_name: method.name,
method_type: method.type,
cost: method.cost,
delivery_days: method.delivery_days,
is_active: method.is_active,
performance_score: 100,
issues: []
};
// Оценка производительности
if (!method.is_active) {
performance.performance_score -= 50;
performance.issues.push('Метод доставки неактивен');
}
if (method.cost > 1000) {
performance.performance_score -= 20;
performance.issues.push('Высокая стоимость доставки');
}
if (method.delivery_days > 7) {
performance.performance_score -= 25;
performance.issues.push('Долгое время доставки');
}
if (!method.delivery_zones || method.delivery_zones.length === 0) {
performance.performance_score -= 15;
performance.issues.push('Нет зон доставки');
}
performances.push(performance);
}
// Задержка для соблюдения лимитов API
await new Promise(resolve => setTimeout(resolve, 200));
}
return performances;
}
private calculateKPIs(
warehouseStatus: WarehouseStatus[],
deliveryPerformance: DeliveryPerformance[]
): KPIs {
const activeWarehouses = warehouseStatus.filter(w => w.is_active);
const activeMethods = deliveryPerformance.filter(d => d.is_active);
return {
warehouse_availability: (activeWarehouses.length / warehouseStatus.length) * 100,
average_delivery_cost: activeMethods.reduce((sum, m) => sum + m.cost, 0) / activeMethods.length,
average_delivery_time: activeMethods.reduce((sum, m) => sum + m.delivery_days, 0) / activeMethods.length,
service_coverage: this.calculateServiceCoverage(warehouseStatus)
};
}
private calculateServiceCoverage(warehouses: WarehouseStatus[]): number {
const totalRegions = new Set(warehouses.map(w => w.region)).size;
const activeRegions = new Set(warehouses.filter(w => w.is_active).map(w => w.region)).size;
return (activeRegions / totalRegions) * 100;
}
private generateAlerts(
warehouseStatus: WarehouseStatus[],
deliveryPerformance: DeliveryPerformance[]
): Alert[] {
const alerts: Alert[] = [];
// Критические проблемы складов
const criticalWarehouses = warehouseStatus.filter(w => w.health_score < 50);
if (criticalWarehouses.length > 0) {
alerts.push({
type: 'warehouse_critical',
severity: 'high',
message: `${criticalWarehouses.length} складов в критическом состоянии`,
details: criticalWarehouses.map(w => `${w.warehouse_name}: ${w.issues.join(', ')}`),
timestamp: new Date().toISOString()
});
}
// Проблемы с доставкой
const problematicMethods = deliveryPerformance.filter(d => d.performance_score < 60);
if (problematicMethods.length > 0) {
alerts.push({
type: 'delivery_issues',
severity: 'medium',
message: `${problematicMethods.length} методов доставки с проблемами`,
details: problematicMethods.map(m => `${m.warehouse_name} - ${m.method_name}: ${m.issues.join(', ')}`),
timestamp: new Date().toISOString()
});
}
// Проверка покрытия регионов
const activeRegions = new Set(warehouseStatus.filter(w => w.is_active).map(w => w.region));
const totalRegions = new Set(warehouseStatus.map(w => w.region));
const uncoveredRegions = [...totalRegions].filter(r => !activeRegions.has(r));
if (uncoveredRegions.length > 0) {
alerts.push({
type: 'coverage_gap',
severity: 'medium',
message: `${uncoveredRegions.length} регионов без активных складов`,
details: uncoveredRegions,
timestamp: new Date().toISOString()
});
}
return alerts;
}
private generateRecommendations(report: MonitoringReport): string[] {
const recommendations: string[] = [];
// Рекомендации по KPI
if (report.kpis.warehouse_availability < 80) {
recommendations.push('Активировать неактивные склады или исследовать причины их отключения');
}
if (report.kpis.average_delivery_cost > 500) {
recommendations.push('Пересмотреть тарифы доставки или найти более экономные методы');
}
if (report.kpis.average_delivery_time > 5) {
recommendations.push('Оптимизировать время доставки за счет экспресс-методов');
}
if (report.kpis.service_coverage < 90) {
recommendations.push('Расширить покрытие регионов для улучшения доступности сервиса');
}
// Рекомендации по предупреждениям
const highSeverityAlerts = report.alerts.filter(a => a.severity === 'high');
if (highSeverityAlerts.length > 0) {
recommendations.push('Немедленно устранить критические проблемы складов');
}
return recommendations;
}
async generateDetailedReport(): Promise<string> {
const report = await this.runCompleteMonitoring();
let output = '# 📊 ДЕТАЛЬНЫЙ ОТЧЕТ МОНИТОРИНГА СКЛАДОВ\n\n';
output += `**Время создания:** ${new Date(report.timestamp).toLocaleString()}\n\n`;
// KPI
output += '## 🎯 Ключевые показатели\n\n';
output += `- **Доступность складов:** ${report.kpis.warehouse_availability.toFixed(1)}%\n`;
output += `- **Средняя стоимость доставки:** ${report.kpis.average_delivery_cost.toFixed(0)} руб.\n`;
output += `- **Среднее время доставки:** ${report.kpis.average_delivery_time.toFixed(1)} дней\n`;
output += `- **Покрытие сервиса:** ${report.kpis.service_coverage.toFixed(1)}%\n\n`;
// Предупреждения
if (report.alerts.length > 0) {
output += '## 🚨 Предупреждения\n\n';
report.alerts.forEach(alert => {
const emoji = alert.severity === 'high' ? '🔥' : alert.severity === 'medium' ? '⚠️' : 'ℹ️';
output += `### ${emoji} ${alert.message}\n`;
if (alert.details) {
alert.details.forEach(detail => {
output += `- ${detail}\n`;
});
}
output += '\n';
});
}
// Рекомендации
if (report.recommendations.length > 0) {
output += '## 💡 Рекомендации\n\n';
report.recommendations.forEach((rec, index) => {
output += `${index + 1}. ${rec}\n`;
});
output += '\n';
}
// Статус складов
output += '## 🏭 Статус складов\n\n';
report.warehouse_status.forEach(status => {
const healthEmoji = status.health_score >= 80 ? '✅' : status.health_score >= 60 ? '⚠️' : '❌';
output += `### ${healthEmoji} ${status.warehouse_name}\n`;
output += `- **Регион:** ${status.region}, ${status.city}\n`;
output += `- **Тип:** ${status.type}\n`;
output += `- **Активен:** ${status.is_active ? 'Да' : 'Нет'}\n`;
output += `- **Оценка здоровья:** ${status.health_score}/100\n`;
if (status.issues.length > 0) {
output += `- **Проблемы:** ${status.issues.join(', ')}\n`;
}
output += '\n';
});
return output;
}
}
// Интерфейсы для системы мониторинга
interface MonitoringConfig {
check_interval_minutes: number;
alert_thresholds: {
warehouse_health_score: number;
delivery_performance_score: number;
cost_threshold: number;
time_threshold: number;
};
notification_settings: {
email_alerts: boolean;
webhook_url?: string;
};
}
interface MonitoringReport {
timestamp: string;
warehouse_status: WarehouseStatus[];
delivery_performance: DeliveryPerformance[];
alerts: Alert[];
recommendations: string[];
kpis: KPIs;
}
interface WarehouseStatus {
warehouse_id: number;
warehouse_name: string;
is_active: boolean;
type: string;
city: string;
region: string;
health_score: number;
issues: string[];
last_checked: string;
}
interface DeliveryPerformance {
warehouse_id: number;
warehouse_name: string;
delivery_method_id: number;
method_name: string;
method_type: string;
cost: number;
delivery_days: number;
is_active: boolean;
performance_score: number;
issues: string[];
}
interface Alert {
type: string;
severity: 'low' | 'medium' | 'high';
message: string;
details?: string[];
timestamp: string;
}
interface KPIs {
warehouse_availability: number;
average_delivery_cost: number;
average_delivery_time: number;
service_coverage: number;
}
// Использование системы мониторинга
const monitoringConfig: MonitoringConfig = {
check_interval_minutes: 60,
alert_thresholds: {
warehouse_health_score: 70,
delivery_performance_score: 60,
cost_threshold: 500,
time_threshold: 7
},
notification_settings: {
email_alerts: true,
webhook_url: 'https://your-webhook-url.com/alerts'
}
};
const monitoringSystem = new WarehouseMonitoringSystem(api, monitoringConfig);
// Запуск мониторинга
const monitoringReport = await monitoringSystem.runCompleteMonitoring();
console.log('🔍 РЕЗУЛЬТАТЫ МОНИТОРИНГА:');
console.log(`Проверено складов: ${monitoringReport.warehouse_status.length}`);
console.log(`Проверено методов доставки: ${monitoringReport.delivery_performance.length}`);
console.log(`Найдено предупреждений: ${monitoringReport.alerts.length}`);
// Вывод KPI
console.log('\n📈 КЛЮЧЕВЫЕ ПОКАЗАТЕЛИ:');
console.log(`Доступность складов: ${monitoringReport.kpis.warehouse_availability.toFixed(1)}%`);
console.log(`Средняя стоимость доставки: ${monitoringReport.kpis.average_delivery_cost.toFixed(0)} руб.`);
console.log(`Среднее время доставки: ${monitoringReport.kpis.average_delivery_time.toFixed(1)} дней`);
console.log(`Покрытие сервиса: ${monitoringReport.kpis.service_coverage.toFixed(1)}%`);
// Генерация детального отчета
const detailedReport = await monitoringSystem.generateDetailedReport();
console.log('\n📄 ДЕТАЛЬНЫЙ ОТЧЕТ ГОТОВ');
// В реальном приложении здесь можно сохранить отчет в файл
// fs.writeFileSync('./warehouse_monitoring_report.md', detailedReport);
Обработка ошибок
async function safeWarehouseOperation() {
try {
const warehouses = await api.warehouse.getWarehousesList();
return warehouses;
} catch (error) {
if (error.code === 'ACCESS_DENIED') {
console.error('Нет доступа к информации о складах');
} else if (error.code === 'WAREHOUSE_NOT_FOUND') {
console.error('Склад не найден');
} else if (error.code === 'DELIVERY_METHOD_UNAVAILABLE') {
console.error('Метод доставки недоступен');
} else if (error.code === 'RATE_LIMIT_EXCEEDED') {
console.error('Превышен лимит запросов - повторите через минуту');
await new Promise(resolve => setTimeout(resolve, 60000));
// Повторная попытка
} else {
console.error('Неизвестная ошибка:', error);
}
return null;
}
}
// Функция с повторными попытками для получения методов доставки
async function getDeliveryMethodsWithRetry(
warehouseId: number,
maxRetries: number = 3
): Promise<any> {
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
return await api.warehouse.getDeliveryMethods({ warehouse_id: warehouseId });
} catch (error) {
console.error(`Попытка ${attempt}/${maxRetries} не удалась:`, error.message);
if (attempt === maxRetries) {
throw new Error(`Не удалось получить методы доставки после ${maxRetries} попыток`);
}
// Экспоненциальная задержка
const delay = Math.pow(2, attempt) * 1000;
await new Promise(resolve => setTimeout(resolve, delay));
}
}
}
Лучшие практики
1. Кэширование данных о складах
class WarehouseCache {
private warehouseCache = new Map<string, { data: any; expiry: number }>();
private readonly CACHE_TTL = 30 * 60 * 1000; // 30 минут
async getWarehouses(useCache: boolean = true): Promise<any> {
const cacheKey = 'warehouses_list';
if (useCache) {
const cached = this.warehouseCache.get(cacheKey);
if (cached && Date.now() < cached.expiry) {
return cached.data;
}
}
const data = await api.warehouse.getWarehousesList();
this.warehouseCache.set(cacheKey, {
data,
expiry: Date.now() + this.CACHE_TTL
});
return data;
}
}
2. Оптимизация запросов методов доставки
async function getOptimizedDeliveryMethods(warehouseIds: number[]) {
const results = new Map();
// Группируем запросы для минимизации API calls
for (const warehouseId of warehouseIds) {
try {
const methods = await api.warehouse.getDeliveryMethods({
warehouse_id: warehouseId,
is_active: true // Получаем только активные
});
results.set(warehouseId, methods);
// Соблюдаем лимиты API
await new Promise(resolve => setTimeout(resolve, 100));
} catch (error) {
console.error(`Ошибка для склада ${warehouseId}:`, error);
results.set(warehouseId, null);
}
}
return results;
}
3. Валидация данных склада
function validateWarehouseData(warehouse: Warehouse): string[] {
const errors: string[] = [];
if (!warehouse.name || warehouse.name.trim() === '') {
errors.push('Название склада обязательно');
}
if (!warehouse.address || warehouse.address.trim() === '') {
errors.push('Адрес склада обязателен');
}
if (!warehouse.city || warehouse.city.trim() === '') {
errors.push('Город обязателен');
}
if (warehouse.coordinates) {
if (warehouse.coordinates.latitude < -90 || warehouse.coordinates.latitude > 90) {
errors.push('Некорректная широта');
}
if (warehouse.coordinates.longitude < -180 || warehouse.coordinates.longitude > 180) {
errors.push('Некорректная долгота');
}
}
return errors;
}
Интеграция с другими API
Связь с FBS/FBO API
async function getWarehouseOrderCapacity() {
// Получаем склады
const warehouses = await api.warehouse.getWarehousesList();
// Для каждого склада получаем данные о заказах
for (const warehouse of warehouses.warehouses || []) {
if (warehouse.type === 'fbs') {
// Получаем FBS заказы для склада
// const fbsOrders = await api.fbs.getOrdersList({ warehouse_id: warehouse.warehouse_id });
console.log(`FBS склад ${warehouse.name}: обработка заказов`);
} else if (warehouse.type === 'fbo') {
// Получаем FBO поставки для склада
// const fboSupplies = await api.fbo.getSupplyList({ warehouse_id: warehouse.warehouse_id });
console.log(`FBO склад ${warehouse.name}: управление поставками`);
}
}
}
Интеграция с товарами и остатками
async function optimizeInventoryByWarehouses() {
const warehouses = await api.warehouse.getWarehousesList({ is_active: true });
for (const warehouse of warehouses.warehouses || []) {
console.log(`Анализ товаров для склада ${warehouse.name}:`);
// Получаем остатки товаров на складе
// const stocks = await api.pricesStocks.getStocksList({ warehouse_id: warehouse.warehouse_id });
// Анализируем ограничения склада
if (warehouse.restrictions) {
console.log(`Ограничения склада:`);
console.log(`- Максимальный вес: ${warehouse.restrictions.max_weight} кг`);
console.log(`- Запрещенные категории: ${warehouse.restrictions.prohibited_categories?.join(', ')}`);
}
}
}