Skip to content

Миграция API финансовых отчётов: snake_case → camelCase (WB API v5 → v1)

⚠️ Жёсткий дедлайн: 15.07.2026. Эндпоинт v5 GET /api/v5/supplier/reportDetailByPeriod будет отключён Wildberries в эту дату. Любой код, всё ещё вызывающий sdk.finances.getSupplierReportDetailByPeriod() после этой даты, перестанет работать в продакшене с ошибками HTTP 4xx/5xx.

Аудитория: Разработчики, использующие SDK v3.5 или новее и вызывающие getSupplierReportDetailByPeriod(). Ориентировочное время миграции: 30 минут на каждое место вызова. Начиная с: SDK v3.7.0

Кратко

typescript
// ❌ СТАРЫЙ (v5, устаревший, отключается 15.07.2026)
const rows = await sdk.finances.getSupplierReportDetailByPeriod({
  dateFrom: '2026-03-17',
  dateTo: '2026-03-20',
});
const total = rows.reduce((s, r) => s + (r.ppvz_for_pay ?? 0), 0);  // number

// ✅ НОВЫЙ (v1, начиная с v3.7.0)
import { parseMoneyAmount } from 'daytona-wildberries-typescript-sdk';

const rows = await sdk.finances.getSalesReportsDetailed({
  dateFrom: '2026-03-17',
  dateTo: '2026-03-20',
});
const total = rows.reduce((s, r) => s + parseMoneyAmount(r.forPay), 0);  // number (парсится из строки)

Найдите все устаревшие вызовы в вашем коде

Перед миграцией найдите все места вызовов:

bash
grep -rn "getSupplierReportDetailByPeriod" src/
grep -rn "DetailReportItem" src/

Или с помощью ripgrep:

bash
rg "getSupplierReportDetailByPeriod|DetailReportItem"

Что изменилось (v5 → v1)

Аспектv5 (устаревший)v1 (замена)
МетодgetSupplierReportDetailByPeriod()getSalesReportsDetailed()
HTTP-методGETPOST
Доменstatistics-api.wildberries.rufinance-api.wildberries.ru
Именование полейsnake_case (напр. ppvz_for_pay)camelCase (напр. forPay)
Денежные суммыnumberstring
Типы токеновВсе типыТолько Personal/Service (НЕ Basic/Test)
Выборочные поляНе поддерживаетсяНовый параметр fields: string[]
Эндпоинт спискаНетНовый getSalesReportsList()
Эндпоинт по IDНетНовый getSalesReportsDetailedByReportId()

Почему денежные суммы теперь string

В v5 денежные суммы были типа number. В v1 они стали string. Это сделано намеренно согласно спецификации WB — тип number в JavaScript (IEEE-754) теряет точность при суммах выше 2^53 (редко, но возможно в агрегированных итогах). Строковые значения сохраняют точность, возвращённую API.

Если вам нужны вычисления, используйте хелпер parseMoneyAmount(), который поставляется с SDK:

typescript
import { parseMoneyAmount } from 'daytona-wildberries-typescript-sdk';

const total = rows.reduce((sum, row) => sum + parseMoneyAmount(row.forPay), 0);

Предупреждение о точности: Для сумм с более чем 15 значащими цифрами (крайне редкий случай) используйте специализированную библиотеку для работы с десятичными числами, например decimal.js или big.js. Для всех типичных сумм продавца parseMoneyAmount() безопасен.

Остерегайтесь багов конкатенации строк

Самая частая ошибка при миграции — неявная конкатенация строк:

typescript
// ❌ НЕПРАВИЛЬНО — конкатенирует строки вместо сложения чисел!
const total = row.forPay + row.acquiringFee;
// "376.99" + "14.89" = "376.9914.89"  ← БАГ

// ✅ ПРАВИЛЬНО — сначала парсим, потом складываем
import { parseMoneyAmount } from 'daytona-wildberries-typescript-sdk';
const total = parseMoneyAmount(row.forPay) + parseMoneyAmount(row.acquiringFee);
// 376.99 + 14.89 = 391.88

Правило: каждый раз, когда вы выполняете арифметику с денежными полями v1, оборачивайте их в parseMoneyAmount().

Таблица маппинга полей (поиск по старому или новому имени)

Каждая строка показывает имя v5 в snake_case и имя v1 в camelCase рядом — Ctrl+F по любому из них найдёт нужную строку.

Денежные поля (тип изменён: numberstring)

