sábado, 12 de noviembre de 2016

Macro para conectar Excel y SAP y extraer la información de Costos ABC: Ciclos, Segmentos y Procesos.

Después de haber visto como construir una macro para conectar Excel y SAP y tener claro los objetos requeridos y los pasos necesarios para poder lograrlo, hoy vamos a ver una macro un poco mas avanzada.

La misión es construir una macro que nos permita ingresar a la transacción CPV2, ingresar a cada uno de los ciclos de reparto, extraer la información de los segmentos y finalmente obtener los procesos que componen el segmento, las clases de costos, los cecos que se utilizan y los porcentajes utilizados para distribuir los costos.


Cuál es el beneficio de esta macro? Generación de eficiencias en recursos, ya que hacer este proceso de forma manual, requiere de la dedicación de una persona a tiempo completo por unas 2 o 3 horas aproximadamente y hay que tener en cuenta que por tratarse de un proceso manual de copiar y pegar en el que hay que navegar por distintas pestañas y ventanas, la probabilidad de cometer errores es alta. 

Empecemos entonces, por construir una tabla en excel con los siguientes encabezados:



Esos campos, son los que vamos a extraer de SAP mapeandolos en nuestra macro

Lo primero es encender nuestro grabador de scripts, tal y como lo vimos en: como construir una macro para conectar Excel y SAP


Y vamos a ir ejecutando cada uno de los pasos necesarios. Lo primero es ingresar la transacción:




Ingresar el ciclo que queremos trabajar:



Ya estando dentro del ciclo, vamos a buscar los segmentos que lo componen (Shift + F4):





Y ya estando dentro del segmento, vamos a la pestaña Emisor/receptor, para extraer los centros de costo, que pueden estar por rangos o por grupos, al igual que las clases de coste es importante que demos clic en dichos campos, para que queden grabados en el script:






Luego, pasamos a la pestaña Base refer.recept. que es donde están las participaciones o el driver con el que vamos a realizar el reparto y damos clic en dichos campos, incluyendo el campo que nos muestra el total de registros encontrados:





Detenemos la grabadora, abrimos nuestro script, lo copiamos y pegamos en el editor de vba y hacemos los ajustes que aprendimos en el post: como construir una macro para conectar Excel y SAP y después de hacer algunas modificaciones, nuestro código va a ser el siguiente:

Código:
Sub script_sap()
Dim Application
Dim Connection
If Not IsObject(Application) Then
Set SapGuiAuto = GetObject("SAPGUI")
Set Application = SapGuiAuto.GetScriptingEngine
End If
If Not IsObject(Connection) Then
Set Connection = Application.Children(0)
End If
If Not IsObject(session) Then
Set session = Connection.Children(0)
End If
If IsObject(WScript) Then
WScript.ConnectObject session, "on"
WScript.ConnectObject Application, "on"
End If
With session
.findById("wnd[0]").maximize
.findById("wnd[0]/tbar[0]/okcd").Text = "CPV2"
.findById("wnd[0]").sendVKey 0
End With
filas = 0
For k = 1 To 17
session.findById("wnd[0]/usr/ctxtRKAL1-KSCYC").Text = Sheets("Hoja4").Range("A" & k).Text
ciclo = Sheets("Hoja4").Range("A" & k).Text
nombre_ciclo = Sheets("Hoja4").Range("B" & k).Text
session.findById("wnd[0]").sendVKey 0
session.findById("wnd[0]/tbar[1]/btn[16]").press
total_segmentos = session.findById("wnd[1]/usr/txtRCEVM-ENTRIES").Text
For j = 1 To total_segmentos
If j >= 2 Then
session.findById("wnd[1]/usr/tblSAPLKGALUEBERSICHT").verticalScrollbar.Position = j - 1
End If
segmento = session.findById("wnd[1]/usr/tblSAPLKGALUEBERSICHT/txtKGALS-NAME[0,0]").Text
nombre_segmento = session.findById("wnd[1]/usr/tblSAPLKGALUEBERSICHT/txtKGALS-TXT[1,0]").Text
session.findById("wnd[1]/usr/tblSAPLKGALUEBERSICHT/txtKGALS-NAME[0,0]").SetFocus
session.findById("wnd[1]").sendVKey 2
session.findById("wnd[0]/usr/tabsSEG_TABSTRIP/tabpOBJS").Select
ceco_desde = session.findById("wnd[0]/usr/tabsSEG_TABSTRIP/tabpOBJS/ssubSUB1:SAPMKAL1:0306/sub:SAPMKAL1:0306/ctxtKGALK-VALMIN[1,17]").Text
ceco_hasta = session.findById("wnd[0]/usr/tabsSEG_TABSTRIP/tabpOBJS/ssubSUB1:SAPMKAL1:0306/sub:SAPMKAL1:0306/ctxtKGALK-VALMAX[1,42]").Text
grupo_ceco = session.findById("wnd[0]/usr/tabsSEG_TABSTRIP/tabpOBJS/ssubSUB1:SAPMKAL1:0306/sub:SAPMKAL1:0306/ctxtKGALK-SETID[1,67]").Text
clase_desde = session.findById("wnd[0]/usr/tabsSEG_TABSTRIP/tabpOBJS/ssubSUB1:SAPMKAL1:0306/sub:SAPMKAL1:0306/ctxtKGALK-VALMIN[3,17]").Text
clase_hasta = session.findById("wnd[0]/usr/tabsSEG_TABSTRIP/tabpOBJS/ssubSUB1:SAPMKAL1:0306/sub:SAPMKAL1:0306/ctxtKGALK-VALMAX[3,42]").Text
grupo_clase = session.findById("wnd[0]/usr/tabsSEG_TABSTRIP/tabpOBJS/ssubSUB1:SAPMKAL1:0306/sub:SAPMKAL1:0306/ctxtKGALK-SETID[3,67]").Text
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
session.findById("wnd[0]/usr/tabsSEG_TABSTRIP/tabpRECE").Select
If ciclo = "3A130" Or ciclo = "3A997" Then
session.findById("wnd[0]/usr/tabsSEG_TABSTRIP/tabpRWFC").Select
registros = session.findById("wnd[0]/usr/tabsSEG_TABSTRIP/tabpRWFC/ssubSUB1:SAPMKAL1:0481/txtRKAL1-KGALKMAX").Text
For i = 1 To registros
With session
.findById("wnd[0]/usr/tabsSEG_TABSTRIP/tabpRECE/ssubSUB1:SAPMKAL1:0481/txtRKAL1-KGALKPOS").Text = "" & i
.findById("wnd[0]/usr/tabsSEG_TABSTRIP/tabpRWFC/ssubSUB1:SAPMKAL1:0481/txtRKAL1-KGALKPOS").SetFocus
.findById("wnd[0]/usr/tabsSEG_TABSTRIP/tabpRWFC/ssubSUB1:SAPMKAL1:0481/txtRKAL1-KGALKPOS").caretPosition = 5
.findById("wnd[0]").sendVKey 0
End With
Range("E" & filas + 2) = session.findById("wnd[0]/usr/tabsSEG_TABSTRIP/tabpRECE/ssubSUB1:SAPMKAL1:0481/sub:SAPMKAL1:0481/txtKGALF-TEXT1[0,0]").Text
Range("F" & filas + 2) = 100
Range("A" & filas + 2) = ciclo
Range("B" & filas + 2) = nombre_ciclo
Range("C" & filas + 2) = segmento
Range("D" & filas + 2) = nombre_segmento
Range("G" & filas + 2) = ceco_desde
Range("H" & filas + 2) = ceco_hasta
Range("I" & filas + 2) = grupo_ceco
Range("J" & filas + 2) = clase_desde
Range("K" & filas + 2) = clase_hasta
Range("L" & filas + 2) = grupo_clase
filas = filas + 1
Next i
Else
registros = session.findById("wnd[0]/usr/tabsSEG_TABSTRIP/tabpRECE/ssubSUB1:SAPMKAL1:0421/txtRKAL1-KGALKMAX").Text
For i = 1 To registros
With session
.findById("wnd[0]/usr/tabsSEG_TABSTRIP/tabpRECE").Select
.findById("wnd[0]/usr/tabsSEG_TABSTRIP/tabpRECE/ssubSUB1:SAPMKAL1:0421/txtRKAL1-KGALKPOS").Text = "" & i
.findById("wnd[0]/usr/tabsSEG_TABSTRIP/tabpRECE/ssubSUB1:SAPMKAL1:0421/txtRKAL1-KGALKPOS").SetFocus
.findById("wnd[0]/usr/tabsSEG_TABSTRIP/tabpRECE/ssubSUB1:SAPMKAL1:0421/txtRKAL1-KGALKPOS").caretPosition = 5
.findById("wnd[0]").sendVKey 0
End With
Range("E" & filas + 2) = session.findById("wnd[0]/usr/tabsSEG_TABSTRIP/tabpRECE/ssubSUB1:SAPMKAL1:0421/sub:SAPMKAL1:0421/txtKGALF-TEXT1[0,0]").Text
Range("F" & filas + 2) = session.findById("wnd[0]/usr/tabsSEG_TABSTRIP/tabpRECE/ssubSUB1:SAPMKAL1:0421/sub:SAPMKAL1:0421/txtKGALF-PERCENT[0,69]").Text
Range("G" & filas + 2) = ceco_desde
Range("H" & filas + 2) = ceco_hasta
Range("I" & filas + 2) = grupo_ceco
Range("J" & filas + 2) = clase_desde
Range("K" & filas + 2) = clase_hasta
Range("L" & filas + 2) = grupo_clase
Range("A" & filas + 2) = ciclo
Range("B" & filas + 2) = nombre_ciclo
Range("C" & filas + 2) = segmento
Range("D" & filas + 2) = nombre_segmento
filas = filas + 1
Next i
End If
With session
.findById("wnd[0]/tbar[0]/btn[3]").press
.findById("wnd[0]/tbar[1]/btn[16]").press
.findById("wnd[1]/usr/tblSAPLKGALUEBERSICHT/txtKGALS-NAME[0,1]").SetFocus
End With
Next j
With session
.findById("wnd[0]/tbar[1]/btn[16]").press
.findById("wnd[1]/usr/tblSAPLKGALUEBERSICHT/txtKGALS-NAME[0,0]").caretPosition = 6
.findById("wnd[1]/tbar[0]/btn[12]").press
.findById("wnd[0]/tbar[0]/btn[3]").press
.findById("wnd[0]/tbar[0]/btn[3]").press
.findById("wnd[1]/usr/btnSPOP-OPTION2").press
End With
Next k
End Sub
view raw sap_1.vb hosted with ❤ by GitHub

