Sustituí 3 Informes Manuales de SAP por Agentes de IA — Este Fue el ROI

Sustituí 3 Informes Manuales de SAP por Agentes de IA — Este Fue el ROI

Los Informes Que Consumían la Semana de Mi Equipo

Cada lunes por la mañana, tres analistas de mi equipo abrían SAP GUI y comenzaban un ritual que consumía aproximadamente 22 horas de trabajo colectivo cada semana. Ejecutaban la transacción MB52 para extraer valores de stock de almacén en 14 plantas, exportaban a Excel, cruzaban referencias con órdenes de compra abiertas de ME2M, y después construían manualmente un análisis de cobertura. Un segundo analista extraía partidas abiertas de clientes vía FBL5N para el aging de cuentas por cobrar, limpiaba los datos, aplicaba reglas de negocio para categorías de escalamiento, y enviaba los resultados por correo a los controllers regionales. El tercero generaba un informe de cumplimiento de compras comparando órdenes de compra de ME2M contra precios negociados en contratos de ME33K.

No eran informes de vanidad. Finanzas dependía del aging de cuentas por cobrar para proyecciones de flujo de caja. Supply chain usaba el informe de cobertura de stock para tomar decisiones diarias de reposición. Compras necesitaba el informe de cumplimiento para auditorías trimestrales. Los informes importaban — lo que no tenía sentido era tener analistas cualificados gastando sus mañanas copiando datos entre SAP y Excel.

Durante Q3 y Q4 de 2025, reemplacé los tres informes con agentes de IA que extraen datos directamente de SAP, aplican lógica de negocio, generan el análisis y distribuyen los resultados automáticamente. Aquí está exactamente cómo funciona cada uno, cuánto costó y el ROI medible.

Informe #1: Análisis de Cobertura de Stock (MB52 + ME2M)

Cómo Era el Proceso Manual

La analista entraba a SAP GUI cada lunes y miércoles, ejecutaba la transacción MB52 (Stocks de Almacén) filtrada por planta y ubicación de almacenamiento. Para nuestra configuración, eso significaba 14 plantas, cada una con 3-8 ubicaciones de almacenamiento. Ejecutaba el informe, exportaba a una hoja de cálculo local usando la función de exportación del grid ALV (Lista > Exportar > Hoja de cálculo), y luego lo hacía de nuevo para la siguiente planta.

Después de recopilar todos los datos de stock, cambiaba a ME2M (Pedidos de Compra por Material) para extraer POs abiertos con fechas de entrega en los próximos 30 días. Esto requería otra ronda de exportaciones — filtrando por planta, tipo de documento (NB para pedidos estándar, UB para traslados de stock), y eliminando posiciones completadas.

Luego venía el análisis real: calcular días de cobertura dividiendo stock actual entre consumo medio diario (que extraía de MC.9 — estadísticas de consumo de material), marcar artículos por debajo de umbrales de stock de seguridad, y resaltar materiales sin suministro entrante en el pipeline.

Tiempo total: aproximadamente 8 horas por semana.

El Agente de IA Que Lo Reemplazó

El agente corre sobre un backend Python con ejecución programada vía APScheduler. Se conecta a SAP vía RFC usando la librería PyRFC, que da acceso directo a BAPIs y módulos de función — mucho más eficiente que hacer scraping de la GUI o usar OData para extracción de datos en alto volumen.

from pyrfc import Connection
import pandas as pd

def get_warehouse_stocks(conn, plants):
    # Extraer datos de stock equivalente a MB52
    stocks = []
    for plant in plants:
        result = conn.call('BAPI_MATERIAL_STOCK_REQ_LIST',
            PLANT=plant,
            MATERIAL='',  # todos los materiales
            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):
    # Extraer POs abiertos equivalente a 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)

El componente de IA entra en la capa de análisis. En vez de reglas hardcodeadas para marcar problemas, entrené un modelo de clasificación con 18 meses de eventos históricos de rotura de stock. El modelo considera niveles de stock actuales, velocidad de consumo, tiempos de entrega del maestro de materiales (tabla MARC, campo PLIFZ para tiempo de entrega planificado), patrones estacionales, y fiabilidad de POs abiertos (qué porcentaje de POs de cada proveedor realmente llegan a tiempo, extraído de EKBE — historial de pedidos de compra).

def calculate_coverage_with_ai(stocks_df, orders_df, consumption_df, model):
    # Análisis de cobertura mejorado con 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'
    )

    # Calcular días de cobertura básicos
    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
    )

    # Predicción IA: probabilidad de rotura en próximos 14 días
    features = merged[['coverage_days', 'incoming_qty', 'vendor_reliability',
                        'seasonal_factor', 'consumption_volatility']].fillna(0)
    merged['stockout_probability'] = model.predict_proba(features)[:, 1]

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

    return merged

