SAP ERP es un Enterprise Resource Planner creado por SAP.
Alguno de los módulos más conocidos del SAP ERP son:
- El módulo financiero contable
- Control de gastos
- Gestión de materiales
- Ventas y distribución
- Gestión de planta, entre otros
Cada módulo de SAP ERP contiene entidades que representan los objetos de negocios o Business Objects (BO) del ERP, definiendo su estructura y las operaciones que se pueden realizar con ellas, respetando las reglas de negocios de cada una, estas se conocen con el nombre de Business Object API (BAPIs).
SAP cuenta con un repositorio para estos objetos de negocio que recibe el nombre de Business Object Repository (BOR).
Un ejemplo de un Business Object podría ser Material en el módulo de Gestión de Materiales o Sales Order en el módulo de ventas y distribución.
Un método de la BAPI Material, sería GetDetail() que permite obtener la información detallada de un material en particular.
SAP ERP Connector de GeneXus for SAP Systems permite explorar el Business Object Repository, accediendo a todas las BAPIs publicadas y así poder importar los métodos para que sean llamados desde GeneXus permitiendo una integración entre GeneXus y SAP ERP.
Tip: En SAP se pueden crear objetos y funciones personalizadas. Por convención estos elementos se nombran prefijandolos con una Z, para diferenciarlos de los elementos estándar. En el caso de las BAPIs, los administradores de un sistema SAP, pueden haber creado ZBAPIs para implementar una personalización en particular. Las ZBAPIs también pueden ser incluidas en el Business Object Repository y por ende ser accesibles por GeneXus for SAP System ERP Connector.
Para Explorar/Importar las BAPIs disponibles en un sistema SAP, diríjase a Tools > Application Integration > SAP BAPI IMPORT.
Esta opción presenta un diálogo, donde se pueden ingresar los datos de conexión del sistema SAP ERP a explorar.
Los valores a ser ingresados en este diálogo se encuentran en la configuración de la cuenta de la interfaz del ERP, llamada SAP GUI.
Se puede probar si la conexión está disponible con el botón Test Connection. Notificará si la conexión fue exitosa o no.
Para comenzar a explorar el BOR oprima el botón OK.
Tip: Tener más de una cierta cantidad de intentos fallidos de ingreso a SAP bloqueará la cuenta. Cada sistema puede tener una cantidad diferente de máximos intentos fallidos. La prueba de conexión también realiza un intento de ingreso.
A continuación se detallan los campos a completar:
Connection Name
|
Nombre que recibirá la conexión
|
Application Server
|
Dirección del servidor SAP ERP al que desea conectarse
|
Instance Number
|
Número de instancia del servidor
|
System ID
|
Identificador del Sistema SAP a conectarse.
|
Client Number
|
Número de mandante (Entorno de ejecución)
|
Router String
|
Se especifican las estaciones de una conexión entre dos anfitriones
|
Use SAPGUI
|
Se inicia SAPGUI (interfaz de SAP) para mostrar el resultado de la conexión
|
Language
|
Lenguaje utilizado en la conexión.
|
User Name
|
Nombre de usuario de la cuenta SAP
|
Password
|
Contraseña de la cuenta SAP
|
Una vez ingresados los datos de conexión al ERP SAP, seleccione OK.
Podrá visualizar, en el formulario que se ha cargado, el Business Object Repository en el Panel izquierdo, mostrando todos los Business Objects dentro de un árbol jerárquico.
Cada Business Object se puede expandir para ver los métodos correspondientes.
Si se selecciona una BAPI, en el Panel derecho podrá ver información sobre la misma, junto con los parámetros requeridos y documentación de cómo realizar la llamada al método.
Seleccionando el Tab Info (Method) verá la opción de hacer un Test en Runtime, que permitirá probar el funcionamiento del método en tiempo de ejecución, para esto se debe completar los parámetros solicitados.
Para esta demo diríjase a la categoría Sales and Distribution > Sales Organization y seleccione dentro del objeto Sales Order el método CreateFromDat2.
Este método permitirá crear una Sales Order, cumpliendo con el requerimiento solicitado de que el sistema cree órdenes de venta en SAP.
Una vez seleccionada la BAPI haga click en import para incorporarla en su KB.
Se puede importar más de una BAPI a la vez.
Una vez seleccionadas las BAPIs a importar, se muestra un listado de las mismas y se puede configurar un prefijo para nombrar los objetos.
Las BAPIs serán importadas al módulo especificado.
Haga click en Confirm para completar el proceso de importación.
Una vez importadas las BAPIs cierre el ERP Connector y diríjase al KB Explorer.
Se puede ver que GeneXus ha generado de forma automática objetos, una vez importada la BAPI.
Para cada parámetro del método se ha generado un Structured Data Type (SDT).
Se generan 2 objetos externos:
- GXEnterpriseSessionManager (gestiona la conexión al ERP)
- sapCustomerOrder (representa al Business Object Sales Order que fue importado)
El objeto GXEnterpriseSessionManager define los datos de sesión para establecer la conexión con el ERP SAP.
Se puede observar que los atributos son los mismos que se deben ingresar cuando se explora el árbol de BAPIs.
Para manejar los datos de sesión de SAP adecuadamente, se puede definir un Structured Data Type que permita almacenar, en una variable, los datos de sesión para la conexión con el ERP.
Para crear el Structured Data Type cree un folder llamado ‘SAPIntegration’ haciendo click derecho en el módulo Root y seleccione New > Folder.
Una vez que haya creado la carpeta, haga click derecho y seleccione New > Object y cree el Structured Data Type llamado ‘SAPSessionData’.
Defina los siguientes atributos:
Nombre Atributo
|
Tipo
|
SAPSessionAppServer
|
Character (512)
|
SAPSessionInstanceNumber
|
Character (10)
|
SAPSessionRouterString
|
Character (512)
|
SAPSessionClientNumber
|
Character (10)
|
SAPSessionSystemId
|
Character (10)
|
SAPSessionSessionName
|
Character (40)
|
SAPSessionSAPGUI
|
Character (10)
|
SAPSessionLanguage
|
Character (3)
|
SAPSessionUserName
|
Character (40)
|
SAPSessionPassword
|
Character (40)
|
El Structured Data Type debe quedar definido de la siguiente manera:
De esta manera queda definida la estructura permitiendo almacenar información sobre las sesiones SAP que se manejan desde la aplicación.
En la siguiente demo se considera que se va a utilizar una sola sesión de SAP. En este caso, las conexiones con el sistema SAP se realizan al mismo servidor y con un único juego de credenciales.
Tip: En un escenario real es recomendable que los datos del Server SAP ERP se encuentren en alguna tabla para facilitar el mantenimiento y permitir varios servers a los cuales conectar la aplicación. Del mismo modo, cada usuario tendrá sus credenciales para acceder a SAP ERP.
En este caso, por ser una POC, se cargará la sesión a través de un Objeto Data Provider.
Haga click derecho en la carpeta ‘SAPIntegration’ y seleccione New > Object.
Seleccione Data Provider en la categoría Common y nombre al objeto ‘SAPSessionDataDP’
Una vez creado, en KB Explorer arrastre el icono del SDT ‘SAPSessionData’ y suelte el elemento en el código del Data Provider ‘SAPSessionDataDP’.
De esta forma, automáticamente quedan especificados los atributos del SDT dentro del Data Provider.
Ingrese la configuración sistema SAP incluida las credenciales para almacenar la información a utilizar en futuras conexiones.
Haga click en el Icono del diskette o presione Ctrl+S para salvar el progreso realizado.
Tip: Es altamente recomendable implementar medidas de seguridad para el manejo de credenciales, así como también toda la información que considere sensible. Esto lo puede hacer encriptando y desencriptando la misma donde corresponda, utilizando las funciones GeneXus encrypt64() y decrypt64().
Hasta el momento se ha definido un Structured Data Type donde la sesión de SAP es almacenada mediante la carga de datos realizada por un Data Provider.
Otro punto importante es resolver cómo gestionar los datos de la conexión al Sistema SAP a lo largo de la aplicación, de forma que sea accesible por todos los objetos GeneXus que requieran utilizarlos.
Hay varios enfoques para resolver el punto anterior, una de estas opciones es utilizar una variable de tipo WebSession, que permite almacenar información en el servidor. De esta forma se puede guardar la información de la conexión con el sistema SAP. Esta información estará disponible para todos los objetos GeneXus que necesiten hacer uso de la misma.
Para esta demo se utilizara este enfoque de almacenar la información en WebSession.
La información de la conexión con SAP se debe almacenar en la WebSession al inicio de las aplicaciones, tanto la aplicación web como la aplicación para Smart Devices.
El procedimiento es similar para ambos casos.
Empiece por la aplicación para Smart Devices.
Seleccione el objeto de inicio de la aplicación Smart Devices llamado ‘DemoCarPartsSD’ y especifique el siguiente código en el evento ‘Refresh’.
&SapSessionData = SapSessionDataDP()
Define automáticamente una variable del tipo SAPSessionData (inferido por el nombre) y carga en la variable la información especificada en el Data Provider SAPSessionDataDP.
&WebSession.Set('sapserver', &SapSessionData.ToJson())
Se define automáticamente una variable del tipo WebSession (inferido por el nombre) y se ejecuta el método Set, donde se almacena bajo el identificador 'sapserver', la información de la variable, serializada a través del método ToJson().
De manera análoga se debe cargar la información en la sesión para el inicio de la aplicación web.
En el evento ‘Start’ del objeto ‘FioriLaunchpad’ especifique el código anterior.
Haga click en el Icono del Diskette o presione Ctrl+S para salvar el progreso realizado.
En el siguiente paso verá cómo generar un objeto Procedure que establezca la conexión con el sistema SAP, utilizando la información de la cuenta SAP almacenada en la WebSession.
De esta forma cada vez que necesite conectarse al sistema SAP para llamar a una BAPI, podrá llamar al Procedure definido a continuación.
Dentro de la carpeta ‘SAPIntegration’ cree un objeto Procedure y llámelo ‘SAPConnect’.
Puede crear el objeto haciendo click derecho en la carpeta y seleccionando New > Create.
En el selector de Rules defina el siguiente parámetro de salida.
parm(out:&GXEnterpriseSessionManager);
Este parámetro es una variable del tipo del objeto externo generado (GxEnterpriseSessionManager) al importar la BAPI, la variable se definirá de forma automática de este tipo de datos.
Haga click en el Icono del Diskette o presione Ctrl+S para salvar el progreso realizado.
En la pestaña de Source escriba el siguiente código.
&SAPSessionData.FromJson(&WebSession.Get('sapserver'))
&GXEnterpriseSessionManager.AppServer = &SAPSessionData.SAPSessionAppServer
&GXEnterpriseSessionManager.ClientNumber = &SAPSessionData.SAPSessionClientNumber
&GXEnterpriseSessionManager.RouterString = &SAPSessionData.SAPSessionRouterString
&GXEnterpriseSessionManager.SystemId = &SAPSessionData.SAPSessionSystemId
&GXEnterpriseSessionManager.InstanceNumber = &SAPSessionData.SAPSessionInstanceNumber
&GXEnterpriseSessionManager.SessionName = &SAPSessionData.SAPSessionSessionName
&GXEnterpriseSessionManager.UserName = &SAPSessionData.SAPSessionUserName
&GXEnterpriseSessionManager.Password = &SAPSessionData.SAPSessionPassword
&GXEnterpriseSessionManager.Connect()
Utilizando una variable del tipo WebSession se obtiene la sesión que se guardó al inicio de la aplicación, llamada ‘sapserver’.
En esta sesión se carga una variable del tipo SAPSessionData utilizando el método FromJson.
Luego asignamos a una variable del tipo GXEnterpriseSessionManager los datos obtenidos de la sesión.
Se invoca al método Connect para iniciar la conexión con el Sistema SAP
Haga click en el Icono del Diskette o presione Ctrl+S para salvar el progreso realizado.
Automáticamente se definen las variables SAPSessionData y WebSession inferidas por GeneXus.
Ha definido un Procedimiento que permite conectarse al Sistema SAP utilizando credenciales que se guardan en la sesión del servidor y puede ser referenciado por cualquier objeto definido.
Ya ha definido las bases para poder manejar la conexión con el ERP:
- Importación de la BAPI a utilizar, generando el objeto externo que establece la conexión.
- Definición de la estructura para la gestión de credenciales para la conexión.
- Gestión de las credenciales para establecer una sesión de conexión con el ERP.
Ahora verá los pasos necesarios para ingresar el registro de Sales Order en la aplicación.
Reference:
DemoCarPartsXpz5.xpz. Contenido: EO: GXEnterpriseSessionManager y carpeta SAPIntegration con objetos para conectarse a SAP ERP).
En esta sección se cubrirá como crear una Sales Order en SAP ERP haciendo uso de la BAPI importada en el paso anterior.
La estrategia elegida para implementar este requerimiento es utilizar una tabla auxiliar (o de redundancia controlada) a efectos de registrar los datos de la Sales Order ingresada en esta tabla, creada desde el sistema desarrollado en GeneXus. Luego de esto el pedido es enviado a SAP ERP y se registra en la tabla de redundancia, el número de pedido devuelto por SAP.
Esto significa que si un usuario de la aplicación ingresa una Sales Order y por algún motivo falla el envío de la misma al sistema SAP ERP (fallo en la conexión, downtime del servidor, etc.) el registro de la Sales Order queda almacenado en las tablas del sistema desarrollado con GeneXus para que no se pierda la información.
Comenzaremos definiendo el objeto que ingresa el registro en SAP ERP.
Cree un nuevo Objeto de tipo procedimiento (dentro del folder SAPIntegration ) y llámelo ‘CreateSOSAP’.
En la pestaña de Rules defina los siguientes parámetros de entrada y salida
parm(in:&SalesOrderId, out:&SalesOrderSAPNumber, out:&BAPIRET2);
El parámetro SalesOrderId contiene el identificador de la SalesOrder grabada en la tabla de redundancia (del sistema y la DB creada por GeneXus) a ser ingresada en SAP ERP.
El parámetro SAPSONumber retorna el número asignado por SAP ERP a la SalesOrder creada en el ERP.
La estructura BAPIRET2 contiene el retorno de la operación en SAP, indicando si se realizó exitosamente o si tuvo errores.
Los tipos de las variables SalesOrderId, SalesOrderSAPNumber y BAPIRET2 se infieren automáticamente por GeneXus.
Marque el tipo BAPIRET2 como una colección, ya que SAP ERP puede retornar más de un mensaje al intentar crear el pedido.
En la pestaña Source comience a especificar el código con la siguiente línea:
SAPConnect(&GxEnterpriseSessionManager)
Este es el Procedimiento definido anteriormente que se encarga de gestionar a través de la sesión, la conexión con el sistema SAP utilizando un juego de credenciales.
Como resultado retorna la sesión y si se pudo establecer la conexión con el ERP.
Una vez llamado el método SAPConnect se trabajará con la variable resultado (GxEnterpriseSessionManager) a lo largo del Procedure.
La variable GxEnterpriseSessionManager se define de forma automática.
Los atributos ErrorCode y ErrorMessage almacenados dentro de la variable GxEnterpriseSessionManager contienen la información resultante de intentar establecer una conexión. Si la conexión fue exitosa el atributo ErrorCode se retorna vacío.
ErrorMessage es una descripción del error.
De esta manera cada vez que se realiza una llamada externa a una BAPI se debe establecer una conexión al sistema utilizando el método Connect.
A continuación especifique el siguiente bloque condicional:
if &GXEnterpriseSessionManager.ErrorCode.IsEmpty()
endif
Dentro de este bloque definirá las operaciones a realizar en el caso de una conexión exitosa, para el caso contrario posteriormente se incluirá una clausula else.
Comenzará a especificar código haciendo uso de las estructuras generadas en la importación de la BAPI.
Por más información sobre las estructuras de la BAPI utilizada puede referirse a la documentación presente en el explorador de BAPIs de SAP ERP Connector.
Escriba el siguiente código dentro del bloque if/endif.
for each
where SalesOrderId = &SalesOrderId
// * Sales Order Header
&BAPISDHD1.DOC_TYPE = 'TA'
&BAPISDHD1.SALES_ORG = 'UY01'
&BAPISDHD1.SALES_DIST = ''
&BAPISDHD1.DIVISION = '01'
&BAPISDHD1.DISTR_CHAN = '01'
&BAPISDHD1.DOC_DATE = SalesOrderDate
// * Sales Order Partner
&BAPIPARNRRow.PARTN_ROLE = 'AG'
&BAPIPARNRRow.PARTN_NUMB = CustomerId
&BAPIPARNR.Add(&BAPIPARNRRow)
// * Sales Order Item
&BAPISDITMRow.ITM_NUMBER = 10
&BAPISDITMRow.MATERIAL = ProductId
&BAPISDITMRow.TARGET_QTY = SalesOrderProductQty
&BAPISDITMRow.TARGET_VAL = '0'
&BAPISDITM.Add(&BAPISDITMRow)
&BAPISCHDLRow.ITM_NUMBER = 10
&BAPISCHDLRow.REQ_QTY = SalesOrderProductQty
&BAPISCHDL.Add(&BAPISCHDLRow)
Endfor
A continuación se detalla cada sección para dar una introducción sobre el manejo de la BAPI para la creación de SalesOrder y algunos conceptos GeneXus.
for each
where SalesOrderId = &SalesOrderId
. . . . .
Endfor
El bloque for each /Endfor' target='_blank'>https://wiki.genexus.com/commwiki/servlet/wiki?24744,For+Each+command,' target='_blank'>for each /Endfor es la estructura utilizada en GeneXus para obtener un conjunto de datos de la Base de Datos. El developer solamente menciona los atributos que desea utilizar y GeneXus automáticamente infiere las tablas y/o Joins necesarios para obtenerlos.
Como se puede apreciar, el where se utiliza para indicar que los datos de la orden que se desea utilizar, son los de la que tenga el SalesOrderId recibido como parámetro.
Tip: Si en lugar de haber recibido dicho valor en una variable se hiciera directamente sobre el atributo, podría haberse omitido el where y GeneXus infiere la condición de filtro de forma automática:
parm(in:SalesOrderId, ...
for each
. . . . .
Endfor
Cabezal de la Sales Order
// * Sales Order Header
&BAPISDHD1.DOC_TYPE = 'TA'
&BAPISDHD1.SALES_ORG = 'UY01'
&BAPISDHD1.SALES_DIST = ''
&BAPISDHD1.DIVISION = '01'
&BAPISDHD1.DISTR_CHAN = '01'&APISDHD1.DOC_DATE = SalesOrderDate
La estructura BAPISDHD1 maneja la información referente al cabezal de una Sales Order. Si bien se puede asignar valor a muchos atributos para el cabezal de una Sales Order, en este caso se asignan los mínimos necesarios para poder crear un pedido. Para este caso se asignan datos estáticos en ciertos atributos, esto depende de la parametrización del Sistema SAP ERP implantado.
La variable &BAPISDHD1 de tipo BAPISDHD1 se define de forma automática.
Para la fecha del documento en SAP, se asigna la fecha que GeneXus obtendrá de la tabla redundante, donde ya se grabó el pedido.
Interlocutor comercial de la Sales Order
// * Sales Order Partner
&BAPIPARNRRow.PARTN_ROLE = 'AG'
&BAPIPARNRRow.PARTN_NUMB = CustomerId
&BAPIPARNR.Add(&BAPIPARNRRow)
Aquí se carga la estructura de partners, notar que la estructura (BAPIPARNR) es una colección por lo que debe definir una variable &BAPIPARNR de tipo BAPIPARNR e indicar que es una colección en la pestaña de variables.
Al ser una colección se pueden cargar varios registros (cada registro tendrá un rol, esto es destinatario de mercancía, responsable de pago, etc., en este caso solo se cargará un registro PARTN_ROLE = 'AG'), para esto se define la variable &BAPIPARNRRow de tipo BAPIPARNR sin indicar que el mismo es una colección.
En el número de partner se asocia el número de cliente que GeneXus obtendrá de la tabla redundante, donde ya se grabó el pedido.
Líneas de la Sales Order
// * Sales Order Item
&BAPISDITMRow.ITM_NUMBER = 10
&BAPISDITMRow.MATERIAL = ProductId
&BAPISDITMRow.TARGET_QTY = SalesOrderProductQty
&BAPISDITMRow.TARGET_VAL = '0'
&BAPISDITM.Add(&BAPISDITMRow)
&BAPISCHDLRow.ITM_NUMBER = 10
&BAPISCHDLRow.REQ_QTY = SalesOrderProductQty
&BAPISCHDL.Add(&BAPISCHDLRow)
En esta sección se realiza la carga de los productos o ítems a ingresar en la SalesOrder (en ese caso de la POC, solamente un producto).
Cada ítem tiene un número de línea o posición en SAP ERP, como en este caso se ingresará solamente una línea, se numera de forma fija con el valor 10.
En esta sección se deben cargar datos en dos colecciones:
- &BAPISDITM como una colección del tipo BAPISDITM
- &BAPISCHDL como una colección del tipo BAPISCHDL
Defina una variable &BAPISDITMRow de tipo BAPISDITM para ingresar en la colección &BAPISDITM.
Aquí se almacena el identificador de producto y la cantidad requerida, que GeneXus obtendrá de la tabla redundante, donde ya se grabó el pedido.
Defina una variable &BAPISCHDLRow de tipo BAPISDITM para ingresar en la colección &BAPISCHDL.
Esta colección se utiliza en SAP ERP para poder indicar diferentes valores, relacionado a la entrega, a cantidades parciales de la cantidad total pedida (Por ejemplo: si se pidieron 12 unidades de un producto, se puede indicar una fecha de entrega para 6 de ellos y otra fecha para las restantes 6 unidades). Por lo tanto cada línea de esta estructura debe estar relacionada a una línea del pedido (de la estructura &BAPISDITM) a través de los campos &BAPISDITMRow.ITM_NUMBER y &BAPISCHDLRow.ITM_NUMBER (en este caso, donde utilizamos solo una línea por Sales Order, a ambos campos se les asigna el mismo numero de linea = 10 y también se crea solamente una linea de entrega por la cantidad total pedida).
Creación de la Sales Order
Una vez especificado el código anterior, se tiene completa la carga de datos mínima necesaria en las estructuras, para dar de alta una SalesOrder en SAP ERP.
Es momento de realizar la llamada a la BAPI importada para crear el registro de SalesOrder en SAP ERP.
Antes de ejecutar la llamada a la BAPI se debe ejecutar el método TransactionBegin para comunicarle al Sistema SAP del inicio de la Transacción. A su vez, luego de realizar la llamada a la BAPI pasando los parámetros necesarios, se debe ejecutar el método TransactionCommit para notificar al sistema SAP que aplique los cambios realizados. Ambos son métodos del External Object GXEnterpriseSessionManager.
Escriba el siguiente código luego del bloque for each/endfor del Procedimiento.
&GXEnterpriseSessionManager.TransactionBegin()
&sapCustomerOrder.CREATEFROMDAT2(&SALESDOCUMENTIN, &BAPISDHD1, &BAPISDHD1X,&BAPI_SENDER,
&BINARY_RELATIONSHIPTYPE, &INT_NUMBER_ASSIGNMENT,
&BEHAVE_WHEN_ERROR, &BAPISDLS, &TESTRUN, &CONVERT, &BAPIRET2, &BAPISDITM,
&BAPISDITMX, &BAPIPARNR, &BAPISCHDL, &BAPISCHDLX, &BAPICOND, &BAPICONDX,
&BAPICUCFG, &BAPICUINS, &BAPICUPRT, &BAPICUVAL, &BAPICUBLB, &BAPICUVK,
&BAPICUREF, &BAPICCARD, &BAPISDTEXT, &BAPISDKEY, &BAPIPAREX, &BAPIADDR1)
&GXEnterpriseSessionManager.TransactionCommit()
&sapCustomerOrder.CREATEFROMDAT2(...) es la llamada a BAPI de SAP ERP.
La variable &sapCustomerOrder, de tipo sapCustomerOrder (nombre del objeto externo generado al importar la BAPI) se define de forma automática inferido por el nombre.
A continuación se detallan las variables pasadas por parámetro y sus tipos, las cuales deberá definir.
Nombre Variable
|
Tipo Variable
|
Colección
|
SALESDOCUMENTIN
|
Character(20)
|
|
BAPISDHD1
|
BAPISDHD1
|
|
BAPISDHD1X
|
BAPISDHD1X
|
|
BAPI_SENDER
|
BAPI_SENDER
|
|
BINARY_RELATIONSHIPTYPE
|
Character(8)
|
|
INT_NUMBER_ASSIGNMENT
|
Character(2)
|
|
BEHAVE_WHEN_ERROR
|
Character(2)
|
|
BAPISDLS
|
BAPISDLS
|
|
TESTRUN
|
Character(2)
|
|
CONVERT
|
Character(2)
|
|
BAPIRET2
|
BAPIRET2
|
X
|
BAPISDITM
|
BAPISDITM
|
X
|
BAPISDITMX
|
BAPISDITMX
|
X
|
BAPIPARNR
|
BAPIPARNR
|
X
|
BAPISCHDL
|
BAPISCHDL
|
X
|
BAPISCHDLX
|
BAPISCHDLX
|
X
|
BAPICOND
|
BAPICOND
|
X
|
BAPICONDX
|
BAPICONDX
|
X
|
BAPICUCFG
|
BAPICUCFG
|
X
|
BAPICUINS
|
BAPICUINS
|
X
|
BAPICUPRT
|
BAPICUPRT
|
X
|
BAPICUVAL
|
BAPICUVAL
|
X
|
BAPICUBLB
|
BAPICUBLB
|
X
|
BAPICUVK
|
BAPICUVK
|
X
|
BAPICUREF
|
BAPICUREF
|
X
|
BAPICCARD
|
BAPICCARD
|
X
|
BAPISDTEXT
|
BAPISDTEXT
|
X
|
BAPISDKEY
|
BAPISDKEY
|
X
|
BAPIPAREX
|
BAPIPAREX
|
X
|
BAPIADDR1
|
BAPIADDR1
|
X
|
Tip: una forma fácil de definir todas estas variables, es seleccionarlas todas desde el módulo Enterprise en el KBExplorer y arrastrarlas sobre la solapa Variables del Procedure CreateSOSAP (click sobre la primera y Ctrl+click sobre la última, arrastrar y soltar), luego de esto, solo resta marcar como Collection las que se indican en la lista anterior.
Resultado del llamado a la BAPI
Una vez realizada la llamada a la BAPI y luego de llamar al método TransactionCommit se debe analizar el resultado de la llamada a la BAPI, para esto se consulta los datos retornados en la variable &BAPIRET2 (que almacena el resultado de la ejecución de un método y su descripción).
// Analyze the BAPI answer to obtain &SAPSONumber
&SalesOrderSAPNumber.SetEmpty()
for &BAPIRET2Row in &BAPIRET2
if &BAPIRET2Row.TYPE <> 'E' and &BAPIRET2Row.TYPE <> 'A'
// Save the document number created
&SalesOrderSAPNumber = &BAPIRET2Row.MESSAGE_V2
endif
endfor
Se inicializa la &SalesOrderSAPNumber (Empty) para fijar o no un valor, dependiendo del resultado de la llamada.
Defina una variable &BAPIRET2Row de tipo BAPIRET2 para leer de la colección &BAPIRET2.
Al evaluar si el atributo TYPE es distinto de ‘E’ y de ‘A’ comprobamos que el resultado no haya sido de error (TYPE puede tener los valores S para Success, I para Info, W para Warning, A para Abort y E para Error)
Si el resultado no es erróneo, se asigna el atributo MESSAGE_V2 que contiene el número asignado por SAP para la orden creada.
En caso contrario, la variable &SalesOrderSAPNumber permanece vacía, indicando que no se pudo dar de alta la SalesOrder en SAP (y queda pendiente de poder ser reprocesada desde las tablas redundantes del sistema GeneXus).
Registrar el resultado de la llamada a la BAPI
Para concluir con el código del Procedimiento, en caso que la creación haya sido exitosa, se asigna el número de Sales Order devuelto por SAP ERP, al pedido en la tabla redundante creada por GeneXus y se describe la cláusula else del condicional
if &GXEnterpriseSessionManager.ErrorCode.IsEmpty() para definir las acciones a ejecutar en caso de que no se haya podido establecer la conexión con el sistema SAP.
if &GXEnterpriseSessionManager.ErrorCode.IsEmpty()
. . . . .
if not &SalesOrderSAPNumber.IsEmpty()
for each
where SalesOrderId = &SalesOrderId
SalesOrderSAPNumber = &SalesOrderSAPNumber
endfor
endif
else
&BAPIRET2Row.NUMBER = &GXEnterpriseSessionManager.ErrorCode
&BAPIRET2Row.MESSAGE = &GXEnterpriseSessionManager.ErrorMessage
&BAPIRET2.Add(&BAPIRET2Row)
endif
Y aquí finaliza la especificación a realizar para crear una Sales Order en SAP utilizando la BAPI.
Haga click en el Icono del Diskette o presione Ctrl+S para salvar el progreso realizado.
A continuación se muestra como debería quedar especificado el código:
SAPConnect(&GxEnterpriseSessionManager)
if &GxEnterpriseSessionManager.ErrorCode.IsEmpty()
for each
where SalesOrderId = &SalesOrderId
// * Sales Order Header
&BAPISDHD1.DOC_TYPE = 'TA'
&BAPISDHD1.SALES_ORG = 'UY01'
&BAPISDHD1.SALES_DIST = ''
&BAPISDHD1.DIVISION = '01'
&BAPISDHD1.DISTR_CHAN = '01'
&BAPISDHD1.DOC_DATE = SalesOrderDate
// * Sales Order Partner
&BAPIPARNRRow.PARTN_ROLE = 'AG'
&BAPIPARNRRow.PARTN_NUMB = CustomerId
&BAPIPARNR.Add(&BAPIPARNRRow)
// * Sales Order Item
&BAPISDITMRow.ITM_NUMBER = 10
&BAPISDITMRow.MATERIAL = ProductId
&BAPISDITMRow.TARGET_QTY = SalesOrderProductQty
&BAPISDITMRow.TARGET_VAL = '0'
&BAPISDITM.Add(&BAPISDITMRow)
&BAPISCHDLRow.ITM_NUMBER = 10
&BAPISCHDLRow.REQ_QTY = SalesOrderProductQty
&BAPISCHDL.Add(&BAPISCHDLRow)
endfor
&GXEnterpriseSessionManager.TransactionBegin()
&sapCustomerOrder.CREATEFROMDAT2(&SALESDOCUMENTIN, &BAPISDHD1, &BAPISDHD1X, &BAPI_SENDER, &BINARY_RELATIONSHIPTYPE, &INT_NUMBER_ASSIGNMENT, &BEHAVE_WHEN_ERROR, &BAPISDLS, &TESTRUN, &CONVERT, &BAPIRET2, &BAPISDITM, &BAPISDITMX, &BAPIPARNR, &BAPISCHDL, &BAPISCHDLX, &BAPICOND, &BAPICONDX, &BAPICUCFG, &BAPICUINS, &BAPICUPRT, &BAPICUVAL, &BAPICUBLB, &BAPICUVK, &BAPICUREF, &BAPICCARD, &BAPISDTEXT, &BAPISDKEY, &BAPIPAREX, &BAPIADDR1)
&GXEnterpriseSessionManager.TransactionCommit()
// Analyze the BAPI answer to obtain &SAPSONumber
&SalesOrderSAPNumber.SetEmpty()
for &BAPIRET2Row in &BAPIRET2
if &BAPIRET2Row.TYPE <> 'E' and &BAPIRET2Row.TYPE <> 'A'
// Save the document number created
&SalesOrderSAPNumber = &BAPIRET2Row.MESSAGE_V2
endif
endfor
if not &SalesOrderSAPNumber.IsEmpty()
for each
where SalesOrderId = &SalesOrderId
SalesOrderSAPNumber = &SalesOrderSAPNumber
endfor
endif
else
&BAPIRET2Row.NUMBER = &GXEnterpriseSessionManager.ErrorCode
&BAPIRET2Row.MESSAGE = &GXEnterpriseSessionManager.ErrorMessage
&BAPIRET2.Add(&BAPIRET2Row)
endif
Una vez que contamos con el Procedimiento que crea la Sales Order en SAP ERP a partir de los datos ingresados en la tabla de redundancia, resta solamente incorporar el llamado en los puntos necesarios y mostrar el resultado devuelto por SAP ERP.
Com pretendemos que esta redundancia sea totalmente controlada, este Procedimiento lo invocaremos, de forma automática, inmediatamente luego de confirmar la grabación del pedido en la tabla de redundancia creada por GeneXus, desde un Panel (Web Panel para Web o Smart device Panel para Mobile) que adicionalmente nos mostrará el resultado de la creación del pedido en SAP ERP.
Escribamos entonces primero estos dos Paneles.
Web Panel de creación de Sales Order en SAP ERP
Cree un Panel de nombre SOSAPSaveResultWeb en el folder SAPIntegration (botón derecho sobre el folder SAPIntegration y New/Object/Web/Web Panel).
Agregue una variable de tipo Image (Toolbox + Drag and drop del control Attribute/Variable, New Variable y nombrela ResultImage, esto influirá para ella, el tipo de datos Image. Al dar OK se agrega al webform).
Modifíquele las siguientes Properties a la variable:
Label Position: None
Horizontal Alignment: Center
Este Panel recibirá como parámetro, el Id del pedido creado en la tabla de redundancia, por lo tanto agregue la regla (en la solapa Rules) parm(in:&SalesOrderId);
Finalmente, en la solapa Events, agregue el Evento Start con el siguiente código, con lo cual se llamará al Procedimiento de creación de la Sales Order en SAP ERP y según el resultado muestra el número de pedido devuelto por SAP o el mensaje de error.
Según el resultado sea erróneo o no, se mostrará en la variable definida de tipo Image, un Icono que indique el tipo de resultado (en esta caso Image:OKSAP o Image:ErrorSAP).
Event Start
CreateSOSAP(&SalesOrderId, &SalesOrderSAPNumber, &BAPIRET2)
if &SalesOrderSAPNumber.IsEmpty()
&ResultImage.FromImage(Image:ErrorSAP)
msg(format('SAP SO Error: %1', &BAPIRET2.Item(1).MESSAGE))
else
&ResultImage.FromImage(Image:OKSAP)
msg(format('SAP SO nbr.created: %1', &SalesOrderSAPNumber))
endif
Endevent
Las variable &SalesOrderId, &SalesOrderSAPNumber y &BAPIRET2 se definen automáticamente, solamente hay que indicarle a &BAPIRET2 que es una Collection.
Panel for Smart Device de creación de Sales Order en SAP ERP
Cree un Panel para Smart Devices de nombre SOSAPSaveResultSD en el folder SAPIntegration (botón derecho sobre el folder SAPIntegration y New/Object/Smart Devices/Panel for Smart Devices).
Al oprimir el botón Create, GeneXus automaticamente propone el selector de Templates para Fiori Mobile, en este caso no usaremos ninguno, ya que usaremos un Panel muy sencillo, por lo tanto oprimir Skip.
Desde la toolbox, arrastramos sobre el form del panel un control de tipo Image y seleccionamos el que usemos como indicador de Sales Order creada correctamente (Por ejemplo: ). Hacemos lo mismo insertando debajo de este otro control de tipo Image con la imagen elegida para indicar algún error en la creación de la Sales Order (Por ejemplo: ).
A ambos controles (Imagenes) seteamos las siguientes propiedades:
Control Name = ImageOK / ImageError (según corresponda)
Visible = false
Invisible Mode = Collapse Space
Finalmente cree y arrastre a la parte superior del Form, desde la Toolbox, una variable de nombre ResultSAP, definida como VarChar de 100 y con las siguientes propiedades:
Readonly = True
Label Position = None
=
En la solapa Events, elija desde el selector de Eventos el evento Refresh para insertarlo.
De forma análoga a como hizo en el Web Panel SOSAPSaveResultWeb, escriba el código para llamar al Procedimiento de creación de la Sales Order en SAP y de acuerdo al resultado muestre el nro. de pedido creado en SAP o el error recibido.
Event Refresh
&SalesOrderId.FromString(&WebSession.Get('salesorderid'))
CreateSOSAP(&SalesOrderId, &SalesOrderSAPNumber, &BAPIRET2)
if &SalesOrderSAPNumber.IsEmpty()
ImageOK.Visible = false
ImageError.Visible = true
&ResultSAP = format('SAP SO Error: %1', &BAPIRET2.Item(1).MESSAGE)
else
ImageError.Visible = false
ImageOK.Visible = true
&ResultSAP = format('SAP SO nbr.created: %1', &SalesOrderSAPNumber)
endif
Endevent
Las variable &SalesOrderId, &SalesOrderSAPNumber y &BAPIRET2 se definen automáticamente, solamente hay que indicarle a &BAPIRET2 que es una Collection.
En este caso, por la forma en que se invocara a este panel, el parámetro se pasará a través de una Web Session, por lo tanto, en esta línea es justamente donde se recupera ese valor.
&SalesOrderId.FromString(&WebSession.Get('salesorderid'))
Tip: La variable WebSession se define de forma automática del tipo de datos del mismo nombre y cuenta con los métodos Save y Get para guardar y recuperar valores en la session web, esto es posible utilizarlo aquí, ya que el evento Start de un Panel SD OnLine en GeneXus, se ejecuta del lado del Server. La función FromString, se utiliza ya que los valores en la web session siempre se almacena en formato de texto y la variable &SalesOrderId es numérica, esta función convierte de Texto a Numérico.
Invocación de los Paneles de creación de Sales Order en SAP ERP
Finalmente, resta agregar la llamada a los Paneles de creación de la Sales Order en SAP ERP, recién detallados.
Para el caso web, simplemente agregamos una regla en la Transacción SalesOrder, de tal forma que esta se dispare en caso de Insert de un nuevo registro (una nueva Sales Order) y luego que esta haya sido grabada en las tablas de redundancias (adicionalmente condicionamos que esta regla se dispare solamente si la Transacción se ejecuta en un ambiente Web. Por lo tanto, en la solapa Rules de la Transacción SalesOrder agregamos la siguiente regla:
[web]
{
SOSAPSaveResultWeb(SalesOrderId) if Insert On AfterComplete;
}
Para el caso Mobile, la llamada la realizaremos desde el objeto WorkWithDevicesSalesOrder creado por el pattern, inmediatamente luego de realizar el Insert.
Por lo tanto en el evento ‘Insert’, en la solapa Events del List dentro del Panel for Smart Devices WorkWithDevicesSalesOrder (que se encuentra relacionado a la Transaccion SalesOrder), se agrega al código, la llamada al Panel creado anteriormente.
Código del evento ‘Insert’ creado por el pattern:
Event 'Insert'
// Generated by FioriMobile [Start] - Template: FioriMobileListSubtitle
WorkWithDevicesSalesOrder.SalesOrder.Detail.Insert()
// Generated by FioriMobile [End] - Template: FioriMobileListSubtitle
EndEvent
Se modifica, dejándolo como sigue:
Event 'Insert'
Composite
// Generated by FioriMobile [Start] - Template: FioriMobileListSubtitle
WorkWithDevicesSalesOrder.SalesOrder.Detail.Insert()
// Generated by FioriMobile [End] - Template: FioriMobileListSubtitle
SOSAPSaveResultSD.Call()
endcomposite
EndEvent
Tip: El bloque de código
Composite-endcomposite' target='_blank'>https://wiki.genexus.com/commwiki/servlet/wiki?17389,Composite%20command' target='_blank'>Composite-endcomposite agrupa código GeneXus, de tal forma que ese código se ejecuta secuencialmente hasta la última línea, excepto cuando ocurre algún error en alguna de las líneas. En cuyo caso la secuencia se ve interrumpida.
Como comentamos al momento de definir el Panel que invoca la creación de la orden en SAP ERP, la forma de pasar el Id de la Sales Order creada en la tabla de redundancia, la cual tiene los datos a pasar a SAP ERP, es a través de la WebSession, ya que en el Panel WorkWithDevicesSalesOrder, al momento de llamar a SOSAPSaveResultSD, ya no se cuenta con la Id de la orden recién creada.
Por lo tanto, agregamos en la Transacción SalesOrder, una regla que Grabe el la sesión, el Id de la orden creada, en caso que se esté Insertando y luego que los datos hayan sido grabados. En este caso este código lo condicionamos para que se ejecute solamente cuando se invoque en caso de usar la Transacción en modalidad Business Component, que es como se invoca de forma automática desde la aplicación mobile al insertar un registro.
Para esto, en la solapa Rules de la Transacción SalesOrder agregamos la siguiente regla:
[BC]
{
&WebSession.Set('salesorderid', SalesOrderId.ToString())
if Insert
On AfterComplete;
}
Haga click en el Icono del Diskette o presione Ctrl+S para salvar el progreso realizado.
Si ejecuta la Aplicación para Smart Devices (DemoCarPartsSD) podrá ingresar una SalesOrder y verificar que desde la aplicación web (FioriLaunchpad) quedó guardado el registro en las tablas del sistema desarrollado en GeneXus y en SAP ERP.
Tip: Al momento de ejecutar, la aplicación utiliza SAP Net Connector, por tal motivo debe copiar al directorio de la aplicación (\bin) las siguientes dlls: sapnco.dll y sapnco_utils.dll.
Ejecutando la aplicación web podrá ver en el Tile de Sales Order el registro en las tablas del sistema desarrollado con GeneXus.
Finalmente comprobamos desde el sistema SAP ERP el ingreso de la SalesOrder.
Important note: La integración con SAP ERP en esta demo es parcial, ya que está orientada solo a presentar las funcionalidades de GeneXus for SAP Systems. En este caso los materiales fueron ingresados de forma manual en las tablas desarrolladas con GeneXUs y los códigos de los mismos coinciden deliberadamente con los códigos en SAP ERP. Al realizar la aplicación con integración completa con SAP ERP, se deben obtener los materiales desde SAP utilizando las BAPIs asociadas al BO Material y lo mismo con los códigos de Clientes.
Reference:
DemoCarPartsXpz7.xpz. Contenido: contiene Paneles: SOSAPSaveResultSD y SOSAPSaveResultWeb, Transaction: Sales order con la llamada a ambos.