Vamos a crear una hoja adicional, donde vamos a listar los diferentes ciclos que componen nuestro sistema (estos los copiamos directamente de SAP):





Y vamos a ejecutar la macro paso a paso usando F8 y vamos a ver que es lo que hace cada una de las líneas del código.


En esta línea de código vamos a ingresar a la transacción:




Vamos a pasar a SAP el ciclo que tenemos en la hoja que construimos en excel:




Vamos a ingresar a los segmentos:




Vamos a extraer la cantidad de segmentos que componen el ciclo:




Y con esto vamos a empezar a iterar para recorrer todos los segmentos:




Vamos a extraer el segmento y el nombre del segmento:




Y vamos a ingresar a los procesos:




Seleccionamos la pestaña Emisor/Receptor:




Extraemos la información de los cecos y las cuentas:




Seleccionamos la pestaña Base refer.recept:




Extraemos la cantidad de registros que componen el segmento:





Y empezamos a extraer y a mapear en excel los valores de los diferentes campos de la tabla que creamos con anterioridad:



Al completar la primera iteración tenemos el siguiente resultado:



Y si le damos a la macro Ejecutar, tenemos después de 10 minutos:




Esa es la extracción completa. El resultado es un proceso optimizado que pasó de un tiempo de ejecución de entre 120 y 180 minutos a solo 10 minutos. 

