Substituí 3 Relatórios Manuais SAP por Agentes de IA — Este Foi o ROI

Substituí 3 Relatórios Manuais SAP por Agentes de IA — Este Foi o ROI

Os Relatórios Que Consumiam a Semana da Minha Equipa

Todas as segundas-feiras de manhã, três analistas da minha equipa abriam o SAP GUI e iniciavam um ritual que consumia aproximadamente 22 horas de trabalho coletivo por semana. Executavam a transação MB52 para extrair valores de stock de armazém em 14 centros, exportavam para Excel, cruzavam referências com ordens de compra abertas do ME2M, e depois construíam manualmente uma análise de cobertura. Um segundo analista extraía partidas abertas de clientes via FBL5N para o aging de contas a receber, limpava os dados, aplicava regras de negócio para categorias de escalonamento, e enviava os resultados por email aos controllers regionais. O terceiro gerava um relatório de conformidade de compras comparando ordens de compra do ME2M contra preços negociados em contratos do ME33K.

Não eram relatórios de vaidade. As Finanças dependiam do aging de contas a receber para projeções de cash flow. A Supply chain usava o relatório de cobertura de stock para tomar decisões diárias de reposição. As Compras precisavam do relatório de conformidade para auditorias trimestrais. Os relatórios importavam — o que não fazia sentido era ter analistas qualificados a gastar as manhãs a copiar dados entre SAP e Excel.

Durante o Q3 e Q4 de 2025, substituí os três relatórios por agentes de IA que extraem dados diretamente do SAP, aplicam lógica de negócio, geram a análise e distribuem os resultados automaticamente. Aqui está exatamente como cada um funciona, quanto custou e o ROI mensurável.

Relatório #1: Análise de Cobertura de Stock (MB52 + ME2M)

Como Era o Processo Manual

A analista entrava no SAP GUI todas as segundas e quartas, executava a transação MB52 (Stocks de Armazém) filtrada por centro e localização de armazém. Para a nossa configuração, isso significava 14 centros, cada um com 3-8 localizações de armazém. Executava o relatório, exportava para uma folha de cálculo local usando a função de exportação da grelha ALV (Lista > Exportar > Folha de cálculo), e depois repetia para o centro seguinte.

Depois de recolher todos os dados de stock, mudava para ME2M (Pedidos de Compra por Material) para extrair POs abertos com datas de entrega nos próximos 30 dias. Isto exigia outra ronda de exportações — filtrando por centro, tipo de documento (NB para pedidos standard, UB para transferências de stock), e removendo itens completados.

Depois vinha a análise real: calcular dias de cobertura dividindo stock atual pelo consumo médio diário (que extraía do MC.9 — estatísticas de consumo de material), sinalizar artigos abaixo dos limiares de stock de segurança, e destacar materiais sem fornecimento a caminho no pipeline.

Tempo total: aproximadamente 8 horas por semana.

O Agente de IA Que o Substituiu

O agente corre sobre um backend Python com execução agendada via APScheduler. Liga-se ao SAP via RFC usando a biblioteca PyRFC, que dá acesso direto a BAPIs e módulos de função — muito mais eficiente do que fazer scraping à GUI ou usar OData para extração de dados em grande volume.

from pyrfc import Connection
import pandas as pd

def get_warehouse_stocks(conn, plants):
    # Extrair dados de stock equivalente ao MB52
    stocks = []
    for plant in plants:
        result = conn.call('BAPI_MATERIAL_STOCK_REQ_LIST',
            PLANT=plant,
            MATERIAL='',  # todos os materiais
            RAW_DATA='X'
        )
        for item in result['STOCK_REQ_LIST']:
            stocks.append({
                'plant': plant,
                'material': item['MATERIAL'],
                'storage_loc': item['STGE_LOC'],
                'unrestricted': float(item['UNRESTRICTED']),
                'in_quality': float(item['QUAL_INSP']),
                'blocked': float(item['BLOCKED']),
                'unit': item['BASE_UOM']
            })
    return pd.DataFrame(stocks)