El agente formatea los resultados como un informe HTML interactivo y lo envía por correo al equipo de supply chain, con elementos críticos resaltados arriba. También envía los elementos CRITICAL a un canal de Microsoft Teams vía webhook.

ROI del Informe #1

CategoríaProceso ManualAgente IA
Horas laborales semanales8 horas0.5 horas (solo revisión)
Costo laboral anual (€65/hr costo total)€27,040€1,690
Costo de infraestructura (anual)€0 (licencia SAP GUI incluida)€2,400 (VM + licencia PyRFC)
Incidentes de rotura de stock (anual)3411
Impacto estimado en ingresos de roturas prevenidas-€180,000
Beneficio neto anual-€202,950

La gran victoria aquí no fue el ahorro laboral — fue la reducción de roturas de stock. El modelo de IA detecta patrones de riesgo que los humanos no ven porque procesa las 14 plantas simultáneamente y considera posibilidades de transferencia entre plantas. Cuando la Planta 1200 se está quedando sin un material pero la Planta 1400 tiene exceso, el agente marca la oportunidad de transferencia. La analista nunca tenía tiempo de hacer análisis entre plantas manualmente.

Informe #2: Aging de Cuentas por Cobrar (FBL5N)

El Proceso Manual

Cada martes y jueves, un analista ejecutaba FBL5N (Partidas de Cliente) para cada sociedad (operamos cinco). Configuraba los parámetros para mostrar solo partidas abiertas, ordenaba por fecha de vencimiento neto, exportaba a Excel, y después aplicaba un conjunto complejo de reglas de negocio:

  • Partidas 1-30 días vencidas: categoría "Recordatorio", sin escalamiento
  • Partidas 31-60 días vencidas: categoría "Seguimiento", email al representante de ventas
  • Partidas 61-90 días vencidas: categoría "Escalamiento", email al gerente de ventas + controller regional
  • Partidas 90+ días vencidas: categoría "Crítico", email al VP de Ventas + Director Financiero
  • Reglas especiales: clientes gubernamentales obtienen 15 días de gracia extra, clientes con acuerdos de plan de pago se excluyen, partidas menores a €500 se agrupan en un resumen separado

También extraía historial de pagos de la tabla BSAD (partidas compensadas de clientes) para calcular el comportamiento promedio de pago de cada cliente — ¿pagan típicamente a tiempo, 10 días tarde, 30 días tarde?

Tiempo total: aproximadamente 6 horas por semana.

El Agente de IA

Este agente usa conexiones RFC para extraer datos de tablas FI directamente. Los datos principales vienen de BSID (partidas abiertas de clientes) y BSAD (partidas compensadas para historial de pagos):

def get_ar_aging_data(conn, company_codes):
    # Extraer datos AR equivalente a FBL5N partidas abiertas
    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)

El componente de IA aquí hace dos cosas que el proceso manual no podía:

1. Predicción de pagos. Usando datos históricos de pago de BSAD, el modelo predice cuándo cada partida abierta será realmente pagada. No solo "tiene 45 días vencida" sino "basado en el patrón de comportamiento de este cliente, esta partida tiene un 78% de probabilidad de ser pagada en los próximos 7 días." Esto transforma el informe de aging de una foto retroactiva a una proyección hacia adelante.

from sklearn.ensemble import GradientBoostingClassifier
import numpy as np

def train_payment_predictor(historical_data):
    # Entrenar modelo con partidas compensadas para predecir timing de pago
    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'
    ]]

    # Objetivo: pagará en 7 días (1) o no (0)
    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. Enrutamiento inteligente de escalamiento. En vez de reglas rígidas basadas en tramos, el agente considera el contexto completo. Una factura de €50,000 de un cliente que siempre paga 5 días tarde no es el mismo riesgo que una factura de €50,000 de un cliente con patrones de pago deteriorándose. La IA califica cada partida y enruta emails de escalamiento a la persona correcta con el contexto apropiado.

El agente genera informes individualizados para cada controller regional, mostrando solo sus clientes. Los representantes de ventas reciben un email matutino con sus partidas específicas de seguimiento, incluyendo puntos de conversación sugeridos basados en el historial de pago del cliente. "El Cliente XYZ tiene 3 facturas que suman €127,000 vencidas hace 45 días. Su retraso promedio de pago ha aumentado de 12 a 28 días durante el último trimestre — sugerimos discutir condiciones de pago en la próxima reunión."

ROI del Informe #2

CategoríaProceso ManualAgente IA
Horas laborales semanales6 horas0.3 horas (revisión de excepciones)
Costo laboral anual€20,280€1,014
Costo de infraestructura (anual)€0€1,800
DSO promedio (Días de Ventas Pendientes)52 días44 días
Capital circulante liberado (anual, basado en €40M de ingresos)-€876,712
Deudas incobrables (anual)€145,000€82,000
Beneficio neto anual-€957,178

