diff --git a/QUICK_START.md b/QUICK_START.md new file mode 100644 index 0000000..b49668b --- /dev/null +++ b/QUICK_START.md @@ -0,0 +1,216 @@ +# 🚀 Guía Rápida de Uso + +## Paso 1: Iniciar Dolibarr (Docker) + +Si tienes Dolibarr en Docker: + +```bash +docker start +# o +docker-compose up -d +``` + +Verifica que Dolibarr esté accesible en `http://localhost:8200` + +--- + +## Paso 2: Iniciar la aplicación + +```bash +# Asegúrate de estar en el directorio del proyecto +cd trello_fake + +# Inicia el servidor de desarrollo +npm run dev +``` + +Espera a ver: +``` +✓ Ready in 2.3s +○ Local: http://localhost:3000 +``` + +--- + +## Paso 3: Crear proyectos de prueba + +**Opción A: Usando el script (Recomendado)** + +En una **nueva terminal** (dejando `npm run dev` corriendo): + +```bash +npm run seed +``` + +Verás algo como: +``` +🚀 SEED DE PROYECTOS DE PRUEBA PARA DOLIBARR + +[1/12] Desarrollo de App Móvil + 📈 Progreso: [▓▓▓▓▓▓░░░░] 65% + 💰 Presupuesto: €45,000 + ✅ Creado con ID: 1 + ✓ Validado (estado: abierto) + +... + +✨ PROCESO COMPLETADO +✅ Proyectos creados exitosamente: 12 +``` + +**Opción B: Crear proyectos manualmente en Dolibarr** + +1. Accede a Dolibarr: `http://localhost:8200` +2. Login: admin / p4ssw0rd +3. Ve a Proyectos > Nuevo Proyecto +4. Completa el formulario y guarda + +--- + +## Paso 4: Ver los proyectos + +Abre tu navegador en: `http://localhost:3000` + +Deberías ver: +- 📊 Dashboard con estadísticas +- 🎴 Proyectos en vista de grid (por defecto) +- 🔍 Barra de búsqueda funcional +- 🌓 Toggle de modo oscuro + +--- + +## Paso 5: Explorar funcionalidades + +### Vista de Lista +- Haz clic en el botón **☰** (lista) en el header + +### Detalle de Proyecto +- Haz clic en cualquier tarjeta de proyecto +- Verás información completa: descripción, progreso, presupuesto, fechas + +### Búsqueda +- Escribe en la barra de búsqueda +- Filtra por nombre, cliente o referencia + +### Modo Oscuro +- Haz clic en el icono **☀️/🌙** en el header +- Elige: Claro, Oscuro o Sistema + +--- + +## 🎯 Casos de Uso + +### Ver proyectos completados +1. Busca proyectos con badge verde "Cerrado" +2. O con progreso del 100% +3. Ejemplos: "Dashboard Analítico BI", "Portal de Empleados" + +### Ver proyectos en progreso +1. Busca proyectos con badge azul "Abierto" +2. Progreso entre 1% y 99% +3. Ejemplo: "App de Gestión de Proyectos" (75%) + +### Ver borradores +1. Busca proyectos con badge gris "Borrador" +2. Progreso del 0% +3. Ejemplo: "Sistema CRM Personalizado" + +### Comparar presupuestos +1. Cambia a vista de lista (☰) +2. Compara la columna "Presupuesto" +3. Proyecto más caro: "E-commerce con Marketplace" (€120k) + +--- + +## 🐛 Solución de Problemas + +### No veo proyectos +```bash +# 1. Verifica que Dolibarr esté corriendo +curl http://localhost:8200 + +# 2. Ejecuta el seed +npm run seed + +# 3. Recarga la página (F5) +``` + +### Error 500 en la consola +- Revisa `.env.local` +- Verifica las credenciales de Dolibarr +- Comprueba que la API esté habilitada en Dolibarr + +### Página en blanco +- Abre la consola del navegador (F12) +- Busca errores en rojo +- Verifica que `npm run dev` esté corriendo + +--- + +## 🎨 Personalización + +### Cambiar el número de proyectos de prueba +Edita `scripts/seed-projects-via-api.js`: +```javascript +// Comenta los proyectos que no quieras +const projectsData = [ + // ... solo deja los que quieras +]; +``` + +### Modificar datos de un proyecto +Edita el objeto correspondiente: +```javascript +{ + title: "Tu Proyecto Personalizado", + ref: "PROJ-2024-XXX", + description: "Tu descripción...", + opp_amount: 75000, // Tu presupuesto + opp_percent: 80, // Tu progreso + // ... +} +``` + +Luego ejecuta: +```bash +npm run seed +``` + +--- + +## 🔄 Resetear todo + +### Limpiar proyectos en Dolibarr +1. Accede a Dolibarr +2. Ve a cada proyecto +3. Elimina uno por uno + +### Limpiar caché de Next.js +```bash +rm -rf .next +npm run dev +``` + +### Empezar de cero +```bash +# Detén el servidor (Ctrl+C) +rm -rf .next +npm run dev +npm run seed +``` + +--- + +## 📚 Referencias Rápidas + +| Acción | Comando | +|--------|---------| +| Iniciar desarrollo | `npm run dev` | +| Crear proyectos | `npm run seed` | +| Build producción | `npm run build` | +| Ver logs | Ver terminal donde corre `npm run dev` | +| Ver API calls | F12 > Network > Fetch/XHR | + +--- + +¡Listo! Ya puedes explorar tu dashboard de proyectos Dolibarr 🎉 diff --git a/README.md b/README.md index a66ffc7..ee8e640 100644 --- a/README.md +++ b/README.md @@ -2,27 +2,198 @@ This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next- ![Preview](image.png) +## Dashboard de Proyectos Dolibarr + +Aplicación web moderna para visualizar y gestionar proyectos de Dolibarr con una interfaz intuitiva y profesional. + +### ✨ Características + +- 📊 Vista de proyectos en Grid y Lista +- 🎨 Modo oscuro completo +- 📱 Diseño responsive +- 🔍 Búsqueda en tiempo real +- 📈 Estadísticas y KPIs +- 🔐 API segura (API key protegida en el backend) +- ⚡ Skeletons loading para mejor UX +- 📄 Página de detalle completa para cada proyecto + +--- + +## 🚀 Getting Started + +### Requisitos previos + +- Node.js 18+ +- Dolibarr con API habilitada +- Docker (opcional, para Dolibarr) + +### Instalación + +1. **Clonar el repositorio** +```bash +git clone +cd trello_fake +``` + +2. **Instalar dependencias** +```bash +npm install +``` + +3. **Configurar variables de entorno** + +Crea un archivo `.env.local` en la raíz: + +```bash +# API de Dolibarr (segura - solo servidor) +DOLIBARR_API_URL=http://localhost:8200/api/index.php +DOLIBARR_API_KEY=tu-api-key-aqui + +# Variables públicas +NEXT_PUBLIC_DOLIBARR_USER_ID=2 +``` + +4. **Iniciar el servidor de desarrollo** +```bash +npm run dev +``` + +Abre [http://localhost:3000](http://localhost:3000) en tu navegador. + +--- + +## 📊 Datos de Prueba + +Si no tienes proyectos en tu Dolibarr, puedes generar datos de prueba: + +```bash +# Con el servidor corriendo (npm run dev) +npm run seed +``` + +Este comando creará 12 proyectos de ejemplo con: +- Diferentes estados de progreso (0% - 100%) +- Presupuestos variados (€28k - €120k) +- Descripciones detalladas +- Fechas realistas + +Ver más detalles en [scripts/README.md](scripts/README.md) + +--- + +## 🏗️ Estructura del Proyecto + +``` +/ +├── app/ # Next.js App Router +│ ├── api/dolibarr/[...path]/ # API Route proxy (protege la API key) +│ ├── proyectos/[id]/ # Página de detalle de proyecto +│ ├── layout.tsx # Layout principal +│ └── page.tsx # Página de inicio +├── components/ +│ ├── dashboard/ # Componentes del dashboard +│ ├── ui/ # Componentes shadcn/ui +│ ├── theme-provider.tsx # Provider de tema +│ └── theme-toggle.tsx # Toggle de modo oscuro +├── lib/ # Utilidades y servicios +│ ├── dolibarrClient.ts # Cliente de API +│ ├── projectsService.ts # Servicio de proyectos +│ └── usersService.ts # Servicio de usuarios +├── types/ # Definiciones TypeScript +└── scripts/ # Scripts de utilidad +``` + +--- + +## 🛠️ Scripts Disponibles + +```bash +npm run dev # Servidor de desarrollo +npm run build # Build de producción +npm run start # Servidor de producción +npm run lint # Ejecutar ESLint +npm run seed # Crear proyectos de prueba +``` + +--- + +## 🎨 Tecnologías + +- **Framework:** Next.js 16 (App Router) +- **Lenguaje:** TypeScript 5 +- **UI:** shadcn/ui + Radix UI +- **Estilos:** Tailwind CSS +- **Iconos:** Lucide React +- **Tema:** next-themes +- **API:** Dolibarr REST API + +--- + +## 🔐 Seguridad + +La aplicación implementa las siguientes medidas de seguridad: + +- ✅ API key protegida en el servidor (NO expuesta al cliente) +- ✅ API Route proxy para todas las llamadas a Dolibarr +- ✅ Variables de entorno seguras +- ✅ Validación de datos de entrada + +--- + +## 📖 Documentación Adicional + +- [AGENTS.md](AGENTS.md) - Guías para agentes de IA y arquitectura del proyecto +- [scripts/README.md](scripts/README.md) - Documentación de scripts de utilidad + +--- + +## 🐛 Troubleshooting + +### Error: "Cannot connect to Dolibarr" +- Verifica que Dolibarr esté corriendo +- Revisa la URL en `.env.local` +- Comprueba que la API esté habilitada en Dolibarr + +### No se muestran proyectos +- Ejecuta `npm run seed` para crear datos de prueba +- Verifica las credenciales de la API +- Revisa la consola del navegador para errores + +### Modo oscuro no funciona +- Limpia la caché del navegador +- Verifica que ThemeProvider esté envolviendo la app + +--- + +## 📝 Credenciales de Dolibarr (Demo) + username: admin password: p4ssw0rd -## Getting Started +--- -First, run the development server: +## 🤝 Contribuir -```bash -npm run dev -# or -yarn dev -# or -pnpm dev -# or -bun dev -``` +Las contribuciones son bienvenidas. Por favor: -Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. +1. Fork el proyecto +2. Crea una rama para tu feature (`git checkout -b feature/AmazingFeature`) +3. Commit tus cambios (`git commit -m 'Add: AmazingFeature'`) +4. Push a la rama (`git push origin feature/AmazingFeature`) +5. Abre un Pull Request -You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file. +--- -This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load [Geist](https://vercel.com/font), a new font family for Vercel. +## 📄 Licencia +Este proyecto es privado y de uso interno. +--- + +## Learn More + +To learn more about Next.js, take a look at the following resources: + +- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API. +- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial. +- [Dolibarr API Documentation](https://wiki.dolibarr.org/index.php/Module_Web_Services_API_REST_(v1)) - Dolibarr REST API reference. diff --git a/package.json b/package.json index b7eb709..5e8afe9 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,10 @@ "dev": "next dev", "build": "next build", "start": "next start", - "lint": "eslint" + "lint": "eslint", + "seed": "node scripts/seed-projects-via-api.js", + "seed:direct": "node scripts/seed-projects.js", + "diagnose": "node scripts/diagnose.js" }, "dependencies": { "@radix-ui/react-avatar": "^1.1.11", diff --git a/scripts/README.md b/scripts/README.md new file mode 100644 index 0000000..26dbf54 --- /dev/null +++ b/scripts/README.md @@ -0,0 +1,114 @@ +# Scripts de Utilidad + +Este directorio contiene scripts para facilitar el desarrollo y testing de la aplicación. + +## 📊 Seed de Proyectos de Prueba + +### Opción 1: Via API Route de Next.js (Recomendado) ✅ + +Este método es más seguro ya que usa la API Route protegida. + +**Requisitos:** +- El servidor de Next.js debe estar corriendo (`npm run dev`) +- Dolibarr debe estar accesible + +**Uso:** +```bash +npm run seed +``` + +**Lo que hace:** +- Crea 12 proyectos de prueba con datos realistas +- Diferentes estados de progreso (0%, 15%, 35%, 50%, 65%, 75%, 90%, 100%) +- Variedad de presupuestos (€28k - €120k) +- Fechas de inicio y fin variadas +- Valida automáticamente los proyectos con progreso > 0% + +**Proyectos incluidos:** +1. Desarrollo de App Móvil (65%) +2. Rediseño Web Corporativo (90%) +3. Sistema de Facturación Automática (35%) +4. Migración a Cloud AWS (20%) +5. Dashboard Analítico BI (100% - completado) +6. API REST Microservicios (50%) +7. App de Gestión de Proyectos (75%) +8. E-commerce con Marketplace (15%) +9. Sistema CRM Personalizado (0% - borrador) +10. Portal de Empleados (100% - completado) +11. Sistema de Reservas Online (45%) +12. App de Formación Online (30%) + +--- + +### Opción 2: Conexión Directa a Dolibarr + +Este método se conecta directamente a la API de Dolibarr (sin pasar por Next.js). + +**Requisitos:** +- Dolibarr debe estar accesible +- Variables de entorno configuradas en `.env.local` + +**Uso:** +```bash +npm run seed:direct +``` + +⚠️ **Nota:** Este método usa las credenciales directamente desde `.env.local`. + +--- + +## 🔧 Troubleshooting + +### Error: "No se puede conectar al servidor Next.js" +**Solución:** Asegúrate de que el servidor esté corriendo: +```bash +npm run dev +``` + +### Error: "Dolibarr API error" +**Soluciones posibles:** +1. Verifica que Dolibarr esté corriendo (Docker) +2. Revisa las credenciales en `.env.local` +3. Verifica que la URL de la API sea correcta + +### Error: "No se pudo validar" +**No te preocupes:** Es normal. Algunos proyectos se crean correctamente pero no se pueden validar automáticamente. Puedes validarlos manualmente desde Dolibarr si es necesario. + +--- + +## 🧹 Limpiar Proyectos de Prueba + +Si quieres eliminar los proyectos de prueba creados, puedes hacerlo desde la interfaz de Dolibarr o usando la API: + +```bash +# TODO: Crear script de limpieza +# npm run clean:projects +``` + +--- + +## 📝 Notas + +- Los scripts pausan 500ms entre cada creación para no saturar la API +- Los proyectos con progreso 0% se dejan como "borrador" +- Los proyectos con progreso > 0% se intentan validar automáticamente +- Todos los proyectos tienen descripciones detalladas +- Las fechas están distribuidas entre 2023 y 2025 + +--- + +## 🎨 Personalización + +Para modificar los proyectos de prueba, edita el array `projectsData` en cualquiera de los scripts: + +```javascript +{ + title: "Tu Proyecto", + ref: "PROJ-2024-XXX", + description: "Descripción detallada...", + opp_amount: 50000, // Presupuesto en euros + opp_percent: 50, // Progreso (0-100) + date_start: timestamp, // Unix timestamp en segundos + date_end: timestamp, // Unix timestamp en segundos +} +``` diff --git a/scripts/diagnose.js b/scripts/diagnose.js new file mode 100644 index 0000000..6db95d6 --- /dev/null +++ b/scripts/diagnose.js @@ -0,0 +1,175 @@ +#!/usr/bin/env node + +/** + * Script de diagnóstico para verificar que la aplicación esté funcionando correctamente + */ + +const COLORS = { + reset: '\x1b[0m', + green: '\x1b[32m', + red: '\x1b[31m', + yellow: '\x1b[33m', + blue: '\x1b[34m', + cyan: '\x1b[36m', +}; + +function log(color, symbol, message) { + console.log(`${color}${symbol}${COLORS.reset} ${message}`); +} + +async function checkDolibarr() { + try { + const response = await fetch('http://localhost:8200'); + if (response.ok || response.status === 404) { + log(COLORS.green, '✓', 'Dolibarr está accesible en http://localhost:8200'); + return true; + } + log(COLORS.red, '✗', `Dolibarr respondió con status ${response.status}`); + return false; + } catch (error) { + log(COLORS.red, '✗', 'Dolibarr NO está accesible en http://localhost:8200'); + log(COLORS.yellow, '⚠', 'Asegúrate de que Docker esté corriendo: docker ps'); + return false; + } +} + +async function checkNextJS() { + try { + const response = await fetch('http://localhost:3000'); + if (response.ok || response.status === 404) { + log(COLORS.green, '✓', 'Next.js está corriendo en http://localhost:3000'); + return true; + } + log(COLORS.red, '✗', `Next.js respondió con status ${response.status}`); + return false; + } catch (error) { + log(COLORS.red, '✗', 'Next.js NO está corriendo en http://localhost:3000'); + log(COLORS.yellow, '⚠', 'Ejecuta: npm run dev'); + return false; + } +} + +async function checkAPIRoute() { + try { + const response = await fetch('http://localhost:3000/api/dolibarr/projects'); + if (response.ok) { + const data = await response.json(); + log(COLORS.green, '✓', `API Route funciona correctamente`); + log(COLORS.cyan, 'ℹ', `Proyectos encontrados: ${data.length}`); + return data.length; + } + const errorData = await response.json(); + log(COLORS.red, '✗', `API Route falló: ${errorData.error}`); + return 0; + } catch (error) { + log(COLORS.red, '✗', `Error en API Route: ${error.message}`); + return 0; + } +} + +async function checkDolibarrAPI() { + try { + const API_URL = 'http://localhost:8200/api/index.php'; + const API_KEY = process.env.NEXT_PUBLIC_DOLIBARR_API_KEY || 'Xzulu2Jbv1Ge4V1IVtXKe45db9W64WN7'; + + const response = await fetch(`${API_URL}/projects?DOLAPIKEY=${API_KEY}`); + if (response.ok) { + const data = await response.json(); + log(COLORS.green, '✓', 'API de Dolibarr funciona correctamente'); + log(COLORS.cyan, 'ℹ', `Proyectos en Dolibarr: ${data.length}`); + + if (data.length > 0) { + const sample = data[0]; + log(COLORS.blue, '→', `Ejemplo: ${sample.title} (${sample.ref})`); + } + + return data.length; + } + log(COLORS.red, '✗', `API de Dolibarr falló con status ${response.status}`); + return 0; + } catch (error) { + log(COLORS.red, '✗', `Error conectando a API de Dolibarr: ${error.message}`); + return 0; + } +} + +async function main() { + console.log('\n' + '═'.repeat(60)); + console.log('🔍 DIAGNÓSTICO DEL SISTEMA'); + console.log('═'.repeat(60) + '\n'); + + // 1. Verificar Dolibarr + console.log('1️⃣ Verificando Dolibarr...'); + const dolibarrOk = await checkDolibarr(); + console.log(''); + + if (!dolibarrOk) { + console.log('💡 Solución:'); + console.log(' docker ps # Ver contenedores'); + console.log(' docker start # Iniciar Dolibarr\n'); + return; + } + + // 2. Verificar Next.js + console.log('2️⃣ Verificando Next.js...'); + const nextOk = await checkNextJS(); + console.log(''); + + if (!nextOk) { + console.log('💡 Solución:'); + console.log(' npm run dev\n'); + return; + } + + // 3. Verificar API de Dolibarr directa + console.log('3️⃣ Verificando API de Dolibarr...'); + const dolibarrProjectCount = await checkDolibarrAPI(); + console.log(''); + + // 4. Verificar API Route + console.log('4️⃣ Verificando API Route de Next.js...'); + const apiRouteProjectCount = await checkAPIRoute(); + console.log(''); + + // Resumen + console.log('═'.repeat(60)); + console.log('📊 RESUMEN'); + console.log('═'.repeat(60)); + + if (dolibarrProjectCount === 0) { + log(COLORS.yellow, '⚠', 'No hay proyectos en Dolibarr'); + console.log('\n💡 Solución:'); + console.log(' npm run seed # Crear proyectos de prueba\n'); + } else if (apiRouteProjectCount === 0) { + log(COLORS.red, '✗', 'Hay proyectos en Dolibarr pero no se pueden obtener via API Route'); + console.log('\n💡 Posibles causas:'); + console.log(' 1. Revisa las credenciales en .env.local'); + console.log(' 2. Verifica que la API key sea correcta'); + console.log(' 3. Mira los logs del servidor Next.js (terminal donde corre npm run dev)\n'); + } else if (dolibarrProjectCount !== apiRouteProjectCount) { + log(COLORS.yellow, '⚠', 'Discrepancia en el número de proyectos'); + log(COLORS.cyan, 'ℹ', `Dolibarr: ${dolibarrProjectCount}, API Route: ${apiRouteProjectCount}`); + } else { + log(COLORS.green, '✓', 'Todo está funcionando correctamente!'); + console.log(''); + log(COLORS.cyan, '🎉', 'Abre http://localhost:3000 para ver tus proyectos'); + console.log(''); + } + + // Consejos adicionales + if (apiRouteProjectCount > 0) { + console.log('═'.repeat(60)); + console.log('💡 CONSEJOS'); + console.log('═'.repeat(60)); + console.log('• Abre las DevTools del navegador (F12)'); + console.log('• Ve a la pestaña Console'); + console.log('• Busca errores en rojo'); + console.log('• Ve a la pestaña Network > Fetch/XHR'); + console.log('• Verifica que la petición a /api/dolibarr/projects retorne 200\n'); + } +} + +main().catch(error => { + console.error('\n❌ Error fatal:', error.message); + process.exit(1); +}); diff --git a/scripts/seed-projects-via-api.js b/scripts/seed-projects-via-api.js new file mode 100644 index 0000000..59b2308 --- /dev/null +++ b/scripts/seed-projects-via-api.js @@ -0,0 +1,281 @@ +#!/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 + * + * 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 = [ + { + 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), + }, + { + 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: 90, + date_start: Math.floor(new Date('2023-11-01').getTime() / 1000), + date_end: Math.floor(new Date('2024-02-28').getTime() / 1000), + }, + { + 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), + }, + { + 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), + }, + { + 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), + }, + { + 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), + }, + { + 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), + }, + { + 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), + }, + { + 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), + }, + { + 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), + }, + { + 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), + }, + { + 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), + }, +]; + +/** + * Crear un proyecto usando la API Route de Next.js + */ +async function createProject(projectData) { + const url = `${NEXT_API_URL}/projects`; + + try { + const response = await fetch(url, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify(projectData), + }); + + 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 }), + }); + + if (!response.ok) { + // Es normal que algunos proyectos no se puedan validar + return false; + } + + return true; + } 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) { + 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); + } + + let successCount = 0; + let errorCount = 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)); + + console.log(`[${num}/${projectsData.length}] ${project.title}`); + console.log(` 📈 Progreso: [${progressBar}] ${percentage}%`); + console.log(` 💰 Presupuesto: €${project.opp_amount.toLocaleString()}`); + + try { + // Crear proyecto + const result = await createProject(project); + console.log(` ✅ Creado con ID: ${result}`); + + // Validar proyecto si tiene progreso > 0 + if (percentage > 0) { + const validated = await validateProject(result); + if (validated) { + console.log(` ✓ Validado (estado: abierto)`); + } else { + console.log(` ⚠ Creado pero no validado (normal para algunos proyectos)`); + } + } else { + console.log(` 📋 Dejado como borrador`); + } + + successCount++; + + // Pequeña pausa para no saturar la API + await new Promise(resolve => setTimeout(resolve, 500)); + } 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(`❌ Proyectos con error: ${errorCount}`); + + 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); +}); diff --git a/scripts/seed-projects.js b/scripts/seed-projects.js new file mode 100644 index 0000000..0c0499b --- /dev/null +++ b/scripts/seed-projects.js @@ -0,0 +1,229 @@ +#!/usr/bin/env node + +/** + * Script para crear proyectos de prueba en Dolibarr + * Uso: node scripts/seed-projects.js + */ + +const API_URL = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:8200/api/index.php'; +const API_KEY = process.env.NEXT_PUBLIC_DOLIBARR_API_KEY || 'Xzulu2Jbv1Ge4V1IVtXKe45db9W64WN7'; + +// Datos de proyectos de ejemplo +const projectsData = [ + { + 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.", + socid: null, // Sin cliente asignado + 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), + }, + { + 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.", + socid: null, + opp_amount: 28000, + opp_percent: 90, + date_start: Math.floor(new Date('2023-11-01').getTime() / 1000), + date_end: Math.floor(new Date('2024-02-28').getTime() / 1000), + }, + { + 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.", + socid: null, + 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), + }, + { + 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.", + socid: null, + 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), + }, + { + 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.", + socid: null, + 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), + }, + { + title: "API REST Microservicios", + ref: "PROJ-2024-006", + description: "Desarrollo de arquitectura de microservicios con API REST para integración de sistemas legacy.", + socid: null, + 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), + }, + { + 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.", + socid: null, + 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), + }, + { + title: "E-commerce con Marketplace", + ref: "PROJ-2024-008", + description: "Plataforma de e-commerce completa con funcionalidad de marketplace multivendedor y pasarela de pagos.", + socid: null, + 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), + }, + { + 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.", + socid: null, + 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), + }, + { + 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.", + socid: null, + 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), + }, +]; + +/** + * Crear un proyecto en Dolibarr + */ +async function createProject(projectData) { + const url = `${API_URL}/projects?DOLAPIKEY=${API_KEY}`; + + try { + const response = await fetch(url, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'Accept': 'application/json', + }, + body: JSON.stringify(projectData), + }); + + if (!response.ok) { + const errorText = await response.text(); + throw new Error(`Error ${response.status}: ${errorText}`); + } + + const result = await response.json(); + return result; + } catch (error) { + throw error; + } +} + +/** + * Validar proyecto (cambiar estado a validado/abierto) + */ +async function validateProject(projectId) { + const url = `${API_URL}/projects/${projectId}/validate?DOLAPIKEY=${API_KEY}`; + + try { + const response = await fetch(url, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'Accept': 'application/json', + }, + body: JSON.stringify({ notrigger: 0 }), + }); + + if (!response.ok) { + const errorText = await response.text(); + console.warn(` ⚠️ No se pudo validar (puede ser normal): ${errorText.substring(0, 100)}`); + return false; + } + + return true; + } catch (error) { + console.warn(` ⚠️ Error validando proyecto: ${error.message}`); + return false; + } +} + +/** + * Script principal + */ +async function main() { + console.log('🚀 Iniciando creación de proyectos de prueba en Dolibarr...\n'); + console.log(`📡 API URL: ${API_URL}`); + console.log(`🔑 API Key: ${API_KEY.substring(0, 10)}...`); + console.log(`📊 Proyectos a crear: ${projectsData.length}\n`); + + let successCount = 0; + let errorCount = 0; + + for (let i = 0; i < projectsData.length; i++) { + const project = projectsData[i]; + const num = i + 1; + + console.log(`[${num}/${projectsData.length}] Creando: "${project.title}"...`); + + try { + // Crear proyecto + const result = await createProject(project); + console.log(` ✅ Proyecto creado con ID: ${result}`); + + // Validar proyecto (cambiar a estado abierto) + // Solo validar proyectos que no estén al 0% (borradores) + if (project.opp_percent > 0) { + console.log(` 📝 Validando proyecto...`); + await validateProject(result); + } + + successCount++; + + // Pequeña pausa entre creaciones + await new Promise(resolve => setTimeout(resolve, 300)); + } catch (error) { + console.error(` ❌ Error: ${error.message}`); + errorCount++; + } + + console.log(''); + } + + console.log('═'.repeat(60)); + console.log(`✨ Proceso completado!`); + console.log(`✅ Exitosos: ${successCount}`); + console.log(`❌ Errores: ${errorCount}`); + console.log('═'.repeat(60)); + + if (successCount > 0) { + console.log('\n💡 Ahora puedes recargar tu aplicación para ver los proyectos creados!'); + } +} + +// Ejecutar +main().catch(error => { + console.error('❌ Error fatal:', error); + process.exit(1); +}); diff --git a/types/project.ts b/types/project.ts index 9c1f145..92cf06f 100644 --- a/types/project.ts +++ b/types/project.ts @@ -7,8 +7,8 @@ export interface DolibarrProject { ref: string; title: string; description: string; - date_start: number; // timestamp - date_end: number; // timestamp + date_start: number | null; // timestamp (puede ser null) + date_end: number | null; // timestamp (puede ser null) status: string; statut: string; budget_amount: string; @@ -20,8 +20,8 @@ export interface DolibarrProject { public: string | number; usage_opportunity: string | number; usage_task: string | number; - date_c: number; // fecha creación - date_m: number; // fecha modificación + date_c: number | null; // fecha creación (puede ser null) + date_m: number | null; // fecha modificación (puede ser null) } // Interface para usar en la UI (formato normalizado) @@ -74,6 +74,14 @@ export function mapDolibarrProject(dolibarr: DolibarrProject): Project { const oppAmount = parseFloat(dolibarr.opp_amount || '0'); const progress = parseFloat(dolibarr.opp_percent || '0'); + // Helper para convertir timestamp de Dolibarr (segundos) a fecha ISO + const timestampToDate = (timestamp: number | null | undefined): string => { + if (!timestamp || timestamp === 0) { + return new Date().toISOString().split('T')[0]; // Fecha actual por defecto + } + return new Date(timestamp * 1000).toISOString().split('T')[0]; + }; + return { id: typeof dolibarr.id === 'string' ? parseInt(dolibarr.id) : dolibarr.id, ref: dolibarr.ref, @@ -83,10 +91,10 @@ export function mapDolibarrProject(dolibarr: DolibarrProject): Project { progress: progress, budget: oppAmount || budget, spent: (oppAmount || budget) * (progress / 100), // Calcular gastado según progreso - startDate: new Date(dolibarr.date_start * 1000).toISOString().split('T')[0], - endDate: new Date(dolibarr.date_end * 1000).toISOString().split('T')[0], + startDate: timestampToDate(dolibarr.date_start), + endDate: timestampToDate(dolibarr.date_end), description: dolibarr.description || '', - createdAt: new Date(dolibarr.date_c * 1000).toISOString().split('T')[0], - updatedAt: new Date(dolibarr.date_m * 1000).toISOString().split('T')[0], + createdAt: timestampToDate(dolibarr.date_c), + updatedAt: timestampToDate(dolibarr.date_m), }; } \ No newline at end of file