На главную
Войти

Автоматизированный финансовый учет и контроль рентабельности

Автоматический P&L, потоварная рентабельность по каждому SKU и анализ стоимости хранения. Один инструмент вместо десяти Excel-файлов.

✅ Бесплатно ✅ Работает в Google Таблицах ✅ Не нужен сервер ✅ Данные остаются у вас
WBTool — аналитика SKU с ROI и фото товаров

Знакомо?

📊
«Где моя прибыль?»

WB удерживает логистику, хранение, штрафы, рекламу… В итоге выручка есть, а прибыли нет. Вы не видите реальный P&L и не понимаете, зарабатываете ли вообще.

📦
«Какой товар сливает бюджет?»

Без потоварного учета по каждому SKU невозможно понять, какой товар приносит прибыль, а какой — убыток. Штрафы и хранение «размазаны» по всему бизнесу.

⏱️
«Я трачу 3 часа на отчёты каждую неделю»

Скачать 5 отчётов из ЛК, разархивировать, объединить в Excel, вручную сопоставить... И так каждый понедельник. Потерянное время — потерянные деньги.

🏭
«Хранить или вывозить?»

Тарифы WB за хранение растут. Но без расчёта стоимости хранения vs стоимости вывоза по каждому складу и SKU — решение принимается вслепую.

Один инструмент — полная картина бизнеса

WBTool подключается к 7 API Wildberries, загружает все данные и автоматически строит три ключевых отчёта.

💰
Чистый Финансовый Результат

Полный P&L вашего бизнеса на WB:

  • Выручка → Маржинальная прибыль → Операционный ФР → Чистый ФР
  • 38 строк финансовых показателей
  • Детализация: по месяцам / неделям / дням
  • Автоматический расчёт УСН, ROI%, маржинальности
P&L отчёт WBTool
📈
Аналитика по каждому SKU

Потоварная рентабельность каждого SKU:

  • Продажи, возвраты, комиссия WB, логистика
  • Себестоимость, реклама, хранение, штрафы
  • Маржа, ROI%, средняя цена продажи
  • Остатки на складах WB в реальном времени
  • Фото товаров в отчёте
Аналитика SKU WBTool
📦
Хранение / Вывоз

Калькулятор рентабельности хранения:

  • Стоимость хранения за 30 дней по каждому складу WB
  • Стоимость вывоза/возврата по актуальным тарифам
  • Себестоимость замороженных остатков
  • Фото товаров в отчёте
Анализ хранения WBTool

Что загружается автоматически

Одна кнопка «🔄 Актуализировать данные» — и все 8 модулей загрузятся в фоне. Можно закрыть таблицу.

Модуль Данные API
📄 Финансовые отчёты Еженедельные + ежедневные детализации реализации finance-api
💲 Цены и скидки Базовые цены, скидки, СПП по каждому SKU discounts-prices-api
📦 Остатки FBW Остатки по всем складам WB + транзит seller-analytics-api
🚚 Поставки Полная история отгрузок с детализацией по ШК supplies-api
📢 Реклама Расходы, клики, показы по кампаниям и SKU advert-api
🏷️ Карточки товаров SKU, баркоды, артикулы, габариты content-api
🏭 Хранение Ежедневная стоимость хранения по баркодам analytics-api
📥 Платная приёмка Расходы на приёмку товаров analytics-api

📂 Загрузка из Excel

Разархивируйте отчёты из ЛК на Google Диск — WBTool сам объединит их

📋 Номенклатура

Справочник товаров с себестоимостью и привязкой по штрих-кодам

🗂️ Группировка SKU

Объединяйте товары в категории для агрегированной аналитики

Настройка за 5 минут

1

Скопируйте таблицу

Нажмите «Файл → Создать копию». Дождитесь появления меню WBTool.

2

Нажмите «Сгенерировать чистый Ввод_Данных»

При первом запуске дайте скрипту права доступа — это стандартная процедура Google.

3

Настройте WB API Token

Создайте персональный токен в ЛК Wildberries с правами: Контент, Аналитика, Продвижение, Финансы, Поставки, Цены.

4

Загрузите отчёты

Через API (рекомендуется) или из файлов на Google Диске.

5

Заполните себестоимость

Вручную или автоматически из справочника «Номенклатура».

6

Получите результат

Нажмите «Рассчитать ЧФР» или «Рассчитать Аналитику SKU» — готово!

Панель управления WBTool

Проект в цифрах

0
строк кода ядра
0
функций в бизнес-логике
0
API Wildberries интегрировано
0
листов генерируются автоматически
0
строк P&L в отчёте ЧФР
0
модулей фоновой загрузки
0
стоимость для пользователя

Частые вопросы

