-- =============================================================
-- ARCHIVO: 46-purchases-matching.sql
-- DESCRIPCION: 3-Way Matching (PO-Receipt-Invoice)
-- VERSION: 1.0.0
-- PROYECTO: ERP-Core V2
-- FECHA: 2026-01-20
-- DEPENDE DE: 23-purchases.sql
-- =============================================================

-- =====================
-- TABLA: purchase_order_matching
-- Registro de matching por orden de compra
-- =====================
CREATE TABLE IF NOT EXISTS purchases.purchase_order_matching (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    tenant_id UUID NOT NULL REFERENCES auth.tenants(id) ON DELETE CASCADE,
    purchase_order_id UUID NOT NULL REFERENCES purchases.purchase_orders(id) ON DELETE RESTRICT,

    -- Estado del matching
    status VARCHAR(20) NOT NULL DEFAULT 'pending', -- pending, partial_receipt, received, partial_invoice, matched, mismatch

    -- Totales
    total_ordered DECIMAL(15, 2) NOT NULL,
    total_received DECIMAL(15, 2) DEFAULT 0,
    total_invoiced DECIMAL(15, 2) DEFAULT 0,

    -- Varianzas calculadas
    receipt_variance DECIMAL(15, 2) GENERATED ALWAYS AS (total_ordered - total_received) STORED,
    invoice_variance DECIMAL(15, 2) GENERATED ALWAYS AS (total_received - total_invoiced) STORED,

    -- Referencias al ultimo documento
    last_receipt_id UUID REFERENCES purchases.purchase_receipts(id),
    last_invoice_id UUID,

    -- Matching completado
    matched_at TIMESTAMPTZ,
    matched_by UUID REFERENCES auth.users(id),

    -- Metadata
    created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,

    UNIQUE(tenant_id, purchase_order_id)
);

-- Indices para purchase_order_matching
CREATE INDEX IF NOT EXISTS idx_purchase_order_matching_tenant ON purchases.purchase_order_matching(tenant_id);
CREATE INDEX IF NOT EXISTS idx_purchase_order_matching_po ON purchases.purchase_order_matching(purchase_order_id);
CREATE INDEX IF NOT EXISTS idx_purchase_order_matching_status ON purchases.purchase_order_matching(status);
CREATE INDEX IF NOT EXISTS idx_purchase_order_matching_receipt ON purchases.purchase_order_matching(last_receipt_id);

-- =====================
-- TABLA: purchase_matching_lines
-- Matching por linea de orden de compra
-- =====================
CREATE TABLE IF NOT EXISTS purchases.purchase_matching_lines (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    matching_id UUID NOT NULL REFERENCES purchases.purchase_order_matching(id) ON DELETE CASCADE,
    order_item_id UUID NOT NULL REFERENCES purchases.purchase_order_items(id) ON DELETE RESTRICT,
    tenant_id UUID NOT NULL REFERENCES auth.tenants(id) ON DELETE CASCADE,

    -- Cantidades
    qty_ordered DECIMAL(15, 4) NOT NULL,
    qty_received DECIMAL(15, 4) DEFAULT 0,
    qty_invoiced DECIMAL(15, 4) DEFAULT 0,

    -- Precios
    price_ordered DECIMAL(15, 2) NOT NULL,
    price_invoiced DECIMAL(15, 2) DEFAULT 0,

    -- Varianzas calculadas
    qty_variance DECIMAL(15, 4) GENERATED ALWAYS AS (qty_ordered - qty_received) STORED,
    invoice_qty_variance DECIMAL(15, 4) GENERATED ALWAYS AS (qty_received - qty_invoiced) STORED,
    price_variance DECIMAL(15, 2) GENERATED ALWAYS AS (price_ordered - price_invoiced) STORED,

    -- Estado
    status VARCHAR(20) DEFAULT 'pending', -- pending, partial, matched, mismatch

    -- Metadata
    created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP
);

