33800292aa
- apps/api/Dockerfile: build NestJS, run prisma migrate deploy on start - apps/web/Dockerfile + nginx.conf: build Vite, serve static, proxy /api -> api - docker-compose.coolify.yml: full prod stack (postgres, redis, minio, keycloak, api, web) - .dockerignore / .gitignore / .gitattributes Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
663 lines
29 KiB
TypeScript
663 lines
29 KiB
TypeScript
import {
|
|
AnexaType,
|
|
CampaignStatus,
|
|
ContractCategory,
|
|
ContractPeriod,
|
|
ContractType,
|
|
DisciplinarySanctionType,
|
|
DiplomaStatus,
|
|
DocumentType,
|
|
EmployeeStatus,
|
|
EvaluationScore,
|
|
FamilyMemberType,
|
|
InventoryItemType,
|
|
MedicalCheckupType,
|
|
MedicalVerdict,
|
|
OverexposureKind,
|
|
PrismaClient,
|
|
ProposedCategory,
|
|
QualificationCategory,
|
|
RiskExposureType,
|
|
SalaryType,
|
|
ScientificTitle,
|
|
Sex,
|
|
StudyLevel,
|
|
PostUniversityType,
|
|
StudyType,
|
|
TrainingType,
|
|
} from '@prisma/client';
|
|
|
|
const prisma = new PrismaClient();
|
|
|
|
function dbNameFromUrl(url: string): string {
|
|
return decodeURIComponent(new URL(url).pathname.replace(/^\//, ''));
|
|
}
|
|
|
|
function requireTemporaryDatabase() {
|
|
const url = process.env.DATABASE_URL;
|
|
if (!url) throw new Error('DATABASE_URL is required for test seed');
|
|
const dbName = dbNameFromUrl(url);
|
|
if (!dbName.startsWith('hrm_medpark_test_') && process.env.ALLOW_NON_TEST_DB !== 'true') {
|
|
throw new Error(`Refusing to seed non-test database "${dbName}". Expected hrm_medpark_test_*.`);
|
|
}
|
|
return dbName;
|
|
}
|
|
|
|
const d = (value: string) => new Date(`${value}T00:00:00.000Z`);
|
|
|
|
async function resetData() {
|
|
await prisma.auditLog.deleteMany();
|
|
await prisma.anexaTemplateVersion.deleteMany();
|
|
await prisma.anexaTemplate.deleteMany();
|
|
await prisma.radiationOverexposure.deleteMany();
|
|
await prisma.medicalCheckup.deleteMany();
|
|
await prisma.employeeMedicalProfile.deleteMany();
|
|
await prisma.workplaceRiskExposure.deleteMany();
|
|
await prisma.workplaceRiskCard.deleteMany();
|
|
await prisma.evaluationForm.deleteMany();
|
|
await prisma.evaluationCampaign.deleteMany();
|
|
await prisma.cimServiceCategory.deleteMany();
|
|
await prisma.employmentContract.deleteMany();
|
|
await prisma.benefit.deleteMany();
|
|
await prisma.disciplinarySanction.deleteMany();
|
|
await prisma.training.deleteMany();
|
|
await prisma.qualification.deleteMany();
|
|
await prisma.education.deleteMany();
|
|
await prisma.familyMember.deleteMany();
|
|
await prisma.identityDocument.deleteMany();
|
|
await prisma.employee.deleteMany();
|
|
await prisma.inventoryItem.deleteMany();
|
|
await prisma.department.deleteMany();
|
|
await prisma.workSchedule.deleteMany();
|
|
await prisma.taxExemption.deleteMany();
|
|
await prisma.disabilityGrade.deleteMany();
|
|
}
|
|
|
|
async function main() {
|
|
const dbName = requireTemporaryDatabase();
|
|
console.log(`Seeding Medpark test data into ${dbName}...`);
|
|
await resetData();
|
|
|
|
const disability = await prisma.disabilityGrade.create({
|
|
data: { code: 'TEST-GR-I', name: 'Grad dizabilitate I - test' },
|
|
});
|
|
const childTax = await prisma.taxExemption.create({
|
|
data: { code: 'TEST-SCUTIRE-COPIL', description: 'Scutire copil - test' },
|
|
});
|
|
const schedule = await prisma.workSchedule.create({
|
|
data: { name: 'Test 5/2 8h', daysWork: 5, daysRest: 2, hoursPerDay: 8 },
|
|
});
|
|
const shiftSchedule = await prisma.workSchedule.create({
|
|
data: { name: 'Test 12/24', daysWork: 1, daysRest: 1, hoursPerDay: 12 },
|
|
});
|
|
|
|
const root = await prisma.department.create({ data: { name: 'Medpark Test', code: 'TEST_ROOT' } });
|
|
const surgeryDept = await prisma.department.create({
|
|
data: { name: 'Chirurgie Test', code: 'TEST_CHIR', parentId: root.id },
|
|
});
|
|
const radiologyDept = await prisma.department.create({
|
|
data: { name: 'Radiologie Test', code: 'TEST_RAD', parentId: root.id },
|
|
});
|
|
const remoteDept = await prisma.department.create({
|
|
data: { name: 'Administrativ Digital Test', code: 'TEST_REMOTE', parentId: root.id },
|
|
});
|
|
const labDept = await prisma.department.create({
|
|
data: { name: 'Laborator Test', code: 'TEST_LAB', parentId: root.id },
|
|
});
|
|
|
|
const uniform = await prisma.inventoryItem.create({
|
|
data: { sku: 'TEST-UNIFORM-M', name: 'Uniformă test M', type: InventoryItemType.uniforma, size: 'M', color: 'teal', stockQty: 20 },
|
|
});
|
|
const coat = await prisma.inventoryItem.create({
|
|
data: { sku: 'TEST-HALAT-L', name: 'Halat test L', type: InventoryItemType.halat, size: 'L', color: 'alb', stockQty: 20 },
|
|
});
|
|
const shoes = await prisma.inventoryItem.create({
|
|
data: { sku: 'TEST-CIUPICI-40', name: 'Ciupici test 40', type: InventoryItemType.ciupici, size: '40', color: 'alb', stockQty: 20 },
|
|
});
|
|
const phone = await prisma.inventoryItem.create({
|
|
data: { sku: 'TEST-PHONE-A15', name: 'Telefon test Samsung A15', type: InventoryItemType.aparat_telefon, stockQty: 5 },
|
|
});
|
|
|
|
const commonEval = {
|
|
echipa: true,
|
|
oreZi: '8',
|
|
schimburi: '2',
|
|
schimbNoapte: true,
|
|
pauzeOrganizate: true,
|
|
riscInfectare: true,
|
|
riscElectrocutare: true,
|
|
riscTensiuneInalta: false,
|
|
riscInecare: false,
|
|
riscAsfixiere: false,
|
|
riscStrivire: true,
|
|
riscTaiere: true,
|
|
riscIntepare: true,
|
|
riscLovire: true,
|
|
riscMuscatura: false,
|
|
riscMicrotraumatisme: true,
|
|
conduceMasina: true,
|
|
conduceMasinaCategorie: 'B',
|
|
conduceUtilajeIntrauzinal: false,
|
|
spatiuL: '4',
|
|
spatiul: '5',
|
|
spatiuH: '3',
|
|
suprafataVerticala: false,
|
|
suprafataOrizontala: true,
|
|
suprafataOblica: false,
|
|
muncaIzolare: false,
|
|
muncaInaltime: true,
|
|
muncaInMiscare: true,
|
|
pozitieOrtostatica: true,
|
|
pozitieAsezat: false,
|
|
pozitieAplecata: true,
|
|
pozitieMixta: true,
|
|
pozitieFortata: false,
|
|
coloanaCervicala: true,
|
|
coloanaToracala: true,
|
|
coloanaLombara: true,
|
|
manipulareRidicare: true,
|
|
manipulareCoborare: true,
|
|
manipulareImpingere: true,
|
|
manipulareTragere: false,
|
|
manipularePurtare: true,
|
|
manipulareDeplasare: true,
|
|
greutateMaxima: '15 kg',
|
|
suprasolicitariVizuale: true,
|
|
suprasolicitariAuditive: true,
|
|
suprasolicitariNeuropsihice: true,
|
|
microclimatInterior: true,
|
|
microclimatExterior: false,
|
|
radiatiiCaloriceRece: false,
|
|
radiatiiCaloriceCalda: false,
|
|
iluminatSuficient: true,
|
|
iluminatInsuficient: false,
|
|
iluminatNatural: true,
|
|
iluminatArtificial: true,
|
|
iluminatMixt: true,
|
|
};
|
|
|
|
const surgeryCard = await prisma.workplaceRiskCard.create({
|
|
data: {
|
|
name: 'Test - Medic profil chirurgical cu gărzi de noapte',
|
|
riskFactors: { source: 'Control medical (5).docx', categories: ['chimici', 'biologici', 'fizici', 'ergonomici'] },
|
|
filiala: 'Sediul central',
|
|
adresaFiliala: 'str. Nicolae Testemițanu 29, Chișinău',
|
|
telefonFiliala: '+373 22 000 101',
|
|
caemPrimeleDouaCifre: '86',
|
|
cormSubgrupaMajora: 'Personal medical profil chirurgical',
|
|
directiaSectiaSectorul: 'Bloc operator / Chirurgie',
|
|
numarulLoculuiDeMunca: 'TEST-CHIR-01',
|
|
caemDiviziune: '86.10',
|
|
clasaConditiilorDeMunca: '3.2',
|
|
numarLucratoriPosibili: 12,
|
|
tipFisa: 'STANDARD',
|
|
evaluareDetalii: commonEval,
|
|
radiatiiIonizante: false,
|
|
mijloaceProtectieColectiva: 'Ventilație locală, containere pentru obiecte ascuțite',
|
|
mijloaceProtectieIndividuala: 'Mănuși, mască, halat steril, vizieră',
|
|
echipamentLucru: 'Uniformă chirurgicală',
|
|
anexeIgienicoSanitare: { vestiar: true, chiuveta: true, wc: true, dus: true, salaMese: true, recreere: true },
|
|
observatii: 'Set complet pentru testarea Anexa 4.',
|
|
exposures: {
|
|
create: [
|
|
{ tip: RiskExposureType.AGENT_CHIMIC, denumire: 'Glutaraldehidă', cas: '111-30-8', einecs: '203-856-5', timpExpunere: '2 h/zi', vep: '0,03 ppm', vlep: '0,1 ppm', caracteristici: 'iritant respirator' },
|
|
{ tip: RiskExposureType.PULBERI, denumire: 'Pulberi textile sterile', cas: '—', einecs: '—', timpExpunere: '1 h/zi', vep: '2 mg/m3', vlep: '5 mg/m3', caracteristici: 'pulberi inhalabile' },
|
|
{ tip: RiskExposureType.AGENT_BIOLOGIC, denumire: 'HBV/HCV/HIV', clasificare: 'grupa 3', caracteristici: 'risc prin înțepare/tăiere' },
|
|
{ tip: RiskExposureType.ZGOMOT, denumire: 'Echipamente bloc operator', timpExpunere: '4 h/zi', vep: '80 dB', vlep: '87 dB', caracteristici: 'zgomot intermitent' },
|
|
{ tip: RiskExposureType.VIBRATII, denumire: 'Instrumentar oscilant', zonaAfectata: 'mână-braț', timpExpunere: '30 min/zi', vep: '2,5 m/s2', vlep: '5 m/s2', caracteristici: 'vibrații locale' },
|
|
{ tip: RiskExposureType.CAMP_ELECTROMAGNETIC, denumire: 'Electrocauter', zonaAfectata: 'corp întreg', timpExpunere: '1 h/zi', vep: 'conform NU-10', vlep: 'conform NU-10', caracteristici: 'câmp EM local' },
|
|
{ tip: RiskExposureType.RADIATII_OPTICE, denumire: 'Lămpi chirurgicale', zonaAfectata: 'ochi', timpExpunere: '6 h/zi', vep: 'conform NU-10', vlep: 'conform NU-10', caracteristici: 'lumină intensă' },
|
|
],
|
|
},
|
|
},
|
|
});
|
|
|
|
const radiologyCard = await prisma.workplaceRiskCard.create({
|
|
data: {
|
|
name: 'Test - Radiologie cu radiații ionizante',
|
|
riskFactors: { source: 'Control medical (5).docx', categories: ['radiații ionizante', 'câmp electromagnetic'] },
|
|
filiala: 'Sediul central',
|
|
adresaFiliala: 'str. Nicolae Testemițanu 29, Chișinău',
|
|
telefonFiliala: '+373 22 000 102',
|
|
caemPrimeleDouaCifre: '86',
|
|
cormSubgrupaMajora: 'Personal imagistică medicală',
|
|
directiaSectiaSectorul: 'Diagnostic / Radiologie',
|
|
numarulLoculuiDeMunca: 'TEST-RAD-01',
|
|
caemDiviziune: '86.90',
|
|
clasaConditiilorDeMunca: '3.3',
|
|
numarLucratoriPosibili: 8,
|
|
tipFisa: 'STANDARD',
|
|
evaluareDetalii: { ...commonEval, riscInfectare: false, pozitieAsezat: true, pozitieOrtostatica: false },
|
|
radiatiiIonizante: true,
|
|
radiatiiGrupa: 'A',
|
|
radiatiiAparatura: 'CT, Rx digital',
|
|
radiatiiSurse: 'închise',
|
|
radiatiiTipExpunere: 'X externă',
|
|
radiatiiMasuriProtectie: 'Ecran de protecție, șorț plumb, dozimetru individual',
|
|
mijloaceProtectieColectiva: 'Ecrane plumbate și semnalizare zonă controlată',
|
|
mijloaceProtectieIndividuala: 'Șorț plumb, ochelari, dozimetru',
|
|
echipamentLucru: 'Uniformă radiologie',
|
|
anexeIgienicoSanitare: { vestiar: true, chiuveta: true, wc: true, dus: true, salaMese: true, recreere: false },
|
|
exposures: {
|
|
create: [
|
|
{ tip: RiskExposureType.CAMP_ELECTROMAGNETIC, denumire: 'Câmp electromagnetic RMN', zonaAfectata: 'corp întreg', timpExpunere: '4 h/zi', vep: 'conform NU-10', vlep: 'conform NU-10', caracteristici: 'câmp magnetic static intens' },
|
|
{ tip: RiskExposureType.ZGOMOT, denumire: 'Aparatură imagistică', timpExpunere: '3 h/zi', vep: '75 dB', vlep: '87 dB', caracteristici: 'zgomot tehnic' },
|
|
],
|
|
},
|
|
},
|
|
});
|
|
|
|
const remoteCard = await prisma.workplaceRiskCard.create({
|
|
data: {
|
|
name: 'Test - Activități administrative la distanță',
|
|
riskFactors: { source: 'Control medical (5).docx', categories: ['vizual', 'neuropsihic', 'platforme digitale'] },
|
|
filiala: 'Sediul central',
|
|
adresaFiliala: 'str. Nicolae Testemițanu 29, Chișinău',
|
|
telefonFiliala: '+373 22 000 103',
|
|
caemPrimeleDouaCifre: '86',
|
|
cormSubgrupaMajora: 'Personal administrativ',
|
|
directiaSectiaSectorul: 'Administrativ / Digital',
|
|
numarulLoculuiDeMunca: 'TEST-REMOTE-01',
|
|
caemDiviziune: '86.90',
|
|
clasaConditiilorDeMunca: '2',
|
|
numarLucratoriPosibili: 4,
|
|
tipFisa: 'DISTANTA_DIGITAL',
|
|
evaluareDetalii: {
|
|
echipa: false,
|
|
oreZi: '8',
|
|
schimburi: '1',
|
|
schimbNoapte: false,
|
|
pauzeOrganizate: true,
|
|
lucruMonitor: true,
|
|
platformeDigitale: true,
|
|
conduceMasina: false,
|
|
operatiuni: 'Operare HIS, e-mail, raportare digitală',
|
|
deplasari: true,
|
|
deplasariDescriere: 'Deplasări ocazionale la sediu',
|
|
manipulareRidicare: false,
|
|
manipulareCoborare: false,
|
|
manipulareImpingere: false,
|
|
manipulareTragere: false,
|
|
manipularePurtare: false,
|
|
manipulareDeplasare: false,
|
|
greutateMaxima: 'sub 3 kg',
|
|
suprasolicitariVizuale: true,
|
|
suprasolicitariAuditive: false,
|
|
suprasolicitariNeuropsihice: true,
|
|
alteRiscuri: 'Lucru prelungit la monitor',
|
|
},
|
|
radiatiiIonizante: false,
|
|
mijloaceProtectieIndividuala: 'Scaun ergonomic, monitor extern',
|
|
echipamentLucru: 'Laptop corporativ',
|
|
anexeIgienicoSanitare: { vestiar: false, chiuveta: true, wc: true, dus: false, salaMese: false, recreere: true },
|
|
observatii: 'Set pentru testarea Anexa 4A.',
|
|
},
|
|
});
|
|
|
|
const employees = await Promise.all([
|
|
prisma.employee.create({
|
|
data: {
|
|
idnp: '1985061500016',
|
|
nume: 'Popescu',
|
|
prenume: 'Alexandru',
|
|
patronimic: 'Ion',
|
|
dataNasterii: d('1985-06-15'),
|
|
domiciliu: 'mun. Chișinău, str. Ștefan cel Mare 1',
|
|
adresaReala: 'mun. Chișinău, str. Test 1',
|
|
telefonPersonal: '+37369100001',
|
|
telefonServiciu: '+37322100001',
|
|
emailPersonal: 'alexandru.popescu.test@example.com',
|
|
emailCorporativ: 'alexandru.popescu@medpark.test',
|
|
sex: Sex.M,
|
|
codCpas: 'CPAS-001',
|
|
stareCivila: 'casatorit',
|
|
titluStiintific: ScientificTitle.doctor,
|
|
status: EmployeeStatus.activ,
|
|
},
|
|
}),
|
|
prisma.employee.create({
|
|
data: {
|
|
idnp: '1990032200017',
|
|
nume: 'Ionescu',
|
|
prenume: 'Maria',
|
|
patronimic: 'Vasile',
|
|
dataNasterii: d('1990-03-22'),
|
|
domiciliu: 'mun. Chișinău, str. Mihai Viteazul 5',
|
|
telefonPersonal: '+37369100002',
|
|
telefonServiciu: '+37322100002',
|
|
emailCorporativ: 'maria.ionescu@medpark.test',
|
|
sex: Sex.F,
|
|
status: EmployeeStatus.activ,
|
|
gradDizabilitateId: disability.id,
|
|
},
|
|
}),
|
|
prisma.employee.create({
|
|
data: {
|
|
idnp: '1978110800016',
|
|
nume: 'Rusu',
|
|
prenume: 'Viorel',
|
|
dataNasterii: d('1978-11-08'),
|
|
domiciliu: 'mun. Chișinău, str. Alba Iulia 12',
|
|
telefonPersonal: '+37369100003',
|
|
emailCorporativ: 'viorel.rusu@medpark.test',
|
|
sex: Sex.M,
|
|
status: EmployeeStatus.activ,
|
|
},
|
|
}),
|
|
prisma.employee.create({
|
|
data: {
|
|
idnp: '2001091400010',
|
|
nume: 'Cojocaru',
|
|
prenume: 'Elena',
|
|
dataNasterii: d('2001-09-14'),
|
|
domiciliu: 'mun. Chișinău, str. Trandafirilor 3',
|
|
telefonPersonal: '+37369100004',
|
|
emailCorporativ: 'elena.cojocaru@medpark.test',
|
|
sex: Sex.F,
|
|
status: EmployeeStatus.activ,
|
|
},
|
|
}),
|
|
prisma.employee.create({
|
|
data: {
|
|
idnp: '1995120100019',
|
|
nume: 'Munteanu',
|
|
prenume: 'Ana',
|
|
dataNasterii: d('1995-12-01'),
|
|
domiciliu: 'mun. Chișinău, bd. Dacia 20',
|
|
telefonPersonal: '+37369100005',
|
|
emailCorporativ: 'ana.munteanu@medpark.test',
|
|
sex: Sex.F,
|
|
status: EmployeeStatus.activ,
|
|
},
|
|
}),
|
|
prisma.employee.create({
|
|
data: {
|
|
idnp: '1989020300012',
|
|
nume: 'Lungu',
|
|
prenume: 'Sergiu',
|
|
dataNasterii: d('1989-02-03'),
|
|
domiciliu: 'mun. Chișinău, str. Laboratorului 7',
|
|
telefonPersonal: '+37369100006',
|
|
emailCorporativ: 'sergiu.lungu@medpark.test',
|
|
sex: Sex.M,
|
|
status: EmployeeStatus.activ,
|
|
},
|
|
}),
|
|
]);
|
|
|
|
const [surgeon, nurse, radiologist, radiologyNurse, remoteAdmin, labDoctor] = employees;
|
|
|
|
await prisma.identityDocument.createMany({
|
|
data: employees.map((employee, index) => ({
|
|
employeeId: employee.id,
|
|
tipAct: DocumentType.buletin_de_identitate,
|
|
seria: `T${index + 1}`,
|
|
nr: `TESTDOC${index + 1}`,
|
|
dataEmiterii: d('2021-01-10'),
|
|
autoritateEmitenta: 'ASP Test',
|
|
dataExpirarii: d(`2031-01-${10 + index}`),
|
|
})),
|
|
});
|
|
|
|
await prisma.familyMember.createMany({
|
|
data: [
|
|
{ employeeId: surgeon.id, tip: FamilyMemberType.contact_principal, numePrenume: 'Popescu Elena', telefon: '+37368111111' },
|
|
{ employeeId: surgeon.id, tip: FamilyMemberType.copil, numePrenume: 'Popescu Andrei', dataNasterii: d('2015-05-20'), idnp: '2015052000015', tipScutireId: childTax.id },
|
|
{ employeeId: nurse.id, tip: FamilyMemberType.mama, numePrenume: 'Ionescu Tatiana', telefon: '+37368222222' },
|
|
],
|
|
});
|
|
|
|
await prisma.education.createMany({
|
|
data: [
|
|
{ employeeId: surgeon.id, tipStudii: StudyType.superioare, institutia: 'USMF Nicolae Testemițanu', specialitatea: 'Chirurgie', dataAbsolvirii: d('2008-06-30'), nrSeriaDiploma: 'DIP-TEST-001', dataEmiterii: d('2008-07-10'), nrInregistrare: 'REG-001', confirmare: DiplomaStatus.confirmata, nivel: StudyLevel.postuniversitar, tipPostuniversitar: PostUniversityType.rezidentiat },
|
|
{ employeeId: nurse.id, tipStudii: StudyType.medii_de_specialitate, institutia: 'Colegiul Național de Medicină', specialitatea: 'Nursing', dataAbsolvirii: d('2012-06-30'), nrSeriaDiploma: 'DIP-TEST-002', confirmare: DiplomaStatus.confirmata, nivel: StudyLevel.de_baza },
|
|
{ employeeId: radiologist.id, tipStudii: StudyType.superioare, institutia: 'USMF Nicolae Testemițanu', specialitatea: 'Radiologie', dataAbsolvirii: d('2002-06-30'), nrSeriaDiploma: 'DIP-TEST-003', confirmare: DiplomaStatus.confirmata, nivel: StudyLevel.postuniversitar, tipPostuniversitar: PostUniversityType.rezidentiat },
|
|
{ employeeId: radiologyNurse.id, tipStudii: StudyType.medii_de_specialitate, institutia: 'Colegiul Național de Medicină', specialitatea: 'Radiologie', dataAbsolvirii: d('2022-06-30'), nrSeriaDiploma: 'DIP-TEST-004', confirmare: DiplomaStatus.confirmata, nivel: StudyLevel.de_baza },
|
|
{ employeeId: remoteAdmin.id, tipStudii: StudyType.superioare, institutia: 'ASEM', specialitatea: 'Management', dataAbsolvirii: d('2017-06-30'), nrSeriaDiploma: 'DIP-TEST-005', confirmare: DiplomaStatus.confirmata, nivel: StudyLevel.de_baza },
|
|
{ employeeId: labDoctor.id, tipStudii: StudyType.superioare, institutia: 'USMF Nicolae Testemițanu', specialitatea: 'Medicină de laborator', dataAbsolvirii: d('2013-06-30'), nrSeriaDiploma: 'DIP-TEST-006', confirmare: DiplomaStatus.confirmata, nivel: StudyLevel.postuniversitar, tipPostuniversitar: PostUniversityType.rezidentiat },
|
|
],
|
|
});
|
|
|
|
await prisma.qualification.createMany({
|
|
data: [
|
|
{ employeeId: surgeon.id, categorie: QualificationCategory.superioara, dataObtinerii: d('2020-02-01'), dataUltimeiConfirmari: d('2024-02-01'), dataExpirarii: d('2029-02-01'), specialitate: 'Chirurgie' },
|
|
{ employeeId: nurse.id, categorie: QualificationCategory.cat_I, dataObtinerii: d('2021-03-01'), dataUltimeiConfirmari: d('2024-03-01'), dataExpirarii: d('2029-03-01'), specialitate: 'Nursing' },
|
|
{ employeeId: radiologist.id, categorie: QualificationCategory.superioara, dataObtinerii: d('2019-04-01'), dataUltimeiConfirmari: d('2024-04-01'), dataExpirarii: d('2029-04-01'), specialitate: 'Radiologie' },
|
|
{ employeeId: radiologyNurse.id, categorie: QualificationCategory.cat_II, dataObtinerii: d('2024-05-01'), dataUltimeiConfirmari: d('2024-05-01'), dataExpirarii: d('2029-05-01'), specialitate: 'Radiologie' },
|
|
],
|
|
});
|
|
|
|
await prisma.training.createMany({
|
|
data: employees.map((employee, index) => ({
|
|
employeeId: employee.id,
|
|
denumire: `Instruire Control medical test ${index + 1}`,
|
|
inceput: d('2026-01-10'),
|
|
sfirsit: d('2026-01-12'),
|
|
tip: index % 2 === 0 ? TrainingType.intern : TrainingType.extern_RM,
|
|
tara: 'Republica Moldova',
|
|
nrOre: 16,
|
|
organizatia: 'Medpark Academy Test',
|
|
certificat: true,
|
|
cost: '1000.00',
|
|
})),
|
|
});
|
|
|
|
await prisma.disciplinarySanction.createMany({
|
|
data: [
|
|
{ employeeId: nurse.id, tip: DisciplinarySanctionType.avertisment, dataAplicarii: d('2026-02-01'), dataExpirarii: d('2026-08-01') },
|
|
{ employeeId: remoteAdmin.id, tip: DisciplinarySanctionType.mustrare, dataAplicarii: d('2025-09-01'), dataExpirarii: d('2026-03-01'), isStinsa: true },
|
|
],
|
|
});
|
|
|
|
const contractRows = [
|
|
{ employee: surgeon, dept: surgeryDept, nr: 'TEST-CIM-001', role: 'Chirurg', corm: '221201', card: surgeryCard, schedule: shiftSchedule },
|
|
{ employee: nurse, dept: surgeryDept, nr: 'TEST-CIM-002', role: 'Asistentă medicală chirurgie', corm: '222101', card: surgeryCard, schedule: shiftSchedule },
|
|
{ employee: radiologist, dept: radiologyDept, nr: 'TEST-CIM-003', role: 'Medic radiolog', corm: '221203', card: radiologyCard, schedule },
|
|
{ employee: radiologyNurse, dept: radiologyDept, nr: 'TEST-CIM-004', role: 'Asistentă radiologie', corm: '222102', card: radiologyCard, schedule },
|
|
{ employee: remoteAdmin, dept: remoteDept, nr: 'TEST-CIM-005', role: 'Specialist documente digitale', corm: '242101', card: remoteCard, schedule },
|
|
{ employee: labDoctor, dept: labDept, nr: 'TEST-CIM-006', role: 'Medic laborator', corm: '221207', card: surgeryCard, schedule },
|
|
];
|
|
|
|
for (const row of contractRows) {
|
|
const contract = await prisma.employmentContract.create({
|
|
data: {
|
|
nrCim: row.nr,
|
|
employeeId: row.employee.id,
|
|
categorie: ContractCategory.principal,
|
|
dataSemnarii: d('2024-01-05'),
|
|
dataAngajarii: d('2024-01-15'),
|
|
perioada: ContractPeriod.nedeterminata,
|
|
functiaClasificator: row.corm,
|
|
codFunctie: row.corm,
|
|
functiaOrganigrama: row.role,
|
|
tipCim: ContractType.de_baza,
|
|
departmentId: row.dept.id,
|
|
regimMunca: 'normă întreagă',
|
|
tipSalarizare: SalaryType.fix,
|
|
salarizareDetails: { tip: 'fix', salariu: 15000 + contractRows.indexOf(row) * 500, zileConcediu: 28 },
|
|
clausaAditionala: { test: true, source: 'Rubrici necesare (6).xlsx / CIM' },
|
|
workScheduleId: row.schedule.id,
|
|
categoriiServicii: {
|
|
create: [
|
|
{ categorieId: `TEST-SERV-${contractRows.indexOf(row) + 1}`, tipRemunerare: 'tarif', sumaNeta: '250.00' },
|
|
],
|
|
},
|
|
},
|
|
});
|
|
await prisma.auditLog.create({
|
|
data: { userId: 'seed-test', userRole: 'hr_admin', action: 'CREATE', entity: 'EmploymentContract', entityId: contract.id },
|
|
});
|
|
}
|
|
|
|
await prisma.benefit.createMany({
|
|
data: [
|
|
{
|
|
employeeId: nurse.id,
|
|
uniformaId: uniform.id,
|
|
halatId: coat.id,
|
|
ciupiciId: shoes.id,
|
|
ticheteMasa: true,
|
|
valoareTichet: '70.00',
|
|
alimentatiePersonal: true,
|
|
abonamentTel: '150.00',
|
|
aparatTelefonId: phone.id,
|
|
cardCompanie: 'TEST-CARD-001',
|
|
},
|
|
{
|
|
employeeId: radiologyNurse.id,
|
|
uniformaId: uniform.id,
|
|
halatId: coat.id,
|
|
ticheteMasa: true,
|
|
valoareTichet: '70.00',
|
|
},
|
|
],
|
|
});
|
|
|
|
const profileByEmployeeId = new Map<string, string>();
|
|
for (const row of contractRows) {
|
|
const radiology = row.card.id === radiologyCard.id;
|
|
const profile = await prisma.employeeMedicalProfile.create({
|
|
data: {
|
|
employeeId: row.employee.id,
|
|
ocupatieCorm: `${row.role} (${row.corm})`,
|
|
workplaceRiskCardId: row.card.id,
|
|
dataUltimControlMedical: row.employee.id === surgeon.id ? null : d(row.employee.id === nurse.id ? '2025-02-01' : '2025-06-01'),
|
|
expusRadiatiiIonizante: radiology,
|
|
dataIntrarii: radiology ? d('2020-01-15') : null,
|
|
expunereAnterioaraPerioda: radiology ? '2017-2019' : null,
|
|
expunereAnterioaraAni: radiology ? 3 : null,
|
|
dozaCumulataExternaMsv: radiology ? '4.2500' : null,
|
|
dozaCumulataInternaMsv: radiology ? '0.8000' : null,
|
|
overexposures: radiology && row.employee.id === radiologist.id
|
|
? {
|
|
create: [
|
|
{ fel: OverexposureKind.EXCEPTIONALA, tipExpunere: 'X externă', data: d('2023-05-12'), dozaMsv: '2.5000' },
|
|
{ fel: OverexposureKind.ACCIDENTALA, tipExpunere: 'gamma externă', data: d('2024-09-03'), dozaMsv: '1.2000' },
|
|
],
|
|
}
|
|
: undefined,
|
|
},
|
|
});
|
|
profileByEmployeeId.set(row.employee.id, profile.id);
|
|
}
|
|
|
|
await prisma.medicalCheckup.createMany({
|
|
data: [
|
|
{ employeeId: surgeon.id, tip: MedicalCheckupType.la_angajare, dataPlanificata: d('2026-05-20') },
|
|
{ employeeId: nurse.id, tip: MedicalCheckupType.periodic, dataPlanificata: d('2026-05-28') },
|
|
{ employeeId: radiologist.id, tip: MedicalCheckupType.la_reluarea_activitatii, dataPlanificata: d('2026-05-29') },
|
|
{ employeeId: surgeon.id, tip: MedicalCheckupType.periodic, dataPlanificata: d('2025-05-20'), dataEfectuata: d('2025-05-20'), verdict: MedicalVerdict.apt, recomandari: 'Control anual', valabilPanaLa: d('2026-05-20'), semnatDe: 'Dr. Test Apt', documenteGenerate: [{ name: 'Anexa_6_Final_Apt', url: 's3://test/anexa6_apt.docx', type: 'ANEXA_6' }] },
|
|
{ employeeId: nurse.id, tip: MedicalCheckupType.periodic, dataPlanificata: d('2025-04-20'), dataEfectuata: d('2025-04-20'), verdict: MedicalVerdict.apt_perioada_adaptare, recomandari: 'Adaptare 30 zile', valabilPanaLa: d('2026-04-20'), semnatDe: 'Dr. Test Adaptare', documenteGenerate: [{ name: 'Anexa_6_Final_Adaptare', url: 's3://test/anexa6_adaptare.docx', type: 'ANEXA_6' }] },
|
|
{ employeeId: radiologist.id, tip: MedicalCheckupType.periodic, dataPlanificata: d('2025-03-20'), dataEfectuata: d('2025-03-20'), verdict: MedicalVerdict.apt_conditionat, recomandari: 'Dozimetru obligatoriu', valabilPanaLa: d('2026-03-20'), semnatDe: 'Dr. Test Conditionat', documenteGenerate: [{ name: 'Anexa_6_Final_Conditionat', url: 's3://test/anexa6_conditionat.docx', type: 'ANEXA_6' }] },
|
|
{ employeeId: radiologyNurse.id, tip: MedicalCheckupType.suplimentar, dataPlanificata: d('2025-02-20'), dataEfectuata: d('2025-02-20'), verdict: MedicalVerdict.inapt_temporar, recomandari: 'Reevaluare peste 30 zile', valabilPanaLa: d('2025-03-20'), semnatDe: 'Dr. Test Temporar', documenteGenerate: [{ name: 'Anexa_6_Final_Temporar', url: 's3://test/anexa6_temporar.docx', type: 'ANEXA_6' }] },
|
|
{ employeeId: remoteAdmin.id, tip: MedicalCheckupType.periodic, dataPlanificata: d('2025-01-20'), dataEfectuata: d('2025-01-20'), verdict: MedicalVerdict.inapt, recomandari: 'Inapt pentru postul curent', valabilPanaLa: d('2025-02-20'), semnatDe: 'Dr. Test Inapt', documenteGenerate: [{ name: 'Anexa_6_Final_Inapt', url: 's3://test/anexa6_inapt.docx', type: 'ANEXA_6' }] },
|
|
],
|
|
});
|
|
|
|
const campaign = await prisma.evaluationCampaign.create({
|
|
data: {
|
|
name: 'Test evaluare anuală nursing - Chirurgie 2026',
|
|
departmentId: surgeryDept.id,
|
|
month: d('2026-05-01'),
|
|
status: CampaignStatus.in_progress,
|
|
},
|
|
});
|
|
await prisma.evaluationForm.createMany({
|
|
data: [
|
|
{
|
|
campaignId: campaign.id,
|
|
employeeId: nurse.id,
|
|
abilitatiClinice: EvaluationScore.bine,
|
|
judecataClinica: EvaluationScore.bine,
|
|
manopere: EvaluationScore.bine,
|
|
gestionareaSarcinilor: EvaluationScore.mediu,
|
|
constiintaProfesionala: EvaluationScore.bine,
|
|
atitudineaPacienti: EvaluationScore.bine,
|
|
atitudineaColegi: EvaluationScore.bine,
|
|
atitudineaPersonalNonMed: EvaluationScore.mediu,
|
|
utilizareSmartphone: EvaluationScore.bine,
|
|
respectareaProgramului: EvaluationScore.bine,
|
|
respectareaDressCode: EvaluationScore.bine,
|
|
testJci: { score: 18, max_score: 20, percent: 90, source: 'academy_ocean_test' },
|
|
completareaDocMed: true,
|
|
perfectioneazaCunostinte: true,
|
|
membruComitetCalitate: true,
|
|
functieDeMonitor: false,
|
|
inlocuiesteSuperiorul: false,
|
|
categorieCalculata: ProposedCategory.superioara,
|
|
},
|
|
{
|
|
campaignId: campaign.id,
|
|
employeeId: surgeon.id,
|
|
abilitatiClinice: EvaluationScore.mediu,
|
|
judecataClinica: EvaluationScore.mediu,
|
|
manopere: EvaluationScore.bine,
|
|
categorieCalculata: ProposedCategory.fara,
|
|
},
|
|
],
|
|
});
|
|
|
|
const closedCampaign = await prisma.evaluationCampaign.create({
|
|
data: {
|
|
name: 'Test evaluare nursing - Radiologie 2025',
|
|
departmentId: radiologyDept.id,
|
|
month: d('2025-11-01'),
|
|
status: CampaignStatus.closed,
|
|
},
|
|
});
|
|
await prisma.evaluationForm.create({
|
|
data: {
|
|
campaignId: closedCampaign.id,
|
|
employeeId: radiologyNurse.id,
|
|
abilitatiClinice: EvaluationScore.bine,
|
|
judecataClinica: EvaluationScore.bine,
|
|
manopere: EvaluationScore.bine,
|
|
gestionareaSarcinilor: EvaluationScore.bine,
|
|
constiintaProfesionala: EvaluationScore.bine,
|
|
atitudineaPacienti: EvaluationScore.mediu,
|
|
atitudineaColegi: EvaluationScore.bine,
|
|
atitudineaPersonalNonMed: EvaluationScore.bine,
|
|
utilizareSmartphone: EvaluationScore.bine,
|
|
respectareaProgramului: EvaluationScore.bine,
|
|
respectareaDressCode: EvaluationScore.mediu,
|
|
completareaDocMed: true,
|
|
perfectioneazaCunostinte: true,
|
|
membruComitetCalitate: false,
|
|
functieDeMonitor: false,
|
|
inlocuiesteSuperiorul: false,
|
|
categorieCalculata: ProposedCategory.cat_I,
|
|
categorieAprobata: ProposedCategory.cat_I,
|
|
observatii: 'Formular închis pentru test read-only.',
|
|
completedAt: d('2025-11-20'),
|
|
},
|
|
});
|
|
|
|
for (const type of [AnexaType.ANEXA_3, AnexaType.ANEXA_4, AnexaType.ANEXA_4A, AnexaType.ANEXA_4B, AnexaType.ANEXA_6]) {
|
|
await prisma.anexaTemplate.create({
|
|
data: {
|
|
type,
|
|
name: `Test ${type}`,
|
|
contentJson: { source: 'templates/docx', note: 'DOCX template is stored on disk' },
|
|
updatedById: 'seed-test',
|
|
},
|
|
});
|
|
}
|
|
|
|
console.log('Seed summary:');
|
|
console.log(` employees=${await prisma.employee.count()}`);
|
|
console.log(` workplaceRiskCards=${await prisma.workplaceRiskCard.count()}`);
|
|
console.log(` riskExposures=${await prisma.workplaceRiskExposure.count()}`);
|
|
console.log(` medicalCheckups=${await prisma.medicalCheckup.count()}`);
|
|
console.log(` evaluationForms=${await prisma.evaluationForm.count()}`);
|
|
console.log(` profiles=${profileByEmployeeId.size}`);
|
|
}
|
|
|
|
main()
|
|
.catch((error: unknown) => {
|
|
console.error(error);
|
|
process.exitCode = 1;
|
|
})
|
|
.finally(async () => {
|
|
await prisma.$disconnect();
|
|
});
|