Es una disminución en tiempo de proceso de mas del 90% y un recurso que no se tiene que ocupar en una tarea operativa y repetitiva que no agrega valor.

9 comentarios:

  1. Tienes mas publicaciones al respecto, PD: Eres un Crack

    ResponderBorrar
  2. Buen día; tienes una para sacar los saldos de dos almacenes?

    ResponderBorrar
  3. Buen dia.

    Yo tengo un problema con una tabla de sap que al parecer no me toma los datos, te pongo el scrpit

    Este es el script original

    session.findById("wnd[0]/usr/ctxtSP$00005-LOW").text = suc"
    session.findById("wnd[0]/usr/ctxtSP$00006-LOW").text = "Almacen"
    session.findById("wnd[0]/usr/ctxtSP$00001-HIGH").setFocus
    session.findById("wnd[0]/usr/ctxtSP$00001-HIGH").caretPosition = 0
    session.findById("wnd[0]/usr/btn%_SP$00001_%_APP_%-VALU_PUSH").press

    *Aqui toma los datos en tabla
    > session.findById("wnd[1]/usr/tabsTAB_STRIP/tabpSIVA/ssubSCREEN_HEADER:SAPLALDB:3010/tblSAPLALDBSINGLE/ctxtRSCSEL_255-SLOW_I[1,0]").text = "10237452321"
    > session.findById("wnd[1]/usr/tabsTAB_STRIP/tabpSIVA/ssubSCREEN_HEADER:SAPLALDB:3010/tblSAPLALDBSINGLE/ctxtRSCSEL_255-SLOW_I[1,1]").text = "10234567890"
    > session.findById("wnd[1]/usr/tabsTAB_STRIP/tabpSIVA/ssubSCREEN_HEADER:SAPLALDB:3010/tblSAPLALDBSINGLE/ctxtRSCSEL_255-SLOW_I[1,2]").text = "10513264201"
    session.findById("wnd[1]/usr/tabsTAB_STRIP/tabpSIVA/ssubSCREEN_HEADER:SAPLALDB:3010/tblSAPLALDBSINGLE/ctxtRSCSEL_255-SLOW_I[1,2]").setFocus
    session.findById("wnd[1]/usr/tabsTAB_STRIP/tabpSIVA/ssubSCREEN_HEADER:SAPLALDB:3010/tblSAPLALDBSINGLE/ctxtRSCSEL_255-SLOW_I[1,2]").caretPosition = 11

    ** Hasta aqui
    session.findById("wnd[1]/tbar[0]/btn[8]").press
    session.findById("wnd[0]/usr/ctxtSP$00002-LOW").text = "*"
    session.findById("wnd[0]/usr/ctxtSP$00002-LOW").setFocus
    session.findById("wnd[0]/usr/ctxtSP$00002-LOW").caretPosition = 1
    session.findById("wnd[0]/tbar[1]/btn[8]").press

    Modificado para tomar datos de excel

    session.FindById("wnd[0]/usr/ctxtSP$00005-LOW").Text = "almacen"
    session.FindById("wnd[0]/usr/ctxtSP$00006-LOW").Text = "PISO"
    session.FindById("wnd[0]/usr/ctxtSP$00002-LOW").Text = "*"
    session.FindById("wnd[0]/usr/ctxtSP$00001-HIGH").SetFocus
    session.FindById("wnd[0]/usr/ctxtSP$00001-HIGH").CaretPosition = 0
    session.FindById("wnd[0]/usr/btn%_SP$00001_%_APP_%-VALU_PUSH").Press

    > Set Cantou = session.FindById("wnd[1]/usr/tabsTAB_STRIP/tabpSIVA/ssubSCREEN_HEADER:SAPLALDB:3010/tblSAPLALDBSINGLE/ctxtRSCSEL_255-SLOW_I ")
    *esta parte me falla**

    Destino2 = ActiveSheet.Cells(Rows.Count, "A").End(xlUp).Row
    For I = 1 To (Destino2 + 1)
    Cantou.Text [1,I] = ActiveCell("A" & I + 1)
    Next
    Cantou.Text [1,I+1].SetFocus
    Cantou.Text [1,I+1].CaretPosition = 10

    ResponderBorrar
  4. Buenos dias, Alguien me puede ayudar a conectar el script con un excel que tome los datos de dos columnas y actualice los dato en sap.

    If Not IsObject(application) Then
    Set SapGuiAuto = GetObject("SAPGUI")
    Set application = SapGuiAuto.GetScriptingEngine
    End If
    If Not IsObject(connection) Then
    Set connection = application.Children(0)
    End If
    If Not IsObject(session) Then
    Set session = connection.Children(0)
    End If
    If IsObject(WScript) Then
    WScript.ConnectObject session, "on"
    WScript.ConnectObject application, "on"
    End If
    session.findById("wnd[0]").resizeWorkingPane 88,24,false
    session.findById("wnd[0]/tbar[0]/okcd").text = "sm30"
    session.findById("wnd[0]").sendVKey 0
    session.findById("wnd[0]/usr/radVIMDYNFLDS-LTD_DTA_AR").select
    session.findById("wnd[0]/usr/ctxtVIEWNAME").text = "v_t179"
    session.findById("wnd[0]/usr/radVIMDYNFLDS-LTD_DTA_AR").setFocus
    session.findById("wnd[0]/usr/btnUPDATE_PUSH").press
    session.findById("wnd[1]/usr/sub:SAPLSVIX:0210/chkMARK_CHECKBOX[0,0]").selected = true
    session.findById("wnd[1]").sendVKey 0
    session.findById("wnd[1]/usr/sub:SAPLSVIX:0100/ctxtD0100_FIELD_TAB-LOWER_LIMIT[0,37]").text = "R12313723"
    session.findById("wnd[1]/usr/sub:SAPLSVIX:0100/ctxtD0100_FIELD_TAB-LOWER_LIMIT[0,37]").caretPosition = 13
    session.findById("wnd[1]").sendVKey 0
    session.findById("wnd[0]/usr/tblSAPL080HTCTRL_V_T179/txtV_T179-VTEXT[2,0]").text = "Mf13245C"
    session.findById("wnd[0]/usr/tblSAPL080HTCTRL_V_T179/txtV_T179-VTEXT[2,0]").setFocus
    session.findById("wnd[0]/usr/tblSAPL080HTCTRL_V_T179/txtV_T179-VTEXT[2,0]").caretPosition = 4
    session.findById("wnd[0]/tbar[0]/btn[11]").press
    session.findById("wnd[0]/tbar[0]/btn[3]").press

    Muchas gracias por vuestra ayuda

    ResponderBorrar
  5. que lastima que nadie me pueda ayudar. De todas formas excelente blog.

    ResponderBorrar
    Respuestas
    1. Hola bonitronch no es difícil, necesitas unir la información de las dos columnas y ponerla en un campo de sap? Para hacerlo, puedes recurrir a concatenar los datos. En vba sería algo así: celda1 & “ “ & celda2.

      Slds

      Borrar
    2. El signo raro que aparece en la respuesta es el ampersand.

      Slds,

      Borrar
  6. Hola, si tienes que especificar una fecha, cómo se haría? ya que cada vez que ejecutes la macro habrá cambiado esta fecha. Gracias

    ResponderBorrar
  7. Hola, tengo una macro creada para descargar archivos del modulo F&R de SAP, pero en cada descarga me abre el archivo, se podría impedir esto?
    Si le digo que no tiene permiso para ejectuar en la carpeta, me sale un mensaje que no puedo confirmar desde Visual Basic.
    ¿Que puedo hacer? Muchas gracias.

    ResponderBorrar