# PLAN DE EJECUCION COMPLETO - CIERRE DE GAPS **ID:** PLAN-EXEC-COMPLETO-2026-01-10 **Fecha:** 2026-01-10 **Version:** 1.0 **Sistema:** SIMCO v3.5 + CAPVED **Orquestador:** Claude Code - Opus 4.5 **Fase:** P (Planeacion) - FASE 3 --- ## 1. CONTEXTO ### 1.1 Vinculacion | Campo | Valor | |-------|-------| | Proyecto | erp-core | | Documento Base | ANALISIS-COMPLETO-PROYECTO-2026-01-10.md | | Epic | EPIC-CIERRE-GAPS-2026-01 | | Total GAPS | 33 | | Story Points | 220 SP | ### 1.2 Principios SIMCO Aplicables - @OP_BACKEND - Operaciones de backend - @OP_FRONTEND - Operaciones de frontend - @OP_DATABASE - Operaciones de base de datos - @VALIDAR - Validacion obligatoria - @DOC-PRIMERO - Documentacion primero - @TAREA - Gestion de tareas --- ## 2. ESTRUCTURA DEL PLAN ### 2.1 Fases de Ejecucion ``` SPRINT 1 (GAPS CRITICOS) -> 45 SP -> Prioridad: CRITICA SPRINT 2 (GAPS ALTOS) -> 47 SP -> Prioridad: ALTA SPRINT 3 (GAPS MEDIOS - P1) -> 45 SP -> Prioridad: MEDIA SPRINT 4 (GAPS MEDIOS - P2) -> 40 SP -> Prioridad: MEDIA SPRINT 5 (GAPS BAJOS + E2E) -> 43 SP -> Prioridad: BAJA ``` ### 2.2 Orden de Ejecucion por Sprint ``` Siempre: DATABASE -> BACKEND -> FRONTEND -> TESTS -> VALIDACION ``` --- ## 3. SPRINT 1: GAPS CRITICOS (45 SP) ### 3.1 Objetivos - Desbloquear funcionalidad core del ERP - Seeds de datos maestros criticos - Corregir calculo de impuestos - Habilitar API services criticos en frontend ### 3.2 Tareas en Orden de Ejecucion #### 3.2.1 DATABASE - Seeds Criticos (24 SP) | ID | Tarea | Archivo | Dependencias | SP | |----|-------|---------|--------------|-----| | S1-DB-01 | Crear seed de secuencias | `seeds/05-sequences.sql` | 04-users.sql | 5 | | S1-DB-02 | Crear seed de categorias producto | `seeds/06-product-categories.sql` | 05-sequences.sql | 3 | | S1-DB-03 | Crear seed financiero (COA, journals, taxes) | `seeds/07-financial-setup.sql` | 05-sequences.sql | 8 | | S1-DB-04 | Crear seed de inventario (warehouses, locations) | `seeds/08-inventory-setup.sql` | 06-product-categories.sql | 3 | | S1-DB-05 | Crear seed de productos | `seeds/09-products.sql` | 08-inventory-setup.sql | 5 | **Detalle S1-DB-01: Secuencias** ```sql -- Archivo: seeds/05-sequences.sql -- Contenido requerido: INSERT INTO core.sequences (id, tenant_id, company_id, code, name, prefix, suffix, padding, next_number, step) VALUES -- Ventas ('seq-so', 'tenant-1', 'company-1', 'SO', 'Sales Order', 'SO', '', 6, 1, 1), ('seq-qt', 'tenant-1', 'company-1', 'QT', 'Quotation', 'QT', '', 6, 1, 1), -- Compras ('seq-po', 'tenant-1', 'company-1', 'PO', 'Purchase Order', 'PO', '', 6, 1, 1), ('seq-rfq', 'tenant-1', 'company-1', 'RFQ', 'Request for Quotation', 'RFQ', '', 6, 1, 1), -- Financiero ('seq-inv', 'tenant-1', 'company-1', 'INV', 'Invoice', 'INV', '', 6, 1, 1), ('seq-bill', 'tenant-1', 'company-1', 'BILL', 'Vendor Bill', 'BILL', '', 6, 1, 1), ('seq-pay', 'tenant-1', 'company-1', 'PAY', 'Payment', 'PAY', '', 6, 1, 1), ('seq-je', 'tenant-1', 'company-1', 'JE', 'Journal Entry', 'JE', '', 6, 1, 1), -- Inventario ('seq-pick', 'tenant-1', 'company-1', 'PICK', 'Picking', 'PICK', '', 6, 1, 1), ('seq-adj', 'tenant-1', 'company-1', 'ADJ', 'Stock Adjustment', 'ADJ', '', 6, 1, 1), ('seq-lot', 'tenant-1', 'company-1', 'LOT', 'Lot/Batch', 'LOT', '', 6, 1, 1), -- Productos ('seq-prod', 'tenant-1', 'company-1', 'PROD', 'Product', 'PROD', '', 6, 1, 1), -- Partners ('seq-cust', 'tenant-1', 'company-1', 'CUST', 'Customer', 'CUST', '', 6, 1, 1), ('seq-vend', 'tenant-1', 'company-1', 'VEND', 'Vendor', 'VEND', '', 6, 1, 1), -- HR ('seq-emp', 'tenant-1', 'company-1', 'EMP', 'Employee', 'EMP', '', 6, 1, 1); ``` **Detalle S1-DB-03: Financial Setup** ```sql -- Archivo: seeds/07-financial-setup.sql -- Contenido requerido: -- 1. Account Types (10 registros) INSERT INTO financial.account_types (id, code, name, type, internal_group, balance_type) VALUES ('at-asset', 'ASSET', 'Activos', 'asset', 'asset', 'debit'), ('at-liability', 'LIABILITY', 'Pasivos', 'liability', 'liability', 'credit'), ('at-equity', 'EQUITY', 'Capital', 'equity', 'equity', 'credit'), ('at-revenue', 'REVENUE', 'Ingresos', 'revenue', 'income', 'credit'), ('at-expense', 'EXPENSE', 'Gastos', 'expense', 'expense', 'debit'), ('at-cogs', 'COGS', 'Costo de Ventas', 'expense', 'expense', 'debit'), ('at-bank', 'BANK', 'Bancos', 'asset', 'bank', 'debit'), ('at-cash', 'CASH', 'Efectivo', 'asset', 'cash', 'debit'), ('at-receivable', 'AR', 'Cuentas por Cobrar', 'asset', 'receivable', 'debit'), ('at-payable', 'AP', 'Cuentas por Pagar', 'liability', 'payable', 'credit'); -- 2. Chart of Accounts (50+ registros) -- Ver detalle en archivo completo -- 3. Journals (5 registros) INSERT INTO financial.journals (id, tenant_id, company_id, code, name, type, default_account_id) VALUES ('jnl-sales', 'tenant-1', 'company-1', 'SAL', 'Ventas', 'sale', 'acc-sales'), ('jnl-purchase', 'tenant-1', 'company-1', 'PUR', 'Compras', 'purchase', 'acc-purchases'), ('jnl-bank', 'tenant-1', 'company-1', 'BNK', 'Banco', 'bank', 'acc-bank'), ('jnl-cash', 'tenant-1', 'company-1', 'CSH', 'Caja', 'cash', 'acc-cash'), ('jnl-misc', 'tenant-1', 'company-1', 'MISC', 'Miscelaneos', 'general', null); -- 4. Fiscal Year (2 registros) INSERT INTO financial.fiscal_years (id, tenant_id, company_id, name, date_from, date_to, state) VALUES ('fy-2025', 'tenant-1', 'company-1', 'Ejercicio 2025', '2025-01-01', '2025-12-31', 'open'), ('fy-2026', 'tenant-1', 'company-1', 'Ejercicio 2026', '2026-01-01', '2026-12-31', 'open'); -- 5. Fiscal Periods (24 registros - 2 anios x 12 meses) -- Ver detalle en archivo completo -- 6. Taxes (5 registros) INSERT INTO financial.taxes (id, tenant_id, company_id, name, type_tax_use, amount_type, amount, tax_group_id, active) VALUES ('tax-iva-16', 'tenant-1', 'company-1', 'IVA 16%', 'sale', 'percent', 16.00, 'tg-iva', true), ('tax-iva-16-purchase', 'tenant-1', 'company-1', 'IVA 16% Compras', 'purchase', 'percent', 16.00, 'tg-iva', true), ('tax-iva-0', 'tenant-1', 'company-1', 'IVA 0%', 'sale', 'percent', 0.00, 'tg-iva', true), ('tax-isr-ret', 'tenant-1', 'company-1', 'Retencion ISR 10%', 'purchase', 'percent', -10.00, 'tg-isr', true), ('tax-iva-ret', 'tenant-1', 'company-1', 'Retencion IVA 2/3', 'purchase', 'percent', -10.67, 'tg-iva', true); -- 7. Payment Terms (5 registros) INSERT INTO financial.payment_terms (id, tenant_id, company_id, name, note, line_ids) VALUES ('pt-immediate', 'tenant-1', 'company-1', 'Pago Inmediato', 'Pago al contado', null), ('pt-15d', 'tenant-1', 'company-1', '15 Dias', 'Pago a 15 dias', null), ('pt-30d', 'tenant-1', 'company-1', '30 Dias', 'Pago a 30 dias', null), ('pt-60d', 'tenant-1', 'company-1', '60 Dias', 'Pago a 60 dias', null), ('pt-90d', 'tenant-1', 'company-1', '90 Dias', 'Pago a 90 dias', null); -- 8. Payment Methods (5 registros) INSERT INTO financial.payment_methods (id, tenant_id, company_id, name, code, payment_type) VALUES ('pm-cash', 'tenant-1', 'company-1', 'Efectivo', 'CASH', 'inbound'), ('pm-transfer', 'tenant-1', 'company-1', 'Transferencia', 'TRANSFER', 'inbound'), ('pm-check', 'tenant-1', 'company-1', 'Cheque', 'CHECK', 'inbound'), ('pm-card', 'tenant-1', 'company-1', 'Tarjeta', 'CARD', 'inbound'), ('pm-outbound', 'tenant-1', 'company-1', 'Pago a Proveedores', 'OUTBOUND', 'outbound'); ``` #### 3.2.2 BACKEND - Correccion de TODOs Criticos (8 SP) | ID | Tarea | Archivo | Linea | Descripcion | SP | |----|-------|---------|-------|-------------|-----| | S1-BE-01 | Implementar calculo de impuestos | `sales/quotations.service.ts` | 416 | Calcular taxes con TaxesService | 4 | | S1-BE-02 | Implementar calculo de impuestos | `sales/orders.service.ts` | 466 | Calcular taxes con TaxesService | 4 | **Detalle S1-BE-01: Implementacion de Calculo de Impuestos** ```typescript // Archivo: backend/src/modules/sales/quotations.service.ts // Linea 416 - Reemplazar: // const amountTax = 0; // TODO: Calculate taxes // Por: private async calculateLineTaxes(line: QuotationLine, tenantId: string): Promise { if (!line.taxIds || line.taxIds.length === 0) { return 0; } const taxes = await this.taxesService.findByIds(line.taxIds, tenantId); let taxAmount = 0; for (const tax of taxes) { if (tax.amountType === 'percent') { taxAmount += (line.priceSubtotal * tax.amount) / 100; } else if (tax.amountType === 'fixed') { taxAmount += tax.amount * line.productUomQty; } } return taxAmount; } // Y actualizar recalculateTotals: async recalculateTotals(quotationId: string, tenantId: string): Promise { const quotation = await this.findById(quotationId, tenantId); let amountUntaxed = 0; let amountTax = 0; for (const line of quotation.lines) { amountUntaxed += line.priceSubtotal; amountTax += await this.calculateLineTaxes(line, tenantId); } const amountTotal = amountUntaxed + amountTax; await this.quotationRepository.update(quotationId, { amountUntaxed, amountTax, amountTotal, updatedAt: new Date(), }); } ``` #### 3.2.3 FRONTEND - API Services Criticos (13 SP) | ID | Tarea | Archivo | Endpoints | SP | |----|-------|---------|-----------|-----| | S1-FE-01 | Crear Products API service | `features/products/api/products.api.ts` | 8 | 3 | | S1-FE-02 | Crear Inventory API service | `features/inventory/api/inventory.api.ts` | 25 | 5 | | S1-FE-03 | Crear Sales API service | `features/sales/api/sales.api.ts` | 20 | 5 | **Detalle S1-FE-01: Products API Service** ```typescript // Archivo: frontend/src/features/products/api/products.api.ts import { axiosInstance } from '@/services/api/axios-instance'; import { API_ENDPOINTS } from '@/shared/constants/api-endpoints'; import { Product, CreateProductDto, UpdateProductDto, PaginatedResponse } from '../types'; export const productsApi = { getAll: async (params?: Record): Promise> => { const response = await axiosInstance.get(API_ENDPOINTS.INVENTORY.PRODUCTS, { params }); return response.data; }, getById: async (id: string): Promise => { const response = await axiosInstance.get(`${API_ENDPOINTS.INVENTORY.PRODUCTS}/${id}`); return response.data; }, getStock: async (id: string): Promise => { const response = await axiosInstance.get(`${API_ENDPOINTS.INVENTORY.PRODUCTS}/${id}/stock`); return response.data; }, create: async (data: CreateProductDto): Promise => { const response = await axiosInstance.post(API_ENDPOINTS.INVENTORY.PRODUCTS, data); return response.data; }, update: async (id: string, data: UpdateProductDto): Promise => { const response = await axiosInstance.put(`${API_ENDPOINTS.INVENTORY.PRODUCTS}/${id}`, data); return response.data; }, delete: async (id: string): Promise => { await axiosInstance.delete(`${API_ENDPOINTS.INVENTORY.PRODUCTS}/${id}`); }, getByCategory: async (categoryId: string): Promise => { const response = await axiosInstance.get(API_ENDPOINTS.INVENTORY.PRODUCTS, { params: { categoryId } }); return response.data.data; }, search: async (query: string): Promise => { const response = await axiosInstance.get(API_ENDPOINTS.INVENTORY.PRODUCTS, { params: { search: query } }); return response.data.data; }, }; ``` **Detalle S1-FE-02: Inventory API Service** ```typescript // Archivo: frontend/src/features/inventory/api/inventory.api.ts import { axiosInstance } from '@/services/api/axios-instance'; import { API_ENDPOINTS } from '@/shared/constants/api-endpoints'; export const inventoryApi = { // Warehouses warehouses: { getAll: async (params?: Record) => { const response = await axiosInstance.get(API_ENDPOINTS.INVENTORY.WAREHOUSES, { params }); return response.data; }, getById: async (id: string) => { const response = await axiosInstance.get(`${API_ENDPOINTS.INVENTORY.WAREHOUSES}/${id}`); return response.data; }, getStock: async (id: string) => { const response = await axiosInstance.get(`${API_ENDPOINTS.INVENTORY.WAREHOUSES}/${id}/stock`); return response.data; }, create: async (data: any) => { const response = await axiosInstance.post(API_ENDPOINTS.INVENTORY.WAREHOUSES, data); return response.data; }, update: async (id: string, data: any) => { const response = await axiosInstance.put(`${API_ENDPOINTS.INVENTORY.WAREHOUSES}/${id}`, data); return response.data; }, delete: async (id: string) => { await axiosInstance.delete(`${API_ENDPOINTS.INVENTORY.WAREHOUSES}/${id}`); }, }, // Locations locations: { getAll: async (params?: Record) => { const response = await axiosInstance.get(API_ENDPOINTS.INVENTORY.LOCATIONS, { params }); return response.data; }, getById: async (id: string) => { const response = await axiosInstance.get(`${API_ENDPOINTS.INVENTORY.LOCATIONS}/${id}`); return response.data; }, getStock: async (id: string) => { const response = await axiosInstance.get(`${API_ENDPOINTS.INVENTORY.LOCATIONS}/${id}/stock`); return response.data; }, create: async (data: any) => { const response = await axiosInstance.post(API_ENDPOINTS.INVENTORY.LOCATIONS, data); return response.data; }, update: async (id: string, data: any) => { const response = await axiosInstance.put(`${API_ENDPOINTS.INVENTORY.LOCATIONS}/${id}`, data); return response.data; }, }, // Stock Moves stockMoves: { getAll: async (params?: Record) => { const response = await axiosInstance.get(API_ENDPOINTS.INVENTORY.STOCK_MOVES, { params }); return response.data; }, getById: async (id: string) => { const response = await axiosInstance.get(`${API_ENDPOINTS.INVENTORY.STOCK_MOVES}/${id}`); return response.data; }, }, // Pickings pickings: { getAll: async (params?: Record) => { const response = await axiosInstance.get(API_ENDPOINTS.INVENTORY.PICKINGS, { params }); return response.data; }, getById: async (id: string) => { const response = await axiosInstance.get(`${API_ENDPOINTS.INVENTORY.PICKINGS}/${id}`); return response.data; }, create: async (data: any) => { const response = await axiosInstance.post(API_ENDPOINTS.INVENTORY.PICKINGS, data); return response.data; }, confirm: async (id: string) => { const response = await axiosInstance.post(`${API_ENDPOINTS.INVENTORY.PICKINGS}/${id}/confirm`); return response.data; }, validate: async (id: string) => { const response = await axiosInstance.post(`${API_ENDPOINTS.INVENTORY.PICKINGS}/${id}/validate`); return response.data; }, cancel: async (id: string) => { const response = await axiosInstance.post(`${API_ENDPOINTS.INVENTORY.PICKINGS}/${id}/cancel`); return response.data; }, }, // Lots lots: { getAll: async (params?: Record) => { const response = await axiosInstance.get(API_ENDPOINTS.INVENTORY.LOTS, { params }); return response.data; }, getById: async (id: string) => { const response = await axiosInstance.get(`${API_ENDPOINTS.INVENTORY.LOTS}/${id}`); return response.data; }, create: async (data: any) => { const response = await axiosInstance.post(API_ENDPOINTS.INVENTORY.LOTS, data); return response.data; }, getMovements: async (id: string) => { const response = await axiosInstance.get(`${API_ENDPOINTS.INVENTORY.LOTS}/${id}/movements`); return response.data; }, }, // Adjustments adjustments: { getAll: async (params?: Record) => { const response = await axiosInstance.get(API_ENDPOINTS.INVENTORY.ADJUSTMENTS, { params }); return response.data; }, getById: async (id: string) => { const response = await axiosInstance.get(`${API_ENDPOINTS.INVENTORY.ADJUSTMENTS}/${id}`); return response.data; }, create: async (data: any) => { const response = await axiosInstance.post(API_ENDPOINTS.INVENTORY.ADJUSTMENTS, data); return response.data; }, confirm: async (id: string) => { const response = await axiosInstance.post(`${API_ENDPOINTS.INVENTORY.ADJUSTMENTS}/${id}/confirm`); return response.data; }, validate: async (id: string) => { const response = await axiosInstance.post(`${API_ENDPOINTS.INVENTORY.ADJUSTMENTS}/${id}/validate`); return response.data; }, cancel: async (id: string) => { const response = await axiosInstance.post(`${API_ENDPOINTS.INVENTORY.ADJUSTMENTS}/${id}/cancel`); return response.data; }, }, }; ``` ### 3.3 Validacion Sprint 1 | Tipo | Comando | Criterio Exito | |------|---------|----------------| | Seeds | `./scripts/recreate-database.sh --force` | 0 errores | | Build Backend | `npm run build` | 0 errores | | Lint Backend | `npm run lint` | 0 errores | | Tests Backend | `npm test` | PASS all | | Build Frontend | `npm run build` | 0 errores | --- ## 4. SPRINT 2: GAPS ALTOS (47 SP) ### 4.1 Objetivos - Implementar email service productivo - Completar permission middleware - Tests para Sales y Purchases - Tests para Audit (compliance) - Seeds de listas de precio ### 4.2 Tareas en Orden de Ejecucion #### 4.2.1 DATABASE - Seeds Adicionales (6 SP) | ID | Tarea | Archivo | SP | |----|-------|---------|-----| | S2-DB-01 | Crear seed de listas de precio | `seeds/10-pricelists.sql` | 3 | | S2-DB-02 | Actualizar seed de partners con direcciones | `seeds/11-sample-partners.sql` | 3 | #### 4.2.2 BACKEND - Correccion de TODOs Altos (15 SP) | ID | Tarea | Archivo | Linea | SP | |----|-------|---------|-------|-----| | S2-BE-01 | Implementar email service productivo | `shared/services/email.service.ts` | 66 | 5 | | S2-BE-02 | Implementar envio de email cotizacion | `sales/quotations.service.ts` | 478 | 3 | | S2-BE-03 | Completar permission middleware | `shared/middleware/auth.middleware.ts` | 81 | 5 | | S2-BE-04 | Integrar notifications con scheduler | `reports/scheduler.service.ts` | 360 | 2 | **Detalle S2-BE-01: Email Service Productivo** ```typescript // Archivo: backend/src/shared/services/email.service.ts // Linea 66 - Implementar SendGrid/Nodemailer/AWS SES import { Injectable } from '@nestjs/common'; import * as nodemailer from 'nodemailer'; import { ConfigService } from '@nestjs/config'; @Injectable() export class EmailService { private transporter: nodemailer.Transporter; constructor(private configService: ConfigService) { const emailProvider = this.configService.get('EMAIL_PROVIDER'); if (emailProvider === 'smtp') { this.transporter = nodemailer.createTransport({ host: this.configService.get('SMTP_HOST'), port: this.configService.get('SMTP_PORT'), secure: this.configService.get('SMTP_SECURE'), auth: { user: this.configService.get('SMTP_USER'), pass: this.configService.get('SMTP_PASSWORD'), }, }); } else if (emailProvider === 'sendgrid') { // SendGrid implementation this.transporter = nodemailer.createTransport({ service: 'SendGrid', auth: { user: 'apikey', pass: this.configService.get('SENDGRID_API_KEY'), }, }); } } async sendEmail(options: { to: string; subject: string; html: string; attachments?: any[]; }): Promise { const from = this.configService.get('EMAIL_FROM'); if (this.configService.get('NODE_ENV') === 'development') { console.log('[EMAIL-DEV] Would send:', { to: options.to, subject: options.subject }); return; } await this.transporter.sendMail({ from, to: options.to, subject: options.subject, html: options.html, attachments: options.attachments, }); } async sendQuotationEmail(quotation: any, recipientEmail: string): Promise { const html = this.generateQuotationHtml(quotation); await this.sendEmail({ to: recipientEmail, subject: `Cotizacion ${quotation.name} - ${quotation.companyName}`, html, }); } private generateQuotationHtml(quotation: any): string { return `