def get_open_purchase_orders(conn, plants):
    # Extrair POs abertos equivalente ao ME2M
    pos = []
    for plant in plants:
        result = conn.call('BAPI_PO_GETITEMS',
            PLANT=plant,
            DOC_TYPE='NB',
            ITEMS_OPEN_ONLY='X'
        )
        for item in result['PO_ITEMS']:
            if float(item['STILL_TO_DL']) > 0:
                pos.append({
                    'plant': plant,
                    'po_number': item['PO_NUMBER'],
                    'material': item['PUR_MAT'],
                    'quantity_open': float(item['STILL_TO_DL']),
                    'delivery_date': item['DELIV_DATE'],
                    'vendor': item['VENDOR']
                })
    return pd.DataFrame(pos)

O componente de IA entra na camada de análise. Em vez de regras hardcoded para sinalizar problemas, treinei um modelo de classificação com 18 meses de eventos históricos de rutura de stock. O modelo considera níveis de stock atuais, velocidade de consumo, tempos de entrega do mestre de materiais (tabela MARC, campo PLIFZ para tempo de entrega planeado), padrões sazonais, e fiabilidade de POs abertos (que percentagem de POs de cada fornecedor realmente chega a tempo, extraído da EKBE — historial de pedidos de compra).

def calculate_coverage_with_ai(stocks_df, orders_df, consumption_df, model):
    # Análise de cobertura melhorada com IA
    merged = stocks_df.merge(consumption_df, on=['plant', 'material'], how='left')
    merged = merged.merge(
        orders_df.groupby(['plant', 'material']).agg(
            incoming_qty=('quantity_open', 'sum'),
            earliest_delivery=('delivery_date', 'min')
        ).reset_index(),
        on=['plant', 'material'], how='left'
    )

    merged['daily_consumption'] = merged['avg_monthly_consumption'] / 30
    merged['coverage_days'] = merged.apply(
        lambda r: r['unrestricted'] / r['daily_consumption']
        if r['daily_consumption'] > 0 else 999, axis=1
    )

    features = merged[['coverage_days', 'incoming_qty', 'vendor_reliability',
                        'seasonal_factor', 'consumption_volatility']].fillna(0)
    merged['stockout_probability'] = model.predict_proba(features)[:, 1]

    merged['risk_level'] = merged['stockout_probability'].apply(
        lambda p: 'CRITICAL' if p > 0.7 else ('WARNING' if p > 0.4 else 'OK')
    )

    return merged

O agente formata os resultados como um relatório HTML interativo e envia por email à equipa de supply chain, com itens críticos destacados no topo. Também envia itens CRITICAL para um canal Microsoft Teams via webhook.

ROI do Relatório #1

CategoriaProcesso ManualAgente IA
Horas de trabalho semanais8 horas0.5 horas (apenas revisão)
Custo laboral anual (€65/hr custo total)€27,040€1,690
Custo de infraestrutura (anual)€0 (licença SAP GUI incluída)€2,400 (VM + licença PyRFC)
Incidentes de rutura de stock (anual)3411
Impacto estimado em receitas de ruturas prevenidas-€180,000
Benefício líquido anual-€202,950

A grande vitória aqui não foi a poupança laboral — foi a redução de ruturas de stock. O modelo de IA deteta padrões de risco que os humanos não veem porque processa os 14 centros simultaneamente e considera possibilidades de transferência entre centros. Quando o Centro 1200 está a ficar sem um material mas o Centro 1400 tem excesso, o agente sinaliza a oportunidade de transferência. A analista nunca tinha tempo de fazer análise entre centros manualmente.

Relatório #2: Aging de Contas a Receber (FBL5N)

O Processo Manual

