import 'dotenv/config'; import { prisma } from '../src/prisma-client.js'; const CATALOG_PAGES = ['https://fregat.org/catalog/', 'https://fregat.org/catalog/page/2/']; const managerEmail = 'manager@fregat.local'; const clientEmail = 'client@fregat.local'; function decodeHtmlEntities(value) { return value .replaceAll(' ', ' ') .replaceAll('&', '&') .replaceAll('"', '"') .replaceAll(''', "'") .replaceAll('«', '«') .replaceAll('»', '»') .replaceAll('—', '—') .replaceAll('–', '-'); } function normalizeText(value) { return decodeHtmlEntities(value.replaceAll(/<[^>]*>/g, ' ').replaceAll(/\s+/g, ' ')).trim(); } function skuFromHref(href, index) { const pathname = href.replace(/^https?:\/\/[^/]+/i, '').split('?')[0] || ''; const segments = pathname.split('/').filter(Boolean); const slug = segments[segments.length - 1] ?? ''; if (!slug) { return `FREGAT-CATALOG-${String(index + 1).padStart(3, '0')}`; } const normalized = slug.toUpperCase().replaceAll(/[^A-Z0-9]+/g, '-').replace(/^-+|-+$/g, ''); return `FREGAT-${normalized || String(index + 1).padStart(3, '0')}`; } function parseCatalogCards(html) { const cards = []; const cardRegex = /]*)class="[^"]*product-card[^"]*"([^>]*)>([\s\S]*?)<\/a>/g; let match; while ((match = cardRegex.exec(html)) !== null) { const attrs = `${match[1]} ${match[2]}`; const body = match[3]; const hrefMatch = attrs.match(/href="([^"]+)"/); const titleMatch = body.match(/
([\s\S]*?)<\/div>/); const typeMatch = body.match(/
([\s\S]*?)<\/div>/); const href = hrefMatch?.[1] ?? ''; const title = normalizeText(titleMatch?.[1] ?? ''); const type = normalizeText(typeMatch?.[1] ?? ''); if (!title) { continue; } cards.push({ href, title, type }); } return cards; } async function loadCatalogProducts() { const parsed = []; for (const pageUrl of CATALOG_PAGES) { const response = await fetch(pageUrl, { redirect: 'follow' }); if (!response.ok) { throw new Error(`Catalog request failed: ${pageUrl} (${response.status})`); } const html = await response.text(); const cards = parseCatalogCards(html); if (!cards.length) { throw new Error(`No product cards found at ${pageUrl}`); } parsed.push(...cards); } const deduped = new Map(); for (const [index, card] of parsed.entries()) { const sku = skuFromHref(card.href, index); if (deduped.has(sku)) { continue; } const descriptionParts = []; if (card.type) { descriptionParts.push(card.type); } descriptionParts.push(`Источник: ${card.href}`); deduped.set(sku, { sku, name: card.title, description: descriptionParts.join('. '), isCustomizable: /логотип|печать/i.test(`${card.title} ${card.type}`), qtyMain: 300 + index * 17, qtyReserve: 120 + index * 9, }); } return [...deduped.values()]; } const company = await prisma.company.upsert({ where: { inn: '7701000000' }, update: {}, create: { name: 'Fregat Client LLC', inn: '7701000000', }, }); const manager = await prisma.user.upsert({ where: { email: managerEmail }, update: { fullName: 'Default Manager' }, create: { email: managerEmail, fullName: 'Default Manager', role: 'MANAGER', }, }); await prisma.user.upsert({ where: { email: clientEmail }, update: { fullName: 'Demo Client', companyId: company.id }, create: { email: clientEmail, fullName: 'Demo Client', role: 'CLIENT', companyId: company.id, }, }); const warehouseMain = await prisma.warehouse.upsert({ where: { code: 'MSK-01' }, update: { name: 'Main warehouse' }, create: { code: 'MSK-01', name: 'Main warehouse' }, }); const warehouseReserve = await prisma.warehouse.upsert({ where: { code: 'SPB-01' }, update: { name: 'Reserve warehouse' }, create: { code: 'SPB-01', name: 'Reserve warehouse' }, }); const products = await loadCatalogProducts(); console.log(`Loaded ${products.length} products from fregat.org catalog.`); for (const product of products) { const dbProduct = await prisma.product.upsert({ where: { sku: product.sku }, update: { name: product.name, description: product.description, isCustomizable: product.isCustomizable, isActive: true, }, create: { sku: product.sku, name: product.name, description: product.description, isCustomizable: product.isCustomizable, isActive: true, }, }); await prisma.productStock.upsert({ where: { productId_warehouseId: { productId: dbProduct.id, warehouseId: warehouseMain.id, }, }, update: { availableQty: product.qtyMain }, create: { productId: dbProduct.id, warehouseId: warehouseMain.id, availableQty: product.qtyMain, }, }); await prisma.productStock.upsert({ where: { productId_warehouseId: { productId: dbProduct.id, warehouseId: warehouseReserve.id, }, }, update: { availableQty: product.qtyReserve }, create: { productId: dbProduct.id, warehouseId: warehouseReserve.id, availableQty: product.qtyReserve, }, }); } console.log('Seed complete. Use manager header x-user-id:', manager.id); await prisma.$disconnect();