v5 snake_casev1 camelCaseПримечания
retail_priceretailPriceбыло number, теперь string
retail_amountretailAmountбыло number, теперь string
retail_price_withdisc_rubretailPriceWithDiscпереименовано + тип изменён
delivery_rubdeliveryServiceпереименовано + тип изменён
supplier_promosellerPromoпереименовано + тип изменён
ppvz_sales_commissionppvzSalesCommissionбыло number, теперь string
ppvz_for_payforPayчасто используемое поле — переименовано + тип изменён
ppvz_rewardppvzRewardбыло number, теперь string
acquiring_feeacquiringFeeбыло number, теперь string
ppvz_vwvwпереименовано + тип изменён
ppvz_vw_ndsvwNdsпереименовано + тип изменён
penaltypenaltyтип изменён на string
additional_paymentadditionalPaymentтип изменён на string
rebill_logistic_costrebillLogisticCostтип изменён на string
storage_feepaidStorageпереименовано + тип изменён
deductiondeductionтип изменён на string
acceptancepaidAcceptanceпереименовано + тип изменён
installment_cofinancing_amountinstallmentCofinancingAmountтип изменён на string
cashback_amountcashbackAmountтип изменён на string
cashback_discountcashbackDiscountтип изменён на string
cashback_commission_changecashbackCommissionChangeтип изменён на string
payment_schedulepaymentScheduleтип изменён на string

Поля идентификаторов (переименованы)

v5 snake_casev1 camelCaseПримечания
realizationreport_idreportIdпереименовано
rrd_idrrdIdкурсор пагинации
gi_idgiId
nm_idnmIdартикул WB
shk_idshkId
assembly_idorderIdпереименовано в orderId
sa_namevendorCodeчасто используемое поле — переименовано
barcodeskuпереименовано
ts_nametechSizeпереименовано
order_uidorderUid
sridsridбез изменений
sticker_idstickerId
trbx_idtrbxId

Поля даты/времени (переименованы)

v5 snake_casev1 camelCaseПримечания
date_fromdateFrom
date_todateTo
create_dtcreateDateпереименовано
fix_tariff_date_fromfixTariffDateFrom
fix_tariff_date_tofixTariffDateTo
order_dtorderDt
sale_dtsaleDt
rr_dtrrDateпереименовано

Поля процентов/соотношений (по-прежнему number)

v5 snake_casev1 camelCaseПримечания
sale_percentsalePercent
commission_percentcommissionPercent
dlv_prcdlvPrc
product_discount_for_reportproductDiscountForReport
ppvz_spp_prcsppпереименовано
ppvz_kvw_prc_basekvwBaseпереименовано
ppvz_kvw_prckvwпереименовано
sup_rating_prc_upsupRatingUpпереименовано
is_kgvp_v2isKgvpV2
acquiring_percentacquiringPercent
wibes_wb_discount_percentwibesDiscountPercentпереименовано
seller_promo_discountsellerPromoDiscount
loyalty_discountloyaltyDiscount
sale_price_promocode_discount_prcsalePricePromocodeDiscountPrc
sale_price_affiliated_discount_prcsalePriceAffiliatedDiscountPrcначиная с v3.6.0
agency_vatagencyVatсемантика не документирована WB
sale_price_wholesale_discount_prcsalePriceWholesaleDiscountPrcначиная с v3.6.0

Строковые поля (тип не изменился)

v5 snake_casev1 camelCaseПримечания
currency_namecurrencyпереименовано
subject_namesubjectName
brand_namebrandName
doc_type_namedocTypeName
office_nameofficeName
supplier_oper_namesellerOperNameпереименовано
ppvz_office_nameppvzOfficeName
ppvz_supplier_nameppvzSupplierName
ppvz_innppvzSupplierInnпереименовано
acquiring_bankacquiringBank
payment_processingpaymentProcessing
declaration_numberdeclarationNumber
bonus_type_namebonusTypeName
site_countrycountryпереименовано
delivery_methoddeliveryMethod
rebill_logistic_orgrebillLogisticOrg
gi_box_type_namegiBoxTypeName
uuid_promocodeuuidPromocode
kizkizбез изменений
article_substitutionarticleSubstitutionначиная с v3.6.0

Булевы поля (без изменений)

v5 snake_casev1 camelCaseПримечания
srv_dbssrvDbs
is_legal_entityisB2bпереименовано

Целочисленные поля / поля ID (по-прежнему number)