Это бесплатно?
Да, полностью. WBTool работает in Google Таблицах и не требует подписки, серверов или установки.
Мои данные в безопасности?
Да. API-токен хранится в защищённом хранилище Google (DocumentProperties), а не в ячейках таблицы. При передаче копии другому человеку токен не передаётся. Все данные остаются в вашем Google-аккаунте.
Скрипт говорит «Время вышло, нажмите ещё раз» — что делать?
Это нормально. Google ограничивает время работы скрипта до 6 минут. Просто нажмите ту же кнопку повторно — скрипт продолжит с того же места.
Можно ли использовать для нескольких магазинов?
Каждая таблица привязана к одному WB API-токену. Для каждого магазина создайте отдельную копию шаблона.
Чем это лучше платных сервисов?
Вы не платите подписку, ваши данные не уходят на сторонние серверы, и вы можете свободно модифицировать формулы и логику под свои нужды.

Перестаньте считать вручную

Скопируйте таблицу, подключите API-токен — и WBTool соберет полную историю продаж в фоновом режиме. Первичная загрузка крупных магазинов может занять время, но затем все отчеты будут обновляться в один клик.

🎯 Получить WBTool бесплатно

Google Таблица • Без установки • Без подписки • Без серверов

< / > Под капотом

Этот раздел — для разработчиков, Tech Lead'ов и HR. Ниже — технический разбор архитектуры, паттернов и инженерных решений проекта.

Обзор проекта

Stack:           Google Apps Script (V8 Runtime)
Core:            LibraryScript.js — 8 800+ LOC, 110 functions
Client Wrapper:  Code.js — 82 LOC
APIs integrated: 7 (Wildberries) + Sheets API v4 + Drive API
Architecture:    Library Pattern + State Machine Orchestrator
Deployment:      clasp CLI → obfuscated build → Google Cloud

Ключевые характеристики:

  • Полностью serverless — работает в облаке Google, zero-cost infrastructure
  • Обфускация ядра для защиты IP (JavaScript Obfuscator)
  • CI/CD через clasp CLI: dev:push:lib / prod:push пайплайны
  • 17 листов генерируются и форматируются программно

Архитектурные паттерны

Wrapper + Core (Code.js → LibraryScript.js)

+-----------------------------------------------------+
|  Client Spreadsheet (Code.js - 82 LOC)              |
|                                                     |
|  onOpen(e) -> WBToolLibrary.buildMenu()             |
|                                                     |
|  menuAction1()  --+                                 |
|  menuAction2()  --+                                 |
|  ...            --+--> _run(slot)                   |
|  menuAction25() --+      |                          |
|                          v                          |
|              try { WBToolLibrary                    |
|                .dispatchMenuAction(slot) }          |
|              catch(e) { _showError(e) }             |
+-----------------------+-----------------------------+
                        | Library Bridge              |
+-----------------------v-----------------------------+
|  WBToolLibrary (LibraryScript.js - 8800+ LOC)       |
|                                                     |
|  dispatchMenuAction(slot) {                         |
|    switch(slot) {                                   |
|      case 1: return startReportMerging();           |
|      case 7: return calculateCFR();                 |
|      case 18: return actualizeSkuData();            |
|      ...                                            |
|    }                                                |
|  }                                                  |
+-----------------------------------------------------+

            
IP Protection: Бизнес-логика скрыта в обфусцированной библиотеке. Пользователь видит только 25 пустых слотов.
Hot-swap обновления: Обновление ядра для всех пользователей — один clasp push. Клиентский код не меняется.
Dynamic Dispatch: Клиенту не нужно знать, что выполняет menuAction7(). Маршрутизация жёстко прописана в ядре.

State Machine Orchestrator (обход 6-минутного лимита)

Google Apps Script убивает любой скрипт через 6 минут. WBTool загружает данные из 8 API-эндпоинтов, что занимает 15–40 минут. Решение — Finite State Machine на базе минутных триггеров.

+-----------------------------------------------------+
|              actualizeSkuData(isBackground)         |
|                                                     |
|  State = PropertiesService.get("WB_ACTUALIZE_STATE")|
|  {                                                  |
|    "currentStep": 3,        // 0..7                 |
|    "dateTo": "2024-05-31",                          |
|    "startTime": 1717144800  // stale session guard  |
|  }                                                  |
|                                                     |
|  while (state.currentStep <= 7) {                   |
|    if (elapsed > 250s) {    // <- 4.1 min guard     |
|      saveState();                                   |
|      return;  // exit gracefully, trigger continues |
|    }                                                |
|    executeStep(state.currentStep);                  |
|    state.currentStep++;                             |
|  }                                                  |
|                                                     |
|  deleteAllTriggers();                               |
|  showSuccess("✅ Завершено");                       |
+-----------------------------------------------------+
         ^                          |
         |  every 1 min             | on first call
         |                          v
    +----+----------------------------------+
    |  ScriptApp.newTrigger('menuAction25') |
    |    .timeBased()                       |
    |    .everyMinutes(1)                   |
    |    .create();                         |
    +---------------------------------------+

Механика:

  • Пользователь нажимает «🔄 Актуализировать» → запускается Step 0
  • Оркестратор создаёт ежеминутный фоновый триггер
  • Каждую минуту триггер «будит» оркестратор с сохранённого шага
  • При превышении 250 секунд — graceful exit + сохранение JSON-состояния
  • На финальном шаге триггер удаляется, статус → «✅ Завершено»
  • Пользователь может закрыть таблицу — процесс продолжится в облаке
