Налаштування відстеження цін конкурентів для 1С-Бітрікс
Відстеження цін конкурентів будується одним із двох способів: через готовий сервіс моніторингу (Competera, Metacommerce, Priceva) або через власний парсер. Готовий сервіс — простіше, надійніше, але дорого при великому каталозі. Власний парсер — гнучко, дешево в експлуатації, але вимагає регулярного обслуговування при змінах на сайтах конкурентів. Завдання налаштування в обох випадках однакове: зібрати дані, зберегти в 1С-Бітрікс, показати менеджеру в зручному вигляді.
Архітектура зберігання даних
Незалежно від джерела даних (сервіс або парсер), структура зберігання однакова:
Конкуренти bl_price_competitors:
CREATE TABLE bl_price_competitors (
id SERIAL PRIMARY KEY,
name VARCHAR(255) NOT NULL,
domain VARCHAR(255) UNIQUE,
active BOOLEAN DEFAULT true,
logo_url VARCHAR(512)
);
Ціни конкурентів bl_competitor_prices:
CREATE TABLE bl_competitor_prices (
id SERIAL PRIMARY KEY,
product_id INT NOT NULL, -- b_iblock_element.ID
competitor_id INT REFERENCES bl_price_competitors(id),
price NUMERIC(12,2) NOT NULL,
url VARCHAR(512), -- URL сторінки конкурента
in_stock BOOLEAN DEFAULT true,
checked_at TIMESTAMP NOT NULL DEFAULT NOW(),
UNIQUE (product_id, competitor_id) -- одна актуальна ціна
);
CREATE INDEX idx_comp_prices_product ON bl_competitor_prices(product_id, checked_at DESC);
Історія bl_competitor_prices_history — партиціонована за місяцями таблиця для зберігання змін без роздування основної.
Інтеграція через API сервісу моніторингу
При використанні готового сервісу агент запитує дані та записує в bl_competitor_prices:
function SyncCompetitorPrices(): string
{
$client = new PriceMonitoringClient(MONITORING_API_KEY);
$data = $client->getPrices(['date' => date('Y-m-d')]);
foreach ($data['products'] as $item) {
$productId = ProductMapper::findBySku($item['sku']);
if (!$productId) continue;
foreach ($item['competitors'] as $comp) {
$competitorId = CompetitorTable::getOrCreateByDomain($comp['domain']);
// Зберігаємо в історію перед оновленням
$current = CompetitorPriceTable::getByProductAndCompetitor($productId, $competitorId);
if ($current && $current['PRICE'] != $comp['price']) {
CompetitorPriceHistoryTable::add([
'PRODUCT_ID' => $productId,
'COMPETITOR_ID' => $competitorId,
'PRICE' => $current['PRICE'],
'RECORDED_AT' => $current['CHECKED_AT'],
]);
}
CompetitorPriceTable::addOrUpdate([
'PRODUCT_ID' => $productId,
'COMPETITOR_ID' => $competitorId,
'PRICE' => $comp['price'],
'URL' => $comp['url'],
'IN_STOCK' => $comp['in_stock'],
'CHECKED_AT' => new \Bitrix\Main\Type\DateTime(),
]);
}
}
return __FUNCTION__ . '();';
}
Обчислення цінової позиції
При кожному оновленні обчислюємо агрегати та позицію в bl_product_price_position:
-- Оновлюється тригером або агентом після синхронізації
INSERT INTO bl_product_price_position (product_id, our_price, min_comp, avg_comp, max_comp, rank, updated_at)
SELECT
cp.product_id,
bcp.PRICE as our_price,
MIN(cp.price) as min_comp,
ROUND(AVG(cp.price), 2) as avg_comp,
MAX(cp.price) as max_comp,
(SELECT COUNT(*) + 1 FROM bl_competitor_prices cp2
WHERE cp2.product_id = cp.product_id AND cp2.price < bcp.PRICE) as rank,
NOW()
FROM bl_competitor_prices cp
JOIN b_catalog_price bcp ON bcp.PRODUCT_ID = cp.product_id AND bcp.CATALOG_GROUP_ID = 1
GROUP BY cp.product_id, bcp.PRICE
ON CONFLICT (product_id) DO UPDATE SET
our_price = EXCLUDED.our_price, min_comp = EXCLUDED.min_comp,
avg_comp = EXCLUDED.avg_comp, rank = EXCLUDED.rank, updated_at = NOW();
Сповіщення при зміні цін конкурентів
Агент порівнює нові ціни з попередніми та відправляє сповіщення менеджерам при суттєвих змінах (конкурент знизив ціну нижче нашої):
foreach ($priceChanges as $change) {
if ($change['new_price'] < $change['our_price'] && $change['old_price'] >= $change['our_price']) {
// Конкурент щойно став дешевшим за нас
$message = sprintf(
'Конкурент %s знизив ціну на %s до %s грн (наша: %s грн)',
$change['competitor_name'],
$change['product_name'],
number_format($change['new_price'], 2, ',', ' '),
number_format($change['our_price'], 2, ',', ' ')
);
\Bitrix\Main\Mail\Event::send([
'EVENT_NAME' => 'COMPETITOR_PRICE_ALERT',
'LID' => SITE_ID,
'C_FIELDS' => ['MESSAGE' => $message],
]);
}
}
Терміни
| Етап | Термін |
|---|---|
| Схема БД та репозиторії | 2 дні |
| Агент синхронізації з джерелом даних | 2 дні |
| Розрахунок позиції та агрегатів | 1 день |
| Відображення в картці товару (адмінка) | 2 дні |
| Сповіщення при змінах | 1 день |
| Тестування | 1 день |
| Разом | 9–10 днів |







