Skip to content

Instantly share code, notes, and snippets.

@daniil-burdygin
Created February 26, 2026 23:37
Show Gist options
  • Select an option

  • Save daniil-burdygin/533047d43f0f720fe930a9f6269ed74c to your computer and use it in GitHub Desktop.

Select an option

Save daniil-burdygin/533047d43f0f720fe930a9f6269ed74c to your computer and use it in GitHub Desktop.
WB API → Google Sheets: загрузка отчёта о продажах по реализации. Подробнее — в статье на dev.wildberries.ru
// ---------------------------------------------------------------------------
// WB API → Google Sheets — ознакомительная интеграция
// Эндпоинт: GET /api/v5/supplier/reportDetailByPeriod
// Хост: https://statistics-api.wildberries.ru
// ---------------------------------------------------------------------------
/** Добавляет меню «WB API» при открытии таблицы */
function onOpen() {
SpreadsheetApp.getUi()
.createMenu('WB API')
.addItem('Ввести токен', 'setApiToken')
.addItem('Загрузить отчёт', 'loadReport')
.addToUi();
}
// ---- Управление токеном ----------------------------------------------------
/** Запрашивает токен через диалог и сохраняет в PropertiesService */
function setApiToken() {
const ui = SpreadsheetApp.getUi();
const result = ui.prompt(
'WB API — Токен',
'Вставьте ваш API-токен (категория «Статистика»):',
ui.ButtonSet.OK_CANCEL
);
if (result.getSelectedButton() !== ui.Button.OK) return;
const token = result.getResponseText().trim();
if (!token) {
ui.alert('Токен не может быть пустым.');
return;
}
PropertiesService.getUserProperties().setProperty('WB_API_TOKEN', token);
ui.alert('Токен сохранён.');
}
/** Возвращает сохранённый токен или null */
function getApiToken() {
return PropertiesService.getUserProperties().getProperty('WB_API_TOKEN');
}
// ---- Запрос к API ----------------------------------------------------------
/**
* Загружает «Отчёт о продажах по реализации» за указанный период.
* Обрабатывает пагинацию через параметр rrdid.
*/
function fetchReportData(token, dateFrom, dateTo) {
const baseUrl =
'https://statistics-api.wildberries.ru/api/v5/supplier/reportDetailByPeriod';
const allRows = [];
let rrdid = 0;
while (true) {
const url =
baseUrl +
'?dateFrom=' + encodeURIComponent(dateFrom) +
'&dateTo=' + encodeURIComponent(dateTo) +
'&limit=100000' +
'&rrdid=' + rrdid;
const options = {
method: 'get',
headers: { Authorization: token },
muteHttpExceptions: true,
};
const response = UrlFetchApp.fetch(url, options);
const code = response.getResponseCode();
if (code === 204) break;
if (code === 401) {
throw new Error('Ошибка 401: неверный или просроченный токен.');
}
if (code === 429) {
throw new Error(
'Ошибка 429: превышен лимит запросов. Подождите минуту и попробуйте снова.'
);
}
if (code !== 200) {
throw new Error('Ошибка API: HTTP ' + code);
}
const data = JSON.parse(response.getContentText());
if (!Array.isArray(data) || data.length === 0) break;
allRows.push(...data);
const lastRow = data[data.length - 1];
rrdid = lastRow['rrd_id'] ?? 0;
}
return allRows;
}
// ---- Запись в таблицу ------------------------------------------------------
/** Записывает массив объектов на лист «Продажи» */
function writeToSheet(rows) {
const ss = SpreadsheetApp.getActiveSpreadsheet();
let sheet = ss.getSheetByName('Продажи');
if (sheet) {
sheet.clear();
} else {
sheet = ss.insertSheet('Продажи');
}
if (rows.length === 0) return;
const headers = Object.keys(rows[0]);
sheet.appendRow(headers);
const data = rows.map((row) => headers.map((h) => row[h] ?? ''));
if (data.length > 0) {
sheet
.getRange(2, 1, data.length, headers.length)
.setValues(data);
}
}
// ---- Главная функция -------------------------------------------------------
/** Точка входа: загружает отчёт и записывает на лист */
function loadReport() {
const ui = SpreadsheetApp.getUi();
const token = getApiToken();
if (!token) {
ui.alert('Сначала введите токен через меню «WB API → Ввести токен».');
return;
}
const now = new Date();
const weekAgo = new Date(now.getTime() - 7 * 24 * 60 * 60 * 1000);
const dateFrom = formatDate(weekAgo);
const dateTo = formatDate(now);
try {
ui.alert('Загрузка данных за период ' + dateFrom + ' — ' + dateTo + '…');
const rows = fetchReportData(token, dateFrom, dateTo);
if (rows.length === 0) {
ui.alert(
'Нет данных за выбранный период. Проверьте даты или попробуйте другой диапазон.'
);
return;
}
writeToSheet(rows);
ui.alert(
'Готово! Загружено строк: ' +
rows.length +
'. Данные на листе «Продажи».'
);
} catch (e) {
const msg = e instanceof Error ? e.message : String(e);
ui.alert('Ошибка: ' + msg);
}
}
// ---- Утилиты ---------------------------------------------------------------
/** Форматирует Date в строку YYYY-MM-DD */
function formatDate(d) {
const yyyy = d.getFullYear();
const mm = String(d.getMonth() + 1).padStart(2, '0');
const dd = String(d.getDate()).padStart(2, '0');
return yyyy + '-' + mm + '-' + dd;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment