# US-MGN-004-004-001: CRUD de Impuestos **RF Asociado:** [RF-MGN-004-004](../../02-modelado/requerimientos-funcionales/mgn-004/RF-MGN-004-004-gestión-de-impuestos.md) **Módulo:** MGN-004 - Financiero Básico **Epic:** Impuestos **Prioridad:** P0 (MVP) **Story Points:** 5 **Sprint:** Sprint 9 **Estado:** Ready for Development **Fecha:** 2025-11-24 --- ## User Story **Como** contador, **Quiero** crear y gestionar impuestos (IVA, retenciones, etc.), **Para** calcular automáticamente los impuestos en facturas y generar reportes fiscales. --- ## Descripción Detallada Los impuestos son configuraciones que definen cómo calcular impuestos sobre transacciones. Cada impuesto tiene: - Código y nombre (ej: "IVA 21%") - Tipo: sale (ventas), purchase (compras), both (ambos) - Método de cálculo: percentage (porcentaje) o fixed (monto fijo) - Rate (tasa): 0-100 para percentage, monto para fixed - Cuentas contables asociadas (tax_collected_account, tax_paid_account) - Grupo de impuestos (opcional, para impuestos compuestos) --- ## Criterios de Aceptación ### Escenario 1: Crear impuesto porcentual exitosamente **Dado que** soy contador con permisos accounting_manager, **Cuando** creo un impuesto con code="IVA21", name="IVA 21%", type="both", rate=21.0, method="percentage", **Entonces** el sistema crea el impuesto y retorna el registro con id y company_id. ### Escenario 2: Validar rate entre 0 y 100 **Dado que** intento crear un impuesto con rate=150, **Cuando** envío el request, **Entonces** el sistema retorna error 400 "Rate debe estar entre 0 y 100". ### Escenario 3: Listar impuestos con filtro por tipo **Dado que** tengo impuestos de tipo sale y purchase, **Cuando** listo impuestos con filtro type="sale", **Entonces** el sistema retorna solo impuestos aplicables a ventas (type='sale' o type='both'). ### Escenario 4: Calcular monto de impuesto **Dado que** tengo un impuesto con rate=21%, **Cuando** calculo el impuesto sobre base=1000, **Entonces** el sistema retorna tax_amount=210. ### Escenario 5: Validar cuenta contable existe **Dado que** intento crear un impuesto con tax_collected_account_id=999 (no existe), **Cuando** envío el request, **Entonces** el sistema retorna error 400 "Cuenta contable no encontrada". --- ## Reglas de Negocio - **RN-1:** Code debe ser único por empresa. - **RN-2:** Tipos válidos: sale, purchase, both. - **RN-3:** Métodos válidos: percentage, fixed. - **RN-4:** Rate debe estar entre 0 y 100 para percentage. - **RN-5:** tax_collected_account_id es obligatorio para type='sale' o 'both'. - **RN-6:** tax_paid_account_id es obligatorio para type='purchase' o 'both'. - **RN-7:** Impuestos pueden estar activos o inactivos. - **RN-8:** RLS filtra por company_id. --- ## Tareas Técnicas ### Backend - [ ] Endpoint: `POST /api/v1/financial/taxes` - [ ] Endpoint: `GET /api/v1/financial/taxes` (filtros: type, active) - [ ] Endpoint: `GET /api/v1/financial/taxes/:id` - [ ] Endpoint: `PUT /api/v1/financial/taxes/:id` - [ ] Endpoint: `DELETE /api/v1/financial/taxes/:id` (soft delete) - [ ] Endpoint: `POST /api/v1/financial/taxes/calculate` (calcular impuesto) - [ ] Service: `TaxService.create/findAll/findOne/update/remove/calculateTax` - [ ] DTO: `CreateTaxDto` (validaciones @Min(0) @Max(100) para rate) - [ ] DTO: `CalculateTaxDto` (tax_id, base_amount) - [ ] Unit tests (10 test cases) - [ ] Integration tests (8 test cases) ### Frontend - [ ] Página: `TaxesPage.tsx` (/financial/taxes) - [ ] Componente: `TaxesTable.tsx` - [ ] Componente: `CreateTaxForm.tsx` - [ ] API client: `taxApi.ts` - [ ] Store: `useTaxStore.ts` - [ ] Component tests (5 test cases) - [ ] E2E test: "should create tax successfully" ### Database - [ ] Tabla: `financial.taxes` (ya existe) - [ ] Índices: idx_taxes_company_id, idx_taxes_type, idx_taxes_code - [ ] Constraint: uq_taxes_code_company - [ ] RLS policy: company_isolation_taxes --- ## Mockups / Wireframes **Formulario Crear Impuesto:** ``` ┌───────────────────────────────────────┐ │ Código: [IVA21__] (required) │ │ Nombre: [IVA 21%__] (required) │ │ Tipo: [Ambos ▼] (Sale/Purchase/Both) │ │ Método: [Porcentaje ▼] (%) │ │ Tasa: [21___] % │ │ Cuenta Impuesto Cobrado: [Select ▼] │ │ Cuenta Impuesto Pagado: [Select ▼] │ │ Activo: [✓] │ │ [Guardar] [Cancelar] │ └───────────────────────────────────────┘ ``` --- ## Casos de Prueba ### Funcionales 1. **TC-001:** Crear impuesto percentage exitosamente 2. **TC-002:** Crear impuesto fixed exitosamente 3. **TC-003:** Error por rate > 100 4. **TC-004:** Error por código duplicado 5. **TC-005:** Listar impuestos con filtro type 6. **TC-006:** Calcular impuesto 21% sobre 1000 = 210 7. **TC-007:** Validar cuenta contable existe 8. **TC-008:** RLS filtra por empresa ### No Funcionales 1. **Performance:** < 200ms 2. **Seguridad:** JWT + accounting_manager --- ## Dependencias - **US bloqueantes:** - US-MGN-004-001-001 (CRUD Cuentas) - Para tax_collected_account_id - US-MGN-002-001-001 (CRUD Empresas) - **Módulos:** MGN-002, MGN-004 --- ## Estimación Detallada | Tarea | Estimación | |-------|------------| | Backend | 3 horas | | Frontend | 3 horas | | Testing | 2 horas | | Code Review | 1 hora | | **TOTAL** | **9 horas = 5 SP** | --- ## Definition of Done - [ ] Código implementado - [ ] Tests pasando (>80%) - [ ] Code review aprobado - [ ] Swagger docs actualizado - [ ] RLS aplicado - [ ] Merge a develop - [ ] QA validado - [ ] PO aprobado --- ## Referencias - [RF-MGN-004-004](../../02-modelado/requerimientos-funcionales/mgn-004/RF-MGN-004-004-gestión-de-impuestos.md) - [ET-BACKEND-MGN-004-004](../../02-modelado/especificaciones-tecnicas/backend/mgn-004/ET-BACKEND-MGN-004-004-gestión-de-impuestos.md) - [ET-FRONTEND-MGN-004-004](../../02-modelado/especificaciones-tecnicas/frontend/mgn-004/ET-FRONTEND-MGN-004-004-gestión-de-impuestos.md) - [TRACEABILITY-MGN-004.yaml](../../02-modelado/trazabilidad/TRACEABILITY-MGN-004.yaml) - [Financial Schema DDL](../../02-modelado/database-design/schemas/financial-schema-ddl.sql)