trello_fake/scripts/seed-projects-via-api.js

602 lines
24 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env node
/**
* Script para crear proyectos de prueba en Dolibarr usando la API Route
* Este script usa la API Route segura de Next.js
*
* Incluye:
* - Proyectos en diferentes estados (borrador, abierto, cerrado)
* - Tareas asociadas a cada proyecto
* - Limpieza de proyectos existentes antes de crear nuevos
*
* REQUISITO: El servidor de Next.js debe estar corriendo (npm run dev)
* Uso: node scripts/seed-projects-via-api.js
*/
const NEXT_API_URL = 'http://localhost:3000/api/dolibarr';
// Datos de proyectos de ejemplo con variedad de estados y presupuestos
const projectsData = [
// ==================== PROYECTOS ABIERTOS (EN PROGRESO) ====================
{
title: "Desarrollo de App Móvil",
ref: "PROJ-2024-001",
description: "Aplicación móvil para gestión de inventario con funcionalidades de escaneo QR y sincronización en tiempo real.",
opp_amount: 45000,
opp_percent: 65,
date_start: Math.floor(new Date('2024-01-15').getTime() / 1000),
date_end: Math.floor(new Date('2024-06-30').getTime() / 1000),
targetStatus: 'open', // Validar y dejar abierto
tasks: [
{ label: "Diseño de wireframes", progress: 100, priority: 2, planned_hours: 24, status: 'completed' },
{ label: "Desarrollo frontend React Native", progress: 80, priority: 3, planned_hours: 120, status: 'open' },
{ label: "Integración API backend", progress: 60, priority: 3, planned_hours: 80, status: 'open' },
{ label: "Implementar escáner QR", progress: 40, priority: 2, planned_hours: 40, status: 'open' },
{ label: "Testing y QA", progress: 20, priority: 2, planned_hours: 60, status: 'open' },
]
},
{
title: "Sistema de Facturación Automática",
ref: "PROJ-2024-003",
description: "Desarrollo de sistema automatizado para generación y envío de facturas con integración a contabilidad.",
opp_amount: 62000,
opp_percent: 35,
date_start: Math.floor(new Date('2024-02-01').getTime() / 1000),
date_end: Math.floor(new Date('2024-08-31').getTime() / 1000),
targetStatus: 'open',
tasks: [
{ label: "Análisis de requisitos", progress: 100, priority: 3, planned_hours: 16, status: 'completed' },
{ label: "Diseño de base de datos", progress: 100, priority: 2, planned_hours: 24, status: 'completed' },
{ label: "Módulo de generación PDF", progress: 50, priority: 3, planned_hours: 40, status: 'open' },
{ label: "Integración con pasarela de pago", progress: 10, priority: 2, planned_hours: 32, status: 'open' },
{ label: "Panel de administración", progress: 0, priority: 1, planned_hours: 48, status: 'draft' },
]
},
{
title: "Migración a Cloud AWS",
ref: "PROJ-2024-004",
description: "Migración completa de infraestructura on-premise a AWS con configuración de alta disponibilidad.",
opp_amount: 85000,
opp_percent: 20,
date_start: Math.floor(new Date('2024-03-01').getTime() / 1000),
date_end: Math.floor(new Date('2024-12-31').getTime() / 1000),
targetStatus: 'open',
tasks: [
{ label: "Auditoría de infraestructura actual", progress: 100, priority: 3, planned_hours: 40, status: 'completed' },
{ label: "Diseño de arquitectura AWS", progress: 60, priority: 3, planned_hours: 32, status: 'open' },
{ label: "Configuración de VPC y networking", progress: 20, priority: 2, planned_hours: 24, status: 'open' },
{ label: "Migración de bases de datos", progress: 0, priority: 3, planned_hours: 48, status: 'draft' },
{ label: "Configuración de CI/CD", progress: 0, priority: 2, planned_hours: 32, status: 'draft' },
{ label: "Testing de carga", progress: 0, priority: 2, planned_hours: 24, status: 'draft' },
]
},
{
title: "API REST Microservicios",
ref: "PROJ-2024-006",
description: "Desarrollo de arquitectura de microservicios con API REST para integración de sistemas legacy.",
opp_amount: 72000,
opp_percent: 50,
date_start: Math.floor(new Date('2024-01-20').getTime() / 1000),
date_end: Math.floor(new Date('2024-07-31').getTime() / 1000),
targetStatus: 'open',
tasks: [
{ label: "Diseño de arquitectura", progress: 100, priority: 3, planned_hours: 24, status: 'completed' },
{ label: "Servicio de autenticación", progress: 100, priority: 3, planned_hours: 40, status: 'completed' },
{ label: "Servicio de usuarios", progress: 80, priority: 2, planned_hours: 32, status: 'open' },
{ label: "Servicio de productos", progress: 60, priority: 2, planned_hours: 32, status: 'open' },
{ label: "Gateway API", progress: 30, priority: 3, planned_hours: 24, status: 'open' },
{ label: "Documentación OpenAPI", progress: 20, priority: 1, planned_hours: 16, status: 'open' },
]
},
{
title: "App de Gestión de Proyectos",
ref: "PROJ-2024-007",
description: "Plataforma web para gestión ágil de proyectos con tableros Kanban, Gantt y reporting automático.",
opp_amount: 55000,
opp_percent: 75,
date_start: Math.floor(new Date('2023-12-01').getTime() / 1000),
date_end: Math.floor(new Date('2024-05-31').getTime() / 1000),
targetStatus: 'open',
tasks: [
{ label: "Maquetación UI/UX", progress: 100, priority: 2, planned_hours: 32, status: 'completed' },
{ label: "Sistema de autenticación", progress: 100, priority: 3, planned_hours: 24, status: 'completed' },
{ label: "Tablero Kanban", progress: 100, priority: 3, planned_hours: 48, status: 'completed' },
{ label: "Vista Gantt", progress: 80, priority: 2, planned_hours: 40, status: 'open' },
{ label: "Sistema de notificaciones", progress: 50, priority: 2, planned_hours: 24, status: 'open' },
{ label: "Exportación de reportes", progress: 30, priority: 1, planned_hours: 20, status: 'open' },
]
},
{
title: "E-commerce con Marketplace",
ref: "PROJ-2024-008",
description: "Plataforma de e-commerce completa con funcionalidad de marketplace multivendedor y pasarela de pagos.",
opp_amount: 120000,
opp_percent: 15,
date_start: Math.floor(new Date('2024-04-01').getTime() / 1000),
date_end: Math.floor(new Date('2025-03-31').getTime() / 1000),
targetStatus: 'open',
tasks: [
{ label: "Investigación de mercado", progress: 100, priority: 2, planned_hours: 20, status: 'completed' },
{ label: "Diseño de experiencia de usuario", progress: 70, priority: 3, planned_hours: 40, status: 'open' },
{ label: "Catálogo de productos", progress: 20, priority: 2, planned_hours: 60, status: 'open' },
{ label: "Carrito de compras", progress: 0, priority: 3, planned_hours: 40, status: 'draft' },
{ label: "Integración Stripe/PayPal", progress: 0, priority: 3, planned_hours: 32, status: 'draft' },
{ label: "Panel de vendedores", progress: 0, priority: 2, planned_hours: 48, status: 'draft' },
{ label: "Sistema de reviews", progress: 0, priority: 1, planned_hours: 24, status: 'draft' },
]
},
{
title: "Sistema de Reservas Online",
ref: "PROJ-2024-011",
description: "Plataforma de reservas con calendario interactivo, confirmación automática y pasarela de pago.",
opp_amount: 42000,
opp_percent: 45,
date_start: Math.floor(new Date('2024-02-15').getTime() / 1000),
date_end: Math.floor(new Date('2024-07-15').getTime() / 1000),
targetStatus: 'open',
tasks: [
{ label: "Diseño de flujo de reservas", progress: 100, priority: 2, planned_hours: 16, status: 'completed' },
{ label: "Calendario interactivo", progress: 80, priority: 3, planned_hours: 40, status: 'open' },
{ label: "Sistema de disponibilidad", progress: 60, priority: 3, planned_hours: 32, status: 'open' },
{ label: "Notificaciones por email/SMS", progress: 20, priority: 2, planned_hours: 24, status: 'open' },
{ label: "Integración de pagos", progress: 0, priority: 3, planned_hours: 28, status: 'draft' },
]
},
{
title: "App de Formación Online",
ref: "PROJ-2024-012",
description: "Plataforma LMS para formación online con seguimiento de progreso, certificados y evaluaciones.",
opp_amount: 68000,
opp_percent: 30,
date_start: Math.floor(new Date('2024-03-10').getTime() / 1000),
date_end: Math.floor(new Date('2024-10-31').getTime() / 1000),
targetStatus: 'open',
tasks: [
{ label: "Análisis de requisitos LMS", progress: 100, priority: 2, planned_hours: 20, status: 'completed' },
{ label: "Sistema de cursos y lecciones", progress: 50, priority: 3, planned_hours: 60, status: 'open' },
{ label: "Reproductor de vídeo", progress: 40, priority: 2, planned_hours: 32, status: 'open' },
{ label: "Sistema de evaluaciones", progress: 10, priority: 2, planned_hours: 40, status: 'open' },
{ label: "Generación de certificados", progress: 0, priority: 1, planned_hours: 24, status: 'draft' },
{ label: "Gamificación y badges", progress: 0, priority: 1, planned_hours: 32, status: 'draft' },
]
},
// ==================== PROYECTOS CERRADOS (COMPLETADOS) ====================
{
title: "Rediseño Web Corporativo",
ref: "PROJ-2024-002",
description: "Renovación completa del sitio web corporativo con nuevo diseño responsive y optimización SEO.",
opp_amount: 28000,
opp_percent: 100,
date_start: Math.floor(new Date('2023-11-01').getTime() / 1000),
date_end: Math.floor(new Date('2024-02-28').getTime() / 1000),
targetStatus: 'closed', // Cerrar el proyecto
tasks: [
{ label: "Auditoría web actual", progress: 100, priority: 2, planned_hours: 16, status: 'completed' },
{ label: "Diseño nuevo branding", progress: 100, priority: 3, planned_hours: 32, status: 'completed' },
{ label: "Desarrollo frontend", progress: 100, priority: 3, planned_hours: 80, status: 'completed' },
{ label: "Optimización SEO", progress: 100, priority: 2, planned_hours: 24, status: 'completed' },
{ label: "Migración de contenidos", progress: 100, priority: 2, planned_hours: 20, status: 'completed' },
{ label: "Testing cross-browser", progress: 100, priority: 2, planned_hours: 16, status: 'completed' },
]
},
{
title: "Dashboard Analítico BI",
ref: "PROJ-2024-005",
description: "Creación de dashboard de Business Intelligence para análisis de ventas y KPIs en tiempo real.",
opp_amount: 38000,
opp_percent: 100,
date_start: Math.floor(new Date('2023-09-01').getTime() / 1000),
date_end: Math.floor(new Date('2023-12-15').getTime() / 1000),
targetStatus: 'closed',
tasks: [
{ label: "Definición de KPIs", progress: 100, priority: 3, planned_hours: 16, status: 'completed' },
{ label: "Conexión a fuentes de datos", progress: 100, priority: 3, planned_hours: 32, status: 'completed' },
{ label: "Diseño de visualizaciones", progress: 100, priority: 2, planned_hours: 24, status: 'completed' },
{ label: "Desarrollo de dashboard", progress: 100, priority: 3, planned_hours: 48, status: 'completed' },
{ label: "Reportes automatizados", progress: 100, priority: 2, planned_hours: 20, status: 'completed' },
{ label: "Formación a usuarios", progress: 100, priority: 1, planned_hours: 8, status: 'completed' },
]
},
{
title: "Portal de Empleados",
ref: "PROJ-2024-010",
description: "Portal interno para empleados con gestión de vacaciones, nóminas, formación y comunicación interna.",
opp_amount: 35000,
opp_percent: 100,
date_start: Math.floor(new Date('2023-10-01').getTime() / 1000),
date_end: Math.floor(new Date('2023-12-31').getTime() / 1000),
targetStatus: 'closed',
tasks: [
{ label: "Portal de noticias interno", progress: 100, priority: 2, planned_hours: 24, status: 'completed' },
{ label: "Gestión de vacaciones", progress: 100, priority: 3, planned_hours: 32, status: 'completed' },
{ label: "Visualización de nóminas", progress: 100, priority: 3, planned_hours: 28, status: 'completed' },
{ label: "Directorio de empleados", progress: 100, priority: 1, planned_hours: 16, status: 'completed' },
{ label: "Integración con RRHH", progress: 100, priority: 2, planned_hours: 24, status: 'completed' },
]
},
{
title: "Migración ERP Legacy",
ref: "PROJ-2023-015",
description: "Migración completa del sistema ERP legacy a nueva plataforma con cero tiempo de inactividad.",
opp_amount: 95000,
opp_percent: 100,
date_start: Math.floor(new Date('2023-06-01').getTime() / 1000),
date_end: Math.floor(new Date('2023-11-30').getTime() / 1000),
targetStatus: 'closed',
tasks: [
{ label: "Mapeo de datos legacy", progress: 100, priority: 3, planned_hours: 40, status: 'completed' },
{ label: "Desarrollo de scripts migración", progress: 100, priority: 3, planned_hours: 60, status: 'completed' },
{ label: "Pruebas de migración", progress: 100, priority: 3, planned_hours: 48, status: 'completed' },
{ label: "Migración en producción", progress: 100, priority: 3, planned_hours: 24, status: 'completed' },
{ label: "Validación post-migración", progress: 100, priority: 2, planned_hours: 32, status: 'completed' },
{ label: "Documentación técnica", progress: 100, priority: 1, planned_hours: 16, status: 'completed' },
]
},
// ==================== PROYECTOS EN BORRADOR ====================
{
title: "Sistema CRM Personalizado",
ref: "PROJ-2024-009",
description: "CRM a medida con automatización de marketing, gestión de leads y pipeline de ventas.",
opp_amount: 48000,
opp_percent: 0,
date_start: Math.floor(new Date('2024-05-01').getTime() / 1000),
date_end: Math.floor(new Date('2024-11-30').getTime() / 1000),
targetStatus: 'draft', // Dejar como borrador
tasks: [
{ label: "Definición de requisitos", progress: 0, priority: 3, planned_hours: 24, status: 'draft' },
{ label: "Diseño de arquitectura", progress: 0, priority: 2, planned_hours: 20, status: 'draft' },
{ label: "Módulo de contactos", progress: 0, priority: 2, planned_hours: 40, status: 'draft' },
{ label: "Pipeline de ventas", progress: 0, priority: 3, planned_hours: 48, status: 'draft' },
{ label: "Automatización de emails", progress: 0, priority: 2, planned_hours: 32, status: 'draft' },
]
},
{
title: "App de Gestión de Flota",
ref: "PROJ-2024-013",
description: "Sistema de tracking GPS y gestión de flota vehicular con alertas y reportes de consumo.",
opp_amount: 58000,
opp_percent: 0,
date_start: Math.floor(new Date('2024-06-01').getTime() / 1000),
date_end: Math.floor(new Date('2024-12-31').getTime() / 1000),
targetStatus: 'draft',
tasks: [
{ label: "Estudio de viabilidad", progress: 0, priority: 2, planned_hours: 16, status: 'draft' },
{ label: "Integración GPS", progress: 0, priority: 3, planned_hours: 40, status: 'draft' },
{ label: "Dashboard de tracking", progress: 0, priority: 3, planned_hours: 48, status: 'draft' },
{ label: "Sistema de alertas", progress: 0, priority: 2, planned_hours: 24, status: 'draft' },
]
},
];
/**
* Obtener todos los proyectos existentes
*/
async function getExistingProjects() {
try {
const response = await fetch(`${NEXT_API_URL}/projects`);
if (!response.ok) {
if (response.status === 404) return [];
throw new Error(`Error ${response.status}`);
}
return await response.json();
} catch (error) {
console.log(' ⚠ No se pudieron obtener proyectos existentes');
return [];
}
}
/**
* Eliminar un proyecto
*/
async function deleteProject(projectId) {
try {
const response = await fetch(`${NEXT_API_URL}/projects/${projectId}`, {
method: 'DELETE',
});
return response.ok;
} catch (error) {
return false;
}
}
/**
* Crear un proyecto usando la API Route de Next.js
*/
async function createProject(projectData) {
const url = `${NEXT_API_URL}/projects`;
// Limpiar datos que no van a la API de creación
const { tasks, targetStatus, ...apiData } = projectData;
try {
const response = await fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(apiData),
});
if (!response.ok) {
const errorData = await response.json();
throw new Error(`Error ${response.status}: ${errorData.error || 'Unknown error'}`);
}
const result = await response.json();
return result;
} catch (error) {
if (error.code === 'ECONNREFUSED') {
throw new Error('No se puede conectar al servidor Next.js. ¿Está corriendo "npm run dev"?');
}
throw error;
}
}
/**
* Validar proyecto (cambiar estado a validado/abierto)
*/
async function validateProject(projectId) {
const url = `${NEXT_API_URL}/projects/${projectId}/validate`;
try {
const response = await fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ notrigger: 0 }),
});
return response.ok;
} catch (error) {
return false;
}
}
/**
* Cerrar proyecto (cambiar estado a cerrado usando PUT)
*/
async function closeProject(projectId) {
const url = `${NEXT_API_URL}/projects/${projectId}`;
try {
const response = await fetch(url, {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ status: "2" }),
});
return response.ok;
} catch (error) {
return false;
}
}
/**
* Crear una tarea para un proyecto
*/
async function createTask(projectId, taskData, index) {
const url = `${NEXT_API_URL}/tasks`;
const timestamp = Date.now().toString(36).toUpperCase();
const taskPayload = {
ref: `TK${projectId}-${index}-${timestamp}`,
label: taskData.label,
fk_project: projectId,
progress: taskData.progress || 0,
priority: String(taskData.priority || 0),
planned_workload: (taskData.planned_hours || 0) * 3600, // Convertir horas a segundos
};
try {
const response = await fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(taskPayload),
});
if (!response.ok) {
return null;
}
const taskId = await response.json();
// Si la tarea debe estar completada o abierta, validarla
if (taskData.status === 'completed' || taskData.status === 'open') {
await validateTask(taskId);
}
return taskId;
} catch (error) {
return null;
}
}
/**
* Validar tarea
*/
async function validateTask(taskId) {
try {
const response = await fetch(`${NEXT_API_URL}/tasks/${taskId}/validate`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ notrigger: 0 }),
});
return response.ok;
} catch (error) {
return false;
}
}
/**
* Script principal
*/
async function main() {
console.log('\n🚀 SEED DE PROYECTOS DE PRUEBA PARA DOLIBARR\n');
console.log('═'.repeat(60));
console.log(`📡 API Next.js: ${NEXT_API_URL}`);
console.log(`📊 Proyectos a crear: ${projectsData.length}`);
console.log('═'.repeat(60));
console.log('');
// Verificar que Next.js esté corriendo
console.log('🔍 Verificando conexión con Next.js...');
try {
const testResponse = await fetch('http://localhost:3000');
if (!testResponse.ok && testResponse.status !== 404 && testResponse.status !== 307) {
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);
}
// ==================== LIMPIEZA DE PROYECTOS EXISTENTES ====================
console.log('🧹 Limpiando proyectos existentes...');
const existingProjects = await getExistingProjects();
if (existingProjects.length > 0) {
let deletedCount = 0;
for (const project of existingProjects) {
const projectId = project.id || project;
const deleted = await deleteProject(projectId);
if (deleted) {
deletedCount++;
process.stdout.write(`\r Eliminados: ${deletedCount}/${existingProjects.length}`);
}
await new Promise(resolve => setTimeout(resolve, 200));
}
console.log(`\n ✅ ${deletedCount} proyectos eliminados\n`);
} else {
console.log(' ℹ No hay proyectos existentes\n');
}
// ==================== CREACIÓN DE NUEVOS PROYECTOS ====================
let successCount = 0;
let errorCount = 0;
let tasksCreated = 0;
const errors = [];
for (let i = 0; i < projectsData.length; i++) {
const project = projectsData[i];
const num = i + 1;
const percentage = project.opp_percent;
// Indicador visual del progreso
const progressBar = '▓'.repeat(Math.floor(percentage / 10)) + '░'.repeat(10 - Math.floor(percentage / 10));
// Emoji según estado objetivo
const statusEmoji = project.targetStatus === 'closed' ? '🏁' :
project.targetStatus === 'draft' ? '📝' : '🔵';
console.log(`[${num}/${projectsData.length}] ${statusEmoji} ${project.title}`);
console.log(` 📈 Progreso: [${progressBar}] ${percentage}%`);
console.log(` 💰 Presupuesto: €${project.opp_amount.toLocaleString()}`);
console.log(` 🎯 Estado objetivo: ${project.targetStatus}`);
try {
// Crear proyecto
const projectId = await createProject(project);
console.log(` ✅ Proyecto creado con ID: ${projectId}`);
// Gestionar estado del proyecto
if (project.targetStatus === 'open' || project.targetStatus === 'closed') {
const validated = await validateProject(projectId);
if (validated) {
console.log(` ✓ Validado (estado: abierto)`);
// Si debe estar cerrado, cerrarlo
if (project.targetStatus === 'closed') {
const closed = await closeProject(projectId);
if (closed) {
console.log(` 🏁 Cerrado (completado)`);
}
}
}
} else {
console.log(` 📋 Dejado como borrador`);
}
// Crear tareas del proyecto
if (project.tasks && project.tasks.length > 0) {
console.log(` 📋 Creando ${project.tasks.length} tareas...`);
let projectTasksCreated = 0;
for (let j = 0; j < project.tasks.length; j++) {
const task = project.tasks[j];
const taskId = await createTask(projectId, task, j + 1);
if (taskId) {
projectTasksCreated++;
tasksCreated++;
}
await new Promise(resolve => setTimeout(resolve, 150));
}
console.log(` ✅ ${projectTasksCreated}/${project.tasks.length} tareas creadas`);
}
successCount++;
// Pequeña pausa para no saturar la API
await new Promise(resolve => setTimeout(resolve, 300));
} catch (error) {
console.log(` ❌ Error: ${error.message}`);
errors.push({ project: project.title, error: error.message });
errorCount++;
}
console.log('');
}
// Resumen final
console.log('═'.repeat(60));
console.log('✨ PROCESO COMPLETADO\n');
console.log(`✅ Proyectos creados exitosamente: ${successCount}`);
console.log(`📋 Tareas creadas: ${tasksCreated}`);
console.log(`❌ Proyectos con error: ${errorCount}`);
// Desglose por estado
const openProjects = projectsData.filter(p => p.targetStatus === 'open').length;
const closedProjects = projectsData.filter(p => p.targetStatus === 'closed').length;
const draftProjects = projectsData.filter(p => p.targetStatus === 'draft').length;
console.log('\n📊 Desglose por estado:');
console.log(` 🔵 Abiertos: ${openProjects}`);
console.log(` 🏁 Cerrados: ${closedProjects}`);
console.log(` 📝 Borradores: ${draftProjects}`);
if (errors.length > 0) {
console.log('\n📋 Errores encontrados:');
errors.forEach(({ project, error }) => {
console.log(` • ${project}: ${error}`);
});
}
console.log('═'.repeat(60));
if (successCount > 0) {
console.log('\n💡 ¡Recarga tu aplicación para ver los proyectos!');
console.log(' Abre http://localhost:3000 en tu navegador\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. Las credenciales en .env.local son correctas\n');
process.exit(1);
});