v5 snake_casev1 camelCaseПримечания
report_typereportTypeперечисление 1-4
quantityquantityбез изменений
delivery_amountdeliveryAmount
return_amountreturnAmount
ppvz_office_idppvzOfficeId
seller_promo_idsellerPromoId
loyalty_idloyaltyId

Новые поля в v1 (нет аналога в v5)

ПолеТипПримечания
titlestringНазвание товара — НОВОЕ

Поэтапная миграция с использованием объединённого типа

Если в вашей кодовой базе метод отчёта вызывается во многих местах, можно мигрировать поэтапно, используя объединённый тип (union type) на время перехода:

typescript
import type {
  DetailReportItem,         // v5 (устаревший)
  SalesReportDetailedItem,  // v1
} from 'daytona-wildberries-typescript-sdk/finances';

// Объединённый тип для вспомогательных функций, которым нужно принимать любую форму
type AnyDetailReport = DetailReportItem | SalesReportDetailedItem;

function logReport(row: AnyDetailReport): void {
  // ВНИМАНИЕ: у этих типов почти НЕТ совпадающих имён свойств.
  // Используйте дискриминантные проверки или мигрируйте каждое место вызова отдельно.
  if ('forPay' in row) {
    // форма v1
    console.log(`Выплата: ${row.forPay}`);
  } else {
    // форма v5
    console.log(`Выплата: ${row.ppvz_for_pay}`);
  }
}

Ограничение: поскольку v5 и v1 используют совершенно разные имена полей, объединённый тип мало полезен для доступа к свойствам. Он в основном служит миграционной заглушкой для сигнатур функций на время перехода. Предпочтительнее мигрировать каждое место вызова «чисто».

Примеры миграции кода

Пример 1: Простой список и сумма (самый частый паттерн)

До (v5):

typescript
const rows = await sdk.finances.getSupplierReportDetailByPeriod({
  dateFrom: '2026-03-01',
  dateTo: '2026-03-31',
});

const totalPayout = rows.reduce((sum, r) => sum + (r.ppvz_for_pay ?? 0), 0);
console.log(`Итого: ${totalPayout.toFixed(2)} руб`);

После (v1):

typescript
import { parseMoneyAmount } from 'daytona-wildberries-typescript-sdk';

const rows = await sdk.finances.getSalesReportsDetailed({
  dateFrom: '2026-03-01',
  dateTo: '2026-03-31',
});

const totalPayout = rows.reduce((sum, r) => sum + parseMoneyAmount(r.forPay), 0);
console.log(`Итого: ${totalPayout.toFixed(2)} руб`);

Пример 2: Фильтрация по подменному артикулу (поле v3.6.0)

До (v5):

typescript
const campaignRows = rows.filter(
  (r) => r.article_substitution && r.article_substitution !== ''
);
const campaignRevenue = campaignRows.reduce((s, r) => s + (r.retail_amount ?? 0), 0);

После (v1):

typescript
const campaignRows = rows.filter(
  (r) => r.articleSubstitution && r.articleSubstitution !== ''
);
const campaignRevenue = campaignRows.reduce(
  (s, r) => s + parseMoneyAmount(r.retailAmount), 0
);

Пример 3: Постраничная загрузка за весь период

До (v5):

typescript
let allRows: DetailReportItem[] = [];
let rrdid = 0;
while (true) {
  const page = await sdk.finances.getSupplierReportDetailByPeriod({
    dateFrom, dateTo, rrdid, limit: 100000,
  });
  if (page.length === 0) break;
  allRows = allRows.concat(page);
  rrdid = page[page.length - 1].rrd_id ?? 0;
}

После (v1):

typescript
let allRows: SalesReportDetailedItem[] = [];
let rrdId = 0;
while (true) {
  const page = await sdk.finances.getSalesReportsDetailed({
    dateFrom, dateTo, rrdId, limit: 100000,
  });
  if (page.length === 0) break;
  allRows = allRows.concat(page);
  rrdId = page[page.length - 1].rrdId ?? 0;
}

Новое в v1: эндпоинт списка + эндпоинт по ID отчёта

getSalesReportsList() — список всех отчётов за период

typescript
const reports = await sdk.finances.getSalesReportsList({
  dateFrom: '2026-03-17',
  dateTo: '2026-03-20',
  period: 'weekly',
});

for (const r of reports) {
  console.log(`Отчёт ${r.reportId}: ${r.dateFrom} по ${r.dateTo}`);
  console.log(`  Итого к выплате: ${parseMoneyAmount(r.forPaySum)}`);
  console.log(`  Итого штрафов: ${parseMoneyAmount(r.penaltySum)}`);
}

