# 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