Todas as terças e quintas, um analista executava FBL5N (Partidas de Cliente) para cada empresa (operamos cinco). Configurava os parâmetros para mostrar apenas partidas abertas, ordenava por data de vencimento líquido, exportava para Excel, e depois aplicava um conjunto complexo de regras de negócio:

  • Partidas 1-30 dias vencidas: categoria "Lembrete", sem escalonamento
  • Partidas 31-60 dias vencidas: categoria "Acompanhamento", email ao representante de vendas
  • Partidas 61-90 dias vencidas: categoria "Escalonamento", email ao gestor de vendas + controller regional
  • Partidas 90+ dias vencidas: categoria "Crítico", email ao VP de Vendas + Diretor Financeiro
  • Regras especiais: clientes governamentais recebem 15 dias de graça extra, clientes com acordos de plano de pagamento são excluídos, partidas abaixo de €500 são agrupadas num resumo separado

Também extraía historial de pagamentos da tabela BSAD (partidas compensadas de clientes) para calcular o comportamento médio de pagamento de cada cliente — pagam tipicamente a tempo, 10 dias atrasados, 30 dias atrasados?

Tempo total: aproximadamente 6 horas por semana.

O Agente de IA

Este agente usa ligações RFC para extrair dados de tabelas FI diretamente. Os dados principais vêm de BSID (partidas abertas de clientes) e BSAD (partidas compensadas para historial de pagamentos):

def get_ar_aging_data(conn, company_codes):
    # Extrair dados AR equivalente ao FBL5N partidas abertas
    open_items = []
    for bukrs in company_codes:
        result = conn.call('RFC_READ_TABLE',
            QUERY_TABLE='BSID',
            DELIMITER='|',
            OPTIONS=[{'TEXT': f"BUKRS = '{bukrs}'"}],
            FIELDS=[
                {'FIELDNAME': 'BUKRS'}, {'FIELDNAME': 'KUNNR'},
                {'FIELDNAME': 'BELNR'}, {'FIELDNAME': 'BUZEI'},
                {'FIELDNAME': 'BLDAT'}, {'FIELDNAME': 'BUDAT'},
                {'FIELDNAME': 'ZFBDT'}, {'FIELDNAME': 'ZBD1T'},
                {'FIELDNAME': 'DMBTR'}, {'FIELDNAME': 'WAERS'},
                {'FIELDNAME': 'SGTXT'}
            ]
        )
        for row in result['DATA']:
            fields = row['WA'].split('|')
            open_items.append(parse_bsid_row(fields, bukrs))
    return pd.DataFrame(open_items)

O componente de IA aqui faz duas coisas que o processo manual não conseguia:

1. Previsão de pagamentos. Usando dados históricos de pagamento da BSAD, o modelo prevê quando cada partida aberta será realmente paga. Não apenas "tem 45 dias vencida" mas "baseado no padrão de comportamento deste cliente, esta partida tem 78% de probabilidade de ser paga nos próximos 7 dias." Isto transforma o relatório de aging de uma fotografia retroativa numa projeção para o futuro.

from sklearn.ensemble import GradientBoostingClassifier
import numpy as np

def train_payment_predictor(historical_data):
    # Treinar modelo com partidas compensadas para prever timing de pagamento
    features = historical_data[[
        'customer_segment', 'invoice_amount_bucket',
        'historical_avg_days_late', 'historical_payment_count',
        'days_since_due', 'company_code', 'is_government',
        'has_payment_plan', 'credit_limit_utilization'
    ]]

    target = (historical_data['actual_days_to_payment'] <= 7).astype(int)

    model = GradientBoostingClassifier(
        n_estimators=200,
        max_depth=5,
        learning_rate=0.1
    )
    model.fit(features, target)
    return model

2. Encaminhamento inteligente de escalonamento. Em vez de regras rígidas baseadas em escalões, o agente considera o contexto completo. Uma fatura de €50,000 de um cliente que sempre paga 5 dias atrasado não é o mesmo risco que uma fatura de €50,000 de um cliente com padrões de pagamento a deteriorar-se. A IA pontua cada partida e encaminha emails de escalonamento à pessoa certa com o contexto apropriado.