getSalesReportsDetailedByReportId() — детали конкретного отчёта

typescript
// Типичный вариант использования
const rows = await sdk.finances.getSalesReportsDetailedByReportId(307401554);

// С выборочной загрузкой полей (быстрее, меньше трафика)
const rows = await sdk.finances.getSalesReportsDetailedByReportId(307401554, {
  fields: ['rrdId', 'nmId', 'forPay', 'retailAmount'],
});

Точность BigInt для ежедневных отчётов

Для ежедневных отчётов значение reportId может превышать Number.MAX_SAFE_INTEGER (2^53). Метод принимает number | bigint | string:

typescript
// Безопасно для BigInt в ежедневных отчётах
const rows = await sdk.finances.getSalesReportsDetailedByReportId(
  '9007199254740993',  // строка сохраняет точность
  { fields: ['rrdId', 'forPay'] }
);

Отчёты по эквайрингу (новое в v1)

Полностью новая группа эндпоинтов для отслеживания стоимости эквайринга платежей. Доступно только для российских продавцов, токены только Personal/Service.

typescript
// Список отчётов по эквайрингу
const reports = await sdk.finances.getAcquiringReportsList({
  dateFrom: '2026-03-17',
  dateTo: '2026-03-20',
});

// Детали за период
const rows = await sdk.finances.getAcquiringReportsDetailed({
  dateFrom: '2026-03-17',
  dateTo: '2026-03-20',
  fields: ['rrdId', 'acquiringBank', 'acquiringFee'],
});

// Сумма комиссий
import { parseMoneyAmount } from 'daytona-wildberries-typescript-sdk';
const totalFees = rows.reduce(
  (s, r) => s + parseMoneyAmount(r.acquiringFee), 0
);

Отчёты по эквайрингу только для РФ

Эндпоинты эквайринга (getAcquiringReports*) доступны только для российских продавцов. Если вы работаете в нескольких регионах (например, как оператор платформы), разделяйте логику по географии:

typescript
async function fetchAcquiring(sdk: WildberriesSDK, isRussianSeller: boolean) {
  if (!isRussianSeller) {
    return []; // Пропускаем для продавцов не из РФ
  }
  return await sdk.finances.getAcquiringReportsDetailed({ dateFrom, dateTo });
}

Требования к типу токена

Все эндпоинты финансовых отчётов v1 требуют токен типа Personal или Service. Токены Basic и Test вернут ошибку 401/403.

typescript
// ✅ Работает
const sdk = new WildberriesSDK({
  apiKey: process.env.WB_PERSONAL_TOKEN,
  tokenType: 'personal',
});

// ❌ 401/403 на эндпоинтах v1
const sdk = new WildberriesSDK({
  apiKey: process.env.WB_BASIC_TOKEN,
  tokenType: 'basic',
});

Если вы используете токены Basic/Test, вам потребуется запросить токен Personal или Service у Wildberries до 15.07.2026.

Чеклист миграции

  • [ ] Выполнить grep -rn "getSupplierReportDetailByPeriod" src/ для поиска всех мест вызова
  • [ ] Выполнить grep -rn "DetailReportItem" src/ для поиска всех ссылок на типы
  • [ ] Убедиться, что ваш API-токен имеет тип Personal или Service (не Basic/Test)
  • [ ] Обновить до SDK v3.7.0+: npm install daytona-wildberries-typescript-sdk@latest
  • [ ] Импортировать хелпер parseMoneyAmount в местах, где выполняются вычисления с деньгами
  • [ ] Заменить каждое место вызова на getSalesReportsDetailed() + поля в camelCase
  • [ ] Обернуть все чтения денежных полей в parseMoneyAmount()
  • [ ] Проверить rrd_idrrdId везде (частое переименование)
  • [ ] Проверить ppvz_for_payforPay везде (частое переименование)
  • [ ] Проверить на баги конкатенации строк (денежные поля теперь строки)
  • [ ] Обновить юнит-тесты
  • [ ] Задеплоить до 15.07.2026

Как узнать вашу версию SDK

bash
npm ls daytona-wildberries-typescript-sdk
# Ожидается: daytona-wildberries-typescript-sdk@3.7.0 или выше

Или в коде:

typescript
import { version } from 'daytona-wildberries-typescript-sdk';
console.log(version); // "3.7.0" или выше

Если у вас версия v3.6.x или ниже, обновитесь немедленно — в этих версиях НЕТ методов-замен v1.

Связанные материалы

Made with ❤️ for the Wildberries developer community