Conectividad de SAP / VB Fecha: 04/Dic/2004 (04/12/2004) Primera Parte:
Introducción (18/Nov)
|
Esta es la tercer publicación (y la última) que tiene que ver con conectarse a SAP usando una DLL creada en C++ mediante DCOM Connector desde un proyecto Visual Basic 6. En las dos anteriores se muestran los conceptos básicos de la conexion (Conectividad de SAP / Visual Basic - Introducción) y en la segunda (Conectividad de SAP / Visual Basic - Obtener una tabla y cargar un combo) se explican los detalles para cargar una grilla con datos extraidos de SAP y se explica cómo cargar un combo con datos específicos de una tabla de validación.
En esta última oportunidad trataremos sobre como cargar un cliente usando DCOM. Es decir que vamos a insertar información en una de las tablas de clientes de SAP que guarda solo "PersonalData" y completaremos unicamente los campos obligatorios, algunos de texto: FIRSTNAME, LASTNAME, STREET, CITY, POSTL_COD1, HOUSE_NO, E_MAIL, TEL1_NUMBR, y otros extraidos de combos: LANGU_P, CURRENCY, REGION y COUNTRY.
Aunque no lo creo necesario ya que los nombres de los campos se explican, estos son: Nombre, Apellido, Calle, Ciudad, Código postal, Número de la casa, Correo electrónico, Teléfono, Idioma, Moneda, Región y País.
Recordando la primer nota, será imprescindible crear una librería de enlace dinámico (DLL que le dicen) con DCOM Connector y hacer referencia a ella en nuestro proyecto Visual Basic. Esta librería tendrá la llamada al método necesario de la BAPI que ejecuta en SAP la inserción de la "PersonalData" de un cliente. Esto de insertar solo estos datos se debe a dos razones.
Una es que SAP guarda los datos de los clientes (así como los de casi todos los maestros) en varias tablas. La segunda razón es que los campos son obligatorios y no podríamos insertar el cliente si no se los enviamos todos.
En la segunda nota vimos que los combos deben cargarse con las tablas de validación de los campos que estamos completando. Pequeño repaso: cuando en SAP una tabla tiene un campo que es el código de un valor que está en otra tabla, como por ejemplo sería el código de país en el registro del cliente, una de las propiedades de este campo es la tabla de valores posibles, que en nuestro ejemplo sería la tabla de países. La utilidad de la BAPI que carga los combos en base al campo que voy a completar es que me muestra solo los valores posibles para el campo en cuestión y no toda la tabla completa. Aunque parezca no haber una razón para que haya que filtrarlos, se dan casos en que hay valores que no corresponde que esten disponibles, así que no vale tomar una lista cualquiera, por ejemplo de paises, aunque conozca de memoria los códigos. Un ejemplo más claro para cargar un único combo puede verse en la segunda publicación.
Van a notar que en esta entrega no hay código ni imagenes SAP y esto es por que estamos usando una BAPI. Esta ya repetida sigla (Business Programming Application Interfaces) es una función provista por SAP, es decir: ellos la hicieron, para emular una transacción por medio de una llamada con parámetros. Una trasacción es la manera que tiene SAP de invocar programas, por lo que mediate una BAPI podemos meternos dentro de SAP y leer o escribir.
Estas BAPI's son indispensables por que en SAP la integridad referencial se administra mediante código y si bien insertar un registro en una tabla no es imposible, es un desastre.A continuacion, la imagen del formulario y el código Visual Basic
Primero declaramos las varibles necesarias para hacer funcionar la DLL y cargar los combos, como habíamos visto. También unos arrays para guardar los códigos de los combos, no podemos usar itemdata por que los valores son todos string. También creamos una función que cargue los combos, ya que la vamos a usar mas de una vez.
Recordamos el método DimAs, expuesto por la DLL, que nos permite dar formato a un recordset de ADO (solo de ADO) en el que enviaremos datos a la BAPI. Cargamos los campos necesarios con los valores (se podría agregar alguna validación de campos vaciós) y al ejecutar la BAPI obtenemos un recordset con errores, si los hubiera.
Que se diviertan.
Option Explicit Private Sesion As DESEJ04Lib.SessionComponent Private CargarCombos As DESEJ04Lib.Helpvalues Private CargarCliente As DESEJ04Lib.Customer Private rsSelectionForHelpValues As ADODB.Recordset Private rsHelpValues As ADODB.Recordset Private rsValuesForField As ADODB.Recordset Private rsDescriptionForHelpValues As ADODB.Recordset Private aRegiones() Private aPaises() Private aMonedas() Private aIdiomas() Private Sub Form_Load() On Error GoTo errSAP Set Sesion = New DESEJ04Lib.SessionComponent Sesion.Destination = "DES" Sesion.UserID = "usuario" Sesion.Password = "password" Sesion.Client = "100" Set CargarCombos = Sesion.CreateInstance("DES.HELPVALUES") CargarCombos.DimAs "BapiGetList", _ "SELECTION4HELPVALUES", rsSelectionForHelpValues CargarCombos.DimAs "BapiGetList", "HELPVALUES", rsHelpValues CargarCombos.DimAs "BapiGetList", "VALUES4FIELD", rsValuesForField CargarCombos.DimAs "BapiGetList", _ "DESCRIPTION4HV", rsDescriptionForHelpValues ' países CargarCombo Combo(0), aPaises(), "KNA1", "Customer", _ "CreateFromData1", "PersonalData", "COUNTRY" ' moneda CargarCombo Combo(2), aMonedas(), "KNA1", "Customer", _ "CreateFromData1", "PersonalData", "CURRENCY" ' idioma CargarCombo Combo(3), aIdiomas(), "KNA1", "Customer", _ "CreateFromData1", "PersonalData", "LANGU_P" Exit Sub errSAP: MsgBox Err.Number & " " & Err.Description End Sub Private Sub Generar() Dim rsCliente As ADODB.Recordset Dim rsReturn As ADODB.Recordset Dim rsCopy As ADODB.Recordset On Error GoTo errGraba Set CargarCliente = Sesion.CreateInstance("DES.CUSTOMER") CargarCliente.DimAs "BapiCreateFromData1", "PersonalData", rsCliente CargarCliente.DimAs "BapiCreateFromData1", "CopyReference", rsCopy CargarCliente.DimAs "BapiCreateFromData1", "Return", rsReturn With rsCliente .AddNew .Fields("FIRSTNAME") = Text1(2).Text .Fields("LASTNAME") = Text1(1).Text .Fields("STREET") = Text1(3).Text .Fields("CITY") = Text1(4).Text .Fields("POSTL_COD1") = Text1(5).Text .Fields("HOUSE_NO") = Text1(6).Text .Fields("E_MAIL") = Text1(7).Text .Fields("TEL1_NUMBR") = Text1(8).Text .Fields("LANGU_P") = aIdiomas(Combo(3).ListIndex) .Fields("CURRENCY") = aMonedas(Combo(2).ListIndex) .Fields("REGION") = aRegiones(Combo(1).ListIndex) .Fields("COUNTRY") = aPaises(Combo(0).ListIndex) End With With rsCopy .AddNew .Fields("SALESORG") = "3500" .Fields("DISTR_CHAN") = "20" .Fields("DIVISION") = "TA" .Fields("REF_CUSTMR") = "0000012864" End With CargarCliente.BapiCreateFromData1 rsCliente, rsCopy, , rsReturn With rsReturn If Not .EOF Then If .Fields(0).Value = "E" Then MsgBox "Cáspita, se produjo un error al grabar" End If End If End With Set rsCliente = Nothing Set rsReturn = Nothing Set rsCopy = Nothing Exit Sub errGraba: MsgBox Err.Number & " " & Err.Description Set rsCliente = Nothing Set rsReturn = Nothing Set rsCopy = Nothing End Sub Private Sub CargarCombo(oCombo As ComboBox, aArray(), _ stObjType As String, stObjName As String, stMethod As String, _ stParameter As String, stField As String, _ Optional stMaxOfRows As Variant, Optional stDescriptionOnly As Variant, _ Optional stExplicitSHlp As Variant) Dim bPaso As Boolean Dim iCodigo As Integer Dim iDescripcion As Integer Dim iMedio As Integer Dim lnRegistros As Long Dim lnContador As Long On Error GoTo errCarga stMaxOfRows = IIf(IsMissing(stMaxOfRows), "0", stMaxOfRows) stDescriptionOnly = IIf(IsMissing(stDescriptionOnly), "", stDescriptionOnly) CargarCombos.BapiGetList stMethod, stParameter, stObjType, stObjName, stField, stMaxOfRows, , _ rsSelectionForHelpValues, rsHelpValues, _ rsValuesForField, rsDescriptionForHelpValues, stDescriptionOnly With rsDescriptionForHelpValues If Not .EOF Then .MoveLast .MoveFirst lnRegistros = .RecordCount Do While Not .EOF lnContador = lnContador + 1 If lnContador = 1 Then iCodigo = .Fields!Leng ElseIf lnContador = lnRegistros Then iDescripcion = .Fields!Leng Else iMedio = iMedio + .Fields!Leng + 1 End If .MoveNext Loop End If End With oCombo.Clear If rsHelpValues Is Nothing Then Exit Sub End If With rsHelpValues If Not .EOF Then .MoveLast .MoveFirst lnRegistros = .RecordCount ReDim aArray(0 To lnRegistros - 1) Do While Not .EOF oCombo.AddItem Mid$(.Fields(0).Value, iCodigo + iMedio + 1) aArray(oCombo.NewIndex) = Left$(.Fields(0).Value, iCodigo) .MoveNext Loop End If End With Exit Sub errCarga: MsgBox Err.Number, Err.Description End Sub Private Function Valida() As Boolean Dim iBucle As Integer For iBucle = Combo.LBound To Combo.UBound If Combo(iBucle).ListIndex = -1 Then MsgBox "Debe seleccionar un valor en todos los combos." Exit Function End If Next iBucle For iBucle = Text1.LBound + 1 To Text1.UBound If Trim(Text1(iBucle).Text) = "" Then MsgBox "Debe completar todos los textos." Exit Function End If Next iBucle Valida = True End Function Private Sub Combo_Click(Index As Integer) If Index = 0 Then CargarCombos.DimAs "BapiGetList", _ "SELECTION4HELPVALUES", rsSelectionForHelpValues CargarCombos.DimAs "BapiGetList", "HELPVALUES", rsHelpValues CargarCombos.DimAs "BapiGetList", "VALUES4FIELD", rsValuesForField CargarCombos.DimAs "BapiGetList", _ "DESCRIPTION4HV", rsDescriptionForHelpValues With rsSelectionForHelpValues .AddNew .Fields("SELECT_FLD") = "LAND1" .Fields("SIGN") = "I" .Fields("OPTION") = "EQ" .Fields("LOW") = aPaises(Combo(0).ListIndex) End With ' regiones CargarCombo Combo(1), aRegiones(), "KNA1", "Customer", _ "CreateFromData1", "PersonalData", "REGION" End If End Sub Private Sub Command1_Click(Index As Integer) If Valida Then Generar End If End SubComo este es la última publicación de esta entrega, debería hacer los agradecimientos de rigor, pero los que me ayudaron y me conocen saben quienes son y adoran el anonimato.
Un Abrazo cordial para todos ellos, y no olviden consultar su abaper de confianza.