Solo la reducción de DSO justificó todo el proyecto diez veces. Cuando puedes predecir qué clientes van a caer en mora antes de que realmente incumplan el plazo, tu equipo de cobranzas puede hacer llamadas proactivas en vez de reactivas. La mejora de 8 días en DSO sobre €40M en ingresos anuales se traduce en casi €900K en capital circulante liberado — dinero que previamente estaba atrapado en facturas impagadas.

Informe #3: Verificación de Cumplimiento de Compras (ME2M + ME33K)

El Proceso Manual

Este era el más doloroso. La analista de cumplimiento extraía todos los pedidos de compra creados en el último mes de ME2M, luego verificaba manualmente cada uno contra el contrato relevante en ME33K para confirmar que el precio del PO coincidiera con el precio negociado del contrato. Para materiales sin contratos, verificaba contra el precio del registro info en ME13.

La lógica de verificación era sorprendentemente compleja:

  • Tolerancia de precio: el precio del PO puede estar hasta 3% por encima del precio del contrato para materiales, 5% para servicios
  • Tolerancia de cantidad: la cantidad del PO debe estar dentro del período de validez del contrato y por debajo de la cantidad restante del contrato
  • Coincidencia de proveedor: el proveedor del PO debe coincidir con el proveedor del contrato (obvio, pero ocurren violaciones cuando alguien escribe manualmente un número de proveedor diferente)
  • Condiciones de pago: las condiciones de pago del PO deben coincidir o ser más favorables que las del contrato
  • Gasto maverick: POs para materiales que tienen un contrato activo pero fueron ordenados fuera del contrato (proveedor diferente o sin referencia a contrato)

Compilaba todas las violaciones en una hoja de cálculo, las categorizaba por severidad y departamento, y la enviaba al Jefe de Compras mensualmente. El informe también alimentaba la auditoría interna trimestral.

Tiempo total: aproximadamente 8 horas por semana (concentradas al cierre de mes).

El Agente de IA

Este agente extrae datos de varias tablas SAP: EKKO/EKPO (cabecera/posición de pedido), EKKO (cabecera de contrato vía categoría de documento "K"), EINE/EINA (registros info de compras), y LFA1 (maestro de proveedores).

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

    # Obtener todos los POs en rango de fechas
    po_data = get_purchase_orders(conn, company_code, date_from, date_to)

    # Obtener todos los contratos activos
    contracts = get_active_contracts(conn, company_code)

    # Obtener registros info como referencia de precios
    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)

La IA agrega valor aquí de tres formas:

1. Detección de patrones en problemas sistemáticos de cumplimiento. El modelo identifica patrones que sugieren problemas organizacionales, no solo violaciones individuales. "El Departamento 4200 ha tenido 23 instancias de gasto maverick en los últimos 90 días, todas del mismo comprador. 18 de ellas son para materiales cubiertos por el contrato 4600012345 con proveedor 100234." Esto no es algo que detectarías revisando POs individuales.

2. Reducción de falsos positivos. Muchas violaciones aparentes tienen razones legítimas — compras de emergencia, enmiendas de contrato aún no reflejadas en el sistema, sustituciones de proveedor aprobadas por la gerencia de compras. El modelo de IA aprende de datos históricos de disposición (qué violaciones fueron marcadas como "justificadas" en auditorías previas) y asigna una puntuación de confianza. Las violaciones que coinciden con patrones de excepciones históricamente justificadas se despriorizan, ahorrando al equipo de cumplimiento la revisión de cientos de no-problemas.

3. Pronóstico de impacto financiero. En vez de solo mostrar "este PO está 7% por encima del precio del contrato," el agente calcula el impacto anual total si esta desviación de precio persiste en todos los pedidos para este material. Un sobrecosto de 7% en un material que pides dos veces al año son €200. El mismo sobrecosto en un material que pides semanalmente podría ser €50,000 anuales.

ROI del Informe #3

CategoríaProceso ManualAgente IA
Horas laborales semanales8 horas1 hora (revisión de excepciones + acciones)
Costo laboral anual€27,040€3,380
Costo de infraestructura (anual)€0€1,800
Gasto maverick identificado (anual)€320,000€890,000
Gasto maverick efectivamente recuperado€48,000 (15%)€356,000 (40%)
Ahorros por cumplimiento de precios€12,000€67,000
Beneficio neto anual-€386,860