O agente gera relatórios individualizados para cada controller regional, mostrando apenas os seus clientes. Os representantes de vendas recebem um email matinal com as suas partidas específicas de acompanhamento, incluindo pontos de conversa sugeridos baseados no historial de pagamento do cliente. "O Cliente XYZ tem 3 faturas que totalizam €127,000 vencidas há 45 dias. O seu atraso médio de pagamento aumentou de 12 para 28 dias durante o último trimestre — sugerimos discutir condições de pagamento na próxima reunião."

ROI do Relatório #2

CategoriaProcesso ManualAgente IA
Horas de trabalho semanais6 horas0.3 horas (revisão de exceções)
Custo laboral anual€20,280€1,014
Custo de infraestrutura (anual)€0€1,800
DSO médio (Dias de Vendas Pendentes)52 dias44 dias
Capital circulante libertado (anual, baseado em €40M de receitas)-€876,712
Dívidas incobráveis (anual)€145,000€82,000
Benefício líquido anual-€957,178

Só a redução de DSO justificou o projeto inteiro dez vezes. Quando consegues prever quais clientes vão entrar em incumprimento antes de realmente falharem o prazo, a tua equipa de cobranças pode fazer chamadas proativas em vez de reativas. A melhoria de 8 dias no DSO sobre €40M em receitas anuais traduz-se em quase €900K em capital circulante libertado — dinheiro que estava previamente parado em faturas por pagar.

Relatório #3: Verificação de Conformidade de Compras (ME2M + ME33K)

O Processo Manual

Este era o mais doloroso. A analista de conformidade extraía todos os pedidos de compra criados no último mês do ME2M, depois verificava manualmente cada um contra o contrato relevante no ME33K para confirmar que o preço do PO correspondia ao preço negociado do contrato. Para materiais sem contratos, verificava contra o preço do registo info no ME13.

A lógica de verificação era surpreendentemente complexa:

  • Tolerância de preço: o preço do PO pode estar até 3% acima do preço do contrato para materiais, 5% para serviços
  • Tolerância de quantidade: a quantidade do PO deve estar dentro do período de validade do contrato e abaixo da quantidade restante do contrato
  • Correspondência de fornecedor: o fornecedor do PO deve corresponder ao fornecedor do contrato (óbvio, mas ocorrem violações quando alguém digita manualmente um número de fornecedor diferente)
  • Condições de pagamento: as condições de pagamento do PO devem corresponder ou ser mais favoráveis que as do contrato
  • Gasto maverick: POs para materiais que têm um contrato ativo mas foram encomendados fora do contrato (fornecedor diferente ou sem referência a contrato)

Compilava todas as violações numa folha de cálculo, categorizava-as por severidade e departamento, e enviava ao Diretor de Compras mensalmente. O relatório também alimentava a auditoria interna trimestral.

Tempo total: aproximadamente 8 horas por semana (concentradas no fecho do mês).

O Agente de IA

Este agente extrai dados de várias tabelas SAP: EKKO/EKPO (cabeçalho/item de pedido), EKKO (cabeçalho de contrato via categoria de documento "K"), EINE/EINA (registos info de compras), e LFA1 (mestre de fornecedores).