-- Indices para purchase_matching_lines
CREATE INDEX IF NOT EXISTS idx_purchase_matching_lines_matching ON purchases.purchase_matching_lines(matching_id);
CREATE INDEX IF NOT EXISTS idx_purchase_matching_lines_order_item ON purchases.purchase_matching_lines(order_item_id);
CREATE INDEX IF NOT EXISTS idx_purchase_matching_lines_tenant ON purchases.purchase_matching_lines(tenant_id);
CREATE INDEX IF NOT EXISTS idx_purchase_matching_lines_status ON purchases.purchase_matching_lines(status);

-- =====================
-- TABLA: matching_exceptions
-- Excepciones de matching
-- =====================
CREATE TABLE IF NOT EXISTS purchases.matching_exceptions (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    tenant_id UUID NOT NULL REFERENCES auth.tenants(id) ON DELETE CASCADE,
    matching_id UUID REFERENCES purchases.purchase_order_matching(id) ON DELETE CASCADE,
    matching_line_id UUID REFERENCES purchases.purchase_matching_lines(id) ON DELETE CASCADE,

    -- Tipo de excepcion
    exception_type VARCHAR(50) NOT NULL, -- over_receipt, short_receipt, over_invoice, short_invoice, price_variance

    -- Valores
    expected_value DECIMAL(15, 4),
    actual_value DECIMAL(15, 4),
    variance_value DECIMAL(15, 4),
    variance_percent DECIMAL(5, 2),

    -- Resolucion
    status VARCHAR(20) DEFAULT 'pending', -- pending, approved, rejected
    resolved_at TIMESTAMPTZ,
    resolved_by UUID REFERENCES auth.users(id),
    resolution_notes TEXT,

    -- Metadata
    created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP
);

-- Indices para matching_exceptions
CREATE INDEX IF NOT EXISTS idx_matching_exceptions_tenant ON purchases.matching_exceptions(tenant_id);
CREATE INDEX IF NOT EXISTS idx_matching_exceptions_matching ON purchases.matching_exceptions(matching_id);
CREATE INDEX IF NOT EXISTS idx_matching_exceptions_line ON purchases.matching_exceptions(matching_line_id);
CREATE INDEX IF NOT EXISTS idx_matching_exceptions_type ON purchases.matching_exceptions(exception_type);
CREATE INDEX IF NOT EXISTS idx_matching_exceptions_status ON purchases.matching_exceptions(status);

-- =====================
-- COMENTARIOS
-- =====================
COMMENT ON TABLE purchases.purchase_order_matching IS 'Registro de 3-way matching por orden de compra (PO-Receipt-Invoice)';
COMMENT ON COLUMN purchases.purchase_order_matching.status IS 'Estado: pending, partial_receipt, received, partial_invoice, matched, mismatch';
COMMENT ON COLUMN purchases.purchase_order_matching.receipt_variance IS 'Varianza = total_ordered - total_received (columna generada)';
COMMENT ON COLUMN purchases.purchase_order_matching.invoice_variance IS 'Varianza = total_received - total_invoiced (columna generada)';

COMMENT ON TABLE purchases.purchase_matching_lines IS 'Matching por linea de detalle de orden de compra';
COMMENT ON COLUMN purchases.purchase_matching_lines.qty_variance IS 'Varianza de cantidad = qty_ordered - qty_received (columna generada)';
COMMENT ON COLUMN purchases.purchase_matching_lines.invoice_qty_variance IS 'Varianza de factura = qty_received - qty_invoiced (columna generada)';
COMMENT ON COLUMN purchases.purchase_matching_lines.price_variance IS 'Varianza de precio = price_ordered - price_invoiced (columna generada)';

COMMENT ON TABLE purchases.matching_exceptions IS 'Excepciones detectadas durante el proceso de matching';
COMMENT ON COLUMN purchases.matching_exceptions.exception_type IS 'Tipo: over_receipt, short_receipt, over_invoice, short_invoice, price_variance';
COMMENT ON COLUMN purchases.matching_exceptions.status IS 'Estado: pending, approved, rejected';
