initial push
This commit is contained in:
729
prisma/seed.mjs
Normal file
729
prisma/seed.mjs
Normal file
@@ -0,0 +1,729 @@
|
||||
import { PrismaClient, ContentPageType, OverallScoreMethod, PriorityLevel } from "@prisma/client";
|
||||
import { readFile } from "node:fs/promises";
|
||||
import path from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
|
||||
const prisma = new PrismaClient();
|
||||
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
||||
|
||||
function yesNoOptions(questionKey) {
|
||||
return [
|
||||
{ key: `${questionKey}-opt-yes`, label: "Si", weight: 5, sortOrder: 1 },
|
||||
{ key: `${questionKey}-opt-no`, label: "No", weight: 0, sortOrder: 2 },
|
||||
];
|
||||
}
|
||||
|
||||
const moduleSeeds = [
|
||||
{
|
||||
key: "liderazgo-vision-estrategica",
|
||||
name: "Liderazgo y Vision Estrategica",
|
||||
description: "Capacidad de la direccion para definir y comunicar una vision clara orientada al valor publico.",
|
||||
sortOrder: 1,
|
||||
questions: [
|
||||
{
|
||||
key: "liderazgo-vision-estrategica-q1",
|
||||
prompt: "La direccion tiene una vision clara del proposito de la empresa mas alla de las ganancias?",
|
||||
helpText: null,
|
||||
sortOrder: 1,
|
||||
options: yesNoOptions("liderazgo-vision-estrategica-q1"),
|
||||
},
|
||||
{
|
||||
key: "liderazgo-vision-estrategica-q2",
|
||||
prompt: "Se comunica regularmente la estrategia empresarial a todo el equipo?",
|
||||
helpText: null,
|
||||
sortOrder: 2,
|
||||
options: yesNoOptions("liderazgo-vision-estrategica-q2"),
|
||||
},
|
||||
{
|
||||
key: "liderazgo-vision-estrategica-q3",
|
||||
prompt: "Existen objetivos medibles alineados con la generacion de valor publico?",
|
||||
helpText: null,
|
||||
sortOrder: 3,
|
||||
options: yesNoOptions("liderazgo-vision-estrategica-q3"),
|
||||
},
|
||||
{
|
||||
key: "liderazgo-vision-estrategica-q4",
|
||||
prompt: "La direccion participa activamente en la toma de decisiones estrategicas?",
|
||||
helpText: null,
|
||||
sortOrder: 4,
|
||||
options: yesNoOptions("liderazgo-vision-estrategica-q4"),
|
||||
},
|
||||
{
|
||||
key: "liderazgo-vision-estrategica-q5",
|
||||
prompt: "Se revisan y ajustan los planes estrategicos al menos anualmente?",
|
||||
helpText: null,
|
||||
sortOrder: 5,
|
||||
options: yesNoOptions("liderazgo-vision-estrategica-q5"),
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
key: "cultura-organizacional",
|
||||
name: "Cultura Organizacional",
|
||||
description: "Valores, comportamientos y mentalidad orientados a la excelencia y el impacto social.",
|
||||
sortOrder: 2,
|
||||
questions: [
|
||||
{
|
||||
key: "cultura-organizacional-q1",
|
||||
prompt: "La empresa promueve valores de integridad y etica en sus operaciones?",
|
||||
helpText: null,
|
||||
sortOrder: 1,
|
||||
options: yesNoOptions("cultura-organizacional-q1"),
|
||||
},
|
||||
{
|
||||
key: "cultura-organizacional-q2",
|
||||
prompt: "Existe un ambiente de trabajo colaborativo y respetuoso?",
|
||||
helpText: null,
|
||||
sortOrder: 2,
|
||||
options: yesNoOptions("cultura-organizacional-q2"),
|
||||
},
|
||||
{
|
||||
key: "cultura-organizacional-q3",
|
||||
prompt: "Se fomenta la mejora continua y el aprendizaje organizacional?",
|
||||
helpText: null,
|
||||
sortOrder: 3,
|
||||
options: yesNoOptions("cultura-organizacional-q3"),
|
||||
},
|
||||
{
|
||||
key: "cultura-organizacional-q4",
|
||||
prompt: "Los empleados conocen y practican los valores de la empresa?",
|
||||
helpText: null,
|
||||
sortOrder: 4,
|
||||
options: yesNoOptions("cultura-organizacional-q4"),
|
||||
},
|
||||
{
|
||||
key: "cultura-organizacional-q5",
|
||||
prompt: "Se reconoce y celebra el buen desempeno del equipo?",
|
||||
helpText: null,
|
||||
sortOrder: 5,
|
||||
options: yesNoOptions("cultura-organizacional-q5"),
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
key: "estructura-procesos",
|
||||
name: "Estructura y Procesos",
|
||||
description: "Organizacion interna, procedimientos y sistemas de gestion eficientes.",
|
||||
sortOrder: 3,
|
||||
questions: [
|
||||
{
|
||||
key: "estructura-procesos-q1",
|
||||
prompt: "Existen procesos documentados para las operaciones principales?",
|
||||
helpText: null,
|
||||
sortOrder: 1,
|
||||
options: yesNoOptions("estructura-procesos-q1"),
|
||||
},
|
||||
{
|
||||
key: "estructura-procesos-q2",
|
||||
prompt: "La empresa cuenta con un organigrama claro y funcional?",
|
||||
helpText: null,
|
||||
sortOrder: 2,
|
||||
options: yesNoOptions("estructura-procesos-q2"),
|
||||
},
|
||||
{
|
||||
key: "estructura-procesos-q3",
|
||||
prompt: "Se utilizan herramientas digitales para la gestion del negocio?",
|
||||
helpText: null,
|
||||
sortOrder: 3,
|
||||
options: yesNoOptions("estructura-procesos-q3"),
|
||||
},
|
||||
{
|
||||
key: "estructura-procesos-q4",
|
||||
prompt: "Existe un sistema de control de calidad en productos o servicios?",
|
||||
helpText: null,
|
||||
sortOrder: 4,
|
||||
options: yesNoOptions("estructura-procesos-q4"),
|
||||
},
|
||||
{
|
||||
key: "estructura-procesos-q5",
|
||||
prompt: "Se llevan registros financieros y contables actualizados?",
|
||||
helpText: null,
|
||||
sortOrder: 5,
|
||||
options: yesNoOptions("estructura-procesos-q5"),
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
key: "innovacion-sostenibilidad",
|
||||
name: "Innovacion y Sostenibilidad",
|
||||
description: "Capacidad de adaptacion, mejora continua y practicas sostenibles.",
|
||||
sortOrder: 4,
|
||||
questions: [
|
||||
{
|
||||
key: "innovacion-sostenibilidad-q1",
|
||||
prompt: "La empresa invierte en innovacion de productos, servicios o procesos?",
|
||||
helpText: null,
|
||||
sortOrder: 1,
|
||||
options: yesNoOptions("innovacion-sostenibilidad-q1"),
|
||||
},
|
||||
{
|
||||
key: "innovacion-sostenibilidad-q2",
|
||||
prompt: "Se implementan practicas de sostenibilidad ambiental?",
|
||||
helpText: null,
|
||||
sortOrder: 2,
|
||||
options: yesNoOptions("innovacion-sostenibilidad-q2"),
|
||||
},
|
||||
{
|
||||
key: "innovacion-sostenibilidad-q3",
|
||||
prompt: "Existe disposicion para adoptar nuevas tecnologias?",
|
||||
helpText: null,
|
||||
sortOrder: 3,
|
||||
options: yesNoOptions("innovacion-sostenibilidad-q3"),
|
||||
},
|
||||
{
|
||||
key: "innovacion-sostenibilidad-q4",
|
||||
prompt: "Se monitorean tendencias del mercado y competencia?",
|
||||
helpText: null,
|
||||
sortOrder: 4,
|
||||
options: yesNoOptions("innovacion-sostenibilidad-q4"),
|
||||
},
|
||||
{
|
||||
key: "innovacion-sostenibilidad-q5",
|
||||
prompt: "Se busca activamente la eficiencia en el uso de recursos?",
|
||||
helpText: null,
|
||||
sortOrder: 5,
|
||||
options: yesNoOptions("innovacion-sostenibilidad-q5"),
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
key: "impacto-social-equidad",
|
||||
name: "Impacto Social y Equidad",
|
||||
description: "Contribucion a la comunidad, inclusion y responsabilidad social.",
|
||||
sortOrder: 5,
|
||||
questions: [
|
||||
{
|
||||
key: "impacto-social-equidad-q1",
|
||||
prompt: "La empresa contribuye positivamente a la comunidad local?",
|
||||
helpText: null,
|
||||
sortOrder: 1,
|
||||
options: yesNoOptions("impacto-social-equidad-q1"),
|
||||
},
|
||||
{
|
||||
key: "impacto-social-equidad-q2",
|
||||
prompt: "Se promueve la equidad de genero en la organizacion?",
|
||||
helpText: null,
|
||||
sortOrder: 2,
|
||||
options: yesNoOptions("impacto-social-equidad-q2"),
|
||||
},
|
||||
{
|
||||
key: "impacto-social-equidad-q3",
|
||||
prompt: "Existen politicas de inclusion para grupos vulnerables?",
|
||||
helpText: null,
|
||||
sortOrder: 3,
|
||||
options: yesNoOptions("impacto-social-equidad-q3"),
|
||||
},
|
||||
{
|
||||
key: "impacto-social-equidad-q4",
|
||||
prompt: "Se considera el impacto social en las decisiones de negocio?",
|
||||
helpText: null,
|
||||
sortOrder: 4,
|
||||
options: yesNoOptions("impacto-social-equidad-q4"),
|
||||
},
|
||||
{
|
||||
key: "impacto-social-equidad-q5",
|
||||
prompt: "La empresa participa en iniciativas de responsabilidad social?",
|
||||
helpText: null,
|
||||
sortOrder: 5,
|
||||
options: yesNoOptions("impacto-social-equidad-q5"),
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
const recommendationSeeds = [
|
||||
{
|
||||
key: "rec-liderazgo-vision",
|
||||
moduleKey: "liderazgo-vision-estrategica",
|
||||
title: "Formalizar vision estrategica anual",
|
||||
description: "Define metas anuales medibles y comunica el avance con revisiones trimestrales para todo el equipo.",
|
||||
priority: PriorityLevel.HIGH,
|
||||
},
|
||||
{
|
||||
key: "rec-cultura-integridad",
|
||||
moduleKey: "cultura-organizacional",
|
||||
title: "Reforzar cultura de integridad y colaboracion",
|
||||
description: "Establece rutinas de reconocimiento y acciones concretas para fortalecer valores compartidos.",
|
||||
priority: PriorityLevel.MEDIUM,
|
||||
},
|
||||
{
|
||||
key: "rec-estructura-procesos",
|
||||
moduleKey: "estructura-procesos",
|
||||
title: "Estandarizar procesos y controles de calidad",
|
||||
description: "Documenta procesos clave y asigna responsables para mantener registros operativos y financieros al dia.",
|
||||
priority: PriorityLevel.HIGH,
|
||||
},
|
||||
{
|
||||
key: "rec-innovacion-sostenibilidad",
|
||||
moduleKey: "innovacion-sostenibilidad",
|
||||
title: "Activar plan de innovacion sostenible",
|
||||
description: "Prioriza proyectos de innovacion con impacto en eficiencia de recursos y seguimiento de tendencias del mercado.",
|
||||
priority: PriorityLevel.MEDIUM,
|
||||
},
|
||||
{
|
||||
key: "rec-impacto-social-equidad",
|
||||
moduleKey: "impacto-social-equidad",
|
||||
title: "Fortalecer estrategia de impacto social",
|
||||
description: "Define iniciativas de inclusion y equidad con indicadores concretos y resultados verificables.",
|
||||
priority: PriorityLevel.MEDIUM,
|
||||
},
|
||||
{
|
||||
key: "rec-gobernanza-global",
|
||||
moduleKey: null,
|
||||
title: "Instalar comite mensual de madurez empresarial",
|
||||
description: "Consolida resultados de los cinco modulos para priorizar inversiones y remover bloqueos.",
|
||||
priority: PriorityLevel.LOW,
|
||||
},
|
||||
];
|
||||
|
||||
const workshopSeeds = [
|
||||
{
|
||||
key: "taller-liderazgo-hoja-ruta",
|
||||
moduleKey: "liderazgo-vision-estrategica",
|
||||
title: "Hoja de Ruta de Liderazgo Estrategico",
|
||||
summary: "Alinea vision, objetivos y ritmos de seguimiento para mejorar la direccion estrategica del equipo.",
|
||||
videoUrl: "https://www.youtube.com/embed/dQw4w9WgXcQ",
|
||||
durationMinutes: 22,
|
||||
evidenceRequired: "Acta de sesion estrategica con objetivos trimestrales y responsables asignados.",
|
||||
learningObjectives: [
|
||||
"Definir prioridades estrategicas medibles",
|
||||
"Comunicar metas de forma transversal",
|
||||
"Establecer seguimiento mensual de resultados",
|
||||
],
|
||||
sortOrder: 1,
|
||||
},
|
||||
{
|
||||
key: "taller-cultura-colaborativa",
|
||||
moduleKey: "cultura-organizacional",
|
||||
title: "Ambiente de Trabajo Colaborativo",
|
||||
summary: "Fortalece dinamicas de comunicacion y colaboracion para elevar desempeno y compromiso del equipo.",
|
||||
videoUrl: "https://www.youtube.com/embed/dQw4w9WgXcQ",
|
||||
durationMinutes: 18,
|
||||
evidenceRequired: "Fotografia o acta de una dinamica de integracion aplicada con tu equipo.",
|
||||
learningObjectives: [
|
||||
"Implementar dinamicas de integracion",
|
||||
"Crear canales de comunicacion efectivos",
|
||||
"Manejar conflictos constructivamente",
|
||||
],
|
||||
sortOrder: 1,
|
||||
},
|
||||
{
|
||||
key: "taller-procesos-auditables",
|
||||
moduleKey: "estructura-procesos",
|
||||
title: "Procesos Auditables y Control Operativo",
|
||||
summary: "Documenta procesos clave y define controles para mejorar trazabilidad y cumplimiento.",
|
||||
videoUrl: "https://www.youtube.com/embed/dQw4w9WgXcQ",
|
||||
durationMinutes: 25,
|
||||
evidenceRequired: "Procedimiento documentado con roles, pasos, entradas y salidas del proceso.",
|
||||
learningObjectives: [
|
||||
"Mapear procesos criticos",
|
||||
"Definir controles de calidad",
|
||||
"Estandarizar evidencias operativas",
|
||||
],
|
||||
sortOrder: 1,
|
||||
},
|
||||
{
|
||||
key: "taller-innovacion-sostenible",
|
||||
moduleKey: "innovacion-sostenibilidad",
|
||||
title: "Innovacion Aplicada con Enfoque Sostenible",
|
||||
summary: "Disena mejoras de alto impacto para reducir costos y aumentar diferenciacion competitiva.",
|
||||
videoUrl: "https://www.youtube.com/embed/dQw4w9WgXcQ",
|
||||
durationMinutes: 20,
|
||||
evidenceRequired: "Ficha de iniciativa de innovacion con costo estimado, impacto y cronograma.",
|
||||
learningObjectives: [
|
||||
"Identificar oportunidades de mejora continua",
|
||||
"Evaluar impacto de iniciativas sostenibles",
|
||||
"Priorizar proyectos de innovacion factibles",
|
||||
],
|
||||
sortOrder: 1,
|
||||
},
|
||||
{
|
||||
key: "taller-impacto-social-evidencia",
|
||||
moduleKey: "impacto-social-equidad",
|
||||
title: "Impacto Social y Equidad con Evidencia",
|
||||
summary: "Define acciones de impacto social medibles para fortalecer tu posicion en licitaciones.",
|
||||
videoUrl: "https://www.youtube.com/embed/dQw4w9WgXcQ",
|
||||
durationMinutes: 24,
|
||||
evidenceRequired: "Plan de impacto social con objetivos, indicadores y responsables.",
|
||||
learningObjectives: [
|
||||
"Disenar iniciativas inclusivas",
|
||||
"Definir indicadores de impacto verificables",
|
||||
"Alinear acciones sociales con estrategia comercial",
|
||||
],
|
||||
sortOrder: 1,
|
||||
},
|
||||
];
|
||||
|
||||
const contentPageSeeds = [
|
||||
{
|
||||
slug: "faq-calculo-puntaje",
|
||||
type: ContentPageType.FAQ,
|
||||
title: "Como se calcula el puntaje global?",
|
||||
content:
|
||||
"El puntaje global se obtiene de la normalizacion de respuestas por modulo y un promedio ponderado entre modulos.",
|
||||
sortOrder: 1,
|
||||
},
|
||||
{
|
||||
slug: "faq-pausa-diagnostico",
|
||||
type: ContentPageType.FAQ,
|
||||
title: "Puedo pausar y continuar luego?",
|
||||
content:
|
||||
"Si. Las respuestas quedan guardadas por usuario para retomar en el ultimo punto completado del cuestionario.",
|
||||
sortOrder: 2,
|
||||
},
|
||||
{
|
||||
slug: "manual-ruta-completa",
|
||||
type: ContentPageType.MANUAL,
|
||||
title: "Ruta completa de uso de la plataforma",
|
||||
content:
|
||||
"Registro, verificacion de correo, onboarding, diagnostico por modulos, resultados y recomendaciones accionables.",
|
||||
sortOrder: 1,
|
||||
},
|
||||
{
|
||||
slug: "manual-interpretacion-dashboard",
|
||||
type: ContentPageType.MANUAL,
|
||||
title: "Interpretacion de dashboard",
|
||||
content:
|
||||
"Use barras para avance relativo por modulo y radar para comparacion de madurez entre capacidades clave.",
|
||||
sortOrder: 2,
|
||||
},
|
||||
];
|
||||
|
||||
async function upsertDiagnosticStructure() {
|
||||
const moduleKeys = moduleSeeds.map((moduleSeed) => moduleSeed.key);
|
||||
|
||||
await prisma.diagnosticModule.deleteMany({
|
||||
where: {
|
||||
key: {
|
||||
notIn: moduleKeys,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
for (const moduleSeed of moduleSeeds) {
|
||||
const moduleRecord = await prisma.diagnosticModule.upsert({
|
||||
where: { key: moduleSeed.key },
|
||||
update: {
|
||||
name: moduleSeed.name,
|
||||
description: moduleSeed.description,
|
||||
sortOrder: moduleSeed.sortOrder,
|
||||
},
|
||||
create: {
|
||||
key: moduleSeed.key,
|
||||
name: moduleSeed.name,
|
||||
description: moduleSeed.description,
|
||||
sortOrder: moduleSeed.sortOrder,
|
||||
},
|
||||
});
|
||||
|
||||
const questionKeys = moduleSeed.questions.map((questionSeed) => questionSeed.key);
|
||||
await prisma.question.deleteMany({
|
||||
where: {
|
||||
moduleId: moduleRecord.id,
|
||||
key: {
|
||||
notIn: questionKeys,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
for (const questionSeed of moduleSeed.questions) {
|
||||
const questionRecord = await prisma.question.upsert({
|
||||
where: { key: questionSeed.key },
|
||||
update: {
|
||||
moduleId: moduleRecord.id,
|
||||
prompt: questionSeed.prompt,
|
||||
helpText: questionSeed.helpText,
|
||||
sortOrder: questionSeed.sortOrder,
|
||||
},
|
||||
create: {
|
||||
key: questionSeed.key,
|
||||
moduleId: moduleRecord.id,
|
||||
prompt: questionSeed.prompt,
|
||||
helpText: questionSeed.helpText,
|
||||
sortOrder: questionSeed.sortOrder,
|
||||
},
|
||||
});
|
||||
|
||||
const optionKeys = questionSeed.options.map((optionSeed) => optionSeed.key);
|
||||
await prisma.answerOption.deleteMany({
|
||||
where: {
|
||||
questionId: questionRecord.id,
|
||||
key: {
|
||||
notIn: optionKeys,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
for (const optionSeed of questionSeed.options) {
|
||||
await prisma.answerOption.upsert({
|
||||
where: { key: optionSeed.key },
|
||||
update: {
|
||||
questionId: questionRecord.id,
|
||||
label: optionSeed.label,
|
||||
weight: optionSeed.weight,
|
||||
sortOrder: optionSeed.sortOrder,
|
||||
},
|
||||
create: {
|
||||
key: optionSeed.key,
|
||||
questionId: questionRecord.id,
|
||||
label: optionSeed.label,
|
||||
weight: optionSeed.weight,
|
||||
sortOrder: optionSeed.sortOrder,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function upsertRecommendations() {
|
||||
const recommendationKeys = recommendationSeeds.map((recommendationSeed) => recommendationSeed.key);
|
||||
const moduleLookup = new Map(
|
||||
(await prisma.diagnosticModule.findMany({ select: { id: true, key: true } })).map((moduleRecord) => [moduleRecord.key, moduleRecord.id]),
|
||||
);
|
||||
|
||||
await prisma.recommendation.deleteMany({
|
||||
where: {
|
||||
key: {
|
||||
notIn: recommendationKeys,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
for (const recommendationSeed of recommendationSeeds) {
|
||||
const moduleId = recommendationSeed.moduleKey ? moduleLookup.get(recommendationSeed.moduleKey) ?? null : null;
|
||||
|
||||
await prisma.recommendation.upsert({
|
||||
where: { key: recommendationSeed.key },
|
||||
update: {
|
||||
moduleId,
|
||||
title: recommendationSeed.title,
|
||||
description: recommendationSeed.description,
|
||||
priority: recommendationSeed.priority,
|
||||
isTemplate: true,
|
||||
},
|
||||
create: {
|
||||
key: recommendationSeed.key,
|
||||
moduleId,
|
||||
title: recommendationSeed.title,
|
||||
description: recommendationSeed.description,
|
||||
priority: recommendationSeed.priority,
|
||||
isTemplate: true,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
async function upsertDevelopmentWorkshops() {
|
||||
const workshopKeys = workshopSeeds.map((workshopSeed) => workshopSeed.key);
|
||||
const moduleLookup = new Map(
|
||||
(await prisma.diagnosticModule.findMany({ select: { id: true, key: true } })).map((moduleRecord) => [moduleRecord.key, moduleRecord.id]),
|
||||
);
|
||||
|
||||
await prisma.developmentWorkshop.deleteMany({
|
||||
where: {
|
||||
key: {
|
||||
notIn: workshopKeys,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
for (const workshopSeed of workshopSeeds) {
|
||||
const moduleId = moduleLookup.get(workshopSeed.moduleKey);
|
||||
|
||||
if (!moduleId) {
|
||||
// Skip orphan workshop seeds when module is unavailable.
|
||||
continue;
|
||||
}
|
||||
|
||||
await prisma.developmentWorkshop.upsert({
|
||||
where: { key: workshopSeed.key },
|
||||
update: {
|
||||
moduleId,
|
||||
title: workshopSeed.title,
|
||||
summary: workshopSeed.summary,
|
||||
videoUrl: workshopSeed.videoUrl,
|
||||
durationMinutes: workshopSeed.durationMinutes,
|
||||
evidenceRequired: workshopSeed.evidenceRequired,
|
||||
learningObjectives: workshopSeed.learningObjectives,
|
||||
sortOrder: workshopSeed.sortOrder,
|
||||
isActive: true,
|
||||
},
|
||||
create: {
|
||||
key: workshopSeed.key,
|
||||
moduleId,
|
||||
title: workshopSeed.title,
|
||||
summary: workshopSeed.summary,
|
||||
videoUrl: workshopSeed.videoUrl,
|
||||
durationMinutes: workshopSeed.durationMinutes,
|
||||
evidenceRequired: workshopSeed.evidenceRequired,
|
||||
learningObjectives: workshopSeed.learningObjectives,
|
||||
sortOrder: workshopSeed.sortOrder,
|
||||
isActive: true,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
async function upsertContentPages() {
|
||||
for (const pageSeed of contentPageSeeds) {
|
||||
await prisma.contentPage.upsert({
|
||||
where: { slug: pageSeed.slug },
|
||||
update: {
|
||||
type: pageSeed.type,
|
||||
title: pageSeed.title,
|
||||
content: pageSeed.content,
|
||||
sortOrder: pageSeed.sortOrder,
|
||||
isPublished: true,
|
||||
},
|
||||
create: {
|
||||
slug: pageSeed.slug,
|
||||
type: pageSeed.type,
|
||||
title: pageSeed.title,
|
||||
content: pageSeed.content,
|
||||
sortOrder: pageSeed.sortOrder,
|
||||
isPublished: true,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
async function upsertDefaultScoringConfig() {
|
||||
await prisma.scoringConfig.upsert({
|
||||
where: { key: "default" },
|
||||
update: {
|
||||
lowScoreThreshold: 70,
|
||||
overallScoreMethod: OverallScoreMethod.EQUAL_ALL_MODULES,
|
||||
moduleWeights: {},
|
||||
},
|
||||
create: {
|
||||
key: "default",
|
||||
lowScoreThreshold: 70,
|
||||
overallScoreMethod: OverallScoreMethod.EQUAL_ALL_MODULES,
|
||||
moduleWeights: {},
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
async function loadMunicipalitySeeds() {
|
||||
const filePath = path.join(__dirname, "data", "municipalities.json");
|
||||
const content = await readFile(filePath, "utf-8");
|
||||
const parsed = JSON.parse(content);
|
||||
|
||||
if (!Array.isArray(parsed)) {
|
||||
throw new Error("Invalid municipalities seed file format.");
|
||||
}
|
||||
|
||||
return parsed.filter((item) => {
|
||||
return (
|
||||
item &&
|
||||
typeof item.stateCode === "string" &&
|
||||
typeof item.stateName === "string" &&
|
||||
typeof item.municipalityCode === "string" &&
|
||||
typeof item.municipalityName === "string"
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
async function upsertMunicipalities() {
|
||||
const municipalities = await loadMunicipalitySeeds();
|
||||
const activeKeys = municipalities.map((item) => `${item.stateCode}-${item.municipalityCode}`);
|
||||
|
||||
await prisma.municipality.updateMany({
|
||||
where: {
|
||||
NOT: municipalities.map((item) => ({
|
||||
stateCode: item.stateCode,
|
||||
municipalityCode: item.municipalityCode,
|
||||
})),
|
||||
},
|
||||
data: {
|
||||
isActive: false,
|
||||
},
|
||||
});
|
||||
|
||||
for (const municipality of municipalities) {
|
||||
await prisma.municipality.upsert({
|
||||
where: {
|
||||
stateCode_municipalityCode: {
|
||||
stateCode: municipality.stateCode,
|
||||
municipalityCode: municipality.municipalityCode,
|
||||
},
|
||||
},
|
||||
update: {
|
||||
stateName: municipality.stateName,
|
||||
municipalityName: municipality.municipalityName,
|
||||
openPortalUrl: municipality.openPortalUrl ?? null,
|
||||
openPortalType: municipality.openPortalType ?? "GENERIC",
|
||||
openSyncIntervalDays:
|
||||
typeof municipality.openSyncIntervalDays === "number" && municipality.openSyncIntervalDays > 0
|
||||
? municipality.openSyncIntervalDays
|
||||
: 7,
|
||||
pntSubjectId: municipality.pntSubjectId ?? null,
|
||||
pntEntityId: municipality.pntEntityId ?? null,
|
||||
pntSectorId: municipality.pntSectorId ?? null,
|
||||
pntEntryUrl: municipality.pntEntryUrl ?? null,
|
||||
backupUrl: municipality.backupUrl ?? null,
|
||||
scrapingEnabled: municipality.scrapingEnabled !== false,
|
||||
isActive: municipality.isActive !== false,
|
||||
},
|
||||
create: {
|
||||
stateCode: municipality.stateCode,
|
||||
stateName: municipality.stateName,
|
||||
municipalityCode: municipality.municipalityCode,
|
||||
municipalityName: municipality.municipalityName,
|
||||
openPortalUrl: municipality.openPortalUrl ?? null,
|
||||
openPortalType: municipality.openPortalType ?? "GENERIC",
|
||||
openSyncIntervalDays:
|
||||
typeof municipality.openSyncIntervalDays === "number" && municipality.openSyncIntervalDays > 0
|
||||
? municipality.openSyncIntervalDays
|
||||
: 7,
|
||||
pntSubjectId: municipality.pntSubjectId ?? null,
|
||||
pntEntityId: municipality.pntEntityId ?? null,
|
||||
pntSectorId: municipality.pntSectorId ?? null,
|
||||
pntEntryUrl: municipality.pntEntryUrl ?? null,
|
||||
backupUrl: municipality.backupUrl ?? null,
|
||||
scrapingEnabled: municipality.scrapingEnabled !== false,
|
||||
isActive: municipality.isActive !== false,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
return activeKeys.length;
|
||||
}
|
||||
|
||||
async function main() {
|
||||
await upsertDiagnosticStructure();
|
||||
await upsertDevelopmentWorkshops();
|
||||
await upsertRecommendations();
|
||||
await upsertContentPages();
|
||||
await upsertDefaultScoringConfig();
|
||||
const municipalitySeedCount = await upsertMunicipalities();
|
||||
|
||||
const moduleCount = await prisma.diagnosticModule.count();
|
||||
const questionCount = await prisma.question.count();
|
||||
const optionCount = await prisma.answerOption.count();
|
||||
const workshopCount = await prisma.developmentWorkshop.count();
|
||||
const recommendationCount = await prisma.recommendation.count();
|
||||
const contentPageCount = await prisma.contentPage.count();
|
||||
const municipalityCount = await prisma.municipality.count({ where: { isActive: true } });
|
||||
|
||||
console.log("Seed completed", {
|
||||
modules: moduleCount,
|
||||
questions: questionCount,
|
||||
answerOptions: optionCount,
|
||||
workshops: workshopCount,
|
||||
recommendations: recommendationCount,
|
||||
contentPages: contentPageCount,
|
||||
municipalities: municipalityCount,
|
||||
municipalitySeedsProcessed: municipalitySeedCount,
|
||||
});
|
||||
}
|
||||
|
||||
main()
|
||||
.catch((error) => {
|
||||
console.error("Seed failed", error);
|
||||
process.exitCode = 1;
|
||||
})
|
||||
.finally(async () => {
|
||||
await prisma.$disconnect();
|
||||
});
|
||||
Reference in New Issue
Block a user