BOT sin SAP BPA
Automatizar MIGO por pantalla sin SAP BPA (para ahorrar costo), la vía
más sólida sin licenciamiento es usar SAP GUI Scripting con Python o
VBScript. No se necesita licencia de RPA.
Opción recomendada : SAP GUI Scripting + Python
Funciona leyendo el Excel, abriendo SAP GUI, entrando a /NMIGO y llenando
campos uno a uno, repitiendo tantas filas como haya.
Qué se necesita
1. Activar SAP GUI Scripting
o En el servidor SAP: RZ11 → sapgui/user_scripting = TRUE.
o En el PC: SAP Logon → Options → Accessibility & Scripting →
Enable scripting.
2. Windows + SAP GUI instalado.
3. Python 3.x + paquetes:
pip install pywin32 pandas openpyxl
4. EL Excel con los movimientos (campos)
Flujo de alto nivel
1. Cargar Excel → recorrer filas.
2. Garantizar sesión SAP abierta (SAP Logon) y login.
3. Ir a /NMIGO.
4. Según TipoMovimiento (101/201/261/309/311), llenar campos de MIGO:
o 101 por OC: Pedido, Posición, Centro, Almacén, Cantidad, Lote (si
aplica), Fechas/Textos.
o 201 CeCo / 261 Orden PP / 309–311 Traslados: campos
correspondientes.
5. Verificar → leer barra de estado.
6. Si OK → Contabilizar → extraer Documento de material de la barra.
7. Escribir resultado por fila en una pestaña Estados (OK/ERROR, mensaje,
doc, fecha).
Script base (Python + COM SAP GUI)
Esto es un esqueleto funcional para adaptarlo a los campos/IDs de MIGO.
Los ID exactos varían por versión/layout, pero la idea es esta.
import time, re
import pandas as pd
import win32com.client as win32
EXCEL_PATH = r"C:\ruta\Plantilla_MIGO_Masiva_BPA.xlsx" # ajusta ruta
def get_sap_session():
SapGuiAuto = win32.GetObject("SAPGUI")
application = SapGuiAuto.GetScriptingEngine
connection = application.Children(0) # primer sistema abierto en SAP
Logon
session = connection.Children(0) # primera sesión
return session
def login_if_needed():
# abre SAP Logon si no está abierto
try:
_ = win32.GetObject("SAPGUI")
except:
shell = win32.Dispatch("WScript.Shell")
shell.Run(r'"C:\Program Files (x86)\SAP\FrontEnd\Sapgui\saplogon.exe"')
time.sleep(3)
# aquí puedes automatizar el clic al sistema y login con
WScript.Shell.SendKeys
# o deja la sesión ya abierta manualmente y el bot continúa.
def goto_migo(ses):
ses.findById("wnd[0]/tbar[0]/okcd").text = "/NMIGO"
ses.findById("wnd[0]").sendVKey(0)
time.sleep(0.5)
def press_check(ses):
ses.findById("wnd[0]/tbar[1]/btn[5]").press() # botón Verificar
time.sleep(0.5)
return ses.findById("wnd[0]/sbar").text,
ses.findById("wnd[0]/sbar").messageType
def press_post(ses):
ses.findById("wnd[0]/tbar[1]/btn[11]").press() # botón Contabilizar
time.sleep(0.8)
msg = ses.findById("wnd[0]/sbar").text
m = re.search(r"\b(\d{10})\b", msg)
return msg, (m.group(1) if m else "")
def fill_101_po(ses, row):
# ejemplo: seleccionar "Entrada de mercancías" + "Pedido"
# Dependiendo del layout, estos son combo/radios. Ajusta IDs:
# ses.findById("wnd[0]/usr/...tipo_doc").key = "R01" # ilustrativo
# Campo pedido:
ses.findById("wnd[0]/usr/ctxtRM07M-EBELN").text = str(row.DocReferencia)
# OC
ses.findById("wnd[0]/usr/ctxtRM07M-EBELP").text = str(row.ItemRef) #
Pos
ses.findById("wnd[0]").sendVKey(0) # Adoptar
time.sleep(0.5)
# Completa cantidad, centro, almacén, lote, textos, fechas...
# Estos IDs varían; inspecciona con el Recorder de SAP GUI:
# ses.findById("wnd[0]/usr/tblSAPL.../txtMSEG-ERFMG[... , rowIndex]").text =
str(row.Cantidad)
# ses.findById("wnd[0]/usr/.../ctxtMSEG-LGORT").text =
row.Almacen_Destino
# ses.findById("wnd[0]/usr/.../ctxtMSEG-WERKS").text = row.Centro
# Fechas si son campos de cabecera:
# ses.findById("wnd[0]/usr/ctxtMKPF-BLDAT").text = "08.08.2025"
# ses.findById("wnd[0]/usr/ctxtMKPF-BUDAT").text = "08.08.2025"
# Textos:
# ses.findById("wnd[0]/usr/.../txtMSEG-SGTXT").text = row.TextoPosicion
pass
def process_row(ses, row):
goto_migo(ses)
tm = str(row.TipoMovimiento)
ref = str(row.Referencia).upper()
if tm == "101" and ref == "PO":
fill_101_po(ses, row)
elif tm == "201":
# TODO: construir subflujo 201 (CeCo)
pass
elif tm == "261":
# TODO: subflujo 261 (Orden PP)
pass
elif tm in ("309","311"):
# TODO: subflujo traslados
pass
else:
return "ERROR", "TipoMovimiento/Referencia no soportado", ""
msg, typ = press_check(ses)
if typ == "S": # Success
msg2, doc = press_post(ses)
return "OK", msg2, doc
else:
return "ERROR", msg, ""
def main():
login_if_needed()
ses = get_sap_session()
df = pd.read_excel(EXCEL_PATH, sheet_name="Movimientos")
log_rows = []
for _, r in df.iterrows():
try:
est, msg, doc = process_row(ses, r)
except Exception as e:
est, msg, doc = "ERROR", f"Excepción: {e}", ""
log_rows.append({
"ID_Fila": r.get("ID_Fila", ""),
"Estatus": est,
"Mensaje": msg,
"DocMaterial": doc,
"FechaHora": pd.Timestamp.now()
})
log_df = pd.DataFrame(log_rows)
with pd.ExcelWriter(EXCEL_PATH, engine="openpyxl", mode="a",
if_sheet_exists="replace") as w:
log_df.to_excel(w, sheet_name="Estados", index=False)
if __name__ == "__main__":
main()
Encuentrar los IDs de los campos en SAP
Abrir SAP, activa Script Recording and Playback (menú Customize
Local Layout → icono “reloj”)
Graba el llenado manual de MIGO una vez; eso te dará los IDs reales
(como wnd[0]/usr/...) para reemplazar en fill_101_po y demás subflujos.
Alternativas similar sin licencia
VBScript (aún más ligero, usa la misma API COM de SAP GUI Scripting).
Robocorp (open-source, Python + robot framework; puede combinarlo
con SAP GUI Scripting).
AutoHotkey (solo teclas/ventanas—rápido pero frágil; no recomendado
para MIGO por cantidad de pop-ups).