Реалізація автоматичного оновлення цін товарів із зовнішніх джерел
В інтернет-магазині з 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% та виключіть ручні помилки. Отримайте індивідуальну комерційну пропозицію вже сьогодні.