def check_procurement_compliance(conn, company_code, date_from, date_to):
    # Verificar POs contra contratos e registos info

    po_data = get_purchase_orders(conn, company_code, date_from, date_to)
    contracts = get_active_contracts(conn, company_code)
    info_records = get_info_records(conn)

    violations = []
    for _, po in po_data.iterrows():
        contract = find_matching_contract(
            contracts,
            material=po['material'],
            vendor=po['vendor'],
            plant=po['plant'],
            date=po['doc_date']
        )

        if contract is not None:
            price_deviation = (po['net_price'] - contract['contract_price']) / contract['contract_price']
            tolerance = 0.05 if po['item_category'] == 'D' else 0.03

            if price_deviation > tolerance:
                violations.append({
                    'type': 'PRICE_OVERRUN',
                    'severity': 'HIGH' if price_deviation > 0.10 else 'MEDIUM',
                    'po_number': po['po_number'],
                    'material': po['material'],
                    'po_price': po['net_price'],
                    'contract_price': contract['contract_price'],
                    'deviation_pct': price_deviation * 100,
                    'financial_impact': (po['net_price'] - contract['contract_price']) * po['quantity']
                })
        else:
            available_contract = find_any_contract_for_material(
                contracts, material=po['material']
            )
            if available_contract is not None:
                violations.append({
                    'type': 'MAVERICK_SPEND',
                    'severity': 'HIGH',
                    'po_number': po['po_number'],
                    'material': po['material'],
                    'vendor_used': po['vendor'],
                    'contract_vendor': available_contract['vendor'],
                    'financial_impact': po['net_price'] * po['quantity']
                })

    return pd.DataFrame(violations)

A IA acrescenta valor aqui de três formas:

1. Deteção de padrões em problemas sistemáticos de conformidade. O modelo identifica padrões que sugerem problemas organizacionais, não apenas violações individuais. "O Departamento 4200 teve 23 instâncias de gasto maverick nos últimos 90 dias, todas do mesmo comprador. 18 delas são para materiais cobertos pelo contrato 4600012345 com fornecedor 100234." Isto não é algo que detetarias a rever POs individuais.

2. Redução de falsos positivos. Muitas violações aparentes têm razões legítimas — compras de emergência, emendas de contrato ainda não refletidas no sistema, substituições de fornecedor aprovadas pela gestão de compras. O modelo de IA aprende de dados históricos de disposição (quais violações foram marcadas como "justificadas" em auditorias anteriores) e atribui uma pontuação de confiança. Violações que correspondem a padrões de exceções historicamente justificadas são despriorizadas, poupando à equipa de conformidade a revisão de centenas de não-problemas.

3. Previsão de impacto financeiro. Em vez de apenas mostrar "este PO está 7% acima do preço do contrato," o agente calcula o impacto anual total se este desvio de preço persistir em todas as encomendas para este material. Um sobrecusto de 7% num material que encomendas duas vezes por ano são €200. O mesmo sobrecusto num material que encomendas semanalmente poderia ser €50,000 anuais.

ROI do Relatório #3

CategoriaProcesso ManualAgente IA
Horas de trabalho semanais8 horas1 hora (revisão de exceções + ações)
Custo laboral anual€27,040€3,380
Custo de infraestrutura (anual)€0€1,800
Gasto maverick identificado (anual)€320,000€890,000
Gasto maverick efetivamente recuperado€48,000 (15%)€356,000 (40%)
Poupanças por conformidade de preços€12,000€67,000
Benefício líquido anual-€386,860

A taxa de recuperação saltou de 15% para 40% porque o agente de IA apresenta cada violação com contexto completo — os detalhes do contrato, o padrão histórico, o impacto anualizado, e uma ação recomendada. Quando um gestor de compras recebe um relatório a dizer "O Comprador X colocou €890,000 em encomendas fora de contratos durante o último trimestre, aqui estão os 5 padrões principais e correções sugeridas," pode tomar ação imediata em vez de passar dias a investigar.

A Infraestrutura Técnica por Trás dos Três Agentes

Os três agentes partilham infraestrutura comum:

  • Runtime: Python 3.11 numa VM Ubuntu com 4 cores e 8 GB RAM
  • Conectividade SAP: PyRFC com SAP NetWeaver RFC SDK, ligando via um utilizador RFC dedicado com autorizações mínimas (acesso apenas de leitura às tabelas e BAPIs específicas necessárias)
  • Agendamento: APScheduler com um job store PostgreSQL para persistência
  • Framework ML: scikit-learn para os modelos de classificação e previsão, re-treinados mensalmente com dados frescos do SAP
  • Geração de relatórios: Templates Jinja2 a produzir emails HTML, com pandas para manipulação de dados
  • Monitorização: Métricas Prometheus exportadas para Grafana — tempo de execução, contagem de registos, taxas de erro

