import { ProductItem, ProductDetailsResponse, ObjectInfo } from '../../scrapers/api/magnit/types.js'; import { CreateProductData } from '../product/ProductService.js'; export class ProductParser { /** * Конвертация цены из копеек в рубли */ private static priceFromKopecks(kopecks: number): number { return kopecks / 100; } /** * Парсинг даты из строки */ private static parseDate(dateString?: string): Date | undefined { if (!dateString) return undefined; try { return new Date(dateString); } catch { return undefined; } } /** * Преобразование массива бейджей в JSON строку */ private static badgesToJson(badges: Array<{ text: string; backgroundColor: string }>): string | undefined { if (!badges || badges.length === 0) return undefined; return JSON.stringify(badges); } /** * Преобразование ProductItem из API в CreateProductData для БД */ static parseProductItem( item: ProductItem, storeId: number, categoryId?: number ): CreateProductData { return { externalId: item.productId, storeId, categoryId, name: item.name, description: item.description, url: item.url, imageUrl: item.gallery && item.gallery.length > 0 ? item.gallery[0].url : undefined, currentPrice: this.priceFromKopecks(item.price), unit: item.unit, weight: item.weight, brand: item.brand, oldPrice: item.promotion?.oldPrice ? this.priceFromKopecks(item.promotion.oldPrice) : undefined, discountPercent: item.promotion?.discountPercent ? item.promotion.discountPercent : undefined, promotionEndDate: this.parseDate(item.promotion?.endDate), rating: item.ratings?.rating, scoresCount: item.ratings?.scoresCount, commentsCount: item.ratings?.commentsCount, quantity: item.quantity, badges: this.badgesToJson(item.badges), }; } /** * Парсинг массива товаров */ static parseProductItems( items: ProductItem[], storeId: number, categoryMap: Map // Map ): CreateProductData[] { return items.map(item => { const categoryId = item.category?.id ? categoryMap.get(item.category.id) : undefined; return this.parseProductItem(item, storeId, categoryId); }); } /** * Парсинг деталей товара из ProductDetailsResponse * Извлекает бренд, описание, вес, единицу измерения из массива details */ static parseProductDetails(detailsResponse: ProductDetailsResponse): { brand?: string; description?: string; weight?: string; unit?: string; categoryId?: number; } { const result: { brand?: string; description?: string; weight?: string; unit?: string; categoryId?: number; } = {}; // Получаем первую категорию из массива if (detailsResponse.categories && detailsResponse.categories.length > 0) { result.categoryId = detailsResponse.categories[0]; } // Парсим массив деталей для извлечения полей for (const detail of detailsResponse.details) { const name = detail.name; const nameLower = detail.name.toLowerCase(); // Бренд - проверяем и русское и английское название if (name === 'Бренд' || nameLower === 'brand') { // Игнорируем "Различные бренды" if (detail.value && !detail.value.includes('Различные бренды')) { result.brand = detail.value; } } // Описание товара else if (name === 'Описание товара' || nameLower.includes('описание')) { if (detail.value) { result.description = detail.value; } } // Вес - может быть на русском else if (nameLower.includes('вес') || nameLower === 'weight') { if (detail.value) { result.weight = detail.value; } } // Единица измерения - может быть на русском else if (name === 'Единица измерения' || nameLower.includes('единица') || nameLower === 'unit') { if (detail.value) { result.unit = detail.value; } } } return result; } /** * Парсинг ObjectInfo для получения рейтингов и описания */ static parseObjectInfo(objectInfo: ObjectInfo): { description?: string; rating?: number; scoresCount?: number; commentsCount?: number; imageUrl?: string; } { const result: { description?: string; rating?: number; scoresCount?: number; commentsCount?: number; imageUrl?: string; } = {}; // Описание из object_info (если есть) if (objectInfo.description) { result.description = objectInfo.description; } // Рейтинг if (objectInfo.average_rating !== undefined) { result.rating = objectInfo.average_rating; } // Количество оценок if (objectInfo.count_ratings !== undefined) { result.scoresCount = objectInfo.count_ratings; } // Количество отзывов if (objectInfo.count_reviews !== undefined) { result.commentsCount = objectInfo.count_reviews; } // URL изображения (если есть) if (objectInfo.url) { result.imageUrl = objectInfo.url; } return result; } }