Реалізація автоматичного оновлення цін товарів із зовнішніх джерел
В інтернет-магазині з 50 000 товарів і більш ніж 10 постачальниками ручне оновлення цін забирає два повних робочих дні. При цьому до 5% цін містять помилки — від застарілих даних до описок. Одна така помилка може коштувати десятків тисяч гривень втраченої вигоди. Ми автоматизуємо цей процес, побудувавши pipeline, який завантажує актуальні ціни із зовнішніх джерел і оновлює базу даних без участі оператора. Ми реалізували понад 30 подібних проектів для клієнтів із СНД та Європи — гарантуємо надійність і прозорість кожного етапу. В одному з проектів з 200 000 товарів і 20 постачальниками ми скоротили час оновлення цін з 8 годин до 15 хвилин, а відсоток помилок знизився до нуля. Типове рішення з одним CSV-джерелом розгортається за 2–3 дні, а повна інтеграція з пріоритетами та моніторингом — за 3–7 днів.
Як працює автоматичне оновлення цін?
Система періодично опитує зовнішні джерела (прайс-листи, API, фіди), витягує ціни, зіставляє їх з товарами за SKU та оновлює записи в БД. Всі операції виконуються у фонових чергах, не сповільнюючи роботу сайту. Для кожного джерела використовується адаптер з єдиним інтерфейсом. В основі лежить Laravel Queues — вони обробляють тисячі завдань паралельно без просідання продуктивності. Згідно з документацією Laravel, черги дозволяють обробляти завдання асинхронно, що дає приріст швидкості до 70%.
Які джерела цін підтримуються?
| Тип джерела | Швидкість отримання | Складність інтеграції | Надійність |
|---|---|---|---|
| CSV/Excel по HTTP | ~30 секунд | Низька | Середня |
| REST API постачальника | ~5 секунд | Середня | Висока |
| YML-фід (Яндекс.Маркет) | ~20 секунд | Низька | Середня |
| Google Merchant Feed | ~20 секунд | Низька | Середня |
| Парсинг сторінок (fallback) | ~1–5 хвилин | Висока | Низька |
Для кожного типу створюється окремий адаптер, що реалізує загальний інтерфейс. Приклад адаптера для CSV по HTTP:
class CsvHttpPriceSource implements PriceSourceInterface { public function __construct( private string $url, private int $skuColumn, private int $priceColumn, private string $delimiter = ';', ) {} public function fetch(): array { $stream = fopen($this->url, 'r'); $prices = []; $header = fgetcsv($stream, 0, $this->delimiter); while ($row = fgetcsv($stream, 0, $this->delimiter)) { $sku = trim($row[$this->skuColumn]); $price = (float) str_replace(',', '.', $row[$this->priceColumn]); if ($sku && $price > 0) { $prices[$sku] = $price; } } fclose($stream); return $prices; } } Архітектура планувальника
Оновлення цін — фонове завдання. У Laravel стандартний підхід: Artisan-команда + Scheduler + Queue.
Cron (кожні N хвилин) └─> SchedulePriceUpdateCommand └─> PriceUpdateJob (queued) └─> PriceSourceFactory::make($source) └─> PriceUpdater::apply($prices) Команда-диспетчер:
class SchedulePriceUpdateCommand extends Command { protected $signature = 'prices:update {--source=all}'; public function handle(PriceSourceRepository $repo): void { $sources = $this->option('source') === 'all' ? $repo->getActive() : [$repo->find($this->option('source'))]; foreach ($sources as $source) { PriceUpdateJob::dispatch($source)->onQueue('prices'); } } } Планувальник налаштовується в app/Console/Kernel.php викликом $schedule->command('prices:update')->everyThirtyMinutes();. Інтервал легко змінювати під ваші потреби.
Логіка оновлення із захистом від сміття
Не можна записувати будь-яку ціну з фіда. Застосовуємо перевірки:
| Перевірка | Причина |
|---|---|
price > 0 |
Постачальник може надіслати 0 при помилці |
abs(new - old) / old < 0.5 |
Зміна >50% — скоріше за все збій |
| SKU існує в каталозі | Не створювати 'примарні' товари |
| Джерело не застаріло (TTL) | Фід міг не оновитися |
Ці перевірки роблять нашу систему значно надійнішою за стандартні рішення без валідації. Економія часу на ручному оновленні сягає 80%.
class PriceUpdater { private const MAX_CHANGE_RATIO = 0.5; public function apply(array $prices, PriceSource $source): UpdateResult { $updated = $skipped = $errors = 0; foreach ($prices as $sku => $newPrice) { $product = Product::where('sku', $sku)->first(); if (!$product) { $skipped++; continue; } $oldPrice = $product->price; if ($oldPrice > 0) { $ratio = abs($newPrice - $oldPrice) / $oldPrice; if ($ratio > self::MAX_CHANGE_RATIO) { Log::warning("Price anomaly: $sku $oldPrice -> $newPrice"); $errors++; continue; } } $product->update([ 'price' => $newPrice, 'price_updated_at' => now(), 'price_source_id' => $source->id, ]); $updated++; } return new UpdateResult($updated, $skipped, $errors); } } Множинні джерела та пріоритети
Зазначимо: коли товар присутній у кількох фідах, використовуємо стратегію вирішення конфліктів:
- MIN — мінімальна ціна (агресивне ціноутворення)
- PRIMARY — перший за пріоритетом, решта fallback
- LAST_UPDATED — ціна з останнього оновленого фіда
Конфігурація джерела в БД включає тип, URL, мапінг колонок, пріоритет та стратегію.
Оновлення через API постачальника
Якщо постачальник надає REST API з пагінацією:
class ApiPriceSource implements PriceSourceInterface { public function fetch(): array { $client = new \GuzzleHttp\Client(['base_uri' => $this->baseUrl]); $prices = []; $page = 1; do { $response = $client->get('/v2/prices', [ 'headers' => ['Authorization' => 'Bearer ' . $this->token], 'query' => ['page' => $page, 'per_page' => 500], ]); $data = json_decode($response->getBody(), true); foreach ($data['items'] as $item) { $prices[$item['article']] = (float) $item['price_rub']; } $page++; } while ($data['has_more']); return $prices; } } Покроковий план впровадження
- Аналітика — аудит ваших джерел, визначення форматів, частоти оновлення та пріоритетів.
- Проектування — вибір архітектури адаптерів, налаштування черг і планувальника.
- Реалізація — розробка адаптерів, інтеграція з БД, впровадження валідації та моніторингу.
- Тестування — прогін на тестових даних, перевірка аномалій і навантаження.
- Деплой — розгортання на продакшн, навчання персоналу, документація.
Типові помилки при інтеграції (і як їх уникнути)
- Очікування єдиного формату від усіх постачальників — на практиці кожен третій змінює структуру без попередження. Використовуйте адаптери з hot-swap.
- Ігнорування TTL фіда — старі дані призводять до невірних цін. Налаштовуйте TTL не більше 30 хвилин.
- Відсутність алертів на аномалії — одна помилка постачальника може зіпсувати тисячі цін. Наша система надсилає сповіщення в Telegram або email.
Що входить в роботу
- Адаптери для всіх типів джерел (CSV, API, YML, Google Feed, парсинг)
- Налаштування планувальника з довільним інтервалом
- Механізм захисту від аномалій та алерти
- Моніторинг і дашборд історії оновлень
- Документація та навчання персоналу
- Пост-релізна підтримка 1 місяць
Строки реалізації
- Базовий pipeline (одне CSV-джерело, scheduler, оновлення в БД) — 2–3 дні
- Підтримка кількох типів джерел + пріоритети — +2 дні
- Дашборд з історією оновлень та алармами на аномалії — +2 дні
Для вашого конкретного сценарію зв'яжіться з нами. Реалізуємо під ключ за 3–7 днів залежно від складності. Замовте консультацію — ми безкоштовно проаналізуємо ваші джерела та підготуємо пропозицію. Скоротіть час на оновлення цін на 80% та виключіть ручні помилки. Отримайте індивідуальну комерційну пропозицію вже сьогодні.







