Conectividad de SAP / VB
Insertar un cliente en SAP desde una aplicación VB

Fecha: 04/Dic/2004 (04/12/2004)
Autor: Luis Elías Carro - luis.carro@gmail.com 

Primera Parte: Introducción (18/Nov)
Segunda Parte: Obtener una tabla y cargar un combo (30/Nov)
Tercera Parte: (esta)

 


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

DCOM: formulario para ingreso de los datos de un cliente.

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 Sub

Como 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.

 


ir al índice