Синхронизация остатков и цен между сайтом и маркетплейсами

Наша компания занимается разработкой, поддержкой и обслуживанием сайтов любой сложности. От простых одностраничных сайтов до масштабных кластерных систем построенных на микро сервисах. Опыт разработчиков подтвержден сертификатами от вендоров.
Разработка и обслуживание любых видов сайтов:
Информационные сайты или веб-приложения
Сайты визитки, landing page, корпоративные сайты, онлайн каталоги, квиз, промо-сайты, блоги, новостные ресурсы, информационные порталы, форумы, агрегаторы
Сайты или веб-приложения электронной коммерции
Интернет-магазины, B2B-порталы, маркетплейсы, онлайн-обменники, кэшбэк-сайты, биржи, дропшиппинг-платформы, парсеры товаров
Веб-приложения для управления бизнес-процессами
CRM-системы, ERP-системы, корпоративные порталы, системы управления производством, парсеры информации
Сайты или веб-приложения электронных услуг
Доски объявлений, онлайн-школы, онлайн-кинотеатры, конструкторы сайтов, порталы предоставления электронных услуг, видеохостинги, тематические порталы

Это лишь некоторые из технических типов сайтов, с которыми мы работаем, и каждый из них может иметь свои специфические особенности и функциональность, а также быть адаптированным под конкретные потребности и цели клиента

Предлагаемые услуги
Показано 1 из 1 услугВсе 2065 услуг
Синхронизация остатков и цен между сайтом и маркетплейсами
Сложная
~5 рабочих дней
Часто задаваемые вопросы
Наши компетенции:
Этапы разработки
Последние работы
  • image_website-b2b-advance_0.png
    Разработка сайта компании B2B ADVANCE
    1214
  • image_web-applications_feedme_466_0.webp
    Разработка веб-приложения для компании FEEDME
    1161
  • image_websites_belfingroup_462_0.webp
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    852
  • image_ecommerce_furnoro_435_0.webp
    Разработка интернет магазина для компании FURNORO
    1041
  • image_crm_enviok_479_0.webp
    Разработка веб-приложения для компании Enviok
    823
  • image_bitrix-bitrix-24-1c_fixper_448_0.png
    Разработка веб-сайта для компании ФИКСПЕР
    815

Синхронизация остатков и цен между сайтом и маркетплейсами

Когда магазин продаёт одновременно через сайт и несколько маркетплейсов, управление остатками становится критичной задачей: продали на сайте — нужно снизить остаток на Ozon и Wildberries; пришёл новый товар — поднять везде. Ценовая синхронизация обеспечивает ценовой паритет или наценку на маркетплейсе.

Архитектура системы

Источник правды (Основной склад / Сайт)
    ↓
Stock Manager Service
    ├── Резервирование при заказе на сайте
    ├── Освобождение при отмене
    └── Пополнение при приёмке товара
         ↓
    Sync Queue (Redis)
         ↓
    Marketplace Workers
    ├── Ozon Worker    → Ozon API
    ├── WB Worker      → WB API
    └── YM Worker      → Яндекс.Маркет API

Расчёт доступного остатка

class StockCalculator
{
    public function getAvailableForMarketplace(int $productId, string $marketplace): int
    {
        $product = Product::with(['reservations', 'warehouseItems'])->findOrFail($productId);

        $totalStock    = $product->warehouseItems->sum('quantity');
        $reservedSite  = $product->reservations()->where('source', 'site')->sum('quantity');
        $reservedOther = $product->reservations()->where('source', '!=', $marketplace)->sum('quantity');

        // Для маркетплейса доступно не более 80% свободного остатка
        $available = $totalStock - $reservedSite - $reservedOther;
        return max(0, (int)($available * 0.8));
    }
}

Коэффициент 0.8 — защита от ситуации, когда несколько маркетплейсов видят полный остаток и одновременно принимают заказы.

Очередь синхронизации

class StockSyncQueue
{
    public function enqueue(int $productId): void
    {
        // Дедупликация: если уже в очереди — обновляем таймер
        Redis::setex("sync:pending:{$productId}", 30, 1);
    }

    public function processQueue(): void
    {
        // Batching: собираем все изменения за 30 секунд и отправляем батчем
        $keys      = Redis::keys('sync:pending:*');
        $productIds = array_map(fn($k) => (int)explode(':', $k)[2], $keys);

        if (empty($productIds)) return;

        Redis::del($keys);
        $this->syncToMarketplaces($productIds);
    }
}

Ценовая синхронизация

class PriceSyncService
{
    private array $marketplacePriceRules = [
        'ozon'    => ['type' => 'markup', 'value' => 5.0],   // +5%
        'wb'      => ['type' => 'markup', 'value' => 7.0],   // +7%
        'ym'      => ['type' => 'fixed',  'value' => 0],     // без наценки
    ];

    public function calculateMarketplacePrice(float $basePrice, string $marketplace): float
    {
        $rule = $this->marketplacePriceRules[$marketplace];

        return match($rule['type']) {
            'markup' => round($basePrice * (1 + $rule['value'] / 100), 0),
            'fixed'  => $basePrice + $rule['value'],
            default  => $basePrice,
        };
    }
}

Обработка пересекающихся заказов

class OrderProcessor
{
    public function process(Order $order): void
    {
        DB::transaction(function () use ($order) {
            foreach ($order->items as $item) {
                $reserved = ProductReservation::create([
                    'product_id' => $item->product_id,
                    'quantity'   => $item->quantity,
                    'source'     => $order->source,  // 'site', 'ozon', 'wb'
                    'order_id'   => $order->id,
                ]);

                // Проверяем не превышен ли физический остаток
                $totalReserved = ProductReservation::where('product_id', $item->product_id)->sum('quantity');
                $actualStock   = WarehouseItem::where('product_id', $item->product_id)->sum('quantity');

                if ($totalReserved > $actualStock) {
                    throw new InsufficientStockException($item->product_id);
                }
            }

            // Ставим задачу на снижение остатков на всех площадках
            StockSyncJob::dispatch($order->items->pluck('product_id')->unique()->all());
        });
    }
}

Мониторинг расхождений

Периодически сверяем фактические остатки на маркетплейсах с нашими данными:

class StockDiscrepancyChecker
{
    public function check(): array
    {
        $discrepancies = [];
        $ozonStocks = $this->ozon->getAllStocks();

        foreach ($ozonStocks as $ozonItem) {
            $ourStock = $this->calculator->getAvailableForMarketplace($ozonItem['offer_id'], 'ozon');

            if (abs($ourStock - $ozonItem['stock']) > 1) {
                $discrepancies[] = [
                    'sku'      => $ozonItem['offer_id'],
                    'our'      => $ourStock,
                    'ozon'     => $ozonItem['stock'],
                    'delta'    => $ourStock - $ozonItem['stock'],
                ];
            }
        }

        return $discrepancies;
    }
}

Сроки

Система синхронизации остатков и цен для 2–3 маркетплейсов: 14–20 рабочих дней.