Обновлен README.md с новыми возможностями платформы Sfera V для управления бизнесом, добавлен раздел о складе Wildberries для селлеров. В компоненте Sidebar добавлена кнопка для перехода к складу ВБ, доступная только для пользователей с типом организации "SELLER". В классе WildberriesService реализованы новые методы для получения остатков товаров и интеграции с API Wildberries, включая обработку ошибок и кэширование данных.
This commit is contained in:
@ -11,6 +11,86 @@ interface WildberriesWarehousesResponse {
|
||||
data: WildberriesWarehouse[]
|
||||
}
|
||||
|
||||
// Интерфейс для совместимости с компонентом склада
|
||||
interface WBStock {
|
||||
nmId: number
|
||||
vendorCode: string
|
||||
title: string
|
||||
brand: string
|
||||
price: number
|
||||
stocks: Array<{
|
||||
warehouseId: number
|
||||
warehouseName: string
|
||||
quantity: number
|
||||
quantityFull: number
|
||||
inWayToClient: number
|
||||
inWayFromClient: number
|
||||
}>
|
||||
totalQuantity: number
|
||||
totalReserved: number
|
||||
photos?: Array<{
|
||||
big?: string
|
||||
c246x328?: string
|
||||
c516x688?: string
|
||||
square?: string
|
||||
tm?: string
|
||||
}>
|
||||
mediaFiles?: string[]
|
||||
characteristics?: Array<{
|
||||
id: number
|
||||
name: string
|
||||
value: string[] | string
|
||||
}>
|
||||
subjectName?: string
|
||||
description?: string
|
||||
}
|
||||
|
||||
// Analytics API interfaces for stocks report by offices
|
||||
interface StocksReportOfficesRequest {
|
||||
nmIDs?: number[]
|
||||
subjectIDs?: number[]
|
||||
brandNames?: string[]
|
||||
tagIDs?: number[]
|
||||
currentPeriod: {
|
||||
start: string
|
||||
end: string
|
||||
}
|
||||
stockType: '' | 'wb' | 'mp'
|
||||
skipDeletedNm: boolean
|
||||
}
|
||||
|
||||
interface StocksReportOfficesResponse {
|
||||
data: {
|
||||
regions: Array<{
|
||||
regionName: string
|
||||
metrics: {
|
||||
stockCount?: number
|
||||
stockSum?: number
|
||||
saleRate?: {
|
||||
days: number
|
||||
hours: number
|
||||
}
|
||||
toClientCount?: number
|
||||
fromClientCount?: number
|
||||
}
|
||||
offices: Array<{
|
||||
officeID: number
|
||||
officeName: string
|
||||
metrics: {
|
||||
stockCount: number
|
||||
stockSum: number
|
||||
saleRate: {
|
||||
days: number
|
||||
hours: number
|
||||
}
|
||||
toClientCount: number
|
||||
fromClientCount: number
|
||||
}
|
||||
}>
|
||||
}>
|
||||
}
|
||||
}
|
||||
|
||||
interface WildberriesCard {
|
||||
nmID: number
|
||||
imtID?: number
|
||||
@ -266,10 +346,15 @@ class WildberriesService {
|
||||
}
|
||||
|
||||
private async makeRequest<T>(url: string, options: RequestInit = {}): Promise<T> {
|
||||
// Определяем правильный заголовок авторизации в зависимости от API
|
||||
const authHeader = url.includes('marketplace-api.wildberries.ru') || url.includes('content-api.wildberries.ru')
|
||||
? { 'Authorization': `Bearer ${this.apiKey}` } // Marketplace и Content API используют Bearer
|
||||
: { 'Authorization': this.apiKey } // Statistics и Advert API используют прямой токен
|
||||
|
||||
const response = await fetch(url, {
|
||||
...options,
|
||||
headers: {
|
||||
'Authorization': this.apiKey,
|
||||
...authHeader,
|
||||
'Content-Type': 'application/json',
|
||||
...options.headers,
|
||||
},
|
||||
@ -393,12 +478,35 @@ class WildberriesService {
|
||||
}
|
||||
}
|
||||
|
||||
// Получение списка складов
|
||||
async getWarehouses(): Promise<WildberriesWarehouse[]> {
|
||||
const url = `${this.baseURL}/api/v2/warehouses`
|
||||
console.log(`WB API: Getting warehouses from ${url}`)
|
||||
const response = await this.makeRequest<WildberriesWarehouse[]>(url)
|
||||
return response || []
|
||||
// Получение списка складов
|
||||
async getWarehouses(): Promise<Array<{ id: number; name: string; cargoType: number; deliveryType: number }>> {
|
||||
try {
|
||||
// Используем правильный API endpoint для получения складов продавца
|
||||
const url = `https://marketplace-api.wildberries.ru/api/v3/warehouses`
|
||||
console.log(`WB API: Getting seller warehouses from ${url}`)
|
||||
|
||||
const response = await this.makeRequest<Array<{
|
||||
id: number
|
||||
name: string
|
||||
officeId?: number
|
||||
cargoType?: number
|
||||
deliveryType?: number
|
||||
}>>(url)
|
||||
|
||||
console.log(`WB API: Got ${response.length} warehouses`)
|
||||
return response.map(w => ({
|
||||
id: w.id,
|
||||
name: w.name,
|
||||
cargoType: w.cargoType || 1,
|
||||
deliveryType: w.deliveryType || 1
|
||||
}))
|
||||
|
||||
} catch (error) {
|
||||
console.error(`WB API: Error getting warehouses:`, error)
|
||||
// При ошибке возвращаем пустой массив вместо статических данных
|
||||
console.log(`WB API: Returning empty warehouses array due to API error`)
|
||||
return []
|
||||
}
|
||||
}
|
||||
|
||||
// Получение карточек товаров
|
||||
@ -444,15 +552,30 @@ class WildberriesService {
|
||||
// Создаем массив URL изображений для совместимости с mediaFiles
|
||||
const mediaFiles: string[] = []
|
||||
|
||||
console.log(`WB API: Processing card ${card.nmID}, photos:`, card.photos)
|
||||
|
||||
if (card.photos && card.photos.length > 0) {
|
||||
card.photos.forEach(photo => {
|
||||
// Добавляем разные размеры изображений, приоритет большим размерам
|
||||
if (photo.big) mediaFiles.push(photo.big)
|
||||
if (photo.c516x688) mediaFiles.push(photo.c516x688)
|
||||
if (photo.c246x328) mediaFiles.push(photo.c246x328)
|
||||
card.photos.forEach((photo, index) => {
|
||||
// Для каждого фото берем лучший доступный размер
|
||||
const bestImage = photo.c516x688 || photo.big || photo.c246x328 || photo.square || photo.tm
|
||||
if (bestImage) {
|
||||
mediaFiles.push(bestImage)
|
||||
console.log(`WB API: Added image ${index + 1} for card ${card.nmID}:`, bestImage)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// Если нет photos, пытаемся сгенерировать fallback изображения
|
||||
if (mediaFiles.length === 0) {
|
||||
const vol = Math.floor(card.nmID / 100000)
|
||||
const part = Math.floor(card.nmID / 1000)
|
||||
const fallbackUrl = `https://basket-${String(vol).padStart(2, '0')}.wbbasket.ru/vol${vol}/part${part}/${card.nmID}/images/c246x328/1.webp`
|
||||
mediaFiles.push(fallbackUrl)
|
||||
console.log(`WB API: Added fallback image for card ${card.nmID}:`, fallbackUrl)
|
||||
}
|
||||
|
||||
console.log(`WB API: Final mediaFiles for card ${card.nmID}:`, mediaFiles)
|
||||
|
||||
// Заполняем размеры с ценами и количеством для совместимости
|
||||
const processedSizes = card.sizes.map(size => ({
|
||||
...size,
|
||||
@ -775,8 +898,14 @@ class WildberriesService {
|
||||
return this.formatDate(date)
|
||||
}
|
||||
|
||||
// Статический метод для получения остатков с токеном
|
||||
static async getStocks(apiKey: string): Promise<unknown[]> {
|
||||
const service = new WildberriesService(apiKey)
|
||||
return service.getStocks()
|
||||
}
|
||||
|
||||
// Статический метод для получения складов с токеном
|
||||
static async getWarehouses(apiKey: string): Promise<WildberriesWarehouse[]> {
|
||||
static async getWarehouses(apiKey: string): Promise<Array<{ id: number; name: string; cargoType: number; deliveryType: number }>> {
|
||||
const service = new WildberriesService(apiKey)
|
||||
return service.getWarehouses()
|
||||
}
|
||||
@ -855,6 +984,367 @@ class WildberriesService {
|
||||
// Fallback на mediaFiles для старых данных
|
||||
return card.mediaFiles || []
|
||||
}
|
||||
|
||||
// Получение остатков товаров на складах
|
||||
async getStocks(): Promise<unknown[]> {
|
||||
try {
|
||||
console.log('WB API: Getting stocks using marketplace API')
|
||||
|
||||
// 1. Сначала получаем список складов продавца
|
||||
const warehouses = await this.getWarehouses()
|
||||
console.log(`WB API: Got ${warehouses.length} warehouses`)
|
||||
|
||||
if (warehouses.length === 0) {
|
||||
console.log('WB API: No warehouses found')
|
||||
return []
|
||||
}
|
||||
|
||||
// 2. Получаем карточки товаров для получения SKU/баркодов
|
||||
const cardsResponse = await this.getCards({ limit: 100 })
|
||||
const cards = cardsResponse.cards
|
||||
console.log(`WB API: Got ${cards.length} cards`)
|
||||
console.log(`WB API: Sample card photos:`, cards[0]?.photos)
|
||||
|
||||
if (cards.length === 0) {
|
||||
console.log('WB API: No cards found')
|
||||
return []
|
||||
}
|
||||
|
||||
// 3. Собираем все SKU из карточек товаров
|
||||
const allSkus: string[] = []
|
||||
const cardSkuMap = new Map<string, WildberriesCard>()
|
||||
|
||||
cards.forEach(card => {
|
||||
if (card.sizes && card.sizes.length > 0) {
|
||||
card.sizes.forEach(size => {
|
||||
if (size.skus && size.skus.length > 0) {
|
||||
size.skus.forEach(sku => {
|
||||
if (sku) {
|
||||
allSkus.push(sku)
|
||||
cardSkuMap.set(sku, card)
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
console.log(`WB API: Collected ${allSkus.length} SKUs from cards`)
|
||||
|
||||
if (allSkus.length === 0) {
|
||||
console.log('WB API: No SKUs found in cards')
|
||||
return []
|
||||
}
|
||||
|
||||
// 4. Для каждого склада получаем остатки
|
||||
const allStocks: unknown[] = []
|
||||
|
||||
for (const warehouse of warehouses) {
|
||||
try {
|
||||
const stocksUrl = `https://marketplace-api.wildberries.ru/api/v3/stocks/${warehouse.id}`
|
||||
console.log(`WB API: Getting stocks for warehouse ${warehouse.id} (${warehouse.name})`)
|
||||
|
||||
// Разбиваем SKUs на порции по 1000 (лимит API)
|
||||
const chunkSize = 1000
|
||||
for (let i = 0; i < allSkus.length; i += chunkSize) {
|
||||
const skuChunk = allSkus.slice(i, i + chunkSize)
|
||||
|
||||
try {
|
||||
const stocksResponse = await this.makeRequest<{
|
||||
stocks: Array<{
|
||||
sku: string
|
||||
amount: number
|
||||
}>
|
||||
}>(stocksUrl, {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ skus: skuChunk })
|
||||
})
|
||||
|
||||
console.log(`WB API: Got ${stocksResponse.stocks?.length || 0} stock records for warehouse ${warehouse.id}`)
|
||||
|
||||
// Преобразуем данные в нужный формат
|
||||
if (stocksResponse.stocks) {
|
||||
stocksResponse.stocks.forEach(stock => {
|
||||
const card = cardSkuMap.get(stock.sku)
|
||||
if (card) {
|
||||
console.log(`WB API: Creating stock entry for card ${card.nmID}`)
|
||||
console.log(`WB API: Card photos:`, card.photos)
|
||||
console.log(`WB API: Card mediaFiles:`, card.mediaFiles)
|
||||
|
||||
allStocks.push({
|
||||
nmId: card.nmID,
|
||||
vendorCode: card.vendorCode,
|
||||
title: card.title,
|
||||
brand: card.brand,
|
||||
subject: card.object || card.subjectName,
|
||||
subjectName: card.subjectName,
|
||||
category: card.subjectName,
|
||||
description: card.description,
|
||||
warehouseId: warehouse.id,
|
||||
warehouseName: warehouse.name,
|
||||
quantity: stock.amount,
|
||||
quantityFull: stock.amount,
|
||||
inWayToClient: 0, // Эти данные недоступны через marketplace API
|
||||
inWayFromClient: 0,
|
||||
price: 0, // Цены получаются отдельно
|
||||
sku: stock.sku,
|
||||
photos: card.photos || [],
|
||||
mediaFiles: card.mediaFiles || [], // ЗДЕСЬ ДОЛЖНЫ БЫТЬ ОБРАБОТАННЫЕ ИЗОБРАЖЕНИЯ!
|
||||
characteristics: card.characteristics || []
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
} catch (chunkError) {
|
||||
console.error(`WB API: Error getting stocks chunk for warehouse ${warehouse.id}:`, chunkError)
|
||||
}
|
||||
}
|
||||
|
||||
} catch (warehouseError) {
|
||||
console.error(`WB API: Error getting stocks for warehouse ${warehouse.id}:`, warehouseError)
|
||||
}
|
||||
}
|
||||
|
||||
// 5. Добавляем карточки, для которых не найдено остатков (показываем их с нулевыми остатками)
|
||||
const stockedCardIds = new Set(allStocks.map(stock => (stock as Record<string, unknown>).nmId))
|
||||
|
||||
cards.forEach(card => {
|
||||
if (!stockedCardIds.has(card.nmID)) {
|
||||
console.log(`WB API: Adding zero-stock entry for card ${card.nmID}`)
|
||||
console.log(`WB API: Card photos:`, card.photos)
|
||||
console.log(`WB API: Card mediaFiles:`, card.mediaFiles)
|
||||
|
||||
// Для каждого склада создаем запись с нулевыми остатками
|
||||
warehouses.forEach(warehouse => {
|
||||
allStocks.push({
|
||||
nmId: card.nmID,
|
||||
vendorCode: card.vendorCode,
|
||||
title: card.title,
|
||||
brand: card.brand,
|
||||
subject: card.object || card.subjectName,
|
||||
subjectName: card.subjectName,
|
||||
category: card.subjectName,
|
||||
description: card.description,
|
||||
warehouseId: warehouse.id,
|
||||
warehouseName: warehouse.name,
|
||||
quantity: 0,
|
||||
quantityFull: 0,
|
||||
inWayToClient: 0,
|
||||
inWayFromClient: 0,
|
||||
price: 0,
|
||||
sku: '',
|
||||
photos: card.photos || [],
|
||||
mediaFiles: card.mediaFiles || [], // ВАЖНО: ОБРАБОТАННЫЕ ИЗОБРАЖЕНИЯ!
|
||||
characteristics: card.characteristics || []
|
||||
})
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
console.log(`WB API: Total collected ${allStocks.length} stock records (including zero stocks)`)
|
||||
return allStocks
|
||||
|
||||
} catch (error) {
|
||||
console.error(`WB API: Error getting stocks:`, error)
|
||||
console.log('WB API: Returning empty stocks array due to API error')
|
||||
return []
|
||||
}
|
||||
}
|
||||
|
||||
// Метод для получения даты N дней назад
|
||||
private getDateDaysAgo(days: number): string {
|
||||
const date = new Date()
|
||||
date.setDate(date.getDate() - days)
|
||||
return date.toISOString().split('T')[0]
|
||||
}
|
||||
|
||||
// Новый метод для получения данных по складам через Analytics API
|
||||
async getStocksReportByOffices(params: {
|
||||
nmIds?: number[]
|
||||
subjectIds?: number[]
|
||||
brandNames?: string[]
|
||||
tagIds?: number[]
|
||||
dateFrom?: string
|
||||
dateTo?: string
|
||||
stockType?: '' | 'wb' | 'mp'
|
||||
} = {}): Promise<WBStock[]> {
|
||||
try {
|
||||
console.log('WB Analytics API: Getting stocks report by offices...')
|
||||
|
||||
const today = new Date().toISOString().split('T')[0]
|
||||
const dateFrom = params.dateFrom || today
|
||||
const dateTo = params.dateTo || today
|
||||
|
||||
const requestBody: StocksReportOfficesRequest = {
|
||||
nmIDs: params.nmIds,
|
||||
subjectIDs: params.subjectIds,
|
||||
brandNames: params.brandNames,
|
||||
tagIDs: params.tagIds,
|
||||
currentPeriod: {
|
||||
start: dateFrom,
|
||||
end: dateTo
|
||||
},
|
||||
stockType: params.stockType || '', // все склады
|
||||
skipDeletedNm: true
|
||||
}
|
||||
|
||||
console.log('WB Analytics API: Request parameters:')
|
||||
console.log('- nmIDs:', params.nmIds)
|
||||
console.log('- subjectIDs:', params.subjectIds)
|
||||
console.log('- brandNames:', params.brandNames)
|
||||
console.log('- tagIDs:', params.tagIds)
|
||||
console.log('- currentPeriod:', { start: dateFrom, end: dateTo })
|
||||
console.log('- stockType:', params.stockType || 'all')
|
||||
console.log('- skipDeletedNm:', true)
|
||||
|
||||
console.log('WB Analytics API: Request body:', JSON.stringify(requestBody, null, 2))
|
||||
|
||||
// Используем Analytics API
|
||||
const analyticsURL = 'https://seller-analytics-api.wildberries.ru'
|
||||
const url = `${analyticsURL}/api/v2/stocks-report/offices`
|
||||
|
||||
const response = await this.makeRequest<StocksReportOfficesResponse>(url, {
|
||||
method: 'POST',
|
||||
body: JSON.stringify(requestBody)
|
||||
})
|
||||
|
||||
console.log('WB Analytics API: Response:', JSON.stringify(response, null, 2))
|
||||
|
||||
console.log('WB Analytics API: Processing response data...')
|
||||
|
||||
// Преобразуем данные Analytics API в формат WBStock
|
||||
const stocks: WBStock[] = []
|
||||
|
||||
if (response.data?.regions) {
|
||||
console.log(`WB Analytics API: Found ${response.data.regions.length} regions`)
|
||||
|
||||
// Получаем карточки товаров и остатки для сопоставления
|
||||
console.log('WB Analytics API: Loading cards and current stocks for matching...')
|
||||
const [cards, currentStocks] = await Promise.all([
|
||||
WildberriesService.getAllCards(this.apiKey).catch(() => []),
|
||||
this.getStocks().catch(() => [])
|
||||
])
|
||||
|
||||
console.log(`WB Analytics API: Loaded ${cards.length} cards and ${currentStocks.length} stock records`)
|
||||
|
||||
const cardsMap = new Map(cards.map((card: WildberriesCard) => [card.nmID, card]))
|
||||
|
||||
// Создаем карту остатков по складам из текущих данных
|
||||
const stocksByWarehouse = new Map<number, Record<string, unknown>[]>()
|
||||
const typedCurrentStocks = currentStocks as Record<string, unknown>[]
|
||||
typedCurrentStocks.forEach((stock: Record<string, unknown>) => {
|
||||
const warehouseId = Number(stock.warehouseId || stock.warehouse) || 0
|
||||
if (!stocksByWarehouse.has(warehouseId)) {
|
||||
stocksByWarehouse.set(warehouseId, [])
|
||||
}
|
||||
stocksByWarehouse.get(warehouseId)!.push(stock)
|
||||
})
|
||||
|
||||
response.data.regions.forEach(region => {
|
||||
console.log(`WB Analytics API: Processing region "${region.regionName}" with ${region.offices.length} offices`)
|
||||
|
||||
region.offices.forEach(office => {
|
||||
console.log(`WB Analytics API: Processing office "${office.officeName}" (ID: ${office.officeID})`)
|
||||
console.log(`WB Analytics API: Office metrics:`, office.metrics)
|
||||
|
||||
// Получаем товары для этого склада WB
|
||||
const warehouseStocks = stocksByWarehouse.get(office.officeID) || []
|
||||
console.log(`WB Analytics API: Found ${warehouseStocks.length} stock records for warehouse ${office.officeID}`)
|
||||
|
||||
// Создаем записи для каждого товара на этом складе WB
|
||||
// Если нет конкретных остатков, создаем на основе карточек товаров
|
||||
if (warehouseStocks.length > 0) {
|
||||
// Группируем по nmId
|
||||
const stocksByNmId = new Map<number, Record<string, unknown>[]>()
|
||||
warehouseStocks.forEach((stock: Record<string, unknown>) => {
|
||||
const nmId = Number(stock.nmId) || 0
|
||||
if (nmId > 0) {
|
||||
if (!stocksByNmId.has(nmId)) {
|
||||
stocksByNmId.set(nmId, [])
|
||||
}
|
||||
stocksByNmId.get(nmId)!.push(stock)
|
||||
}
|
||||
})
|
||||
|
||||
// Создаем записи для каждого товара
|
||||
stocksByNmId.forEach((stockItems, nmId) => {
|
||||
const firstStock = stockItems[0]
|
||||
const card = cardsMap.get(nmId)
|
||||
|
||||
const stock: WBStock = {
|
||||
nmId,
|
||||
vendorCode: String(firstStock.vendorCode || firstStock.supplierArticle || ''),
|
||||
title: String(firstStock.title || firstStock.subject || card?.title || `Товар ${nmId}`),
|
||||
brand: String(firstStock.brand || card?.brand || ''),
|
||||
price: Number(firstStock.price || firstStock.Price) || 0,
|
||||
stocks: [{
|
||||
warehouseId: office.officeID,
|
||||
warehouseName: office.officeName,
|
||||
quantity: Number(firstStock.quantity) || 0,
|
||||
quantityFull: Number(firstStock.quantityFull) || 0,
|
||||
inWayToClient: office.metrics.toClientCount, // Берем из Analytics API
|
||||
inWayFromClient: office.metrics.fromClientCount // Берем из Analytics API
|
||||
}],
|
||||
totalQuantity: Number(firstStock.quantity) || 0,
|
||||
totalReserved: office.metrics.toClientCount,
|
||||
photos: Array.isArray(firstStock.photos) ? firstStock.photos : (card?.photos || []),
|
||||
mediaFiles: Array.isArray(firstStock.mediaFiles) ? firstStock.mediaFiles : [],
|
||||
characteristics: Array.isArray(firstStock.characteristics) ? firstStock.characteristics : (card?.characteristics || []),
|
||||
subjectName: String(firstStock.subjectName || firstStock.subject || card?.subjectName || ''),
|
||||
description: String(firstStock.description || card?.description || '')
|
||||
}
|
||||
|
||||
stocks.push(stock)
|
||||
})
|
||||
} else {
|
||||
console.log(`WB Analytics API: No stock records found for warehouse ${office.officeID}, creating entries for each product`)
|
||||
|
||||
// Создаем записи для каждого товара на этом складе WB
|
||||
// Даже если нет точных остатков, показываем движение товаров
|
||||
cardsMap.forEach((card, nmId) => {
|
||||
const stock: WBStock = {
|
||||
nmId,
|
||||
vendorCode: String(card.vendorCode || ''),
|
||||
title: String(card.title || `Товар ${nmId}`),
|
||||
brand: String(card.brand || ''),
|
||||
price: 0, // У карточки нет цены, используем 0
|
||||
stocks: [{
|
||||
warehouseId: office.officeID,
|
||||
warehouseName: office.officeName,
|
||||
quantity: office.metrics.stockCount, // Общее количество на складе
|
||||
quantityFull: office.metrics.stockCount,
|
||||
inWayToClient: office.metrics.toClientCount, // К клиенту
|
||||
inWayFromClient: office.metrics.fromClientCount // От клиента
|
||||
}],
|
||||
totalQuantity: office.metrics.stockCount,
|
||||
totalReserved: office.metrics.toClientCount,
|
||||
photos: Array.isArray(card.photos) ? card.photos : [],
|
||||
mediaFiles: Array.isArray(card.mediaFiles) ? card.mediaFiles : [],
|
||||
characteristics: Array.isArray(card.characteristics) ? card.characteristics : [],
|
||||
subjectName: String(card.subjectName || region.regionName),
|
||||
description: String(card.description || `Регион: ${region.regionName}, Склад: ${office.officeName}`)
|
||||
}
|
||||
|
||||
stocks.push(stock)
|
||||
})
|
||||
}
|
||||
})
|
||||
})
|
||||
} else {
|
||||
console.log('WB Analytics API: No regions data in response')
|
||||
}
|
||||
|
||||
console.log(`WB Analytics API: Processed ${stocks.length} stock records`)
|
||||
return stocks
|
||||
|
||||
} catch (error) {
|
||||
console.error('WB Analytics API: Error getting stocks report:', error)
|
||||
return []
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
export { WildberriesService }
|
Reference in New Issue
Block a user