trello_fake/scripts/seed-tasks.js

335 lines
10 KiB
JavaScript
Raw Normal View History

#!/usr/bin/env node
/**
* Script para crear tareas de prueba en proyectos de Dolibarr
*
* REQUISITO: El servidor de Next.js debe estar corriendo (npm run dev)
* Uso: node scripts/seed-tasks.js
*/
const NEXT_API_URL = 'http://localhost:3000/api/dolibarr';
// Plantillas de tareas variadas para cada proyecto
const taskTemplates = [
// Tareas de análisis/planificación
{
label: "Análisis de requisitos",
description: "Documentar todos los requisitos funcionales y no funcionales del proyecto con el cliente.",
planned_workload: 28800, // 8 horas en segundos
progress: 100,
priority: 2,
},
{
label: "Diseño de arquitectura",
description: "Definir la arquitectura técnica, selección de tecnologías y patrones de diseño a utilizar.",
planned_workload: 36000, // 10 horas
progress: 100,
priority: 3,
},
{
label: "Creación de wireframes",
description: "Diseñar los wireframes y mockups de las principales pantallas de la aplicación.",
planned_workload: 21600, // 6 horas
progress: 80,
priority: 2,
},
// Tareas de desarrollo
{
label: "Configuración del entorno de desarrollo",
description: "Preparar repositorio, CI/CD, entornos de desarrollo y staging.",
planned_workload: 14400, // 4 horas
progress: 100,
priority: 3,
},
{
label: "Desarrollo del backend",
description: "Implementar la API REST, modelos de datos y lógica de negocio del servidor.",
planned_workload: 72000, // 20 horas
progress: 60,
priority: 3,
},
{
label: "Desarrollo del frontend",
description: "Implementar la interfaz de usuario con componentes, estados y conexión con API.",
planned_workload: 64800, // 18 horas
progress: 45,
priority: 3,
},
{
label: "Integración con servicios externos",
description: "Conectar con APIs de terceros, pasarelas de pago y servicios cloud.",
planned_workload: 28800, // 8 horas
progress: 30,
priority: 2,
},
// Tareas de testing
{
label: "Pruebas unitarias",
description: "Escribir y ejecutar tests unitarios para componentes críticos del sistema.",
planned_workload: 21600, // 6 horas
progress: 25,
priority: 2,
},
{
label: "Pruebas de integración",
description: "Realizar pruebas de integración entre módulos y con servicios externos.",
planned_workload: 18000, // 5 horas
progress: 10,
priority: 2,
},
{
label: "QA y corrección de bugs",
description: "Ejecutar plan de QA, documentar bugs encontrados y corregirlos.",
planned_workload: 36000, // 10 horas
progress: 0,
priority: 1,
},
// Tareas de documentación
{
label: "Documentación técnica",
description: "Crear documentación de API, guías de instalación y arquitectura del sistema.",
planned_workload: 14400, // 4 horas
progress: 15,
priority: 1,
},
{
label: "Manual de usuario",
description: "Redactar el manual de usuario con capturas y tutoriales paso a paso.",
planned_workload: 10800, // 3 horas
progress: 0,
priority: 1,
},
// Tareas de despliegue
{
label: "Configuración de producción",
description: "Preparar servidores, certificados SSL, dominios y configuraciones de producción.",
planned_workload: 18000, // 5 horas
progress: 0,
priority: 3,
},
{
label: "Despliegue inicial",
description: "Realizar el despliegue a producción y verificar el correcto funcionamiento.",
planned_workload: 7200, // 2 horas
progress: 0,
priority: 3,
},
{
label: "Formación al cliente",
description: "Sesión de formación al equipo del cliente sobre el uso del sistema.",
planned_workload: 10800, // 3 horas
progress: 0,
priority: 2,
},
];
/**
* Obtener todos los proyectos existentes
*/
async function getProjects() {
const url = `${NEXT_API_URL}/projects`;
const response = await fetch(url, {
method: 'GET',
headers: {
'Content-Type': 'application/json',
},
});
if (!response.ok) {
throw new Error(`Error obteniendo proyectos: ${response.status}`);
}
return response.json();
}
// Contador global para generar refs únicos
let taskCounter = 0;
/**
* Generar referencia única para una tarea
*/
function generateTaskRef(projectId) {
taskCounter++;
const timestamp = Date.now().toString(36).toUpperCase();
return `TASK-P${projectId}-${String(taskCounter).padStart(3, '0')}`;
}
/**
* Crear una tarea en un proyecto
*/
async function createTask(projectId, taskData) {
const url = `${NEXT_API_URL}/tasks`;
// Calcular fechas basadas en la fecha actual
const now = new Date();
const startDate = new Date(now);
startDate.setDate(startDate.getDate() - Math.floor(Math.random() * 30)); // Hace 0-30 días
const endDate = new Date(startDate);
endDate.setDate(endDate.getDate() + Math.floor(Math.random() * 30) + 7); // 7-37 días después
const payload = {
ref: generateTaskRef(projectId), // Campo requerido por Dolibarr
fk_project: String(projectId), // Dolibarr espera string
label: taskData.label,
description: taskData.description,
planned_workload: taskData.planned_workload,
progress: taskData.progress,
priority: taskData.priority,
dateo: Math.floor(startDate.getTime() / 1000), // Fecha inicio planificada
datee: Math.floor(endDate.getTime() / 1000), // Fecha fin planificada
date_start: taskData.progress > 0 ? Math.floor(startDate.getTime() / 1000) : null,
date_end: taskData.progress >= 100 ? Math.floor(new Date().getTime() / 1000) : null,
};
const response = await fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(payload),
});
if (!response.ok) {
const errorData = await response.json().catch(() => ({}));
throw new Error(`Error ${response.status}: ${errorData.error || 'Unknown error'}`);
}
return response.json();
}
/**
* Seleccionar tareas aleatorias para un proyecto
*/
function selectTasksForProject(projectProgress, count = 6) {
// Mezclar las tareas aleatoriamente
const shuffled = [...taskTemplates].sort(() => Math.random() - 0.5);
// Seleccionar las primeras 'count' tareas
const selected = shuffled.slice(0, count);
// Ajustar el progreso de las tareas según el progreso del proyecto
return selected.map((task, index) => {
let adjustedProgress = task.progress;
// Si el proyecto tiene poco progreso, reducir el progreso de las tareas
if (projectProgress < 30) {
adjustedProgress = Math.min(task.progress, 30 + Math.random() * 20);
} else if (projectProgress >= 100) {
// Si el proyecto está completo, completar más tareas
adjustedProgress = index < count - 1 ? 100 : Math.max(task.progress, 80);
} else {
// Ajustar proporcionalmente
const factor = projectProgress / 50;
adjustedProgress = Math.min(100, Math.round(task.progress * factor));
}
return {
...task,
progress: Math.round(adjustedProgress),
};
});
}
/**
* Script principal
*/
async function main() {
console.log('\n📋 SEED DE TAREAS PARA PROYECTOS DE DOLIBARR\n');
console.log('═'.repeat(60));
console.log(`📡 API Next.js: ${NEXT_API_URL}`);
console.log(`📝 Plantillas de tareas: ${taskTemplates.length}`);
console.log('═'.repeat(60));
console.log('');
// Verificar conexión con Next.js
console.log('🔍 Verificando conexión con Next.js...');
try {
const testResponse = await fetch('http://localhost:3000');
if (!testResponse.ok && testResponse.status !== 404) {
throw new Error('Server not responding');
}
console.log('✅ Servidor Next.js está corriendo\n');
} catch (error) {
console.error('❌ ERROR: No se puede conectar al servidor Next.js');
console.error(' Por favor, ejecuta "npm run dev" en otra terminal primero.\n');
process.exit(1);
}
// Obtener proyectos existentes
console.log('📂 Obteniendo proyectos existentes...');
let projects;
try {
projects = await getProjects();
console.log(`✅ Encontrados ${projects.length} proyectos\n`);
} catch (error) {
console.error('❌ Error obteniendo proyectos:', error.message);
process.exit(1);
}
if (projects.length === 0) {
console.log('⚠️ No hay proyectos. Ejecuta primero: npm run seed\n');
process.exit(0);
}
let totalTasks = 0;
let totalErrors = 0;
const TASKS_PER_PROJECT = 6;
for (let i = 0; i < projects.length; i++) {
const project = projects[i];
const projectId = project.id;
const projectTitle = project.title || project.ref || `Proyecto ${projectId}`;
const projectProgress = parseFloat(project.opp_percent || '0');
console.log(`\n[${i + 1}/${projects.length}] 📁 ${projectTitle}`);
console.log(` ID: ${projectId} | Progreso: ${projectProgress}%`);
console.log(' Creando tareas:');
// Seleccionar tareas para este proyecto
const tasksToCreate = selectTasksForProject(projectProgress, TASKS_PER_PROJECT);
for (let j = 0; j < tasksToCreate.length; j++) {
const task = tasksToCreate[j];
try {
const taskId = await createTask(projectId, task);
const progressBar = '█'.repeat(Math.floor(task.progress / 10)) + '░'.repeat(10 - Math.floor(task.progress / 10));
console.log(` ✅ [${progressBar}] ${task.progress}% - ${task.label}`);
totalTasks++;
// Pequeña pausa para no saturar la API
await new Promise(resolve => setTimeout(resolve, 200));
} catch (error) {
console.log(` ❌ Error: ${task.label} - ${error.message}`);
totalErrors++;
}
}
}
// Resumen final
console.log('\n');
console.log('═'.repeat(60));
console.log('✨ PROCESO COMPLETADO\n');
console.log(`📊 Proyectos procesados: ${projects.length}`);
console.log(`✅ Tareas creadas: ${totalTasks}`);
console.log(`❌ Errores: ${totalErrors}`);
console.log('═'.repeat(60));
if (totalTasks > 0) {
console.log('\n💡 ¡Recarga tu aplicación para ver las tareas!');
console.log(' Haz clic en cualquier proyecto para ver sus tareas.\n');
}
}
// Ejecutar
main().catch(error => {
console.error('\n❌ ERROR FATAL:', error.message);
console.error('\nAsegúrate de que:');
console.error(' 1. El servidor Next.js está corriendo (npm run dev)');
console.error(' 2. Dolibarr está accesible');
console.error(' 3. Existen proyectos (ejecuta "npm run seed" primero)\n');
process.exit(1);
});