Error Recovery: Счётчик ретраев WB_ACTUALIZE_ERROR_COUNT — до 3 попыток на шаг. Между попытками — минутный интервал (Exponential Backoff на уровне инфраструктуры). При 3 фейлах — cleanup всех триггеров, статус «❌ Ошибка». Stale session guard: если процесс завис >12 часов → автоматический сброс.

Работа с API Wildberries

Rate Limiting & Retry Strategy

+-------------------------------------------------+
|           _handleApiResponse(response, apiName) |
|                                                 |
|  HTTP 200-299 -> JSON.parse(body)               |
|    +- catch: "API вернуло невалидный JSON"      |
|                                                 |
|  HTTP 401/403 -> context-aware error            |
|    +- apiName.includes('promotion')             |
|       ? "Нужны права «Продвижение»"             |
|       : "Проверьте токен WB"                    |
|                                                 |
|  HTTP 429 -> throw Error (NOT sleep!)           |
|    +- Перехватывается Оркестратором             |
|       -> increment error counter                |
|       -> exit session                           |
|       -> retry in 1 min via trigger             |
|                                                 |
|  HTTP 5xx -> throw "Сервер WB недоступен"       |
+-------------------------------------------------+
Почему throw, а не sleep при 429? В классическом подходе скрипт «замораживает» поток через Utilities.sleep(30000). Но в среде GAS это сжигает ценные секунды из 6-минутной квоты. Архитектура WBTool выбрасывает ошибку наверх, позволяя оркестратору завершить сеанс и переложить ожидание на инфраструктуру Google.

Исключение — Supplies API (Поставки)

Этот API требует сотни последовательных GET-запросов. Здесь используется динамический парсинг HTTP-заголовков:

if (responseCode === 429) {
  var headers = response.getHeaders();
  var retryAfter = headers['retry-after'] || headers['x-ratelimit-retry'];
  var waitMs = retryAfter ? (parseInt(retryAfter, 10) + 1) * 1000 : 5000;
  Utilities.sleep(waitMs);  // точное время бана от WB
}

Оптимизация производительности

Batch-операции с Sheets API v4

Форматирование P&L-отчёта (38 строк × 50+ колонок) через стандартный getRange().setBackground() занимает ~30 секунд. WBTool использует Advanced Sheets API v4 BatchUpdate:

// Один запрос вместо сотен
var requests = [];
requests.push({ updateSheetProperties: { ... } });
requests.push({ repeatCell: { range: {...}, cell: { format: { backgroundColor: ... } } } });
// ... 50+ операций форматирования

Sheets.Spreadsheets.batchUpdate({ requests: requests }, spreadsheetId);
// Время: ~0.5 секунды
Результат: Форматирование сократилось с 3 минут → 0.5 секунды (x360).

High-Performance XLSX Parser

Стандартная конвертация Excel→Google Sheets через Drive API: 30–60 секунд на файл. WBTool парсит XLSX напрямую в памяти как ZIP-архив:

blob.setContentType('application/zip');
var xmlFiles = Utilities.unzip(blob);
// Парсинг xl/sharedStrings.xml через String.split(' тегов
Результат: Парсинг одного 50k-строчного отчёта — ~5 секунд вместо 60 (x12).

Безопасность и защита данных

Аспект Реализация
Хранение токена PropertiesService.getDocumentProperties() — не в ячейках, не в коде
Передача копии Токен НЕ копируется при «Файл → Создать копию»
Обфускация ядра JavaScript Obfuscator → обфусцированный билд в продакшн-библиотеку
Права токена Только «Чтение» — скрипт не модифицирует данные в ЛК WB
Graceful Error Handling Интерактивный режим → UI Alert; Фоновый режим → console.error

Технологии и инструменты

Google Apps Script V8 Engine JavaScript ES6+ 7× WB REST API Sheets API v4 Drive API PropertiesService clasp CLI JS Obfuscator Git State Machine Dynamic Dispatch Cursor Pagination In-Memory Caching Batch API

Ключевые инженерные решения

Проблема Решение Результат
6-минутный лимит GAS State Machine + минутные триггеры Загрузка 8 API без ограничений
Rate Limit 429 от WB Throw → Orchestrator retry (не sleep) Не сжигает квоту GAS
Медленное форматирование Sheets API v4 BatchUpdate 3 мин → 0.5 сек (x360)
Медленный парсинг XLSX ZIP-распаковка + String.split XML 60 сек → 5 сек (x12)
Квота на Sheets API calls In-memory batch preload всех листов Сотни вызовов → 1 пакетный
Защита бизнес-логики Library Pattern + JS Obfuscator 25 пустых слотов
Безопасность токена DocumentProperties (не ячейки) Токен не утекает при копировании
Изменчивость API WB Column mapping + fallback synonyms Устойчивость к переименованиям
Фоновый режим без UI Dynamic status bar на листе (F5:J5) Цветная плашка прогресса
Зоопарк форматов дат Universal date parser RU-локаль + ISO + Excel serial