Monday, November 19, 2012

Llamando a Python desde ERP (con PyRFC)

Si leyeron mi blog anterior Volviendo a visitar Python y SAP (con PyRFC)  seguramente recordaran que dije que con PyRFC no solo podemos extraer o ejecutar servicios del lado del ERP, pero tambien podemos utiliar PyRFC como un servidor que puede ser llamado desde el ERP.

En otras palabras, podemos crear una funcion en Python que sera servida por PyRFC y luego sera llamada por un modulo de funciones en el ERP.

En este blog vamos a construir un comparador de XML, el cual va a leer dos archivos XML y nos va a devolver lo que se ha agregado y lo que se ha eliminado.

Ya deberian tener el PyRFC instalado, asi que sigamos adelante con los pasos que debemos seguir para hacer que esto funcione...

Primero, necesitamos obtener la informacion del servidor Gateway, asi que vayamos a la transaccion SMGW y escojamos Goto --> Parameters --> Display. Al final de la tabla, encontran la informacion que necesitamos.


Luego, necesitamos crear una conexion TCP/IP, para que podamos llamar a nuestro servidor PyRFC. Vamos a la transaccion SM59 y creamos lo siguiente.


Ahora, necesitamos crear un archivo que contendra la informacion de nuestra conexion, tanto para el ERP como para nuestro servidor Gateway.



En mis pruebas, utilice el gwhost que viene de la SMGW pero por alguna razon no funciono correctamente...Utilice entonces el valor de ashost...asi que traten con el primero y si no funciona, hagan lo mismo que yo.

Ahora, logeense al ERP y creen una estructura simple llamada ZXML_RESPONSE.


Creen un Table Type utilizando la estructura y llamenlo ZXML_RESPONSE_TT.

Ahora, vamos a la transaccion SE37 y creamos un modulo de funciones llamado ZXML_DIFF. Este FM estara vacio puesto que todo el trabajo se hace del lado de Python.


Por ahora...hemos terminado con el lado del ERP...continuemos al lado de Python...

Necesitamos dos librerias para hacer que esto funciones ListComparator and ElementTree, pueden instalar ambas utilizando easy_install.

El codigo es simple, Python va a recibir dos rutas, una para cada archivo XML, va a leer su contenido, comparar las diferencias y devolvernos lo que ha sido agregado y lo que ha sido eliminado.



PyRFC_XML_Diff.py
from sapnwrfc2 import Server, Connection
from ConfigParser import ConfigParser
from elementtree import ElementTree as ET
from listcomparator.comparator import Comparator

config = ConfigParser()
config.read('sapnwrfc.cfg')


def xml_diff(request_context, XML_1="", XML_2="", ROOT="",
                    ADDITIONS=[], DELETIONS=[]):
    add_list = {}
    del_list = {}
    length = 0
    lower_root = ROOT.encode('utf-8')
    root_old = ET.parse(XML_1).getroot()
    root_new = ET.parse(XML_2).getroot()
    objects_old = root_old.findall(lower_root.lower())
    objects_new = root_new.findall(lower_root.lower())
    objects_old = [ET.tostring(o) for o in objects_old]
    objects_new = [ET.tostring(o) for o in objects_new]
    my_comp = Comparator(objects_old, objects_new)
    my_comp.check()

    for e in my_comp.additions:
        line = e.split("\n")
        length = len(line)
        for i in range(0, length):
            add_list = {}
            add_list.update({"LINE": line[i]})
            ADDITIONS.append(add_list)

    for e in my_comp.deletions:
        line = e.split("\n")
        length = len(line)
        for i in range(0, length):
            del_list = {}
            del_list.update({"LINE": line[i]})
            DELETIONS.append(del_list)

    return {
        'ADDITIONS': ADDITIONS,
        'DELETIONS': DELETIONS
    }

params_connection = config._sections['connection']
conn = Connection(**params_connection)
func_xml_diff = conn.get_function_description("ZXML_DIFF")

params_gateway = config._sections['gateway']
server = Server(**params_gateway)
server.install_function(func_xml_diff, xml_diff)
print "--- Server registration and serving ---"
server.serve(100)

Ahora que ya tenemos todo listo del lado del Servidor de Python...vamos a definir un par de archivos XML para probarlo.




Podemos ver claramente que ambos archivos XML son diferentes...y que el individuo Blag ha recibido un raro aumento en su cantidad...vamos a analizar esto...

Regresemos a la transaccion SE37 y ejecutemos la funcion. Es muy importante llenar el parametro RFC Target sys con el nombre que usamos para nuestra conexion RFC.


El parametro ROOT le dira a nuestra funcion cual es el nodo padre de nuestro archivo XML.

Ahora, ejecutamos la aplicacion PyRFC_XML_Diff.py y veremos esto, que nos va a indicar que nuestro servidor esta listo y funcionando.



Ahora, ejecutamos la funcion y recibiremos nuestra respuesta de Python.


Ahora, podemos analizar las tablas ADDITIONS y DELETIONS...


Podemos ver que algo paso con la cuenta 0001, que no fue agregada, pero uno de sus valores fue modificado. Tambien, en el segundo archivo XML, la cuenta de Kiara fue agregada.


Asi que ahora, todo cae por su propio peso...la cuenta de Blag solia tener una cantidad de 100 y ahora tiene una cantidad de 10,000.

Asi que como pueden ver, solo utilizamos una caparazon en el ERP para llamar a toda la funcionalidad desde Python.

Saludos,

Blag.

4 comments:

sergio mesa said...

sNo te imaginas como me ayudaste en este momento, justamente buscaba algo asi. muchas gracias Blag.

Alvaro "Blag" Tejada Galindo said...

Sergio!Que bueno te haya servido el blog -:)

Saludos,

Blag.

Francisco Guerra said...

Buenas tardes Alvaro, tengo problemas al intentar instalar el módulo sapnwrfc en windows para poder realizar el ejemplo, que podría hacer en este caso? Saludos

Alvaro "Blag" Tejada Galindo said...

Francisco:

El sapnwrfc tienes que descargarlo desde el SAP Marketplace (Necesitas un usuario)...

https://websmp109.sap-ag.de/patches --> Browse our download catalog --> Additional Components --> SAP NW RFC SDK

Saludos,

Blag.