193 lines
5.1 KiB
JavaScript
193 lines
5.1 KiB
JavaScript
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 =
|
|
/<a[^>]*class="[^"]*product-card[^"]*"[^>]*href="([^"]+)"[^>]*>[\s\S]*?<div class="product-card__title">([\s\S]*?)<\/div>\s*<div class="product-card__type">([\s\S]*?)<\/div>/g;
|
|
|
|
let match;
|
|
while ((match = cardRegex.exec(html)) !== null) {
|
|
const href = match[1];
|
|
const title = normalizeText(match[2]);
|
|
const type = normalizeText(match[3]);
|
|
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();
|