239 lines
9.3 KiB
TypeScript
239 lines
9.3 KiB
TypeScript
|
|
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();
|
|||
|
|
});
|