La tasa de recuperación saltó de 15% a 40% porque el agente de IA presenta cada violación con contexto completo — los detalles del contrato, el patrón histórico, el impacto anualizado, y una acción recomendada. Cuando un gerente de compras recibe un informe diciendo "El Comprador X ha colocado €890,000 en pedidos fuera de contratos durante el último trimestre, aquí están los 5 patrones principales y correcciones sugeridas," puede tomar acción inmediata en vez de pasar días investigando.

La Infraestructura Técnica Detrás de los Tres Agentes

Los tres agentes comparten infraestructura común:

  • Runtime: Python 3.11 en una VM Ubuntu con 4 cores y 8 GB RAM
  • Conectividad SAP: PyRFC con SAP NetWeaver RFC SDK, conectando vía un usuario RFC dedicado con autorizaciones mínimas (acceso de solo lectura a las tablas y BAPIs específicas necesarias)
  • Programación: APScheduler con un job store PostgreSQL para persistencia
  • Framework ML: scikit-learn para los modelos de clasificación y predicción, re-entrenados mensualmente con datos frescos de SAP
  • Generación de informes: Templates Jinja2 produciendo emails HTML, con pandas para manipulación de datos
  • Monitoreo: Métricas Prometheus exportadas a Grafana — tiempo de ejecución, conteo de registros, tasas de error

El costo total de infraestructura entre los tres agentes es aproximadamente €6,000 por año. El beneficio anual combinado supera €1.5 millones. Eso es un retorno de 250x.

Lo Que Aprendí Construyéndolos

Empieza con el informe que tu equipo más detesta. No elijas el más fácil — elige el que causa más frustración. Ahí es donde conseguirás la adopción más rápida y la menor resistencia de los stakeholders. Nadie discutió con automatizar el informe de cumplimiento porque todos detestaban producirlo y recibirlo tarde.

La IA no es la parte difícil — la extracción de datos sí. Sacar datos de SAP de forma fiable, manejar las peculiaridades de RFC_READ_TABLE (¿límite de 65,535 filas por llamada, alguien?), lidiar con conversión de monedas, diferencias de ejercicio fiscal, y los formatos de fecha únicos de SAP — ahí es donde va el 70% del tiempo de desarrollo. Los modelos de ML reales son problemas directos de clasificación y regresión.

Mantén al humano en el proceso, pero muévelo de "productor" a "revisor." Ninguno de estos agentes corre completamente de forma autónoma. Cada uno produce un informe que un humano revisa antes de la distribución. Pero revisar un informe terminado y contextualizado toma 15-30 minutos. Producirlo desde cero tomaba 6-8 horas. Esa es la ganancia de eficiencia.

RFC es mejor que OData para operaciones batch. Inicialmente intenté usar APIs OData para todo. Para el informe de cobertura de stock, extraer datos de stock de 14 plantas a través de OData tomaba 12 minutos y frecuentemente daba timeout. Los mismos datos a través de RFC toman 45 segundos. OData es genial para operaciones transaccionales e integración de UI, pero para analytics batch, RFC es simplemente más rápido.

Construye el bucle de retroalimentación desde el día uno. Cada agente tiene un mecanismo simple para que los usuarios reporten problemas — un enlace "reportar problema" en el email que crea un ticket. Esta retroalimentación se reincorpora al re-entrenamiento del modelo. El modelo de aging de cuentas por cobrar mejoró su precisión de predicción de pagos de 71% a 89% en seis meses puramente con correcciones de usuarios.

Los Números Combinados

MétricaAntes (3 informes)Después (3 agentes)
Horas laborales semanales22 horas1.8 horas
Costo laboral anual€74,360€6,084
Costo de infraestructura anual€0€6,000
Beneficios financieros anuales (más allá del laboral)€60,000€1,479,712
Beneficio neto anual total-€1,541,988
Costo de desarrollo (único)-€45,000
Período de recuperación-11 días

Un período de recuperación de 11 días. No es un error de tipografía. Los beneficios financieros de la reducción de roturas de stock, mejora de DSO, y recuperación de gasto maverick eclipsan tanto los costos de desarrollo como los continuos.

¿Deberías Hacer Esto?

Si tu equipo gasta más de 4 horas por semana en cualquier informe recurrente de SAP que involucre exportar datos, manipularlos en Excel, y distribuir resultados, la respuesta es sí. El patrón es siempre el mismo: extraer vía RFC, analizar con Python (con o sin ML dependiendo de la complejidad), formatear con templates, distribuir vía email o Teams, monitorear con herramientas estándar.

Los tres informes que elegí no son especiales. El mismo enfoque funciona para análisis de excepciones MRP (MD04), informes de varianza de órdenes de producción (CO03), resultados de inspección de calidad (QA32), informes de gestión de transporte (VT02N), y docenas de otros informes recurrentes de SAP que actualmente se producen manualmente.

Deja de exportar a Excel. Construye un agente. Mide los resultados. El ROI hablará por sí mismo.