Как передать параметры в SAP BAPI из EXCEL VBA

Существует множество описаний параметров для BAPI, но они непонятны. Я публикую решение здесь, потому что у меня было много трудностей с достижением параметризованного вызова BAPI из EXCEL VBA.

Моей задачей было запросить SAP. Должна быть возможность (в Excel через форму) выбрать

  • Диапазон дат
  • Различные состояния (например, 10, 20, 60)
  • Различные коды отделов (например, 10, 20, 60)
  • Показывать проекты Z800 или нет

Чтобы получить доступ к BAPI, вы должны добиться следующего:

  1. Установите соединение с вашим экземпляром SAP (в сети есть много примеров для этой части, поэтому я не буду это объяснять, например, https://turbofuture.com/computers/Silent-Connection-with-SAPLOGON-with-RFCSDK-Example-RFC-Excel-VBA < / а>). В примерах кода у вас будет что-то похожее на
    If Not (connection Is Nothing) Then
                debug.print "connection is successful"
  1. Создайте экземпляр BAPI (в сети тоже есть много примеров для этой части, поэтому я пропущу и это, например, https://turbofuture.com/computers/Silent-Connection-with-SAPLOGON-with-RFCSDK-Example-RFC-Excel-VBA) В примерах кода у вас будет что-то похожее на
    Set functions = sapFunctions(connection)
    Set obSapBapi = functions.Add(BapiName)

Это назначение является успешным, если вы видите, что объект BAPI содержит имя BAPI в режиме отладки: Успешно Назначение BAPI Если назначение не выполнено, объект BAPI не содержит ничего.

  1. Вызов BAPI с параметрами. Везде вы можете прочитать «импорт» / «экспорт» …… и многое другое. Но все, что я хотел знать, это как передать выбор пользователя в SAP? Наиболее распространенный вариант использования - пользователь выбирает данные в таблице Excel, а затем запускает программу, которая извлекает данные из SAP на основе выбора пользователя, и это тоже было моим.

BAPI может иметь 2 различных типа параметров (каждый параметр относится к одному явному полю в представлении SAP):

  1. Передается только 1 значение: это .exporting (например, surname = Smith)
  2. Передается более 1 параметра: это через таблицу (например, фамилия = Смит, Майер или Питт, дата заказа ›01.04.2019 и‹ 15.04.2019) Ввод / вывод BAPI

Таблицы ввода и вывода однотипны. Ваш отдел SAP может назвать вам, какая из них является вашей таблицей данных. Чтобы получить все таблицы (и их поля) BAPI, вы можете запустить этот код (относится как к таблицам ввода, так и к таблицам вывода):

        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

Код субмарины:

    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

Таблицы импорта / ввода Таблицы импорта обычно выглядят следующим образом: Таблица импорта / ввода SAP

Отдельные строки собираются как оператор SQL-WHERE, связанный с оператором OR. Описание входной таблицы:

Поле Zeile (en: row)
Вы должны указать номер строки (i ++, начиная с 1) !!!

Поле SIGN
(Только) возможные значения:
I: включая определенный диапазон
E: исключительный определенный диапазон

Возможные значения для поля OPTION (= оператор):

  • EQ Equal (= низкий)
  • NE Не равно (‹› Низкое)
  • BT между минимумом и максимумом, включая оба (минимум ‹= x‹ = High)
  • NB За пределами минимума и максимума (x ‹Low и x› High)
  • CP Содержит шаблон
  • NP Не содержит паттерна
  • LT ниже (‹Low)
  • LE Нижнее значение (‹= Низкое)
  • GT Больше чем (›низкий)
  • GE Больше равно (›= низкий)

Возможные значения для поля LOW
Зависит от типа данных поля ссылки. Примеры:

  • [C (2)] = ›строка
  • [D (8)] - это дата, ее следует передавать как строку в формате «ггггММдд»
  • [N (2)] = ›целое число

Возможные значения для поля HIGH

  • Пусто, кроме OPTION - BT или NB

Типы данных

    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)  

Пример: я описал свою задачу выше. Должна быть возможность выбрать

  • Диапазон дат (= ›в SAP таблица с именем IT_WORKD_RANGE, LOW и HIGH типа date)
  • Различные состояния (= ›в SAP таблица с именем IT_STATUS_RANGE, LOW и HIGH типа CHAR 2, например, 10, 20, 60)
  • Различные отделы (= ›в SAP таблица с именем IT_ZZIDL_RANGE, LOW и HIGH типа NUMC 2, например, 10, 20, 60)
  • Показывать ли проекты Z800 или нет (= ›в SAP логический тип с именем IF_AWART, параметр экспорта, X или пробел, где пробел по умолчанию и означает ЛОЖЬ)

person Barbara_Munich    schedule 19.07.2019    source источник
comment
вам лучше сделать сообщение в блоге на blogs.sap.com или в другом месте, ваш формат сообщения не совсем подходит для концепции Stackoverflow   -  person Suncatcher    schedule 22.09.2020


Ответы (2)


Что-то не объясненное во внешнем документе, о котором вы говорите, заключается в том, что в версиях SAP GUI до 7.70 (в настоящее время бета, еще не общедоступная) библиотеки SAP GUI Scripting OCX являются 32-битными. Многие люди используют 64-разрядную версию MS Office, поэтому вам необходимо изменить реестр Windows для нескольких записей SAP GUI, как описано там.

Если вызов касается специальных функциональных модулей RFC, называемых BAPI, для создания, обновления или удаления данных вам необходимо вызвать BAPI_TRANSACTION_COMMIT или BAPI_TRANSACTION_COMMIT в зависимости от успеха или неудачи, указанных в сообщениях параметра RESULT ( при наличии сообщения типа E, A или X). Обратите внимание, что objRfcFunc.Call = False означает системную ошибку.

person Sandra Rossi    schedule 11.09.2020

Ниже приводится решение, данное автором вопроса (которое она изначально разместила в своем вопросе).


Решение

После нажатия кнопки на листе отображается форма. Все возможные значения, указанные выше, вводятся и затем записываются в лист Connection, B9: B13.

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

и код:

    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
person Sandra Rossi    schedule 05.07.2021