# 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<number> {
  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<void> {
  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<string, any>): Promise<PaginatedResponse<Product>> => {
    const response = await axiosInstance.get(API_ENDPOINTS.INVENTORY.PRODUCTS, { params });
    return response.data;
  },

  getById: async (id: string): Promise<Product> => {
    const response = await axiosInstance.get(`${API_ENDPOINTS.INVENTORY.PRODUCTS}/${id}`);
    return response.data;
  },

  getStock: async (id: string): Promise<any> => {
    const response = await axiosInstance.get(`${API_ENDPOINTS.INVENTORY.PRODUCTS}/${id}/stock`);
    return response.data;
  },

  create: async (data: CreateProductDto): Promise<Product> => {
    const response = await axiosInstance.post(API_ENDPOINTS.INVENTORY.PRODUCTS, data);
    return response.data;
  },

  update: async (id: string, data: UpdateProductDto): Promise<Product> => {
    const response = await axiosInstance.put(`${API_ENDPOINTS.INVENTORY.PRODUCTS}/${id}`, data);
    return response.data;
  },

  delete: async (id: string): Promise<void> => {
    await axiosInstance.delete(`${API_ENDPOINTS.INVENTORY.PRODUCTS}/${id}`);
  },

  getByCategory: async (categoryId: string): Promise<Product[]> => {
    const response = await axiosInstance.get(API_ENDPOINTS.INVENTORY.PRODUCTS, {
      params: { categoryId }
    });
    return response.data.data;
  },

  search: async (query: string): Promise<Product[]> => {
    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<string, any>) => {
      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<string, any>) => {
      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<string, any>) => {
      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<string, any>) => {
      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<string, any>) => {
      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<string, any>) => {
      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<string>('EMAIL_PROVIDER');

    if (emailProvider === 'smtp') {
      this.transporter = nodemailer.createTransport({
        host: this.configService.get<string>('SMTP_HOST'),
        port: this.configService.get<number>('SMTP_PORT'),
        secure: this.configService.get<boolean>('SMTP_SECURE'),
        auth: {
          user: this.configService.get<string>('SMTP_USER'),
          pass: this.configService.get<string>('SMTP_PASSWORD'),
        },
      });
    } else if (emailProvider === 'sendgrid') {
      // SendGrid implementation
      this.transporter = nodemailer.createTransport({
        service: 'SendGrid',
        auth: {
          user: 'apikey',
          pass: this.configService.get<string>('SENDGRID_API_KEY'),
        },
      });
    }
  }

  async sendEmail(options: {
    to: string;
    subject: string;
    html: string;
    attachments?: any[];
  }): Promise<void> {
    const from = this.configService.get<string>('EMAIL_FROM');

    if (this.configService.get<string>('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<void> {
    const html = this.generateQuotationHtml(quotation);
    await this.sendEmail({
      to: recipientEmail,
      subject: `Cotizacion ${quotation.name} - ${quotation.companyName}`,
      html,
    });
  }

  private generateQuotationHtml(quotation: any): string {
    return `
      <h1>Cotizacion ${quotation.name}</h1>
      <p>Estimado ${quotation.partnerName},</p>
      <p>Adjunto encontrara nuestra cotizacion por un monto de ${quotation.currencySymbol}${quotation.amountTotal.toFixed(2)}.</p>
      <p>Quedo a sus ordenes.</p>
    `;
  }
}
```

#### 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)
