import 'dotenv/config'; import { prisma } from '../src/prisma-client.js'; const managerEmail = 'manager@fregat.local'; const clientEmail = 'client@fregat.local'; const PRODUCT_TYPES = { STANDARD: 'стандартная лента', PAINTING: 'малярный скотч', }; const PRODUCT_ROWS = [ { sku: '480200', productType: PRODUCT_TYPES.STANDARD, widthMm: 48, lengthM: 40, thicknessMicron: 38, sleeveBrand: 'фрегат', quantityPerBox: '72' }, { sku: '481200', productType: PRODUCT_TYPES.STANDARD, widthMm: 48, lengthM: 55, thicknessMicron: 38, sleeveBrand: 'фрегат', quantityPerBox: '72/36' }, { sku: '482200', productType: PRODUCT_TYPES.STANDARD, widthMm: 48, lengthM: 66, thicknessMicron: 38, sleeveBrand: 'фрегат', quantityPerBox: '36' }, { sku: '483200', productType: PRODUCT_TYPES.STANDARD, widthMm: 48, lengthM: 120, thicknessMicron: 38, sleeveBrand: 'фрегат', quantityPerBox: '36' }, { sku: '751200', productType: PRODUCT_TYPES.STANDARD, widthMm: 75, lengthM: 55, thicknessMicron: 38, sleeveBrand: 'фрегат', quantityPerBox: '48' }, { sku: '752200', productType: PRODUCT_TYPES.STANDARD, widthMm: 75, lengthM: 66, thicknessMicron: 38, sleeveBrand: 'фрегат', quantityPerBox: '24' }, { sku: '753200', productType: PRODUCT_TYPES.STANDARD, widthMm: 75, lengthM: 120, thicknessMicron: 38, sleeveBrand: 'фрегат', quantityPerBox: '24' }, { sku: '481400', productType: PRODUCT_TYPES.STANDARD, widthMm: 48, lengthM: 55, thicknessMicron: 43, sleeveBrand: 'фрегат', quantityPerBox: '72/36' }, { sku: '482400', productType: PRODUCT_TYPES.STANDARD, widthMm: 48, lengthM: 66, thicknessMicron: 43, sleeveBrand: 'фрегат', quantityPerBox: '36' }, { sku: '483400', productType: PRODUCT_TYPES.STANDARD, widthMm: 48, lengthM: 120, thicknessMicron: 43, sleeveBrand: 'фрегат', quantityPerBox: '36' }, { sku: '751400', productType: PRODUCT_TYPES.STANDARD, widthMm: 75, lengthM: 55, thicknessMicron: 43, sleeveBrand: 'фрегат', quantityPerBox: '48' }, { sku: '752400', productType: PRODUCT_TYPES.STANDARD, widthMm: 75, lengthM: 66, thicknessMicron: 43, sleeveBrand: 'фрегат', quantityPerBox: '24' }, { sku: '753400', productType: PRODUCT_TYPES.STANDARD, widthMm: 75, lengthM: 120, thicknessMicron: 43, sleeveBrand: 'фрегат', quantityPerBox: '24' }, { sku: '481500', productType: PRODUCT_TYPES.STANDARD, widthMm: 48, lengthM: 55, thicknessMicron: 45, sleeveBrand: 'фрегат', quantityPerBox: '72/36' }, { sku: '482500', productType: PRODUCT_TYPES.STANDARD, widthMm: 48, lengthM: 66, thicknessMicron: 45, sleeveBrand: 'фрегат', quantityPerBox: '36' }, { sku: '483500', productType: PRODUCT_TYPES.STANDARD, widthMm: 48, lengthM: 120, thicknessMicron: 45, sleeveBrand: 'фрегат', quantityPerBox: '36' }, { sku: '487500', productType: PRODUCT_TYPES.STANDARD, widthMm: 48, lengthM: 150, thicknessMicron: 45, sleeveBrand: 'фрегат', quantityPerBox: '36' }, { sku: '751500', productType: PRODUCT_TYPES.STANDARD, widthMm: 75, lengthM: 55, thicknessMicron: 45, sleeveBrand: 'фрегат', quantityPerBox: '48' }, { sku: '752500', productType: PRODUCT_TYPES.STANDARD, widthMm: 75, lengthM: 66, thicknessMicron: 45, sleeveBrand: 'фрегат', quantityPerBox: '24' }, { sku: '743500', productType: PRODUCT_TYPES.STANDARD, widthMm: 75, lengthM: 120, thicknessMicron: 45, sleeveBrand: 'фрегат', quantityPerBox: '24' }, { sku: '482600', productType: PRODUCT_TYPES.STANDARD, widthMm: 48, lengthM: 66, thicknessMicron: 47, sleeveBrand: 'фрегат', quantityPerBox: '36' }, { sku: '483600', productType: PRODUCT_TYPES.STANDARD, widthMm: 48, lengthM: 120, thicknessMicron: 47, sleeveBrand: 'фрегат', quantityPerBox: '36' }, { sku: '752600', productType: PRODUCT_TYPES.STANDARD, widthMm: 75, lengthM: 66, thicknessMicron: 47, sleeveBrand: 'фрегат', quantityPerBox: '24' }, { sku: '753600', productType: PRODUCT_TYPES.STANDARD, widthMm: 75, lengthM: 120, thicknessMicron: 47, sleeveBrand: 'фрегат', quantityPerBox: '24' }, ]; function assertUniqueProductRows(rows) { const seen = new Map(); for (const row of rows) { const signature = [ row.productType, row.widthMm, row.lengthM, row.thicknessMicron, row.sleeveBrand, ].join('|'); const duplicate = seen.get(signature); if (duplicate) { throw new Error( `Duplicate product signature detected for ${row.sku} and ${duplicate.sku}: ${signature}`, ); } seen.set(signature, row); } } function sentenceCase(value) { if (!value) { return value; } return value[0].toUpperCase() + value.slice(1); } function buildName(product) { return [ sentenceCase(product.productType), `${product.widthMm}x${product.lengthM} м`, `${product.thicknessMicron} мкм`, `втулка ${sentenceCase(product.sleeveBrand)}`, `короб ${product.quantityPerBox}`, ].join(', '); } function baseQuantity(quantityPerBox) { const firstValue = quantityPerBox.split('/')[0]; const parsed = Number.parseInt(firstValue, 10); return Number.isFinite(parsed) && parsed > 0 ? parsed : 24; } 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, bonusProgramEnabled: true, }, create: { email: clientEmail, fullName: 'Demo Client', role: 'CLIENT', bonusProgramEnabled: true, 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 activeSkus = PRODUCT_ROWS.map((item) => item.sku); assertUniqueProductRows(PRODUCT_ROWS); await prisma.product.updateMany({ where: { sku: { notIn: activeSkus } }, data: { isActive: false }, }); for (const product of PRODUCT_ROWS) { const qtyBase = baseQuantity(product.quantityPerBox); const qtyMain = qtyBase * 10; const qtyReserve = qtyBase * 5; const dbProduct = await prisma.product.upsert({ where: { sku: product.sku }, update: { name: buildName(product), description: `Артикул: ${product.sku}`, productType: product.productType, widthMm: product.widthMm, lengthM: product.lengthM, thicknessMicron: product.thicknessMicron, sleeveBrand: product.sleeveBrand, quantityPerBox: product.quantityPerBox, isCustomizable: false, isActive: true, }, create: { sku: product.sku, name: buildName(product), description: `Артикул: ${product.sku}`, productType: product.productType, widthMm: product.widthMm, lengthM: product.lengthM, thicknessMicron: product.thicknessMicron, sleeveBrand: product.sleeveBrand, quantityPerBox: product.quantityPerBox, isCustomizable: false, isActive: true, }, }); await prisma.productStock.upsert({ where: { productId_warehouseId: { productId: dbProduct.id, warehouseId: warehouseMain.id, }, }, update: { availableQty: qtyMain }, create: { productId: dbProduct.id, warehouseId: warehouseMain.id, availableQty: qtyMain, }, }); await prisma.productStock.upsert({ where: { productId_warehouseId: { productId: dbProduct.id, warehouseId: warehouseReserve.id, }, }, update: { availableQty: qtyReserve }, create: { productId: dbProduct.id, warehouseId: warehouseReserve.id, availableQty: qtyReserve, }, }); } const client = await prisma.user.findUnique({ where: { email: clientEmail }, }); if (!client) { throw new Error('Demo client was not created.'); } const seededProducts = await prisma.product.findMany({ where: { sku: { in: ['480200', '482500', '753400', '752600'], }, }, orderBy: { sku: 'asc' }, }); const existingOrderCodes = new Set( (await prisma.order.findMany({ where: { code: { in: ['FRG-1001', 'FRG-1002', 'FRG-1003'], }, }, select: { code: true }, })).map((order) => order.code), ); const demoOrders = [ { code: 'FRG-1001', status: 'WAITING_DOUBLE_CONFIRM', deliveryAddress: 'Москва, Ленинградский проспект, 37', deliveryTerms: 'Самовывоз со склада после подтверждения', totalPrice: '125000.00', items: [ { sku: '480200', quantity: '24.000' }, { sku: '752600', quantity: '12.000' }, ], }, { code: 'FRG-1002', status: 'IN_PROGRESS', deliveryAddress: 'Санкт-Петербург, Кубинская улица, 75к1', deliveryTerms: 'Доставка транспортной компанией', totalPrice: '84200.00', items: [ { sku: '482500', quantity: '18.000' }, ], }, { code: 'FRG-1003', status: 'COMPLETED', deliveryAddress: 'Казань, улица Родины, 43', deliveryTerms: 'Доставка до адреса клиента', totalPrice: '156400.00', items: [ { sku: '753400', quantity: '30.000' }, { sku: '482500', quantity: '10.000' }, ], }, ]; for (const demoOrder of demoOrders) { if (existingOrderCodes.has(demoOrder.code)) { continue; } const order = await prisma.order.create({ data: { code: demoOrder.code, kind: 'READY', status: demoOrder.status, customerId: client.id, managerId: manager.id, deliveryAddress: demoOrder.deliveryAddress, deliveryTerms: demoOrder.deliveryTerms, totalPrice: demoOrder.totalPrice, }, }); for (const item of demoOrder.items) { const product = seededProducts.find((entry) => entry.sku === item.sku); if (!product) { throw new Error(`Product ${item.sku} not found for demo order ${demoOrder.code}.`); } await prisma.orderItem.create({ data: { orderId: order.id, productId: product.id, productName: product.name, quantity: item.quantity, }, }); } await prisma.orderStatusEvent.create({ data: { orderId: order.id, status: demoOrder.status, actorUserId: manager.id, note: 'Демо-заказ для отображения клиентского кабинета.', }, }); } console.log(`Seed complete with ${PRODUCT_ROWS.length} products. Use manager header x-user-id: ${manager.id}`); await prisma.$disconnect();