Cotizacion ${quotation.name}

Estimado ${quotation.partnerName},

Adjunto encontrara nuestra cotizacion por un monto de ${quotation.currencySymbol}${quotation.amountTotal.toFixed(2)}.

Quedo a sus ordenes.

`; } } ``` #### 4.2.3 BACKEND - Tests Criticos (26 SP) | ID | Tarea | Archivo | Tests Estimados | SP | |----|-------|---------|-----------------|-----| | S2-BE-05 | Tests orders.service | `sales/__tests__/orders.service.spec.ts` | 35 | 5 | | S2-BE-06 | Tests quotations.service | `sales/__tests__/quotations.service.spec.ts` | 35 | 5 | | S2-BE-07 | Tests pricelists.service | `sales/__tests__/pricelists.service.spec.ts` | 20 | 3 | | S2-BE-08 | Tests purchases.service | `purchases/__tests__/purchases.service.spec.ts` | 30 | 5 | | S2-BE-09 | Tests audit.service | `audit/__tests__/audit.service.spec.ts` | 25 | 3 | | S2-BE-10 | Tests access-logs.service | `audit/__tests__/access-logs.service.spec.ts` | 20 | 3 | | S2-BE-11 | Tests security-events.service | `audit/__tests__/security-events.service.spec.ts` | 15 | 2 | ### 4.3 Validacion Sprint 2 | Tipo | Comando | Criterio Exito | |------|---------|----------------| | Seeds | `./scripts/recreate-database.sh --force` | 0 errores | | Tests Backend | `npm test -- --coverage` | >50% coverage | | Email Test | Manual verification | Email received | --- ## 5. SPRINT 3: GAPS MEDIOS - Parte 1 (45 SP) ### 5.1 Objetivos - Tests para HR, Reports, Projects - Frontend API services para Projects, CRM ### 5.2 Tareas #### 5.2.1 BACKEND - Tests (35 SP) | ID | Tarea | Archivo | Tests | SP | |----|-------|---------|-------|-----| | S3-BE-01 | Tests employees.service | `hr/__tests__/employees.service.spec.ts` | 30 | 5 | | S3-BE-02 | Tests contracts.service | `hr/__tests__/contracts.service.spec.ts` | 25 | 3 | | S3-BE-03 | Tests leaves.service | `hr/__tests__/leaves.service.spec.ts` | 25 | 3 | | S3-BE-04 | Tests payslips.service | `hr/__tests__/payslips.service.spec.ts` | 35 | 5 | | S3-BE-05 | Tests departments.service | `hr/__tests__/departments.service.spec.ts` | 15 | 2 | | S3-BE-06 | Tests reports.service | `reports/__tests__/reports.service.spec.ts` | 20 | 3 | | S3-BE-07 | Tests dashboards.service | `reports/__tests__/dashboards.service.spec.ts` | 20 | 3 | | S3-BE-08 | Tests report-builder.service | `reports/__tests__/report-builder.service.spec.ts` | 20 | 3 | | S3-BE-09 | Tests projects.service | `projects/__tests__/projects.service.spec.ts` | 25 | 3 | | S3-BE-10 | Tests tasks.service | `projects/__tests__/tasks.service.spec.ts` | 25 | 3 | | S3-BE-11 | Tests timesheets.service | `projects/__tests__/timesheets.service.spec.ts` | 20 | 2 | #### 5.2.2 FRONTEND - API Services (10 SP) | ID | Tarea | Archivo | SP | |----|-------|---------|-----| | S3-FE-01 | Crear Projects API service | `features/projects/api/projects.api.ts` | 5 | | S3-FE-02 | Crear CRM API service | `features/crm/api/crm.api.ts` | 5 | --- ## 6. SPRINT 4: GAPS MEDIOS - Parte 2 (40 SP) ### 6.1 Objetivos - Tests para Financial, Inventory, CRM - Frontend API services para HR, Purchases ### 6.2 Tareas #### 6.2.1 BACKEND - Tests (30 SP) | ID | Tarea | Archivo | Tests | SP | |----|-------|---------|-------|-----| | S4-BE-01 | Tests taxes.service | `financial/__tests__/taxes.service.spec.ts` | 25 | 3 | | S4-BE-02 | Tests journals.service | `financial/__tests__/journals.service.spec.ts` | 20 | 3 | | S4-BE-03 | Tests fiscalPeriods.service | `financial/__tests__/fiscalPeriods.service.spec.ts` | 20 | 3 | | S4-BE-04 | Tests reconcile-models.service | `financial/__tests__/reconcile-models.service.spec.ts` | 25 | 5 | | S4-BE-05 | Tests warehouses.service | `inventory/__tests__/warehouses.service.spec.ts` | 20 | 3 | | S4-BE-06 | Tests locations.service | `inventory/__tests__/locations.service.spec.ts` | 20 | 3 | | S4-BE-07 | Tests pickings.service | `inventory/__tests__/pickings.service.spec.ts` | 30 | 5 | | S4-BE-08 | Tests leads.service | `crm/__tests__/leads.service.spec.ts` | 25 | 3 | | S4-BE-09 | Tests opportunities.service | `crm/__tests__/opportunities.service.spec.ts` | 25 | 2 | #### 6.2.2 FRONTEND - API Services (10 SP) | ID | Tarea | Archivo | SP | |----|-------|---------|-----| | S4-FE-01 | Crear HR API service | `features/hr/api/hr.api.ts` | 5 | | S4-FE-02 | Crear Purchases API service | `features/purchases/api/purchases.api.ts` | 5 | --- ## 7. SPRINT 5: GAPS BAJOS + E2E (43 SP) ### 7.1 Objetivos - Tests restantes (System, Shared, minor services) - Tests E2E con Playwright - Seeds opcionales (HR, CRM, Projects) ### 7.2 Tareas #### 7.2.1 BACKEND - Tests Restantes (14 SP) | ID | Tarea | Archivo | Tests | SP | |----|-------|---------|-------|-----| | S5-BE-01 | Tests token.service | `auth/__tests__/token.service.spec.ts` | 20 | 3 | | S5-BE-02 | Tests base.service | `shared/__tests__/base.service.spec.ts` | 15 | 2 | | S5-BE-03 | Tests email.service | `shared/__tests__/email.service.spec.ts` | 15 | 2 | | S5-BE-04 | Tests cache.service | `shared/__tests__/cache.service.spec.ts` | 15 | 2 | | S5-BE-05 | Tests notifications.service | `system/__tests__/notifications.service.spec.ts` | 15 | 2 | | S5-BE-06 | Tests companies.service | `companies/__tests__/companies.service.spec.ts` | 15 | 3 | #### 7.2.2 E2E TESTS (21 SP) | ID | Tarea | Archivo | Flujos | SP | |----|-------|---------|--------|-----| | S5-E2E-01 | Setup Playwright | `e2e/playwright.config.ts` | - | 3 | | S5-E2E-02 | Auth E2E tests | `e2e/tests/auth.spec.ts` | Login, Register, MFA | 5 | | S5-E2E-03 | Sales E2E tests | `e2e/tests/sales.spec.ts` | Quote to Order | 5 | | S5-E2E-04 | Inventory E2E tests | `e2e/tests/inventory.spec.ts` | Stock movement | 5 | | S5-E2E-05 | Financial E2E tests | `e2e/tests/financial.spec.ts` | Invoice to Payment | 3 | #### 7.2.3 DATABASE - Seeds Opcionales (8 SP) | ID | Tarea | Archivo | SP | |----|-------|---------|-----| | S5-DB-01 | Seeds HR demo | `seeds/demo/hr-demo.sql` | 3 | | S5-DB-02 | Seeds CRM demo | `seeds/demo/crm-demo.sql` | 2 | | S5-DB-03 | Seeds Projects demo | `seeds/demo/projects-demo.sql` | 3 | --- ## 8. RESUMEN DEL PLAN ### 8.1 Por Sprint | Sprint | Foco | Story Points | Archivos | |--------|------|--------------|----------| | Sprint 1 | GAPS Criticos | 45 SP | 11 archivos | | Sprint 2 | GAPS Altos | 47 SP | 13 archivos | | Sprint 3 | GAPS Medios P1 | 45 SP | 13 archivos | | Sprint 4 | GAPS Medios P2 | 40 SP | 11 archivos | | Sprint 5 | GAPS Bajos + E2E | 43 SP | 14 archivos | | **TOTAL** | - | **220 SP** | **62 archivos** | ### 8.2 Por Tipo de Trabajo | Tipo | Story Points | % Total | |------|--------------|---------| | Database Seeds | 38 SP | 17% | | Backend TODOs | 23 SP | 10% | | Backend Tests | 96 SP | 44% | | Frontend APIs | 41 SP | 19% | | E2E Tests | 21 SP | 10% | ### 8.3 Cobertura Final Esperada | Metrica | Actual | Esperado Post-Plan | |---------|--------|-------------------| | Servicios con tests | 39.5% | 95%+ | | Tablas con seeds | 14.1% | 80%+ | | Frontend API coverage | 60% | 100% | | E2E flows | 0 | 4 flujos criticos | --- ## 9. DEPENDENCIAS CRITICAS ### 9.1 Dependencias entre Tareas ``` S1-DB-01 (sequences) └── S1-DB-02 (categories) └── S1-DB-03 (financial) └── S1-BE-01 (tax calculation) └── S1-BE-02 (tax calculation) └── S1-DB-04 (inventory) └── S1-DB-05 (products) └── S1-FE-01 (products api) └── S1-FE-02 (inventory api) S2-BE-01 (email service) └── S2-BE-02 (quotation email) S2-BE-03 (permission middleware) └── Depends on: roles/permissions seeds (existentes) ``` ### 9.2 Archivos con Multiples Dependencias | Archivo | Dependencias | Impacto si Falla | |---------|-------------|------------------| | `seeds/05-sequences.sql` | Todos los documentos | CRITICO | | `seeds/07-financial-setup.sql` | Invoices, Payments, Taxes | CRITICO | | `sales/quotations.service.ts` | Taxes, Email, Partners | ALTO | | `shared/services/email.service.ts` | Quotations, Reports, Notifications | ALTO | --- ## 10. CRITERIOS DE ACEPTACION POR SPRINT ### Sprint 1 - [ ] Seeds ejecutan sin errores en recreate-database.sh - [ ] COA tiene 50+ cuentas correctamente jerarquizadas - [ ] Impuestos calculan correctamente en quotations y orders - [ ] Frontend Products API consume endpoint correctamente - [ ] Frontend Inventory API consume endpoints correctamente - [ ] Frontend Sales API consume endpoints correctamente ### Sprint 2 - [ ] Email service envia correos en produccion - [ ] Permission middleware valida permisos desde DB - [ ] Tests Sales tienen >80% coverage - [ ] Tests Purchases tienen >80% coverage - [ ] Tests Audit tienen >80% coverage ### Sprint 3 - [ ] Tests HR tienen >80% coverage - [ ] Tests Reports tienen >80% coverage - [ ] Tests Projects tienen >80% coverage - [ ] Frontend Projects API funcional - [ ] Frontend CRM API funcional ### Sprint 4 - [ ] Tests Financial adicionales >80% coverage - [ ] Tests Inventory adicionales >80% coverage - [ ] Tests CRM tienen >80% coverage - [ ] Frontend HR API funcional - [ ] Frontend Purchases API funcional ### Sprint 5 - [ ] Cobertura total backend >90% - [ ] E2E Auth flow pasa - [ ] E2E Sales flow pasa - [ ] E2E Inventory flow pasa - [ ] E2E Financial flow pasa --- ## 11. RIESGOS Y MITIGACION | Riesgo | Probabilidad | Impacto | Mitigacion | |--------|-------------|---------|------------| | Tax calculation compleja | MEDIA | ALTO | Usar TaxesService existente, solo integrar | | Email provider config | BAJA | MEDIO | Usar nodemailer con SMTP generico | | Tests E2E inestables | ALTA | MEDIO | Usar fixtures, evitar datos dinamicos | | Seeds conflicto IDs | MEDIA | ALTO | Usar UUIDs generados, no hardcoded | | Dependencias circulares | BAJA | ALTO | Revisar imports antes de implementar | --- ## 12. DOCUMENTACION REQUERIDA ### Por Sprint | Sprint | Documentos a Actualizar | |--------|------------------------| | Sprint 1 | MASTER_INVENTORY.yml, REPORTE-EJECUCION-S1.md | | Sprint 2 | MASTER_INVENTORY.yml, REPORTE-EJECUCION-S2.md | | Sprint 3 | MASTER_INVENTORY.yml, REPORTE-EJECUCION-S3.md | | Sprint 4 | MASTER_INVENTORY.yml, REPORTE-EJECUCION-S4.md | | Sprint 5 | MASTER_INVENTORY.yml, REPORTE-FINAL.md | --- **Documento generado por:** ORQUESTADOR (Claude Code Opus 4.5) **Sistema:** SIMCO v3.5 + CAPVED **Fase:** P (Planeacion) - COMPLETADA **Siguiente fase:** V (Validacion de Plan)