0

There exist a lot of descriptions on parameters for BAPIs, but they are not understandable.

I post the solution here, because I myself had many difficulties to achieve a parametrized BAPI call from Excel VBA.

My task was to query data from SAP software. It should be possible (in Excel via a Form) to select

  • A date range
  • Different states ( e.g. 10, 20, 60)
  • Different department codes (e.g. 10, 20, 60)
  • Whether to show Z800 projects or not

To access the BAPI, you have to achieve the following:

  1. Establish a connection to your SAP system instance (there are many examples on the net for this part, so I won’t explicate that, e.g. https://turbofuture.com/computers/Silent-Connection-with-SAPLOGON-with-RFCSDK-Example-RFC-Excel-VBA ). In the example codes you will have something similar to
    If Not (connection Is Nothing) Then
                debug.print "connection is successful"
  1. Instantiate the BAPI (there too are many examples on the net for this part, so I will skip that too, e.g. https://turbofuture.com/computers/Silent-Connection-with-SAPLOGON-with-RFCSDK-Example-RFC-Excel-VBA ) In the example codes you will have something similar to
    Set functions = sapFunctions(connection)
    Set obSapBapi = functions.Add(BapiName)

This assignment is successful, if you see the that the BAPI object contains the BAPI name in debug mode: Successful BAPI assignment If the assignment is not successful, the BAPI object contains "Nothing".

  1. Call the BAPI with parameters Everywhere you can read “importing” / “exporting”…… and a lot more. But all I wanted to know was, how do I pass the user selection to SAP system? The most common use case is, that a user selects data in an excel sheet and then starts a program, which fetches data from SAP system based on the user selection, and this was mine, too.

The BAPI can have 2 distinguished parameter types (every parameter refers to one explicit field in the SAP view):

  1. Only 1 value is passed: this is .exporting (e.g. surname = "Smith")
  2. More than 1 parameter is passed: this is via a table (e.g. surname = "Smith" or "Myer" or "Pitt", order date > 4/1/2019 and < 4/15/2019) Input / Output of a BAPI

Input and Output tables are of the same type. Your SAP department can name you which one is your data table. To get all the tables (and their fields) of a BAPI you can run this code (refers to input as well as output tables):

        If obSapBapi.Call <> False Then
            'Function Call is Successfull
            Dim oTables As Object 
            Set oTables = obSapBapi.Tables     'Tables collection
            Call GetColumnDetails(oTables)
            Set oTables = Nothing
             
            Debug.Print "Function Call is Successfull"
        End If

The Code of the sub:

    Private Sub GetColumnDetails(ByVal obTables As Object)
    on error resume next
    Dim iLoop As Integer, iColIndx As Integer, iColValuePos As Integer
    Dim iTblCnt As Integer, iColCnt As Integer
    dim iRowCnt As Integer,  iRowIndx As Integer
    Dim oTable As Object, oColumn As Object, iValuePosn As Integer
 
    iTblCnt = obTables.Count
    iValuePosn = 1
    For iLoop = 1 To iTblCnt
        Set oTable = obTables.Item(iLoop)
        iColCnt = oTable.ColumnCount
        iRowCnt = oTable.RowCount
        iColValuePos = 1
        Sheet3.Cells(iValuePosn, 1) =  oTable.Name
        iValuePosn = iValuePosn + 1
        For Each oColumn In oTable.Columns
            Sheet3.Cells(iValuePosn, iColValuePos) = oColumn.Name
            iColValuePos = iColValuePos + 1
        Next oColumn
       Set oTable = Nothing
    Next
    End Sub

Import / Input tables Import tables mostly look like: SAP import/input table

The single lines are assembled as an SQL-WHERE Statement connected with OR. Description of the Input table:

Field Zeile (en: row)
You have to give the row number (i++, starting by 1) !!!

Field SIGN
(Only) possible values:
I: inclusive defined range
E: exclusive defined range

Possible values for Field OPTION (=operator):

  • EQ Equal (= Low)
  • NE Not equal (<> Low)
  • BT Between Low and High, including both (Low <= x <= High)
  • NB Outside Low and High (x < Low and x> High)
  • CP Contains pattern
  • NP Does not contain pattern
  • LT Lower than (<Low)
  • LE Lower equal (<= Low)
  • GT Greater than (> low)
  • GE Greater equal (>= low)

Possible values for Field LOW
Depends on the data type of the referring field. Examples:

  • [C(2)] => string
  • [D(8)] is a date, you should transfer it as string with format “yyyyMMdd”
  • [N(2)] => integer

Possible values for Field HIGH

  • Is empty except OPTION is BT or NB

Data types

    SAP BAPI Data Type /  Description   /   Passed from VBA as  
    C (<len>) /           Character    /    string  
    D(8)      /           Date         /    Format$(mydate,”yyyyMMdd”)  
    F(<len>)  /           float        /    Double  
    I(<len>)  /           Integer      /    Integer  
    N(<len>)  /           Numeric      /    Integer / long  
    B         /           Boolean      /    String (length 1)  

Example: I described my task above. It should be possible to select

  • A date range (=> in SAP system a Table named IT_WORKD_RANGE, LOW and HIGH of type date)
  • Different states (=> in SAP system a Table named IT_STATUS_RANGE, LOW and HIGH of type CHAR 2, e.g. 10, 20, 60)
  • Different departments (=> in SAP system a Table named IT_ZZIDL_RANGE, LOW and HIGH of type NUMC 2, e.g. 10, 20, 60)
  • Whether to show Z800 projects or no (=> in SAP system a BOOLEAN named IF_AWART, an exporting parameter, "X" or blank, where blank is default and means FALSE)
Sandra Rossi
  • 11,934
  • 5
  • 22
  • 48
  • you'd better make a blog post on blogs.sap.com or elsewhere, your post format is not quite fit to Stackoverflow concept – Suncatcher Sep 22 '20 at 11:43

2 Answers2

0

Something not explained in the external document you mention, is that in versions of SAP GUI before 7.70 (currently beta, not public yet) the SAP GUI Scripting OCX libraries are 32 bits. Many people use MS Office 64 bits, so you must change the Windows Registry of a few SAP GUI entries as described there.

If the call concerns special RFC function modules called BAPIs, to create, update or delete data, you need to call BAPI_TRANSACTION_COMMIT or BAPI_TRANSACTION_COMMIT based on respectively the success or the failure indicated in the messages of the parameter RESULT (if presence of a message of type E, A or X). Note that objRfcFunc.Call = False means a system error.

Sandra Rossi
  • 11,934
  • 5
  • 22
  • 48
0

Below is the solution given by the author of the question (which she originally posted inside her question).


Solution

After Click on a Button in a sheet a form is shown. All of the possible values above are input and then written to sheet "Connection", B9:B13

     B9: 20190401  
     B10: 20190701  
     B11: 10;20;40  
     B12: X  
     B13: 05;08;11

and the code:

    Function ReadCatsData()
    On Error GoTo ReadCatsDataError

    Dim MyWB As Workbook
    Dim MyWS As Worksheet


    Dim connection As Object
    Dim SAP_System As String
    Dim WinUser As String
    Dim functions  As Object
    Dim ErrText As String
    Dim ErrTitel As String
    Dim BapiName As String

    Dim DatumVon As String
    Dim DatumBis As String
    Dim Status As String
    Dim Z8 As String
    Dim ILC As String
    Dim Result() As String

    Dim a As Integer
    Dim i As Integer

    Dim obSapBapi As Object

    'Basiswerte setzen:

    ErrTitel = "Monitoring times"
    WinUser = UCase(Environ$("Username"))
    SAP_System = ActiveWorkbook.Sheets("Connection").Cells(2, 1) 
    BapiName = "Z_BAPI_CATS_MON_GET"

    Set MyWB = ActiveWorkbook
    Set MyWS = MyWB.Worksheets("SapDaten")

    Debug.Print SAP_System, WinUser, BapiName

    Set connection = sapConnectionLogon(SAP_System, WinUser)  ' "SGI"
    If Not (connection Is Nothing) Then

        Set functions = sapFunctions(connection)
        Set obSapBapi = functions.Add(BapiName)
        If Not (obSapBapi Is Nothing) Then
                DatumVon = Sheets("Connection").Cells(9, 2).Value    
                           'DatumVon = "20190401"
                DatumBis = Sheets("Connection").Cells(10, 2).Value   
                           'DatumBis = "20190418"
                Status = Sheets("Connection").Cells(11, 2).Value      
                           'Status = "10;20;30"
                Z8 = Sheets("Connection").Cells(12, 2).Value
                ILC = Sheets("Connection").Cells(13, 2).Value   
                           'ILC = "05;08"
                
                    
                Debug.Print DatumVon, DatumBis, Status, Z8, ILC
                    
                'Declare the Table Parameters  => Uebergabewerte
                    ' Date table (1)    
                    Dim vbIT_WORKD_RANGE As Object    
                    Set vbIT_WORKD_RANGE = obSapBapi.Tables("IT_WORKD_RANGE")
                    vbIT_WORKD_RANGE.Rows.Add
                    vbIT_WORKD_RANGE(1, "SIGN") = "I"
                    vbIT_WORKD_RANGE(1, "OPTION") = "BT"
                    vbIT_WORKD_RANGE(1, "LOW") = DatumVon
                    vbIT_WORKD_RANGE(1, "HIGH") = DatumBis
                    
                    ' Status (2)
                    If Status <> "" Then              
                        Dim vbIT_STATUS_RANGE As Object
                    Set vbIT_STATUS_RANGE = obSapBapi.Tables("IT_STATUS_RANGE")
                   
                        Result = Split(Status, ";")
                        For i = LBound(Result()) To UBound(Result())
                            vbIT_STATUS_RANGE.Rows.Add
                            vbIT_STATUS_RANGE(vbIT_STATUS_RANGE.Rows.Count, _
                                         "SIGN") = "I"
                            vbIT_STATUS_RANGE(vbIT_STATUS_RANGE.Rows.Count, _
                                         "OPTION") = "EQ"
                            vbIT_STATUS_RANGE(vbIT_STATUS_RANGE.Rows.Count, _
                                         "LOW") = Result(i)
                            Debug.Print i, Result(i)
                        Next i
                    End If
                    
                    Erase Result
                    
                     ' Industry_line  (3)
                    If ILC <> "" Then                
                        Dim vbIT_ZZIDL_RANGE As Object
                    Set vbIT_ZZIDL_RANGE = obSapBapi.Tables("IT_ZZIDL_RANGE")
                   
                        Result = Split(ILC, ";")
                        For i = LBound(Result()) To UBound(Result())
                            vbIT_ZZIDL_RANGE.Rows.Add
                            vbIT_ZZIDL_RANGE(vbIT_ZZIDL_RANGE.Rows.Count, _
                                   "SIGN") = "I"
                            vbIT_ZZIDL_RANGE(vbIT_ZZIDL_RANGE.Rows.Count, _
                                    "OPTION") = "EQ"
                            vbIT_ZZIDL_RANGE(vbIT_ZZIDL_RANGE.Rows.Count, _
                                    "LOW") = Val(Result(i))
                            Debug.Print i, Result(i)

                        Next i
                    End If
            'Declare the Export Parameter 
                    ' show Z800 projects (4) 
                    obSapBapi.exports("IF_AWART") = Z8          
                    
            'Call the function. get error in Bapi via obSapBapi.Exception
            
            If obSapBapi.Call = False Then
                ErrText = "Established connection with SAP system " & _
                          SAP_System  & vbCrLf
                ErrText = ErrText & "BAPI " & BapiName & " exists. " & vbCrLf
                ErrText = ErrText & "BAPI could not be called. " & vbCrLf
                ErrText = ErrText & "SAP delivers the following message: " & _
                          obSapBapi.Exception & vbCrLf 
                ErrText = ErrText & "Data cannot be fetched from SAP." & vbCrLf
                a = MsgBox(ErrText, vbOKOnly + vbCritical, ErrTitel)

            Else
               'Function Call is Successfull
                Dim obSAPTblData As Object
            
                Set obSAPTblData = obSapBapi.Tables("ET_Data")
                            
                Dim SheetRowPos As Integer
                Dim iRowCnt As Integer
                Dim iRowIndx As Integer
                Dim iColCnt As Integer
                Dim iColIndx As Integer
                
                iColCnt = obSAPTblData.ColumnCount
                iRowCnt = obSAPTblData.RowCount
                
                SheetRowPos = 1                            'init
              
                For iRowIndx = 1 To iRowCnt
                    SheetRowPos = SheetRowPos + 1          'start at row 2 
                    For iColIndx = 1 To iColCnt
                        MyWS.Cells(SheetRowPos, _
                           iColIndx) = obSAPTblData.Value(iRowIndx, iColIndx)
            
                    Next
                Next
              
               'Debug.Print "Col.: " & iColCnt & ", Rows: " & iRowCnt
            End If
            
            Set vbIT_WORKD_RANGE = Nothing
            Set vbIT_STATUS_RANGE = Nothing
            Set vbIT_ZZIDL_RANGE = Nothing
            
            functions.Remove (BapiName)
            Set obSapBapi = Nothing
         Else
            ErrText = "Established connection with SAP system " & _
                      SAP_System  & vbCrLf
            ErrText = ErrText & "BAPI " & BapiName & _
                      " was not found (could not instantiate object)." & vbCrLf
            ErrText = ErrText & "Data cannot be fetched from SAP." & vbCrLf
            a = MsgBox(ErrText, vbOKOnly + vbCritical, ErrTitel)
        End If
        
        
        connection.LogOff
        Set connection = Nothing
        Set functions = Nothing
    Else
        ErrText = "Could not establish connection with SAP system." & vbCrLf
        ErrText = ErrText & "User: " & WinUser
        ErrText = ErrText & ", SAP System: " & SAP_System & vbCrLf
        ErrText = ErrText & "Data cannot be fetched from SAP." & vbCrLf
        a = MsgBox(ErrText, vbOKOnly + vbCritical, ErrTitel)
    End If


    ReadCatsDataExit:
        Set MyWS = Nothing
        Set MyWB = Nothing
        Exit Function
    ReadCatsDataError:
        Resume ReadCatsDataExit

    End Function
Sandra Rossi
  • 11,934
  • 5
  • 22
  • 48