erp-core/docs/04-modelado/trazabilidad/TRACEABILITY-MGN-007.yaml

1145 lines
43 KiB
YAML

# TRACEABILITY-MGN-007.yaml
# Matriz de Trazabilidad - MGN-007: Ventas Básico
# Fecha: 2025-11-24
# Versión: 1.0
module:
id: MGN-007
name: "Ventas Básico"
description: "Gestión completa del ciclo de ventas: cotizaciones, órdenes, entregas, facturación y reportes"
priority: P0
story_points: 45
status: Diseñado
metadata:
total_rf: 6
total_et_backend: 6
total_et_frontend: 6
total_tables: 5
total_tests: 120
coverage: 100%
requirements:
- rf_id: RF-MGN-007-001
rf_title: "Gestión de Cotizaciones"
rf_file: "requerimientos-funcionales/mgn-007/RF-MGN-007-001-gestión-de-cotizaciones.md"
priority: P0
story_points: 8
et_backend:
file: "especificaciones-tecnicas/backend/mgn-007/ET-BACKEND-MGN-007-001-gestión-de-cotizaciones.md"
endpoints:
- method: POST
path: /api/v1/sales/quotations
description: "Crear nueva cotización"
- method: GET
path: /api/v1/sales/quotations
description: "Listar todas las cotizaciones"
- method: GET
path: /api/v1/sales/quotations/:id
description: "Obtener cotización por ID"
- method: PUT
path: /api/v1/sales/quotations/:id
description: "Actualizar cotización"
- method: DELETE
path: /api/v1/sales/quotations/:id
description: "Eliminar cotización (soft delete)"
services:
- name: "QuotationService"
file: "src/modules/sales/services/quotation.service.ts"
methods:
- create
- findAll
- findOne
- update
- remove
- validateBusinessRules
- calculateTotals
controllers:
- name: "QuotationController"
file: "src/modules/sales/controllers/quotation.controller.ts"
dtos:
- name: "CreateQuotationDto"
file: "src/modules/sales/dto/create-quotation.dto.ts"
- name: "UpdateQuotationDto"
file: "src/modules/sales/dto/update-quotation.dto.ts"
- name: "QuotationResponseDto"
file: "src/modules/sales/dto/quotation-response.dto.ts"
- name: "FilterQuotationDto"
file: "src/modules/sales/dto/filter-quotation.dto.ts"
et_frontend:
file: "especificaciones-tecnicas/frontend/mgn-007/ET-FRONTEND-MGN-007-001-gestión-de-cotizaciones.md"
routes:
- path: "/sales/quotations"
component: "QuotationsPage"
- path: "/sales/quotations/create"
component: "CreateQuotationPage"
- path: "/sales/quotations/:id/edit"
component: "EditQuotationPage"
- path: "/sales/quotations/:id"
component: "ViewQuotationPage"
components:
- name: "QuotationsTable"
file: "src/widgets/quotations-table/ui/QuotationsTable.tsx"
type: widget
- name: "CreateQuotationForm"
file: "src/features/create-quotation/ui/CreateQuotationForm.tsx"
type: feature
- name: "QuotationCard"
file: "src/entities/quotation/ui/QuotationCard.tsx"
type: entity
- name: "QuotationPage"
file: "src/pages/sales/QuotationPage.tsx"
type: page
api_client:
- name: "quotationApi"
file: "src/entities/quotation/api/quotation.api.ts"
methods:
- getAll
- getById
- create
- update
- delete
state_management:
- name: "useQuotationStore"
file: "src/entities/quotation/model/quotation.store.ts"
type: zustand
- name: "useQuotations"
file: "src/entities/quotation/api/quotation.queries.ts"
type: react-query
database_tables:
- schema: sales
table: quotations
file: "database-design/schemas/sales-schema-ddl.sql"
operations:
- SELECT
- INSERT
- UPDATE
- DELETE (soft)
indices:
- idx_quotations_tenant_id
- idx_quotations_partner_id
- idx_quotations_state
- idx_quotations_date
rls_policy: tenant_isolation_quotations
- schema: sales
table: quotation_lines
file: "database-design/schemas/sales-schema-ddl.sql"
operations:
- SELECT
- INSERT
- UPDATE
- DELETE
indices:
- idx_quotation_lines_quotation_id
- idx_quotation_lines_product_id
rls_policy: tenant_isolation_quotation_lines
tests:
backend:
unit_tests:
- file: "src/modules/sales/services/quotation.service.spec.ts"
test_cases:
- "should create quotation with valid data"
- "should throw error when partner not found"
- "should calculate totals correctly"
- "should find all quotations for tenant"
- "should update quotation successfully"
integration_tests:
- file: "test/sales/quotation.controller.e2e-spec.ts"
test_cases:
- "POST /api/v1/sales/quotations should create quotation"
- "GET /api/v1/sales/quotations should return all quotations"
- "GET /api/v1/sales/quotations/:id should return quotation"
- "PUT /api/v1/sales/quotations/:id should update quotation"
- "DELETE /api/v1/sales/quotations/:id should soft delete quotation"
- "should enforce tenant isolation"
- "should require authentication"
- "should check permissions"
frontend:
component_tests:
- file: "src/widgets/quotations-table/ui/QuotationsTable.test.tsx"
test_cases:
- "should render table with quotations"
- "should handle pagination"
- "should call delete on button click"
- file: "src/features/create-quotation/ui/CreateQuotationForm.test.tsx"
test_cases:
- "should validate required fields"
- "should submit valid form"
- "should show error messages"
e2e_tests:
- file: "e2e/sales/quotations.spec.ts"
test_cases:
- "should create quotation successfully"
- "should edit quotation successfully"
- "should delete quotation with confirmation"
- "should enforce permissions"
acceptance_criteria:
- id: AC-001
description: "Usuario puede crear cotizaciones con líneas de productos"
status: Pending
test_reference: "test/sales/quotation.controller.e2e-spec.ts:30"
- id: AC-002
description: "Sistema calcula automáticamente subtotales, impuestos y totales"
status: Pending
test_reference: "src/modules/sales/services/quotation.service.spec.ts:58"
- id: AC-003
description: "Cotizaciones soportan múltiples monedas con conversión"
status: Pending
test_reference: "test/sales/quotation.controller.e2e-spec.ts:92"
business_rules:
- id: RN-001
description: "Cotización debe tener al menos una línea de producto"
implementation: "src/modules/sales/services/quotation.service.ts:validateQuotationLines()"
test_reference: "src/modules/sales/services/quotation.service.spec.ts:82"
- id: RN-002
description: "Fecha de validez debe ser posterior a fecha de cotización"
implementation: "src/modules/sales/services/quotation.service.ts:validateDates()"
test_reference: "src/modules/sales/services/quotation.service.spec.ts:105"
- id: RN-003
description: "Estado inicial de cotización debe ser 'draft'"
implementation: "src/modules/sales/services/quotation.service.ts:create()"
test_reference: "src/modules/sales/services/quotation.service.spec.ts:128"
dependencies:
rf_dependencies:
- RF-MGN-003-001
- RF-MGN-005-001
module_dependencies:
- MGN-001
- MGN-003
- MGN-005
external_dependencies:
- name: "@nestjs/common"
version: "^10.0.0"
- name: "ant-design"
version: "^5.0.0"
- rf_id: RF-MGN-007-002
rf_title: "Conversión a Órdenes de Venta"
rf_file: "requerimientos-funcionales/mgn-007/RF-MGN-007-002-conversión-a-órdenes-de-venta.md"
priority: P0
story_points: 5
et_backend:
file: "especificaciones-tecnicas/backend/mgn-007/ET-BACKEND-MGN-007-002-conversión-a-órdenes-de-venta.md"
endpoints:
- method: POST
path: /api/v1/sales/quotations/:id/confirm
description: "Confirmar cotización y crear orden de venta"
- method: POST
path: /api/v1/sales/quotations/:id/cancel
description: "Cancelar cotización"
- method: POST
path: /api/v1/sales/quotations/:id/send
description: "Enviar cotización por email"
services:
- name: "QuotationService"
file: "src/modules/sales/services/quotation.service.ts"
methods:
- confirmQuotation
- cancelQuotation
- sendQuotation
- createSalesOrder
controllers:
- name: "QuotationController"
file: "src/modules/sales/controllers/quotation.controller.ts"
dtos:
- name: "ConfirmQuotationDto"
file: "src/modules/sales/dto/confirm-quotation.dto.ts"
et_frontend:
file: "especificaciones-tecnicas/frontend/mgn-007/ET-FRONTEND-MGN-007-002-conversión-a-órdenes-de-venta.md"
routes:
- path: "/sales/quotations/:id/confirm"
component: "ConfirmQuotationPage"
components:
- name: "ConfirmQuotationButton"
file: "src/features/confirm-quotation/ui/ConfirmQuotationButton.tsx"
type: feature
- name: "QuotationActions"
file: "src/widgets/quotation-actions/ui/QuotationActions.tsx"
type: widget
api_client:
- name: "quotationApi"
file: "src/entities/quotation/api/quotation.api.ts"
methods:
- confirm
- cancel
- send
state_management:
- name: "useQuotationStore"
file: "src/entities/quotation/model/quotation.store.ts"
type: zustand
database_tables:
- schema: sales
table: quotations
file: "database-design/schemas/sales-schema-ddl.sql"
operations:
- SELECT
- UPDATE
indices:
- idx_quotations_state
rls_policy: tenant_isolation_quotations
- schema: sales
table: sales_orders
file: "database-design/schemas/sales-schema-ddl.sql"
operations:
- INSERT
- SELECT
indices:
- idx_sales_orders_quotation_id
rls_policy: tenant_isolation_sales_orders
tests:
backend:
unit_tests:
- file: "src/modules/sales/services/quotation.service.spec.ts"
test_cases:
- "should confirm quotation and create sales order"
- "should validate stock availability before confirmation"
- "should cancel quotation successfully"
- "should send quotation email with PDF"
- "should throw error if quotation already confirmed"
integration_tests:
- file: "test/sales/quotation.controller.e2e-spec.ts"
test_cases:
- "POST /api/v1/sales/quotations/:id/confirm should create sales order"
- "POST /api/v1/sales/quotations/:id/cancel should cancel quotation"
- "POST /api/v1/sales/quotations/:id/send should send email"
- "should prevent double confirmation"
- "should enforce permissions"
frontend:
component_tests:
- file: "src/features/confirm-quotation/ui/ConfirmQuotationButton.test.tsx"
test_cases:
- "should show confirmation dialog"
- "should call confirm API"
- "should redirect to sales order"
e2e_tests:
- file: "e2e/sales/quotation-confirm.spec.ts"
test_cases:
- "should confirm quotation successfully"
- "should create sales order from quotation"
- "should send quotation email"
- "should prevent confirming cancelled quotation"
acceptance_criteria:
- id: AC-001
description: "Confirmar cotización crea automáticamente orden de venta"
status: Pending
test_reference: "test/sales/quotation.controller.e2e-spec.ts:142"
- id: AC-002
description: "Sistema envía email con PDF de cotización"
status: Pending
test_reference: "src/modules/sales/services/quotation.service.spec.ts:168"
- id: AC-003
description: "Cotización confirmada no puede ser modificada"
status: Pending
test_reference: "test/sales/quotation.controller.e2e-spec.ts:185"
business_rules:
- id: RN-001
description: "Solo cotizaciones en estado 'sent' pueden ser confirmadas"
implementation: "src/modules/sales/services/quotation.service.ts:validateConfirmation()"
test_reference: "src/modules/sales/services/quotation.service.spec.ts:195"
- id: RN-002
description: "Al confirmar, estado cambia a 'sale' y se crea sales_order"
implementation: "src/modules/sales/services/quotation.service.ts:confirmQuotation()"
test_reference: "src/modules/sales/services/quotation.service.spec.ts:218"
- id: RN-003
description: "Orden de venta hereda todos los datos de la cotización"
implementation: "src/modules/sales/services/quotation.service.ts:createSalesOrder()"
test_reference: "src/modules/sales/services/quotation.service.spec.ts:242"
dependencies:
rf_dependencies:
- RF-MGN-007-001
module_dependencies:
- MGN-001
- MGN-014
external_dependencies:
- name: "nodemailer"
version: "^6.9.0"
- name: "puppeteer"
version: "^21.0.0"
- rf_id: RF-MGN-007-003
rf_title: "Gestión de Órdenes de Venta"
rf_file: "requerimientos-funcionales/mgn-007/RF-MGN-007-003-gestión-de-órdenes-de-venta.md"
priority: P0
story_points: 13
et_backend:
file: "especificaciones-tecnicas/backend/mgn-007/ET-BACKEND-MGN-007-003-gestión-de-órdenes-de-venta.md"
endpoints:
- method: POST
path: /api/v1/sales/orders
description: "Crear nueva orden de venta"
- method: GET
path: /api/v1/sales/orders
description: "Listar todas las órdenes de venta"
- method: GET
path: /api/v1/sales/orders/:id
description: "Obtener orden de venta por ID"
- method: PUT
path: /api/v1/sales/orders/:id
description: "Actualizar orden de venta"
- method: DELETE
path: /api/v1/sales/orders/:id
description: "Cancelar orden de venta"
services:
- name: "SalesOrderService"
file: "src/modules/sales/services/sales-order.service.ts"
methods:
- create
- findAll
- findOne
- update
- cancel
- validateBusinessRules
controllers:
- name: "SalesOrderController"
file: "src/modules/sales/controllers/sales-order.controller.ts"
dtos:
- name: "CreateSalesOrderDto"
file: "src/modules/sales/dto/create-sales-order.dto.ts"
- name: "UpdateSalesOrderDto"
file: "src/modules/sales/dto/update-sales-order.dto.ts"
- name: "SalesOrderResponseDto"
file: "src/modules/sales/dto/sales-order-response.dto.ts"
- name: "FilterSalesOrderDto"
file: "src/modules/sales/dto/filter-sales-order.dto.ts"
et_frontend:
file: "especificaciones-tecnicas/frontend/mgn-007/ET-FRONTEND-MGN-007-003-gestión-de-órdenes-de-venta.md"
routes:
- path: "/sales/orders"
component: "SalesOrdersPage"
- path: "/sales/orders/create"
component: "CreateSalesOrderPage"
- path: "/sales/orders/:id/edit"
component: "EditSalesOrderPage"
- path: "/sales/orders/:id"
component: "ViewSalesOrderPage"
components:
- name: "SalesOrdersTable"
file: "src/widgets/sales-orders-table/ui/SalesOrdersTable.tsx"
type: widget
- name: "CreateSalesOrderForm"
file: "src/features/create-sales-order/ui/CreateSalesOrderForm.tsx"
type: feature
- name: "SalesOrderCard"
file: "src/entities/sales-order/ui/SalesOrderCard.tsx"
type: entity
- name: "SalesOrderPage"
file: "src/pages/sales/SalesOrderPage.tsx"
type: page
api_client:
- name: "salesOrderApi"
file: "src/entities/sales-order/api/sales-order.api.ts"
methods:
- getAll
- getById
- create
- update
- cancel
state_management:
- name: "useSalesOrderStore"
file: "src/entities/sales-order/model/sales-order.store.ts"
type: zustand
- name: "useSalesOrders"
file: "src/entities/sales-order/api/sales-order.queries.ts"
type: react-query
database_tables:
- schema: sales
table: sales_orders
file: "database-design/schemas/sales-schema-ddl.sql"
operations:
- SELECT
- INSERT
- UPDATE
- DELETE (soft)
indices:
- idx_sales_orders_tenant_id
- idx_sales_orders_partner_id
- idx_sales_orders_state
- idx_sales_orders_date
rls_policy: tenant_isolation_sales_orders
- schema: sales
table: sales_order_lines
file: "database-design/schemas/sales-schema-ddl.sql"
operations:
- SELECT
- INSERT
- UPDATE
- DELETE
indices:
- idx_sales_order_lines_order_id
- idx_sales_order_lines_product_id
rls_policy: tenant_isolation_sales_order_lines
tests:
backend:
unit_tests:
- file: "src/modules/sales/services/sales-order.service.spec.ts"
test_cases:
- "should create sales order with valid data"
- "should reserve stock on order confirmation"
- "should calculate delivery dates based on lead time"
- "should find all orders for tenant"
- "should update order successfully"
integration_tests:
- file: "test/sales/sales-order.controller.e2e-spec.ts"
test_cases:
- "POST /api/v1/sales/orders should create order"
- "GET /api/v1/sales/orders should return all orders"
- "GET /api/v1/sales/orders/:id should return order"
- "PUT /api/v1/sales/orders/:id should update order"
- "DELETE /api/v1/sales/orders/:id should cancel order"
- "should enforce tenant isolation"
- "should require authentication"
- "should check permissions"
frontend:
component_tests:
- file: "src/widgets/sales-orders-table/ui/SalesOrdersTable.test.tsx"
test_cases:
- "should render table with orders"
- "should handle pagination"
- "should filter by state"
- file: "src/features/create-sales-order/ui/CreateSalesOrderForm.test.tsx"
test_cases:
- "should validate required fields"
- "should submit valid form"
- "should show error messages"
e2e_tests:
- file: "e2e/sales/sales-orders.spec.ts"
test_cases:
- "should create sales order successfully"
- "should edit sales order successfully"
- "should cancel sales order with confirmation"
- "should enforce permissions"
acceptance_criteria:
- id: AC-001
description: "Usuario puede crear órdenes de venta con líneas de productos"
status: Pending
test_reference: "test/sales/sales-order.controller.e2e-spec.ts:35"
- id: AC-002
description: "Sistema reserva stock automáticamente al confirmar orden"
status: Pending
test_reference: "src/modules/sales/services/sales-order.service.spec.ts:72"
- id: AC-003
description: "Órdenes soportan entregas parciales y facturación parcial"
status: Pending
test_reference: "test/sales/sales-order.controller.e2e-spec.ts:118"
business_rules:
- id: RN-001
description: "Orden debe tener al menos una línea de producto"
implementation: "src/modules/sales/services/sales-order.service.ts:validateOrderLines()"
test_reference: "src/modules/sales/services/sales-order.service.spec.ts:95"
- id: RN-002
description: "Estado inicial de orden debe ser 'draft' o 'sale'"
implementation: "src/modules/sales/services/sales-order.service.ts:create()"
test_reference: "src/modules/sales/services/sales-order.service.spec.ts:142"
- id: RN-003
description: "No se puede cancelar orden con entregas o facturas confirmadas"
implementation: "src/modules/sales/services/sales-order.service.ts:cancel()"
test_reference: "src/modules/sales/services/sales-order.service.spec.ts:168"
dependencies:
rf_dependencies:
- RF-MGN-007-002
- RF-MGN-005-003
module_dependencies:
- MGN-001
- MGN-003
- MGN-005
external_dependencies:
- name: "@nestjs/common"
version: "^10.0.0"
- rf_id: RF-MGN-007-004
rf_title: "Entregas de Ventas"
rf_file: "requerimientos-funcionales/mgn-007/RF-MGN-007-004-entregas-de-ventas.md"
priority: P0
story_points: 8
et_backend:
file: "especificaciones-tecnicas/backend/mgn-007/ET-BACKEND-MGN-007-004-entregas-de-ventas.md"
endpoints:
- method: POST
path: /api/v1/sales/deliveries
description: "Crear nueva entrega"
- method: GET
path: /api/v1/sales/deliveries
description: "Listar todas las entregas"
- method: GET
path: /api/v1/sales/deliveries/:id
description: "Obtener entrega por ID"
- method: PUT
path: /api/v1/sales/deliveries/:id
description: "Actualizar entrega"
- method: POST
path: /api/v1/sales/deliveries/:id/validate
description: "Validar entrega"
services:
- name: "DeliveryService"
file: "src/modules/sales/services/delivery.service.ts"
methods:
- create
- findAll
- findOne
- update
- validate
- validateBusinessRules
controllers:
- name: "DeliveryController"
file: "src/modules/sales/controllers/delivery.controller.ts"
dtos:
- name: "CreateDeliveryDto"
file: "src/modules/sales/dto/create-delivery.dto.ts"
- name: "UpdateDeliveryDto"
file: "src/modules/sales/dto/update-delivery.dto.ts"
- name: "DeliveryResponseDto"
file: "src/modules/sales/dto/delivery-response.dto.ts"
- name: "ValidateDeliveryDto"
file: "src/modules/sales/dto/validate-delivery.dto.ts"
et_frontend:
file: "especificaciones-tecnicas/frontend/mgn-007/ET-FRONTEND-MGN-007-004-entregas-de-ventas.md"
routes:
- path: "/sales/deliveries"
component: "DeliveriesPage"
- path: "/sales/deliveries/create"
component: "CreateDeliveryPage"
- path: "/sales/deliveries/:id/edit"
component: "EditDeliveryPage"
- path: "/sales/deliveries/:id"
component: "ViewDeliveryPage"
components:
- name: "DeliveriesTable"
file: "src/widgets/deliveries-table/ui/DeliveriesTable.tsx"
type: widget
- name: "CreateDeliveryForm"
file: "src/features/create-delivery/ui/CreateDeliveryForm.tsx"
type: feature
- name: "DeliveryCard"
file: "src/entities/delivery/ui/DeliveryCard.tsx"
type: entity
- name: "DeliveryPage"
file: "src/pages/sales/DeliveryPage.tsx"
type: page
api_client:
- name: "deliveryApi"
file: "src/entities/delivery/api/delivery.api.ts"
methods:
- getAll
- getById
- create
- update
- validate
state_management:
- name: "useDeliveryStore"
file: "src/entities/delivery/model/delivery.store.ts"
type: zustand
- name: "useDeliveries"
file: "src/entities/delivery/api/delivery.queries.ts"
type: react-query
database_tables:
- schema: sales
table: deliveries
file: "database-design/schemas/sales-schema-ddl.sql"
operations:
- SELECT
- INSERT
- UPDATE
- DELETE (soft)
indices:
- idx_deliveries_tenant_id
- idx_deliveries_sales_order_id
- idx_deliveries_state
rls_policy: tenant_isolation_deliveries
- schema: inventory
table: stock_moves
file: "database-design/schemas/inventory-schema-ddl.sql"
operations:
- SELECT
- INSERT
- UPDATE
indices:
- idx_stock_moves_picking_id
rls_policy: tenant_isolation_stock_moves
tests:
backend:
unit_tests:
- file: "src/modules/sales/services/delivery.service.spec.ts"
test_cases:
- "should create delivery from sales order"
- "should validate delivery and update stock"
- "should support partial deliveries"
- "should find all deliveries for tenant"
- "should update delivery successfully"
integration_tests:
- file: "test/sales/delivery.controller.e2e-spec.ts"
test_cases:
- "POST /api/v1/sales/deliveries should create delivery"
- "GET /api/v1/sales/deliveries should return all deliveries"
- "GET /api/v1/sales/deliveries/:id should return delivery"
- "PUT /api/v1/sales/deliveries/:id should update delivery"
- "POST /api/v1/sales/deliveries/:id/validate should validate delivery"
- "should enforce tenant isolation"
- "should require authentication"
- "should check permissions"
frontend:
component_tests:
- file: "src/widgets/deliveries-table/ui/DeliveriesTable.test.tsx"
test_cases:
- "should render table with deliveries"
- "should handle pagination"
- "should filter by state"
- file: "src/features/create-delivery/ui/CreateDeliveryForm.test.tsx"
test_cases:
- "should validate required fields"
- "should submit valid form"
- "should show error messages"
e2e_tests:
- file: "e2e/sales/deliveries.spec.ts"
test_cases:
- "should create delivery successfully"
- "should validate delivery successfully"
- "should support partial deliveries"
- "should enforce permissions"
acceptance_criteria:
- id: AC-001
description: "Usuario puede crear entregas desde órdenes de venta"
status: Pending
test_reference: "test/sales/delivery.controller.e2e-spec.ts:42"
- id: AC-002
description: "Validar entrega actualiza stock automáticamente"
status: Pending
test_reference: "src/modules/sales/services/delivery.service.spec.ts:78"
- id: AC-003
description: "Sistema soporta entregas parciales con backorders"
status: Pending
test_reference: "test/sales/delivery.controller.e2e-spec.ts:125"
business_rules:
- id: RN-001
description: "Entrega debe estar asociada a una orden de venta"
implementation: "src/modules/sales/services/delivery.service.ts:validateSalesOrder()"
test_reference: "src/modules/sales/services/delivery.service.spec.ts:102"
- id: RN-002
description: "Al validar entrega, stock se reduce automáticamente"
implementation: "src/modules/sales/services/delivery.service.ts:validate()"
test_reference: "src/modules/sales/services/delivery.service.spec.ts:148"
- id: RN-003
description: "Cantidad entregada no puede exceder cantidad ordenada"
implementation: "src/modules/sales/services/delivery.service.ts:validateQuantities()"
test_reference: "src/modules/sales/services/delivery.service.spec.ts:175"
dependencies:
rf_dependencies:
- RF-MGN-007-003
- RF-MGN-005-003
module_dependencies:
- MGN-001
- MGN-005
external_dependencies:
- name: "@nestjs/common"
version: "^10.0.0"
- rf_id: RF-MGN-007-005
rf_title: "Facturación de Clientes desde Ventas"
rf_file: "requerimientos-funcionales/mgn-007/RF-MGN-007-005-facturación-de-clientes-desde-ventas.md"
priority: P0
story_points: 8
et_backend:
file: "especificaciones-tecnicas/backend/mgn-007/ET-BACKEND-MGN-007-005-facturación-de-clientes-desde-ventas.md"
endpoints:
- method: POST
path: /api/v1/sales/orders/:id/create-invoice
description: "Crear factura desde orden de venta"
- method: GET
path: /api/v1/sales/invoices
description: "Listar facturas de cliente"
- method: GET
path: /api/v1/sales/invoices/:id
description: "Obtener factura por ID"
- method: POST
path: /api/v1/sales/invoices/:id/validate
description: "Validar factura"
- method: POST
path: /api/v1/sales/invoices/:id/cancel
description: "Cancelar factura"
services:
- name: "SalesInvoiceService"
file: "src/modules/sales/services/sales-invoice.service.ts"
methods:
- createFromOrder
- findAll
- findOne
- validate
- cancel
- validateBusinessRules
controllers:
- name: "SalesInvoiceController"
file: "src/modules/sales/controllers/sales-invoice.controller.ts"
dtos:
- name: "CreateSalesInvoiceDto"
file: "src/modules/sales/dto/create-sales-invoice.dto.ts"
- name: "SalesInvoiceResponseDto"
file: "src/modules/sales/dto/sales-invoice-response.dto.ts"
- name: "ValidateSalesInvoiceDto"
file: "src/modules/sales/dto/validate-sales-invoice.dto.ts"
et_frontend:
file: "especificaciones-tecnicas/frontend/mgn-007/ET-FRONTEND-MGN-007-005-facturación-de-clientes-desde-ventas.md"
routes:
- path: "/sales/invoices"
component: "SalesInvoicesPage"
- path: "/sales/invoices/:id"
component: "ViewSalesInvoicePage"
components:
- name: "SalesInvoicesTable"
file: "src/widgets/sales-invoices-table/ui/SalesInvoicesTable.tsx"
type: widget
- name: "CreateInvoiceButton"
file: "src/features/create-sales-invoice/ui/CreateInvoiceButton.tsx"
type: feature
- name: "SalesInvoiceCard"
file: "src/entities/sales-invoice/ui/SalesInvoiceCard.tsx"
type: entity
- name: "SalesInvoicePage"
file: "src/pages/sales/SalesInvoicePage.tsx"
type: page
api_client:
- name: "salesInvoiceApi"
file: "src/entities/sales-invoice/api/sales-invoice.api.ts"
methods:
- getAll
- getById
- createFromOrder
- validate
- cancel
state_management:
- name: "useSalesInvoiceStore"
file: "src/entities/sales-invoice/model/sales-invoice.store.ts"
type: zustand
- name: "useSalesInvoices"
file: "src/entities/sales-invoice/api/sales-invoice.queries.ts"
type: react-query
database_tables:
- schema: financial
table: invoices_client
file: "database-design/schemas/financial-schema-ddl.sql"
operations:
- SELECT
- INSERT
- UPDATE
indices:
- idx_invoices_client_tenant_id
- idx_invoices_client_sales_order_id
- idx_invoices_client_state
rls_policy: tenant_isolation_invoices_client
- schema: financial
table: invoice_lines
file: "database-design/schemas/financial-schema-ddl.sql"
operations:
- SELECT
- INSERT
- UPDATE
indices:
- idx_invoice_lines_invoice_id
rls_policy: tenant_isolation_invoice_lines
tests:
backend:
unit_tests:
- file: "src/modules/sales/services/sales-invoice.service.spec.ts"
test_cases:
- "should create invoice from sales order"
- "should validate invoice and create journal entry"
- "should support partial invoicing"
- "should find all invoices for tenant"
- "should cancel invoice with credit note"
integration_tests:
- file: "test/sales/sales-invoice.controller.e2e-spec.ts"
test_cases:
- "POST /api/v1/sales/orders/:id/create-invoice should create invoice"
- "GET /api/v1/sales/invoices should return all invoices"
- "GET /api/v1/sales/invoices/:id should return invoice"
- "POST /api/v1/sales/invoices/:id/validate should validate invoice"
- "POST /api/v1/sales/invoices/:id/cancel should cancel invoice"
- "should enforce tenant isolation"
- "should require authentication"
- "should check permissions"
frontend:
component_tests:
- file: "src/widgets/sales-invoices-table/ui/SalesInvoicesTable.test.tsx"
test_cases:
- "should render table with invoices"
- "should handle pagination"
- "should filter by state"
- file: "src/features/create-sales-invoice/ui/CreateInvoiceButton.test.tsx"
test_cases:
- "should show invoice options"
- "should create invoice"
- "should handle errors"
e2e_tests:
- file: "e2e/sales/sales-invoices.spec.ts"
test_cases:
- "should create invoice from order successfully"
- "should validate invoice successfully"
- "should cancel invoice with credit note"
- "should enforce permissions"
acceptance_criteria:
- id: AC-001
description: "Usuario puede crear facturas desde órdenes de venta"
status: Pending
test_reference: "test/sales/sales-invoice.controller.e2e-spec.ts:38"
- id: AC-002
description: "Validar factura genera asiento contable automáticamente"
status: Pending
test_reference: "src/modules/sales/services/sales-invoice.service.spec.ts:85"
- id: AC-003
description: "Sistema soporta facturación parcial de órdenes"
status: Pending
test_reference: "test/sales/sales-invoice.controller.e2e-spec.ts:132"
business_rules:
- id: RN-001
description: "Factura debe estar asociada a una orden de venta"
implementation: "src/modules/sales/services/sales-invoice.service.ts:validateSalesOrder()"
test_reference: "src/modules/sales/services/sales-invoice.service.spec.ts:108"
- id: RN-002
description: "Al validar factura, se genera asiento en cuentas por cobrar"
implementation: "src/modules/sales/services/sales-invoice.service.ts:validate()"
test_reference: "src/modules/sales/services/sales-invoice.service.spec.ts:155"
- id: RN-003
description: "Cantidad facturada no puede exceder cantidad entregada"
implementation: "src/modules/sales/services/sales-invoice.service.ts:validateQuantities()"
test_reference: "src/modules/sales/services/sales-invoice.service.spec.ts:182"
dependencies:
rf_dependencies:
- RF-MGN-007-003
- RF-MGN-004-005
module_dependencies:
- MGN-001
- MGN-004
external_dependencies:
- name: "@nestjs/common"
version: "^10.0.0"
- rf_id: RF-MGN-007-006
rf_title: "Reportes de Ventas"
rf_file: "requerimientos-funcionales/mgn-007/RF-MGN-007-006-reportes-de-ventas.md"
priority: P1
story_points: 3
et_backend:
file: "especificaciones-tecnicas/backend/mgn-007/ET-BACKEND-MGN-007-006-reportes-de-ventas.md"
endpoints:
- method: GET
path: /api/v1/sales/reports/summary
description: "Obtener resumen de ventas"
- method: GET
path: /api/v1/sales/reports/by-product
description: "Reporte de ventas por producto"
- method: GET
path: /api/v1/sales/reports/by-customer
description: "Reporte de ventas por cliente"
- method: GET
path: /api/v1/sales/reports/by-salesperson
description: "Reporte de ventas por vendedor"
- method: GET
path: /api/v1/sales/reports/forecast
description: "Pronóstico de ventas"
services:
- name: "SalesReportService"
file: "src/modules/sales/services/sales-report.service.ts"
methods:
- getSummary
- getByProduct
- getByCustomer
- getBySalesperson
- getForecast
controllers:
- name: "SalesReportController"
file: "src/modules/sales/controllers/sales-report.controller.ts"
dtos:
- name: "SalesReportFilterDto"
file: "src/modules/sales/dto/sales-report-filter.dto.ts"
- name: "SalesReportResponseDto"
file: "src/modules/sales/dto/sales-report-response.dto.ts"
et_frontend:
file: "especificaciones-tecnicas/frontend/mgn-007/ET-FRONTEND-MGN-007-006-reportes-de-ventas.md"
routes:
- path: "/sales/reports"
component: "SalesReportsPage"
- path: "/sales/reports/summary"
component: "SalesSummaryPage"
- path: "/sales/reports/products"
component: "ProductsSalesPage"
components:
- name: "SalesReportDashboard"
file: "src/widgets/sales-report-dashboard/ui/SalesReportDashboard.tsx"
type: widget
- name: "SalesChart"
file: "src/features/sales-chart/ui/SalesChart.tsx"
type: feature
- name: "SalesReportFilters"
file: "src/entities/sales-report/ui/SalesReportFilters.tsx"
type: entity
- name: "SalesReportsPage"
file: "src/pages/sales/SalesReportsPage.tsx"
type: page
api_client:
- name: "salesReportApi"
file: "src/entities/sales-report/api/sales-report.api.ts"
methods:
- getSummary
- getByProduct
- getByCustomer
- getBySalesperson
- getForecast
state_management:
- name: "useSalesReportStore"
file: "src/entities/sales-report/model/sales-report.store.ts"
type: zustand
- name: "useSalesReports"
file: "src/entities/sales-report/api/sales-report.queries.ts"
type: react-query
database_tables:
- schema: sales
table: sales_orders
file: "database-design/schemas/sales-schema-ddl.sql"
operations:
- SELECT
indices:
- idx_sales_orders_date
- idx_sales_orders_state
rls_policy: tenant_isolation_sales_orders
- schema: financial
table: invoices_client
file: "database-design/schemas/financial-schema-ddl.sql"
operations:
- SELECT
indices:
- idx_invoices_client_date
rls_policy: tenant_isolation_invoices_client
tests:
backend:
unit_tests:
- file: "src/modules/sales/services/sales-report.service.spec.ts"
test_cases:
- "should generate sales summary report"
- "should group sales by product"
- "should group sales by customer"
- "should group sales by salesperson"
- "should calculate sales forecast"
integration_tests:
- file: "test/sales/sales-report.controller.e2e-spec.ts"
test_cases:
- "GET /api/v1/sales/reports/summary should return summary"
- "GET /api/v1/sales/reports/by-product should return product report"
- "GET /api/v1/sales/reports/by-customer should return customer report"
- "GET /api/v1/sales/reports/by-salesperson should return salesperson report"
- "GET /api/v1/sales/reports/forecast should return forecast"
- "should enforce tenant isolation"
- "should require authentication"
- "should check permissions"
frontend:
component_tests:
- file: "src/widgets/sales-report-dashboard/ui/SalesReportDashboard.test.tsx"
test_cases:
- "should render dashboard with charts"
- "should apply filters"
- "should export report"
- file: "src/features/sales-chart/ui/SalesChart.test.tsx"
test_cases:
- "should render chart with data"
- "should change chart type"
- "should handle empty data"
e2e_tests:
- file: "e2e/sales/sales-reports.spec.ts"
test_cases:
- "should display sales summary"
- "should filter by date range"
- "should export to PDF/Excel"
- "should enforce permissions"
acceptance_criteria:
- id: AC-001
description: "Usuario puede generar reportes de ventas por período"
status: Pending
test_reference: "test/sales/sales-report.controller.e2e-spec.ts:45"
- id: AC-002
description: "Reportes incluyen gráficos y visualizaciones"
status: Pending
test_reference: "src/widgets/sales-report-dashboard/ui/SalesReportDashboard.test.tsx:68"
- id: AC-003
description: "Reportes se pueden exportar a PDF y Excel"
status: Pending
test_reference: "e2e/sales/sales-reports.spec.ts:92"
business_rules:
- id: RN-001
description: "Reportes solo incluyen ventas confirmadas y facturadas"
implementation: "src/modules/sales/services/sales-report.service.ts:filterValidSales()"
test_reference: "src/modules/sales/services/sales-report.service.spec.ts:88"
- id: RN-002
description: "Métricas calculan: ingresos, márgenes, unidades vendidas"
implementation: "src/modules/sales/services/sales-report.service.ts:calculateMetrics()"
test_reference: "src/modules/sales/services/sales-report.service.spec.ts:115"
- id: RN-003
description: "Pronóstico usa promedio móvil de últimos 3 meses"
implementation: "src/modules/sales/services/sales-report.service.ts:getForecast()"
test_reference: "src/modules/sales/services/sales-report.service.spec.ts:142"
dependencies:
rf_dependencies:
- RF-MGN-007-003
- RF-MGN-007-005
module_dependencies:
- MGN-001
- MGN-012
external_dependencies:
- name: "chart.js"
version: "^4.0.0"
- name: "exceljs"
version: "^4.3.0"
coverage:
rf_to_et_backend: 100%
rf_to_et_frontend: 100%
rf_to_database: 100%
rf_to_tests: 100%
backend_tests: 100%
frontend_tests: 100%
statistics:
total_endpoints: 30
total_components: 24
total_tables: 5
total_test_cases: 120
estimated_duration_sprints: 3