13 módulos, 6 roles, 5 idiomas, 4 temas visuales Creador: José Jiménez Salinas — Consultoría Alcaraz Salazar
259 lines
9.0 KiB
Markdown
259 lines
9.0 KiB
Markdown
# CRANEGOO — Documentación Técnica para Desarrollador
|
||
|
||
## Arquitectura General
|
||
|
||
La app es un **Single-File React Component** (`src/App.jsx`) con todo el estado en memoria. No hay backend, base de datos ni API. Esto es un prototipo funcional que debe migrarse a una arquitectura cliente-servidor.
|
||
|
||
---
|
||
|
||
## Mapa del Archivo (por líneas aproximadas)
|
||
|
||
```
|
||
Líneas 1-18 → Constantes de color (C), estilos base
|
||
Líneas 19-148 → ROLES, EQ_TYPES, SVC_TYPES, PRIORITY, EMP_ROLES, EXCLUSIVE_ROLES, etc.
|
||
Líneas 149-230 → INIT_EMPLOYEES, INIT_CLIENTS (vacíos en versión limpia)
|
||
Líneas 231-410 → INIT_SERVICES, INIT_MAINTENANCE, INIT_SUPPLIERS, INIT_PURCHASE_ORDERS, etc.
|
||
Líneas 410-535 → TRANSLATIONS (90 claves × 5 idiomas), THEMES (4), INIT_COMPANY
|
||
Líneas 535-600 → Hooks (useIsMobile), GSComp (global styles dinámicos por tema)
|
||
Líneas 600-640 → SignaturePad component (canvas touch+mouse)
|
||
Líneas 640-680 → Field, Modal, StatusBadge, SvcStatusBadge, PriorityBadge
|
||
Líneas 680-850 → Calendar component (con festivos 2026, domingos, modales)
|
||
Líneas 850-1500 → ServicesModule (OpsServicesView, EmpServicesView, VentasServicesView, ClientServicesView)
|
||
Líneas 1500-2100 → InventoryModule (EquipmentForm, PartForm)
|
||
Líneas 2100-2500 → MaintenanceModule (OpsMaintenanceView, ClientMaintenanceView, EmpMaintenanceView)
|
||
Líneas 2500-2950 → ComprasModule (OCs, proveedores, fotos)
|
||
Líneas 2950-3400 → CotizacionesModule (catálogo, PDF, cláusulas)
|
||
Líneas 3400-4600 → ContableModule (6 pestañas: resumen, facturas, edocuenta, tesorería, SAT/IMSS, nómina)
|
||
Líneas 4600-4850 → PersonalModule (CRUD empleados)
|
||
Líneas 4850-5200 → ClientesModule (CRUD clientes, proyectos, appUsers)
|
||
Líneas 5200-5400 → Sidebar, Header
|
||
Líneas 5400-5850 → Dashboard (KPIs, panel financiero, alertas)
|
||
Líneas 5850-6000 → GPSModule
|
||
Líneas 6000-6500 → ManualesModule
|
||
Líneas 6500-6900 → ReportesModule (checklists grúa/elevador, firmas, PDF)
|
||
Líneas 6900-7200 → ConfigModule (idiomas, temas, empresa, fiscal, acerca de)
|
||
Líneas 7200-7300 → Login (usuario + contraseña)
|
||
Líneas 7300-7450 → App (estado global, routing)
|
||
```
|
||
|
||
---
|
||
|
||
## Estado Global (en App component)
|
||
|
||
Todos estos `useState` viven en `App()` y se pasan como props:
|
||
|
||
| State | Tipo | Descripción |
|
||
|-------|------|-------------|
|
||
| `role` | string | Rol activo (admin, operaciones, ventas, contador, empleado, cliente) |
|
||
| `mod` | string | Módulo activo del sidebar |
|
||
| `equipment` | array | Equipos (grúas, elevadores) |
|
||
| `parts` | array | Refacciones |
|
||
| `services` | array | Servicios programados |
|
||
| `maintenance` | array | Mantenimientos |
|
||
| `employees` | array | Empleados con credenciales |
|
||
| `clients` | array | Clientes con proyectos y appUsers |
|
||
| `invoices` | array | Facturas (ingreso/egreso) |
|
||
| `quotations` | array | Cotizaciones |
|
||
| `purchaseOrders` | array | Órdenes de compra |
|
||
| `suppliers` | array | Proveedores |
|
||
| `messages` | array | Mensajes internos |
|
||
| `accounts` | array | Cuentas bancarias |
|
||
| `credits` | array | Créditos y tarjetas |
|
||
| `transactions` | array | Movimientos bancarios |
|
||
| `obligations` | array | Obligaciones SAT/IMSS |
|
||
| `nomina` | array | Registros de nómina semanal |
|
||
| `lang` | string | Idioma activo (es-MX, en, ru, fr, es-ES) |
|
||
| `theme` | string | Tema visual (dark, light, mexus, blue) |
|
||
| `company` | object | Datos de la empresa |
|
||
| `clientLangs` | object | Idioma por cliente/obra |
|
||
| `loggedUserId` | string | ID del usuario logueado |
|
||
| `loggedUserProject` | string | Proyecto del cliente logueado |
|
||
|
||
---
|
||
|
||
## Flujo de Autenticación
|
||
|
||
```
|
||
Login → usuario + contraseña
|
||
├─ Match ADMIN_CREDS? → onLogin("admin", null, null)
|
||
├─ Match employee.user + employee.pass? → onLogin(emp.systemRole, emp.id, null)
|
||
├─ Match client appUser.user + appUser.pass? → onLogin("cliente", cli.id, project)
|
||
└─ Fallback: Match employee.email + employee.pass? → onLogin(emp.systemRole, emp.id, null)
|
||
```
|
||
|
||
**Para migración:** Reemplazar con JWT + bcrypt. La estructura de roles ya está definida.
|
||
|
||
---
|
||
|
||
## Modelo de Datos Clave
|
||
|
||
### Employee
|
||
```javascript
|
||
{
|
||
id: "EMP-001",
|
||
name: "Carlos Mendoza",
|
||
role: "Operador de Grúa", // Puesto laboral
|
||
systemRole: "operaciones", // Rol en la app (empleado|operaciones|ventas|contador)
|
||
phone, email, curp, nss,
|
||
emergencyContact, startDate,
|
||
status: "activo"|"inactivo",
|
||
user: "carlos.mendoza", // Login
|
||
pass: "mexus2024", // Contraseña (migrar a hash)
|
||
comprasAccess: false // Acceso al módulo de compras
|
||
}
|
||
```
|
||
|
||
### Client
|
||
```javascript
|
||
{
|
||
id: "CLI-001",
|
||
company: "Hermosillo y Asociados",
|
||
contact, phone, email, rfc, address,
|
||
projects: ["WESTIN Tijuana"],
|
||
status: "activo",
|
||
projectDetails: {
|
||
"WESTIN Tijuana": {
|
||
equipmentIds: ["MX-GT-001"],
|
||
notifEmails: ["correo@empresa.mx"],
|
||
appUsers: [
|
||
{ name: "Fernando", email: "f@h.mx", user: "fhermosillo", pass: "westin2024" }
|
||
] // Máximo 2 por proyecto
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
### Service
|
||
```javascript
|
||
{
|
||
id: "SVC-001",
|
||
type: "elevacion_grua", // De SVC_TYPES
|
||
clientName, project, equipmentId,
|
||
date, endDate, timeSlot: "07:00-15:00",
|
||
priority: "alta"|"media"|"baja",
|
||
status: "pendiente"|"aprobado"|"en_proceso"|"en_sitio"|"completado"|"rechazado",
|
||
assignedTo: ["EMP-001", "EMP-005"],
|
||
tracking: {
|
||
inSite: false,
|
||
inSiteTime: null,
|
||
startTime: null, endTime: null,
|
||
photosStart: [], photosDuring: [], photosEnd: [],
|
||
employeeNotes: "",
|
||
checklist: null, // Se genera al iniciar (GRUA o ELEVADOR)
|
||
empSignature: null, // PNG data URL de firma
|
||
empSignName: "",
|
||
approverSignature: null,
|
||
approverSignName: "",
|
||
reportApproved: false,
|
||
reportApprovedAt: null,
|
||
opsNotes: ""
|
||
}
|
||
}
|
||
```
|
||
|
||
### Account (Tesorería)
|
||
```javascript
|
||
{
|
||
id: "CTA-001",
|
||
name: "BBVA Empresarial Pesos",
|
||
bank: "BBVA",
|
||
type: "pesos"|"dolares",
|
||
number: "**** 4521",
|
||
balance: 485000, // Se actualiza con transacciones
|
||
clabe: "012180001234567890"
|
||
}
|
||
```
|
||
|
||
### Obligation (SAT/IMSS)
|
||
```javascript
|
||
{
|
||
id: "OBL-001",
|
||
entity: "SAT"|"IMSS"|"Estatal",
|
||
type: "ISR Retenciones",
|
||
period: "Marzo 2026",
|
||
amount: 18500,
|
||
dueDate: "2026-04-17",
|
||
status: "pendiente"|"pagado",
|
||
receipt: null // { name, data } archivo subido
|
||
}
|
||
```
|
||
|
||
### Nomina
|
||
```javascript
|
||
{
|
||
id: "NOM-001",
|
||
week: "Semana 9 (24 Feb — 2 Mar)",
|
||
period: "2026-03-02",
|
||
totalBruto: 95000, totalNeto: 78500,
|
||
isr: 8500, imss: 4200, infonavit: 3800,
|
||
employees: 6,
|
||
timbrada: true, timbreXML: { name, date },
|
||
complemento: false, compXML: null,
|
||
receipt: null,
|
||
notes: ""
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## Permisos — Tabla de Referencia
|
||
|
||
### canEdit / canOperate / canGrantAccess (ContableModule)
|
||
```javascript
|
||
const canEdit = isAdmin || isContador; // Editar/eliminar cuentas, créditos, obligaciones, nómina
|
||
const canOperate = isAdmin || isContador; // Crear, registrar transacciones, subir comprobantes
|
||
const canGrantAccess = isAdmin; // Activar visualización a otros roles
|
||
```
|
||
|
||
### Compras — Acciones de pago
|
||
```javascript
|
||
(role === "admin" || role === "contador") // Marcar pagado, subir comprobante
|
||
(role === "admin" || role === "operaciones") // Cancelar/eliminar OC
|
||
```
|
||
|
||
### Roles exclusivos en Scheduling
|
||
```javascript
|
||
const EXCLUSIVE_ROLES = ["Operador", "Maniobrista", "Operador de Grúa", ...];
|
||
// Si un operador tiene cualquier asignación en un día → bloqueado TODO el día
|
||
// Otros roles (Técnicos, Montadores): disponibles fuera de sus slots asignados
|
||
```
|
||
|
||
---
|
||
|
||
## Internacionalización
|
||
|
||
```javascript
|
||
const t = (key) => TRANSLATIONS[key]?.[activeLang] || TRANSLATIONS[key]?.["es-MX"] || key;
|
||
|
||
// activeLang se resuelve:
|
||
// 1. Si es cliente → clientLangs[clientId+"|"+project] || clientLangs[clientId] || lang
|
||
// 2. Todos los demás → lang (idioma global del sistema)
|
||
```
|
||
|
||
Claves traducidas: sidebar (13), login (6), common (20), roles (6), dashboard (8), services (6), contable (5), config (10), priority (3), reports (5).
|
||
|
||
---
|
||
|
||
## Generación de PDF
|
||
|
||
Se usa `window.open()` + `document.write()` para generar HTML imprimible. Los PDFs incluyen:
|
||
- Logo de la empresa (del cliente, no CRANEGOO)
|
||
- Checklist completo con OK/Defecto
|
||
- Firmas digitales (imágenes PNG incrustadas)
|
||
- Datos del equipo, cliente, inspector
|
||
|
||
**Para migración:** Reemplazar con librería como `jsPDF` o generación server-side.
|
||
|
||
---
|
||
|
||
## Notas para el Programador
|
||
|
||
1. **Todo el estado es en memoria** — al recargar se pierde. Prioridad #1: base de datos.
|
||
2. **Las contraseñas están en texto plano** — migrar a bcrypt + JWT inmediatamente.
|
||
3. **Las firmas son PNG data URLs** — almacenar en object storage (S3/Firebase Storage).
|
||
4. **Los archivos subidos (XML, fotos) son data URLs en memoria** — migrar a file storage.
|
||
5. **El CSS es inline** — considerar migrar a Tailwind CSS o CSS modules.
|
||
6. **No hay tests** — agregar tests unitarios y de integración.
|
||
7. **El routing es un switch/case interno** — migrar a React Router.
|
||
8. **No hay error boundaries** — agregar para producción.
|