Дата: 2026-04-30 Автор: Cowork session (Serhii / Delta Medical) Призначення: Claude на VPS має змогу самостійно перевіряти та завантажувати дані продажів і UTM-аналітику з Tabletki.ua в BigQuery.
Tabletki.ua API (cab-producer.tabletki.ua)
│
├─ reportId: 4ed497e3... (Продажі)
│ ▼
│ tabletki-sales-loader.js
│ ▼
│ BQ: tabletki.tabletki_sales (393+ rows)
│ ▼ Views → Looker Studio
│
└─ reportId: 72c243dc... (UTM мітки)
▼
tabletki-utm-loader.js
▼
BQ: tabletki.tabletki_utm (22+ rows)
Проект GCP: ad-analytics-hub
Dataset: tabletki (region: EU)
Таблиці: tabletki_sales, tabletki_utm
Розташування на робочому ПК:
D:\Users\Sergey.Vereschak.DELTAMEDICAL\Documents\Claude\Projects\Ads Analyser\
| Файл | Опис |
|---|---|
tabletki-sales-loader.js |
Node.js loader продажів — 3 режими: api, excel, backfill |
tabletki_sales_schema.json |
BigQuery schema продажів (20 полів) |
tabletki-utm-loader.js |
Node.js loader UTM-звіту — API fetch, ChildArray flatten, BQ upsert |
tabletki_utm_schema.json |
BigQuery schema UTM (10 полів) |
utm_insert.sql |
SQL для ручного створення таблиці + INSERT даних |
.env.example |
Шаблон змінних середовища |
looker_studio_views.sql |
4 SQL views для Looker Studio |
tabletki_sales_*.ndjson |
Приклад завантажених даних продажів |
tabletki_utm_*.ndjson |
Приклад завантажених UTM-даних |
TABLETKI_TOKENBigQuery Data Editor + BigQuery Job UserGOOGLE_APPLICATION_CREDENTIALS=path/to/service-account.jsongcloud auth application-default loginBase URL: https://cab-producer.tabletki.ua
Swagger: https://cab-producer.tabletki.ua/report-swagger/
POST /api/ReportExecution/report?reportType=JSON&reportId={uuid}
Authorization: Bearer {TABLETKI_TOKEN}
Content-Type: application/json
Body: { "dateFrom": "2026-04-12", "dateTo": "2026-04-12" }
Додаткові body поля (optional): periodType, sku, area, city, tableSku
| ID | Назва |
|---|---|
4ed497e3-2e47-11ef-9209-000c29baf0b7 |
Продажі по категоріям ← основний |
3f8a03b8-1f1b-11ef-9209-000c29baf0b7 |
Продажі по ATC-групам |
dbc1d89c-4579-11ef-920a-000c29baf0b7 |
По категоріям (по містах) |
dbc1d89d-4579-11ef-920a-000c29baf0b7 |
По категоріям (по областях) |
5d2bb5bd-4989-11ef-920a-000c29baf0b7 |
Динаміка по категоріям |
a65e7e0a-b7ba-11ef-9210-000c29baf0b7 |
Динаміка замовлень погодинна |
72c243dc-7f5a-11f0-9225-000c29baf0b7 |
Звіт за UTM мітками |
730778ee-6168-11f0-9225-000c29baf0b7 |
Заблоковані товари |
351afe8f-7cee-11f0-9225-000c29baf0b7 |
Якість бронювання |
SkuId → sku_id, SkuCode → product_code, SkuName → product_name,
SkuProducer → manufacturer, CategoryCode → category_code,
Category → category_name, Qty → units_sold, SaleSum → revenue_uah,
AvgPrice → avg_price_uah, CatSaleSum → category_revenue_uah,
Weight → pct_category_revenue, WeightQty → pct_category_units,
QtyTop1/2/3 → category_top1/2/3_units
GET /api/Reports → список звітівGET /api/Reports/{id}/Parameters → параметри звітуGET /api/Reports/PeriodTypes → day/week/monthGET /api/Reports/Skus → список товарівВажливо: MVC ендпоінти (/Report/GetReport, /Report/Download) НЕ працюють з Bearer token — тільки /api/* ендпоінти.
npm install dotenv @google-cloud/bigquery xlsx axios
# Одноразове завантаження (один період)
node tabletki-sales-loader.js --mode=api --from=2026-04-21 --to=2026-04-27
# Завантаження з Excel файлу
node tabletki-sales-loader.js --mode=excel --file="path/to/report.xlsx"
# Backfill (автоматична розбивка на чанки)
node tabletki-sales-loader.js --mode=backfill --from=2026-01-01 --to=2026-04-27 --period=week
# Одноразове завантаження UTM-звіту
node tabletki-utm-loader.js --from=2026-04-23 --to=2026-04-29
# Dry run (тест без запису в BQ)
node tabletki-utm-loader.js --from=2026-04-23 --to=2026-04-29 --dry-run
# Зберегти як NDJSON
node tabletki-utm-loader.js --from=2026-04-23 --to=2026-04-29 --out-ndjson=utm_data.ndjson
API повертає масив кампаній. Кожна кампанія має поле ChildArray (JSON string) з розбивкою по source/medium. Loader розгортає (flatten) ChildArray: кожна комбінація campaign/source/medium = окремий рядок.
Маппінг полів з ChildArray:
Utm Source → utm_source
Utm Medium → utm_medium
Кількість переходів → clicks
Кількість ассоційованих бронювань → conversions
Сума заброньованих товарів → conversion_value
| Поле | Тип | Опис |
|---|---|---|
| date_from | DATE (REQUIRED) | Початок звітного періоду |
| date_to | DATE (REQUIRED) | Кінець звітного періоду |
| utm_campaign | STRING (REQUIRED) | Campaign name або ID |
| utm_source | STRING | fb, google, tiktok, dv360, delta... |
| utm_medium | STRING | paid, reach, pmax, sku... |
| clicks | INT64 | Кількість переходів |
| conversions | INT64 | Асоційовані бронювання |
| conversion_value | FLOAT64 | Сума заброньованих товарів (грн) |
| ingested_at | TIMESTAMP | Час завантаження |
| source_file | STRING | api / filename |
Обидва лоадери автоматично видаляють старі записи за той самий date_from + date_to перед вставкою нових. Тому повторний запуск безпечний.
4 views створено в ad-analytics-hub.tabletki:
| View | Опис |
|---|---|
v_delta_sales_daily |
Усі продажі Delta Medical, всі типи періодів |
v_delta_sales_weekly |
Агреговані тижневі продажі (GROUP BY) |
v_delta_sales_trend |
Тижневий тренд з market share % |
v_market_share |
Частка ринку по категоріях |
Фільтр: manufacturer LIKE '%Дельта Медікел%'
SQL для створення views — у файлі looker_studio_views.sql.
# Кількість записів
bq query --use_legacy_sql=false \
'SELECT COUNT(*) as total_rows, MIN(date_from) as min_date, MAX(date_to) as max_date FROM `ad-analytics-hub.tabletki.tabletki_sales`'
# Останні завантаження
bq query --use_legacy_sql=false \
'SELECT date_from, date_to, period_type, COUNT(*) as rows, MAX(ingested_at) as last_ingested FROM `ad-analytics-hub.tabletki.tabletki_sales` GROUP BY 1,2,3 ORDER BY date_to DESC LIMIT 10'
# Продажі Delta Medical за останній тиждень
bq query --use_legacy_sql=false \
'SELECT product_name, units_sold, revenue_uah, ROUND(pct_category_revenue*100,2) as market_share_pct FROM `ad-analytics-hub.tabletki.v_delta_sales_trend` ORDER BY revenue_uah DESC LIMIT 10'
# Перевірка views
bq query --use_legacy_sql=false \
'SELECT COUNT(*) FROM `ad-analytics-hub.tabletki.v_delta_sales_daily`'
# UTM — кількість записів
bq query --use_legacy_sql=false \
'SELECT COUNT(*) as total_rows, MIN(date_from) as min_date, MAX(date_to) as max_date FROM `ad-analytics-hub.tabletki.tabletki_utm`'
# UTM — топ кампаній по кліках
bq query --use_legacy_sql=false \
'SELECT utm_campaign, utm_source, utm_medium, clicks, conversions, conversion_value FROM `ad-analytics-hub.tabletki.tabletki_utm` ORDER BY clicks DESC LIMIT 10'
# Тест API — отримати список звітів
curl -s -H "Authorization: Bearer $TABLETKI_TOKEN" \
https://cab-producer.tabletki.ua/api/Reports | jq '.[].Name'
# Тест API — отримати дані за один день
curl -s -X POST \
"https://cab-producer.tabletki.ua/api/ReportExecution/report?reportType=JSON&reportId=4ed497e3-2e47-11ef-9209-000c29baf0b7" \
-H "Authorization: Bearer $TABLETKI_TOKEN" \
-H "Content-Type: application/json" \
-d '{"dateFrom":"2026-04-28","dateTo":"2026-04-28"}' | jq 'length'
# Тест API — UTM звіт
curl -s -X POST \
"https://cab-producer.tabletki.ua/api/ReportExecution/report?reportType=JSON&reportId=72c243dc-7f5a-11f0-9225-000c29baf0b7" \
-H "Authorization: Bearer $TABLETKI_TOKEN" \
-H "Content-Type: application/json" \
-d '{"dateFrom":"2026-04-23","dateTo":"2026-04-29"}' | jq 'length'
| Проблема | Рішення |
|---|---|
401 Unauthorized від API |
Токен прострочений → оновити на cab-producer.tabletki.ua → API інтеграції |
Access Denied в BigQuery |
Використовуй акаунт master.digital.dm@gmail.com або service account з ролями Data Editor + Job User |
Provided Schema does not match |
При upload в BQ — зняти "Auto-detect schema", використовувати існуючу schema таблиці |
| Порожня відповідь API | Перевір діапазон дат (max -31 день offset, historical max -24 місяці) |
ECONNREFUSED |
VPN може бути потрібен для cab-producer.tabletki.ua |
dateFrom offset: максимум -31 день від dateTo--mode=backfill, loader автоматично розбиває на чанки по 7 днів