# TRACEABILITY-MGN-006.yaml
# Matriz de Trazabilidad - MGN-006: Compras Básico
# Fecha: 2025-11-24
# Versión: 1.0

module:
  id: MGN-006
  name: "Compras Básico"
  description: "RFQ, órdenes de compra, workflow de aprobación, recepciones y facturación"
  priority: P0/P1
  story_points: 42
  status: Diseñado

metadata:
  total_rf: 6
  total_et_backend: 6
  total_et_frontend: 6
  total_tables: 6
  total_tests: 120
  coverage: 100%

requirements:
  - rf_id: RF-MGN-006-001
    rf_title: "Solicitudes de Cotización (RFQ)"
    rf_file: "requerimientos-funcionales/mgn-006/RF-MGN-006-001-solicitudes-de-cotización-rfq.md"
    priority: P1
    story_points: 5
    
    et_backend:
      file: "especificaciones-tecnicas/backend/mgn-006/ET-BACKEND-MGN-006-001-solicitudes-de-cotización-rfq.md"
      endpoints:
        - {method: POST, path: "/api/v1/purchases/rfq", description: "Crear RFQ"}
        - {method: GET, path: "/api/v1/purchases/rfq", description: "Listar RFQs"}
        - {method: GET, path: "/api/v1/purchases/rfq/:id", description: "Obtener RFQ"}
        - {method: PUT, path: "/api/v1/purchases/rfq/:id", description: "Actualizar RFQ"}
        - {method: POST, path: "/api/v1/purchases/rfq/:id/send", description: "Enviar RFQ a proveedores"}
      services:
        - {name: "RfqService", file: "src/modules/purchases/services/rfq.service.ts", methods: [create, findAll, findOne, update, send]}
      controllers:
        - {name: "RfqController", file: "src/modules/purchases/controllers/rfq.controller.ts"}
      dtos:
        - {name: "CreateRfqDto", file: "src/modules/purchases/dto/create-rfq.dto.ts"}
        - {name: "UpdateRfqDto", file: "src/modules/purchases/dto/update-rfq.dto.ts"}
    
    et_frontend:
      file: "especificaciones-tecnicas/frontend/mgn-006/ET-FRONTEND-MGN-006-001-solicitudes-de-cotización-rfq.md"
      routes:
        - {path: "/purchases/rfq", component: "RfqPage"}
        - {path: "/purchases/rfq/create", component: "CreateRfqPage"}
        - {path: "/purchases/rfq/:id", component: "ViewRfqPage"}
      components:
        - {name: "RfqTable", file: "src/widgets/rfq-table/ui/RfqTable.tsx", type: widget}
        - {name: "CreateRfqForm", file: "src/features/create-rfq/ui/CreateRfqForm.tsx", type: feature}
        - {name: "RfqCard", file: "src/entities/rfq/ui/RfqCard.tsx", type: entity}
      api_client:
        - {name: "rfqApi", file: "src/entities/rfq/api/rfq.api.ts", methods: [getAll, getById, create, update, send]}
      state_management:
        - {name: "useRfqStore", file: "src/entities/rfq/model/rfq.store.ts", type: zustand}
    
    database_tables:
      - {schema: purchases, table: rfqs, file: "database-design/schemas/purchases-schema-ddl.sql", operations: [SELECT, INSERT, UPDATE], indices: [idx_rfqs_company_id, idx_rfqs_state], rls_policy: company_isolation_rfqs}
      - {schema: purchases, table: rfq_lines, file: "database-design/schemas/purchases-schema-ddl.sql", operations: [SELECT, INSERT, UPDATE, DELETE], indices: [idx_rfq_lines_rfq_id, idx_rfq_lines_product_id], rls_policy: company_isolation_rfq_lines}
    
    tests:
      backend:
        unit_tests:
          - file: "src/modules/purchases/services/rfq.service.spec.ts"
            test_cases: ["should create RFQ", "should send RFQ to suppliers", "should update RFQ", "should validate RFQ lines", "should soft delete RFQ"]
        integration_tests:
          - file: "test/purchases/rfq.controller.e2e-spec.ts"
            test_cases: ["POST /api/v1/purchases/rfq should create", "GET /api/v1/purchases/rfq should return all", "POST /api/v1/purchases/rfq/:id/send should send", "should enforce company isolation", "should require authentication"]
      frontend:
        component_tests:
          - file: "src/widgets/rfq-table/ui/RfqTable.test.tsx"
            test_cases: ["should render table", "should filter by state"]
          - file: "src/features/create-rfq/ui/CreateRfqForm.test.tsx"
            test_cases: ["should validate fields", "should submit form"]
        e2e_tests:
          - file: "e2e/purchases/rfq.spec.ts"
            test_cases: ["should create RFQ successfully", "should send RFQ to suppliers", "should edit RFQ"]
    
    acceptance_criteria:
      - {id: AC-001, description: "Usuario puede crear RFQ con líneas de productos", status: Pending, test_reference: "test/purchases/rfq.controller.e2e-spec.ts:28"}
      - {id: AC-002, description: "Usuario puede enviar RFQ a múltiples proveedores", status: Pending, test_reference: "src/modules/purchases/services/rfq.service.spec.ts:65"}
      - {id: AC-003, description: "RFQ puede convertirse en orden de compra", status: Pending, test_reference: "test/purchases/rfq.controller.e2e-spec.ts:95"}
    
    business_rules:
      - {id: RN-001, description: "RFQ tiene estados: draft, sent, cancelled", implementation: "database-design/schemas/purchases-schema-ddl.sql:rfqs.state", test_reference: "src/modules/purchases/services/rfq.service.spec.ts:48"}
      - {id: RN-002, description: "RFQ puede enviarse a múltiples proveedores", implementation: "src/modules/purchases/services/rfq.service.ts:send()", test_reference: "src/modules/purchases/services/rfq.service.spec.ts:78"}
      - {id: RN-003, description: "RFQ puede convertirse en orden de compra", implementation: "src/modules/purchases/services/rfq.service.ts:convertToPO()", test_reference: "src/modules/purchases/services/rfq.service.spec.ts:108"}
    
    dependencies:
      rf_dependencies: [RF-MGN-003-001, RF-MGN-005-001]
      module_dependencies: [MGN-003, MGN-005]
      external_dependencies: []

  - rf_id: RF-MGN-006-002
    rf_title: "Gestión de Órdenes de Compra"
    rf_file: "requerimientos-funcionales/mgn-006/RF-MGN-006-002-gestión-de-órdenes-de-compra.md"
    priority: P0
    story_points: 13
    
    et_backend:
      file: "especificaciones-tecnicas/backend/mgn-006/ET-BACKEND-MGN-006-002-gestión-de-órdenes-de-compra.md"
      endpoints:
        - {method: POST, path: "/api/v1/purchases/orders", description: "Crear orden de compra"}
        - {method: GET, path: "/api/v1/purchases/orders", description: "Listar órdenes"}
        - {method: GET, path: "/api/v1/purchases/orders/:id", description: "Obtener orden"}
        - {method: PUT, path: "/api/v1/purchases/orders/:id", description: "Actualizar orden"}
        - {method: POST, path: "/api/v1/purchases/orders/:id/confirm", description: "Confirmar orden"}
      services:
        - {name: "PurchaseOrderService", file: "src/modules/purchases/services/purchase-order.service.ts", methods: [create, findAll, findOne, update, confirm]}
      controllers:
        - {name: "PurchaseOrderController", file: "src/modules/purchases/controllers/purchase-order.controller.ts"}
      dtos:
        - {name: "CreatePurchaseOrderDto", file: "src/modules/purchases/dto/create-purchase-order.dto.ts"}
        - {name: "UpdatePurchaseOrderDto", file: "src/modules/purchases/dto/update-purchase-order.dto.ts"}
    
    et_frontend:
      file: "especificaciones-tecnicas/frontend/mgn-006/ET-FRONTEND-MGN-006-002-gestión-de-órdenes-de-compra.md"
      routes:
        - {path: "/purchases/orders", component: "PurchaseOrdersPage"}
        - {path: "/purchases/orders/create", component: "CreatePurchaseOrderPage"}
        - {path: "/purchases/orders/:id", component: "ViewPurchaseOrderPage"}
      components:
        - {name: "PurchaseOrdersTable", file: "src/widgets/purchase-orders-table/ui/PurchaseOrdersTable.tsx", type: widget}
        - {name: "CreatePurchaseOrderForm", file: "src/features/create-purchase-order/ui/CreatePurchaseOrderForm.tsx", type: feature}
        - {name: "PurchaseOrderCard", file: "src/entities/purchase-order/ui/PurchaseOrderCard.tsx", type: entity}
      api_client:
        - {name: "purchaseOrderApi", file: "src/entities/purchase-order/api/purchase-order.api.ts", methods: [getAll, getById, create, update, confirm]}
      state_management:
        - {name: "usePurchaseOrderStore", file: "src/entities/purchase-order/model/purchase-order.store.ts", type: zustand}
    
    database_tables:
      - {schema: purchases, table: purchase_orders, file: "database-design/schemas/purchases-schema-ddl.sql", operations: [SELECT, INSERT, UPDATE], indices: [idx_purchase_orders_company_id, idx_purchase_orders_partner_id, idx_purchase_orders_state], rls_policy: company_isolation_purchase_orders}
      - {schema: purchases, table: purchase_order_lines, file: "database-design/schemas/purchases-schema-ddl.sql", operations: [SELECT, INSERT, UPDATE, DELETE], indices: [idx_purchase_order_lines_order_id, idx_purchase_order_lines_product_id], rls_policy: company_isolation_purchase_order_lines}
    
    tests:
      backend:
        unit_tests:
          - file: "src/modules/purchases/services/purchase-order.service.spec.ts"
            test_cases: ["should create purchase order", "should calculate totals with taxes", "should confirm order", "should generate picking", "should cancel order"]
        integration_tests:
          - file: "test/purchases/purchase-order.controller.e2e-spec.ts"
            test_cases: ["POST /api/v1/purchases/orders should create", "GET /api/v1/purchases/orders should return all", "POST /api/v1/purchases/orders/:id/confirm should confirm", "should enforce company isolation", "should require authentication"]
      frontend:
        component_tests:
          - file: "src/widgets/purchase-orders-table/ui/PurchaseOrdersTable.test.tsx"
            test_cases: ["should render table", "should filter by state"]
          - file: "src/features/create-purchase-order/ui/CreatePurchaseOrderForm.test.tsx"
            test_cases: ["should validate fields", "should calculate totals", "should submit form"]
        e2e_tests:
          - file: "e2e/purchases/purchase-orders.spec.ts"
            test_cases: ["should create order successfully", "should confirm order", "should show generated picking"]
    
    acceptance_criteria:
      - {id: AC-001, description: "Usuario puede crear órdenes de compra con líneas y impuestos", status: Pending, test_reference: "test/purchases/purchase-order.controller.e2e-spec.ts:28"}
      - {id: AC-002, description: "Confirmar orden genera picking de recepción", status: Pending, test_reference: "src/modules/purchases/services/purchase-order.service.spec.ts:85"}
      - {id: AC-003, description: "Órdenes tienen estados: draft, sent, done, cancelled", status: Pending, test_reference: "test/purchases/purchase-order.controller.e2e-spec.ts:125"}
    
    business_rules:
      - {id: RN-001, description: "Orden tiene estados: draft, sent, done, cancelled", implementation: "database-design/schemas/purchases-schema-ddl.sql:purchase_orders.state", test_reference: "src/modules/purchases/services/purchase-order.service.spec.ts:58"}
      - {id: RN-002, description: "Confirmar orden genera picking de recepción", implementation: "src/modules/purchases/services/purchase-order.service.ts:confirm()", test_reference: "src/modules/purchases/services/purchase-order.service.spec.ts:92"}
      - {id: RN-003, description: "Solo órdenes draft pueden modificarse", implementation: "src/modules/purchases/services/purchase-order.service.ts:update()", test_reference: "src/modules/purchases/services/purchase-order.service.spec.ts:118"}
    
    dependencies:
      rf_dependencies: [RF-MGN-003-001, RF-MGN-005-001, RF-MGN-004-004]
      module_dependencies: [MGN-003, MGN-004, MGN-005]
      external_dependencies: []

  - rf_id: RF-MGN-006-003
    rf_title: "Workflow de Aprobación de Compras"
    rf_file: "requerimientos-funcionales/mgn-006/RF-MGN-006-003-workflow-de-aprobación-de-compras.md"
    priority: P1
    story_points: 5
    
    et_backend:
      file: "especificaciones-tecnicas/backend/mgn-006/ET-BACKEND-MGN-006-003-workflow-de-aprobación-de-compras.md"
      endpoints:
        - {method: POST, path: "/api/v1/purchases/orders/:id/request-approval", description: "Solicitar aprobación"}
        - {method: POST, path: "/api/v1/purchases/orders/:id/approve", description: "Aprobar orden"}
        - {method: POST, path: "/api/v1/purchases/orders/:id/reject", description: "Rechazar orden"}
        - {method: GET, path: "/api/v1/purchases/approvals/pending", description: "Órdenes pendientes de aprobación"}
      services:
        - {name: "PurchaseApprovalService", file: "src/modules/purchases/services/purchase-approval.service.ts", methods: [requestApproval, approve, reject, getPendingApprovals]}
      controllers:
        - {name: "PurchaseApprovalController", file: "src/modules/purchases/controllers/purchase-approval.controller.ts"}
      dtos:
        - {name: "ApprovalRequestDto", file: "src/modules/purchases/dto/approval-request.dto.ts"}
    
    et_frontend:
      file: "especificaciones-tecnicas/frontend/mgn-006/ET-FRONTEND-MGN-006-003-workflow-de-aprobación-de-compras.md"
      routes:
        - {path: "/purchases/approvals", component: "PurchaseApprovalsPage"}
      components:
        - {name: "PendingApprovalsTable", file: "src/widgets/pending-approvals-table/ui/PendingApprovalsTable.tsx", type: widget}
        - {name: "ApprovalButtons", file: "src/features/approval-buttons/ui/ApprovalButtons.tsx", type: feature}
      api_client:
        - {name: "purchaseApprovalApi", file: "src/entities/purchase-approval/api/purchase-approval.api.ts", methods: [requestApproval, approve, reject, getPending]}
      state_management:
        - {name: "usePurchaseApprovalStore", file: "src/entities/purchase-approval/model/purchase-approval.store.ts", type: zustand}
    
    database_tables:
      - {schema: purchases, table: purchase_orders, file: "database-design/schemas/purchases-schema-ddl.sql", operations: [SELECT, UPDATE], indices: [idx_purchase_orders_state, idx_purchase_orders_approver_id], rls_policy: company_isolation_purchase_orders}
      - {schema: purchases, table: approval_logs, file: "database-design/schemas/purchases-schema-ddl.sql", operations: [SELECT, INSERT], indices: [idx_approval_logs_order_id, idx_approval_logs_approver_id], rls_policy: company_isolation_approval_logs}
    
    tests:
      backend:
        unit_tests:
          - file: "src/modules/purchases/services/purchase-approval.service.spec.ts"
            test_cases: ["should request approval", "should approve order", "should reject order", "should validate approval permissions", "should send notifications"]
        integration_tests:
          - file: "test/purchases/purchase-approval.controller.e2e-spec.ts"
            test_cases: ["POST /api/v1/purchases/orders/:id/request-approval should request", "POST /api/v1/purchases/orders/:id/approve should approve", "POST /api/v1/purchases/orders/:id/reject should reject", "GET /api/v1/purchases/approvals/pending should return pending", "should enforce approval permissions"]
      frontend:
        component_tests:
          - file: "src/widgets/pending-approvals-table/ui/PendingApprovalsTable.test.tsx"
            test_cases: ["should render table", "should show approval actions"]
          - file: "src/features/approval-buttons/ui/ApprovalButtons.test.tsx"
            test_cases: ["should call approve", "should call reject"]
        e2e_tests:
          - file: "e2e/purchases/approvals.spec.ts"
            test_cases: ["should request approval successfully", "should approve order", "should reject order with reason"]
    
    acceptance_criteria:
      - {id: AC-001, description: "Órdenes de compra sobre monto límite requieren aprobación", status: Pending, test_reference: "test/purchases/purchase-approval.controller.e2e-spec.ts:28"}
      - {id: AC-002, description: "Solo usuarios con permiso pueden aprobar órdenes", status: Pending, test_reference: "src/modules/purchases/services/purchase-approval.service.spec.ts:65"}
      - {id: AC-003, description: "Sistema registra historial de aprobaciones", status: Pending, test_reference: "test/purchases/purchase-approval.controller.e2e-spec.ts:95"}
    
    business_rules:
      - {id: RN-001, description: "Órdenes sobre límite configurado requieren aprobación", implementation: "src/modules/purchases/services/purchase-approval.service.ts:requiresApproval()", test_reference: "src/modules/purchases/services/purchase-approval.service.spec.ts:48"}
      - {id: RN-002, description: "Solo usuarios con rol de aprobador pueden aprobar", implementation: "src/modules/purchases/guards/approval.guard.ts", test_reference: "src/modules/purchases/services/purchase-approval.service.spec.ts:78"}
      - {id: RN-003, description: "Aprobaciones se registran en approval_logs", implementation: "database-design/schemas/purchases-schema-ddl.sql:approval_logs", test_reference: "src/modules/purchases/services/purchase-approval.service.spec.ts:108"}
    
    dependencies:
      rf_dependencies: [RF-MGN-006-002, RF-MGN-001-002, RF-MGN-014-002]
      module_dependencies: [MGN-001, MGN-014]
      external_dependencies: []

  - rf_id: RF-MGN-006-004
    rf_title: "Recepciones de Compras"
    rf_file: "requerimientos-funcionales/mgn-006/RF-MGN-006-004-recepciones-de-compras.md"
    priority: P0
    story_points: 8
    
    et_backend:
      file: "especificaciones-tecnicas/backend/mgn-006/ET-BACKEND-MGN-006-004-recepciones-de-compras.md"
      endpoints:
        - {method: GET, path: "/api/v1/purchases/orders/:id/receipts", description: "Listar recepciones de orden"}
        - {method: POST, path: "/api/v1/purchases/orders/:id/receipts/:pickingId/validate", description: "Validar recepción"}
      services:
        - {name: "PurchaseReceiptService", file: "src/modules/purchases/services/purchase-receipt.service.ts", methods: [findByOrder, validate]}
      controllers:
        - {name: "PurchaseReceiptController", file: "src/modules/purchases/controllers/purchase-receipt.controller.ts"}
      dtos: []
    
    et_frontend:
      file: "especificaciones-tecnicas/frontend/mgn-006/ET-FRONTEND-MGN-006-004-recepciones-de-compras.md"
      routes:
        - {path: "/purchases/orders/:id/receipts", component: "PurchaseReceiptsPage"}
      components:
        - {name: "PurchaseReceiptsTable", file: "src/widgets/purchase-receipts-table/ui/PurchaseReceiptsTable.tsx", type: widget}
        - {name: "ValidateReceiptButton", file: "src/features/validate-receipt/ui/ValidateReceiptButton.tsx", type: feature}
      api_client:
        - {name: "purchaseReceiptApi", file: "src/entities/purchase-receipt/api/purchase-receipt.api.ts", methods: [getByOrder, validate]}
      state_management:
        - {name: "usePurchaseReceiptStore", file: "src/entities/purchase-receipt/model/purchase-receipt.store.ts", type: zustand}
    
    database_tables:
      - {schema: inventory, table: pickings, file: "database-design/schemas/inventory-schema-ddl.sql", operations: [SELECT, UPDATE], indices: [idx_pickings_purchase_order_id], rls_policy: company_isolation_pickings}
    
    tests:
      backend:
        unit_tests:
          - file: "src/modules/purchases/services/purchase-receipt.service.spec.ts"
            test_cases: ["should find receipts by order", "should validate receipt", "should update order received qty", "should mark order as done when fully received"]
        integration_tests:
          - file: "test/purchases/purchase-receipt.controller.e2e-spec.ts"
            test_cases: ["GET /api/v1/purchases/orders/:id/receipts should return receipts", "POST /api/v1/purchases/orders/:id/receipts/:pickingId/validate should validate", "should update purchase order state", "should enforce company isolation"]
      frontend:
        component_tests:
          - file: "src/widgets/purchase-receipts-table/ui/PurchaseReceiptsTable.test.tsx"
            test_cases: ["should render table", "should show validate button"]
        e2e_tests:
          - file: "e2e/purchases/receipts.spec.ts"
            test_cases: ["should view receipts for order", "should validate receipt successfully", "should show updated order state"]
    
    acceptance_criteria:
      - {id: AC-001, description: "Usuario puede ver recepciones vinculadas a orden de compra", status: Pending, test_reference: "test/purchases/purchase-receipt.controller.e2e-spec.ts:28"}
      - {id: AC-002, description: "Validar recepción actualiza cantidad recibida en orden", status: Pending, test_reference: "src/modules/purchases/services/purchase-receipt.service.spec.ts:65"}
      - {id: AC-003, description: "Orden se marca como done cuando se recibe completamente", status: Pending, test_reference: "test/purchases/purchase-receipt.controller.e2e-spec.ts:95"}
    
    business_rules:
      - {id: RN-001, description: "Recepciones son pickings vinculados a orden de compra", implementation: "database-design/schemas/inventory-schema-ddl.sql:pickings.purchase_order_id", test_reference: "src/modules/purchases/services/purchase-receipt.service.spec.ts:48"}
      - {id: RN-002, description: "Validar recepción actualiza qty_received en orden", implementation: "src/modules/purchases/services/purchase-receipt.service.ts:validate()", test_reference: "src/modules/purchases/services/purchase-receipt.service.spec.ts:78"}
      - {id: RN-003, description: "Orden pasa a done cuando qty_received = qty_ordered", implementation: "src/modules/purchases/services/purchase-receipt.service.ts:checkOrderCompletion()", test_reference: "src/modules/purchases/services/purchase-receipt.service.spec.ts:108"}
    
    dependencies:
      rf_dependencies: [RF-MGN-006-002, RF-MGN-005-004]
      module_dependencies: [MGN-005]
      external_dependencies: []

  - rf_id: RF-MGN-006-005
    rf_title: "Facturación de Proveedores desde Compras"
    rf_file: "requerimientos-funcionales/mgn-006/RF-MGN-006-005-facturación-de-proveedores-desde-compras.md"
    priority: P0
    story_points: 8
    
    et_backend:
      file: "especificaciones-tecnicas/backend/mgn-006/ET-BACKEND-MGN-006-005-facturación-de-proveedores-desde-compras.md"
      endpoints:
        - {method: POST, path: "/api/v1/purchases/orders/:id/create-invoice", description: "Crear factura desde orden"}
        - {method: GET, path: "/api/v1/purchases/orders/:id/invoices", description: "Listar facturas de orden"}
      services:
        - {name: "PurchaseInvoiceService", file: "src/modules/purchases/services/purchase-invoice.service.ts", methods: [createFromOrder, findByOrder]}
      controllers:
        - {name: "PurchaseInvoiceController", file: "src/modules/purchases/controllers/purchase-invoice.controller.ts"}
      dtos:
        - {name: "CreateInvoiceFromOrderDto", file: "src/modules/purchases/dto/create-invoice-from-order.dto.ts"}
    
    et_frontend:
      file: "especificaciones-tecnicas/frontend/mgn-006/ET-FRONTEND-MGN-006-005-facturación-de-proveedores-desde-compras.md"
      routes:
        - {path: "/purchases/orders/:id/invoices", component: "PurchaseInvoicesPage"}
      components:
        - {name: "PurchaseInvoicesTable", file: "src/widgets/purchase-invoices-table/ui/PurchaseInvoicesTable.tsx", type: widget}
        - {name: "CreateInvoiceFromOrderButton", file: "src/features/create-invoice-from-order/ui/CreateInvoiceFromOrderButton.tsx", type: feature}
      api_client:
        - {name: "purchaseInvoiceApi", file: "src/entities/purchase-invoice/api/purchase-invoice.api.ts", methods: [createFromOrder, getByOrder]}
      state_management:
        - {name: "usePurchaseInvoiceStore", file: "src/entities/purchase-invoice/model/purchase-invoice.store.ts", type: zustand}
    
    database_tables:
      - {schema: financial, table: invoices, file: "database-design/schemas/financial-schema-ddl.sql", operations: [SELECT, INSERT], indices: [idx_invoices_purchase_order_id], rls_policy: company_isolation_invoices}
    
    tests:
      backend:
        unit_tests:
          - file: "src/modules/purchases/services/purchase-invoice.service.spec.ts"
            test_cases: ["should create invoice from order", "should copy lines from order", "should calculate taxes", "should link invoice to order"]
        integration_tests:
          - file: "test/purchases/purchase-invoice.controller.e2e-spec.ts"
            test_cases: ["POST /api/v1/purchases/orders/:id/create-invoice should create", "GET /api/v1/purchases/orders/:id/invoices should return invoices", "should enforce company isolation"]
      frontend:
        component_tests:
          - file: "src/widgets/purchase-invoices-table/ui/PurchaseInvoicesTable.test.tsx"
            test_cases: ["should render table", "should show linked invoices"]
        e2e_tests:
          - file: "e2e/purchases/invoices.spec.ts"
            test_cases: ["should create invoice from order successfully", "should view invoices linked to order"]
    
    acceptance_criteria:
      - {id: AC-001, description: "Usuario puede crear factura de proveedor desde orden de compra", status: Pending, test_reference: "test/purchases/purchase-invoice.controller.e2e-spec.ts:28"}
      - {id: AC-002, description: "Factura copia líneas y montos de orden de compra", status: Pending, test_reference: "src/modules/purchases/services/purchase-invoice.service.spec.ts:65"}
      - {id: AC-003, description: "Factura queda vinculada a orden de compra", status: Pending, test_reference: "test/purchases/purchase-invoice.controller.e2e-spec.ts:95"}
    
    business_rules:
      - {id: RN-001, description: "Factura copia datos de orden de compra", implementation: "src/modules/purchases/services/purchase-invoice.service.ts:createFromOrder()", test_reference: "src/modules/purchases/services/purchase-invoice.service.spec.ts:48"}
      - {id: RN-002, description: "Factura se vincula a orden con purchase_order_id", implementation: "database-design/schemas/financial-schema-ddl.sql:invoices.purchase_order_id", test_reference: "src/modules/purchases/services/purchase-invoice.service.spec.ts:78"}
      - {id: RN-003, description: "Orden permite múltiples facturas (facturación parcial)", implementation: "src/modules/purchases/services/purchase-invoice.service.ts:allowMultipleInvoices", test_reference: "src/modules/purchases/services/purchase-invoice.service.spec.ts:108"}
    
    dependencies:
      rf_dependencies: [RF-MGN-006-002, RF-MGN-004-006]
      module_dependencies: [MGN-004]
      external_dependencies: []

  - rf_id: RF-MGN-006-006
    rf_title: "Reportes de Compras"
    rf_file: "requerimientos-funcionales/mgn-006/RF-MGN-006-006-reportes-de-compras.md"
    priority: P1
    story_points: 3
    
    et_backend:
      file: "especificaciones-tecnicas/backend/mgn-006/ET-BACKEND-MGN-006-006-reportes-de-compras.md"
      endpoints:
        - {method: GET, path: "/api/v1/purchases/reports/summary", description: "Reporte resumen de compras"}
        - {method: GET, path: "/api/v1/purchases/reports/by-supplier", description: "Compras por proveedor"}
        - {method: GET, path: "/api/v1/purchases/reports/by-product", description: "Compras por producto"}
      services:
        - {name: "PurchaseReportService", file: "src/modules/purchases/services/purchase-report.service.ts", methods: [generateSummary, generateBySupplier, generateByProduct]}
      controllers:
        - {name: "PurchaseReportController", file: "src/modules/purchases/controllers/purchase-report.controller.ts"}
      dtos:
        - {name: "ReportPeriodDto", file: "src/modules/purchases/dto/report-period.dto.ts"}
    
    et_frontend:
      file: "especificaciones-tecnicas/frontend/mgn-006/ET-FRONTEND-MGN-006-006-reportes-de-compras.md"
      routes:
        - {path: "/purchases/reports", component: "PurchaseReportsPage"}
      components:
        - {name: "PurchaseSummaryReport", file: "src/widgets/purchase-summary-report/ui/PurchaseSummaryReport.tsx", type: widget}
        - {name: "PurchasesBySupplierChart", file: "src/widgets/purchases-by-supplier-chart/ui/PurchasesBySupplierChart.tsx", type: widget}
      api_client:
        - {name: "purchaseReportApi", file: "src/entities/purchase-report/api/purchase-report.api.ts", methods: [getSummary, getBySupplier, getByProduct]}
      state_management:
        - {name: "usePurchaseReportStore", file: "src/entities/purchase-report/model/purchase-report.store.ts", type: zustand}
    
    database_tables:
      - {schema: purchases, table: purchase_orders, file: "database-design/schemas/purchases-schema-ddl.sql", operations: [SELECT], indices: [idx_purchase_orders_order_date, idx_purchase_orders_partner_id], rls_policy: company_isolation_purchase_orders}
    
    tests:
      backend:
        unit_tests:
          - file: "src/modules/purchases/services/purchase-report.service.spec.ts"
            test_cases: ["should generate summary report", "should generate by supplier report", "should filter by date range", "should calculate totals"]
        integration_tests:
          - file: "test/purchases/purchase-report.controller.e2e-spec.ts"
            test_cases: ["GET /api/v1/purchases/reports/summary should return summary", "GET /api/v1/purchases/reports/by-supplier should return by supplier", "should enforce company isolation"]
      frontend:
        component_tests:
          - file: "src/widgets/purchase-summary-report/ui/PurchaseSummaryReport.test.tsx"
            test_cases: ["should render report", "should show totals"]
        e2e_tests:
          - file: "e2e/purchases/reports.spec.ts"
            test_cases: ["should generate summary report", "should filter by date range", "should export to PDF"]
    
    acceptance_criteria:
      - {id: AC-001, description: "Usuario puede generar reporte resumen de compras por período", status: Pending, test_reference: "test/purchases/purchase-report.controller.e2e-spec.ts:28"}
      - {id: AC-002, description: "Usuario puede ver compras agrupadas por proveedor", status: Pending, test_reference: "src/modules/purchases/services/purchase-report.service.spec.ts:65"}
      - {id: AC-003, description: "Reportes pueden exportarse a PDF y Excel", status: Pending, test_reference: "e2e/purchases/reports.spec.ts:85"}
    
    business_rules:
      - {id: RN-001, description: "Reportes filtran por rango de fechas", implementation: "src/modules/purchases/services/purchase-report.service.ts:filterByPeriod()", test_reference: "src/modules/purchases/services/purchase-report.service.spec.ts:48"}
      - {id: RN-002, description: "Reportes calculan totales en moneda de empresa", implementation: "src/modules/purchases/services/purchase-report.service.ts:calculateTotals()", test_reference: "src/modules/purchases/services/purchase-report.service.spec.ts:78"}
      - {id: RN-003, description: "Reportes respetan company isolation", implementation: "src/modules/purchases/services/purchase-report.service.ts:findAll()", test_reference: "src/modules/purchases/services/purchase-report.service.spec.ts:108"}
    
    dependencies:
      rf_dependencies: [RF-MGN-006-002]
      module_dependencies: []
      external_dependencies:
        - {name: "pdfkit", version: "^0.13.0"}
        - {name: "xlsx", version: "^0.18.5"}

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: 6
  total_test_cases: 120
  estimated_duration_sprints: 3
