import { PrismaClient, Prisma } from '@prisma/client'; import * as bcrypt from 'bcrypt'; import * as fs from 'fs'; import * as path from 'path'; const prisma = new PrismaClient(); async function main() { console.log('Starting database seed...'); // Clear existing data (order: children first) await prisma.chatMessage.deleteMany(); await prisma.chatSession.deleteMany(); await prisma.estimateShare.deleteMany(); await prisma.estimateTotal.deleteMany(); await prisma.estimateItem.deleteMany(); await prisma.estimate.deleteMany(); await prisma.user.deleteMany(); await prisma.priceItem.deleteMany(); await prisma.priceTable.deleteMany(); await prisma.priceBook.deleteMany(); await prisma.coefficient.deleteMany(); await prisma.inflationIndex.deleteMany(); await prisma.surveyDirection.deleteMany(); await prisma.setting.deleteMany(); console.log('Cleared existing data'); // Admin user (логин: its@info.ru, пароль: Nemo348ax@) const adminPasswordHash = await bcrypt.hash('Nemo348ax@', 10); await prisma.user.create({ data: { email: 'its@info.ru', passwordHash: adminPasswordHash, name: 'Админ', }, }); console.log('Created admin user (its@info.ru / Nemo348ax@)'); // Demo user for development (email: demo@example.com, password: demo) const demoPasswordHash = await bcrypt.hash('demo', 10); await prisma.user.create({ data: { email: 'demo@example.com', passwordHash: demoPasswordHash, name: 'Демо', }, }); console.log('Created demo user (demo@example.com / demo)'); // Seed Survey Directions const directions = await Promise.all([ prisma.surveyDirection.create({ data: { code: 'geodesy', name: 'Инженерно-геодезические изыскания', shortName: 'Геодезия', }, }), prisma.surveyDirection.create({ data: { code: 'geology', name: 'Инженерно-геологические изыскания', shortName: 'Геология', }, }), prisma.surveyDirection.create({ data: { code: 'ecology', name: 'Инженерно-экологические изыскания', shortName: 'Экология', }, }), prisma.surveyDirection.create({ data: { code: 'hydrology', name: 'Инженерно-гидрометеорологические изыскания', shortName: 'Гидрометеорология', }, }), ]); console.log(`Created ${directions.length} survey directions`); // Seed Inflation Indices const inflationIndices = await Promise.all([ prisma.inflationIndex.create({ data: { baseDate: new Date('1991-01-01'), effectiveFrom: new Date('2015-08-13'), indexValue: new Prisma.Decimal(76.24), documentRef: 'Письмо Минстроя и ЖКХ России № 25760-ЮР/08 от 13.08.2015г.', isActive: true, }, }), prisma.inflationIndex.create({ data: { baseDate: new Date('2001-01-01'), effectiveFrom: new Date('2015-08-13'), indexValue: new Prisma.Decimal(6.70), documentRef: 'Письмо Минстроя и ЖКХ России № 25760-ЮР/08 от 13.08.2015г.', isActive: true, }, }), ]); console.log(`Created ${inflationIndices.length} inflation indices`); // Seed Coefficients const coefficients = [ // Regional coefficients { type: 'regional', code: 'reg-1.08', name: 'Районный коэффициент 1.08', value: 1.08, description: 'К заработной плате 1.15' }, { type: 'regional', code: 'reg-1.10', name: 'Районный коэффициент 1.10', value: 1.10, description: 'К заработной плате 1.20' }, { type: 'regional', code: 'reg-1.15', name: 'Районный коэффициент 1.15', value: 1.15, description: 'К заработной плате 1.30' }, // Company coefficients { type: 'company', code: 'gazprom-544', name: 'Коэффициент ОАО «Газпром»', value: 1.00, description: '№544 от 26.12.2013 г.' }, { type: 'company', code: 'geovector', name: 'Коэффициент ООО «ГеоВектор»', value: 0.2092, description: 'Коэффициент компании' }, // Special coefficients { type: 'special', code: 'computer-tech', name: 'Компьютерные технологии', value: 1.20, description: 'При выполнении камеральных работ с применением компьютерных технологий' }, { type: 'special', code: 'night-work', name: 'Ночные работы', value: 1.35, description: 'При работе в ночное время (22:00-06:00)' }, { type: 'special', code: 'special-regime', name: 'Специальный режим', value: 1.25, description: 'Территории со специальным режимом' }, ]; for (const coef of coefficients) { await prisma.coefficient.create({ data: { type: coef.type, code: coef.code, name: coef.name, value: new Prisma.Decimal(coef.value), description: coef.description, }, }); } console.log(`Created ${coefficients.length} coefficients`); // Seed Settings const settings = [ { key: 'default_executor', value: 'ООО "ГеоВектор"', type: 'string', category: 'company', label: 'Исполнитель по умолчанию' }, { key: 'default_vat_rate', value: '20', type: 'number', category: 'company', label: 'Ставка НДС по умолчанию (%)' }, { key: 'company_coefficient', value: '0.2092', type: 'number', category: 'company', label: 'Коэффициент компании' }, { key: 'ai_provider', value: 'iieasy', type: 'string', category: 'ai', label: 'AI провайдер' }, { key: 'iieasy_model', value: 'google/gemma-3n-e4b', type: 'string', category: 'ai', label: 'Модель iieasy' }, { key: 'lmstudio_url', value: 'http://localhost:1234/v1', type: 'string', category: 'ai', label: 'URL LM Studio' }, ]; for (const setting of settings) { await prisma.setting.create({ data: setting }); } console.log(`Created ${settings.length} settings`); // Load and seed price books from JSON files const dataDir = path.join(__dirname, '../../data/price-books'); // Load Geodesy price book const geodesyPath = path.join(dataDir, 'geodesy-2004.json'); if (fs.existsSync(geodesyPath)) { const geodesyData = JSON.parse(fs.readFileSync(geodesyPath, 'utf-8')); await seedPriceBook(geodesyData); console.log('Loaded geodesy-2004 price book'); } // Load Geology price book const geologyPath = path.join(dataDir, 'geology-ecology-1999.json'); if (fs.existsSync(geologyPath)) { const geologyData = JSON.parse(fs.readFileSync(geologyPath, 'utf-8')); await seedPriceBook(geologyData); console.log('Loaded geology-ecology-1999 price book'); } console.log('Database seeding completed!'); } async function seedPriceBook(data: any) { const priceBook = await prisma.priceBook.create({ data: { code: data.priceBook.code, name: data.priceBook.name, baseDate: new Date(data.priceBook.baseDate), approvedBy: data.priceBook.approvedBy, effectiveDate: data.priceBook.effectiveDate ? new Date(data.priceBook.effectiveDate) : null, }, }); for (const table of data.tables) { const priceTable = await prisma.priceTable.create({ data: { priceBookId: priceBook.id, tableNumber: table.tableNumber, name: table.name, unit: table.unit, notes: table.notes || null, }, }); for (const item of table.items) { await prisma.priceItem.create({ data: { priceBookId: priceBook.id, priceTableId: priceTable.id, paragraph: item.paragraph, workType: item.workType || item.networkType || item.type || `Таблица ${table.tableNumber}`, description: item.description || null, priceField1: item.category1Field ?? item.cat1 ?? item.undevelopedField ?? null, priceOffice1: item.category1Office ?? item.undevelopedOffice ?? null, priceField2: item.category2Field ?? item.cat2 ?? item.builtUpField ?? null, priceOffice2: item.category2Office ?? item.builtUpOffice ?? null, priceField3: item.category3Field ?? item.cat3 ?? item.industrialField ?? null, priceOffice3: item.category3Office ?? item.industrialOffice ?? null, priceSimple: item.price ?? item.fieldPrice ?? null, attributes: { scale: item.scale, category: item.category, reliefHeight: item.reliefHeight, depth: item.depth, diameter: item.diameter, accuracy: item.accuracy, passability: item.passability, ...item, }, }, }); } } } main() .catch((e) => { console.error(e); process.exit(1); }) .finally(async () => { await prisma.$disconnect(); });