Pricing Curve Integration

Integração de Machine Curve (Curva ABC) no Pricing Agent

Data: 2025-01-03
Objetivo: Documentar como a machine_curve é obtida e usada no sistema de precificação


📋 Onde a Tabela product_classification é Usada

A tabela csuite_pricing.product_classification armazena a classificação ABC (machine_curve) de cada produto e é usada em três pontos principais:

1. Stored Procedure sp_price_compute_v8

A stored procedure recebe machine_curve como parâmetro de entrada (p_machine_curve) e usa para calcular o curve_factor:

-- Dentro da stored procedure
SELECT COALESCE((
    SELECT factor
    FROM csuite_pricing.pricing_curve_factors
    WHERE machine_curve = p_machine_curve
      AND is_active = 1
    LIMIT 1
), 1.000000)
INTO v_curve_factor;

-- O curve_factor é então usado para ajustar o desconto final
SET v_discount_final = v_discount_allowed * v_curve_factor;

Arquivo: csuite-pricing/sql/sp_price_compute_v8_corrigida.sql

2. Engine Python (agents/pricing/engine.py)

O engine recebe machine_curve como parâmetro e passa para a stored procedure:

def compute_price_v8(
    org_id: int,
    brand_id: int,
    customer_id: Optional[int],
    sku_id: int,
    sku_qty: int,
    order_value: float,
    payment_term: str,
    stock_level: str,
    machine_curve: str,  # A | B | C | D | E
    db: Optional[Session] = None
) -> Dict[str, Any]:

Arquivo: agents/pricing/engine.py

3. Context Builder (agents/pricing/context.py)

O context builder busca machine_curve da tabela product_classification quando não vem no payload:

# Consultar Machine Curve (curva ABC) da tabela product_classification
if org_id and sku_id:
    machine_curve_from_table = get_machine_curve(org_id, sku_id)
    if machine_curve_from_table:
        context["machine_curve"] = machine_curve_from_table
        context["machine_curve_source"] = "product_classification"

Arquivo: agents/pricing/context.py

4. Repository (agents/pricing/repository.py)

Nova função criada para buscar machine_curve:

def get_machine_curve(org_id: int, sku_id: int) -> Optional[str]:
    """
    Consulta machine_curve (curva ABC) para SKU

    Returns:
        machine_curve (A, B, C, D, E) ou None se não encontrado
    """

Arquivo: agents/pricing/repository.py


🔄 Como Adicionar machine_curve na View vw_pricing_catalog_active

Script SQL Criado

Foi criado o script csuite-pricing/sql/update_vw_pricing_catalog_active_with_curve.sql que:

  1. Dropa a view existente (se houver)
  2. Cria a view atualizada com machine_curve incluído
  3. Faz LEFT JOIN com product_classification para obter a curva
  4. Usa fallback 'B' se não houver classificação
  5. Prioriza classificação mais recente quando há múltiplas org_ids

Estrutura da View Atualizada

CREATE VIEW vw_pricing_catalog_active AS
SELECT 
    ps.brand_id,
    ps.sku_id,
    ps.pt AS PT,
    pf.piso AS PISO,
    COALESCE(pc.machine_curve, 'B') AS machine_curve,  -- ✅ NOVO CAMPO
    pc.is_active AS classification_active,
    ps.is_active AS screen_active,
    pf.is_active AS floor_active,
    GREATEST(...) AS last_updated
FROM 
    csuite_pricing.price_screen ps
    INNER JOIN csuite_pricing.price_floor pf 
        ON ps.sku_id = pf.sku_id
    LEFT JOIN (
        -- Subquery para pegar apenas a classificação mais recente e ativa por sku_id
        SELECT 
            sku_id,
            machine_curve,
            is_active,
            updated_at,
            ROW_NUMBER() OVER (PARTITION BY sku_id ORDER BY updated_at DESC, org_id DESC) AS rn
        FROM csuite_pricing.product_classification
        WHERE is_active = 1
    ) pc ON ps.sku_id = pc.sku_id AND pc.rn = 1
WHERE 
    ps.is_active = 1
    AND pf.is_active = 1
ORDER BY 
    ps.brand_id, ps.sku_id;

Como Executar

# Conectar ao banco e executar o script
mysql -h <host> -u <user> -p csuite_pricing < csuite-pricing/sql/update_vw_pricing_catalog_active_with_curve.sql

Ou via Python:

from agents.pricing.database import get_pricing_db_session

db = get_pricing_db_session()
with open('csuite-pricing/sql/update_vw_pricing_catalog_active_with_curve.sql', 'r') as f:
    sql = f.read()
    db.execute(text(sql))
    db.commit()

📊 Fluxo de Dados

1. product_classification (tabela)
   └─> machine_curve: A, B, C, D, E
       
       ├─> vw_pricing_catalog_active (view)  NOVO
          └─> Exibe machine_curve junto com PT e PISO
       
       ├─> get_machine_curve() (repository)
          └─> context.py
              └─> build_context()
                  └─> engine.compute_price_v8()
                      └─> sp_price_compute_v8()
                          └─> pricing_curve_factors
                              └─> curve_factor
                                  └─> v_discount_final

✅ Resumo das Mudanças

  1. Função get_machine_curve() criada em repository.py
  2. Context builder atualizado para buscar machine_curve da tabela quando não vem no payload
  3. Script SQL criado para atualizar vw_pricing_catalog_active com machine_curve
  4. View atualizada para incluir machine_curve com fallback para 'B'

🔍 Verificação

Após executar o script SQL, verifique a view:

-- Verificar se machine_curve está presente
SELECT 
    brand_id,
    sku_id,
    PT,
    PISO,
    machine_curve,  -- ✅ Deve aparecer aqui
    classification_active
FROM vw_pricing_catalog_active
LIMIT 10;

-- Estatísticas por curva
SELECT 
    machine_curve,
    COUNT(*) AS total
FROM vw_pricing_catalog_active
GROUP BY machine_curve;

🔊 Text-to-Speech

1.0x
1.0
Pronto para reproduzir