O custo total de infraestrutura entre os três agentes é aproximadamente €6,000 por ano. O benefício anual combinado ultrapassa €1.5 milhões. Isso é um retorno de 250x.

O Que Aprendi a Construí-los

Começa com o relatório que a tua equipa mais detesta. Não escolhas o mais fácil — escolhe o que causa mais frustração. É aí que vais conseguir a adoção mais rápida e a menor resistência dos stakeholders. Ninguém discutiu com automatizar o relatório de conformidade porque todos detestavam produzi-lo e recebê-lo atrasado.

A IA não é a parte difícil — a extração de dados é. Tirar dados do SAP de forma fiável, lidar com as peculiaridades do RFC_READ_TABLE (limite de 65,535 linhas por chamada, alguém?), lidar com conversão de moedas, diferenças de exercício fiscal, e os formatos de data únicos do SAP — é aí que vai 70% do tempo de desenvolvimento. Os modelos de ML reais são problemas diretos de classificação e regressão.

Mantém o humano no processo, mas move-o de "produtor" para "revisor." Nenhum destes agentes corre de forma completamente autónoma. Cada um produz um relatório que um humano revê antes da distribuição. Mas rever um relatório terminado e contextualizado demora 15-30 minutos. Produzi-lo do zero demorava 6-8 horas. É essa a ganância de eficiência.

RFC é melhor que OData para operações batch. Inicialmente tentei usar APIs OData para tudo. Para o relatório de cobertura de stock, extrair dados de stock de 14 centros através de OData demorava 12 minutos e frequentemente dava timeout. Os mesmos dados através de RFC demoram 45 segundos. OData é ótimo para operações transacionais e integração de UI, mas para analytics batch, RFC é simplesmente mais rápido.

Constrói o ciclo de feedback desde o primeiro dia. Cada agente tem um mecanismo simples para os utilizadores reportarem problemas — um link "reportar problema" no email que cria um ticket. Este feedback é reincorporado no re-treino do modelo. O modelo de aging de contas a receber melhorou a sua precisão de previsão de pagamentos de 71% para 89% em seis meses puramente com correções de utilizadores.

Os Números Combinados

MétricaAntes (3 relatórios)Depois (3 agentes)
Horas de trabalho semanais22 horas1.8 horas
Custo laboral anual€74,360€6,084
Custo de infraestrutura anual€0€6,000
Benefícios financeiros anuais (para além do laboral)€60,000€1,479,712
Benefício líquido anual total-€1,541,988
Custo de desenvolvimento (único)-€45,000
Período de retorno-11 dias

Um período de retorno de 11 dias. Não é gralha. Os benefícios financeiros da redução de ruturas de stock, melhoria de DSO, e recuperação de gasto maverick eclipsam tanto os custos de desenvolvimento como os contínuos.

Deves Fazer Isto?

Se a tua equipa gasta mais de 4 horas por semana em qualquer relatório recorrente de SAP que envolva exportar dados, manipulá-los em Excel, e distribuir resultados, a resposta é sim. O padrão é sempre o mesmo: extrair via RFC, analisar com Python (com ou sem ML dependendo da complexidade), formatar com templates, distribuir via email ou Teams, monitorizar com ferramentas standard.

Os três relatórios que escolhi não são especiais. A mesma abordagem funciona para análise de exceções MRP (MD04), relatórios de variância de ordens de produção (CO03), resultados de inspeção de qualidade (QA32), relatórios de gestão de transportes (VT02N), e dezenas de outros relatórios recorrentes de SAP que são atualmente produzidos manualmente.

Deixa de exportar para Excel. Constrói um agente. Mede os resultados. O ROI falará por si.