4 SAP R/3 Remote Function Call

Transcrição

4 SAP R/3 Remote Function Call
Kap04.fm Seite 49 Dienstag, 22. April 2003 2:31 14
4
SAP R/3 Remote Function Call
Es gibt verschiedene Begriffsvarianten für RPC, so heißt es bei
SAP Remote Function Call (RFC) und bei Java Remote
Method Invokation (RMI).
Es ist sicher nicht vermessen, zu sagen, dass der andauernde Erfolg von
SAP R/3 zu einem großen Teil dessen RFC-Funktionalität zu verdanken ist.
RFC hat SAP R/3 zu einem offenen System gemacht und das ist es, was
die IT-Welt benötigt. Keine Software ist so integriert und perfekt, dass sie
alle Fälle und Sonderfälle eines Geschäftszweiges abdecken kann. Die
Möglichkeit, mit einem Programm all das zu erzielen, was man auch
durch eine Benutzereingabe erreichen kann, ist eine Grundforderung an
ein modernes Software-Paket.
RFC ist Grundlage
für den Erfolg von
R/3
RFC bildet auch die Grundlage der R/3-Technologien ALE/IDoc und BAPI.
In beiden Fällen kommuniziert SAP R/3 mit einem externen Programm,
im Falle von ALE/IDocs durch asynchronen Austausch von Nachrichten,
im Falle von BAPIs durch direkten Aufruf eines Funktionsbausteins.
RFC ist Grundlage
für IDoc/ALE und
BAPI
4.1
Was ist RFC?
Die SAP-Technologie RFC ist eine auf dem IBM-Protokoll CPI-C aufbauende Schnittstellentechnologie, die es externen Programmen oder anderen R/3-Instanzen erlaubt, auf eine bestimmte R/3-Instanz zuzugreifen.
RFC baut auf
CPI-C auf
Das RFC-Protokoll ist ein bidirektionales, synchrones Kommunikationsprotokoll zum Austausch von Nachrichten über ein Netzwerk. RFC sendet dazu Datagramme von einem Client zu einer Server-Applikation über
ein UDP/IP-Netzwerk. Grundsätzlich tut RFC nichts anderes als HTTP, nur
die benutzte Codierung und Konvention unterscheiden sich.
RFC ist ein
sicheres, bidirektionales Protokoll
Genaue Kenntnis der Details des RFC-Protokolls sind für einen Entwickler
normalerweise nicht notwendig. Um den Zugriff auf RFC zu erleichtern,
stellt SAP eigene RFC-Bibliotheken für die verschiedenen Frameworks zur
Verfügung. Derzeit gibt es RFC-Libraries für alle Plattformen, auf denen
SAP R/3 läuft, namentlich Windows, UNIX, Linux, AS/400 und z/OS.
RFC erlaubt es einem Programm,
왘 R/3-Funktionen in einem anderen R/3-System oder einer weiteren
R/3-Instanz aufzurufen
SAP R/3 Remote Function Call
49
Kap04.fm Seite 50 Dienstag, 22. April 2003 2:31 14
왘 R/3-Funktionen von Nicht-SAP-Programmen aufzurufen, zum Beispiel
Java, C++ oder Visual Basic
왘 externe Programme außerhalb eines SAP-Systems von SAP R/3 aus auf-
zurufen
Die folgenden Abschnitte zeigen konkrete Beispiele zum Aufruf von Programmen über RFC. Den Zugriff von externen Computern zeigen wir
unter Verwendung von DCOM für alle Windows-Betriebssysteme und
von Java aus. Grundsätzlich gibt es auch Zugriffsmöglichkeiten von allen
Betriebssystemen aus, die auch eine R/3-Instanz unterstützen, zum Beispiel einer AS/400 oder von IBM/390. Allerdings werden diese Zugriffsvariationen so selten in der Praxis verwendet, dass auch die Unterstützung dafür leidet. Für all diese Betriebssysteme ist es empfehlenswerter,
die Kommunikation über einen HTTP-Proxy-Server durchzuführen.
&
"
&
"
'
!"#$%
$&
Abbildung 4.1 Remote Program Calls als Kernfunktionalität einer Client-ServerLandschaft
50
SAP R/3 Remote Function Call
Kap04.fm Seite 51 Dienstag, 22. April 2003 2:31 14
4.2
R/3-RFC von einer anderen R/3-Instanz
Eine R/3-Verbindung von einer anderen SAP R/3-Instanz aus erfolgt
immer über die Angabe einer Destination. Eine Destination wird in Transaktion SM59 gepflegt und kann dann von allen ABAPs dieser Instanz
benutzt werden. Im Beispiel in Listing 4.1 definieren wir eine RFC-Verbindung zu einem R/3-Computer, in diesem Fall ist es der SAPOSS-Server.
RFCs via R/3Destination
werden in SM59
definiert
Für alle nachfolgenden Aufrufe in das Remote-System brauchen wir uns
fortan nicht mehr um die Logon-Daten zu kümmern, da grundsätzlich auf
die Angabe in SM59 zurückgegriffen wird. Ein RFC-Aufruf von ABAP in
das Remote-System fügt dann dem CALL FUNCTION einfach noch den
Parameter DESTINATION hinzu (siehe Listing 4.1). Wenn Sie keine Destination definiert haben, aber dennoch einen RFC testen wollen, können
Sie die vordefinierte Destination NONE verwenden, die immer auf das
eigene System verweist und implizit vorhanden ist und demnach nicht
erst mit SM59 angelegt werden muss.
Funktionsaufrufe
erhalten den
Parameter
DESTINATION
Listing 4.1 Aufruf einer RFC-Function von ABAP via Destination NONE (= eigenes
System)
DATA: from_curr_range TYPE STANDARD TABLE OF bapi1093_3.
DATA: to_currncy_range TYPE STANDARD TABLE OF bapi1093_4.
DATA: exch_rate_list TYPE STANDARD TABLE OF bapi1093_0
WITH HEADER LINE.
DATA: return TYPE STANDARD TABLE OF bapiret1 WITH HEADER LINE.
CALL FUNCTION 'BAPI_EXCHRATE_GETCURRENTRATES'
DESTINATION ‘NONE’
EXPORTING
date
= sy-datum
TABLES
from_curr_range
= from_curr_range
to_currncy_range
= to_currncy_range
exch_rate_list
= exch_rate_list
return
= return.
LOOP AT exch_rate_list.
WRITE: / exch_rate_list-from_curr.
WRITE:
exch_rate_list-to_currncy.
WRITE:
exch_rate_list-exch_rate.
ENDLOOP.
R/3-RFC von einer anderen R/3-Instanz
51
Kap04.fm Seite 52 Dienstag, 22. April 2003 2:31 14
4.2.1
Interne Destination NONE
RFC-Destination
NONE
R/3 hat bereits einige RFC-Destinationen fest vorgegeben, unter anderem die Destination NONE. Gibt man NONE als Ziel des Aufrufs an, wird ein
RFC in das rufende, also das eigene System ausgeführt. Hierzu sind natürlich keine Logon-Daten erforderlich. NONE eignet sich zum Testen von
RFC-Aufrufen, wenn das entfernte System nicht zur Verfügung steht. Als
besonderen Nebeneffekt gestattet es aber auch ein Entkoppeln des Aufrufs von der laufenden Transaktion.
Jeder RFC öffnet
eine eigene LUW
Ein RFC startet grundsätzlich einen eigenen Programmkontext (Logical
Unit of Work, LUW). Sie können somit aus einer laufenden Transaktion
heraus mehrere RFC-Bausteine mit Destination NONE aufrufen. Zum
Abschluss können Sie dann mit den BAPI-Bausteinen BAPI_COMMIT_
WORK beziehungsweise BAPI_ROLLBACK_WORK die Remote-Aufrufe beenden, ohne dass sich der COMMIT auf die rufende Transaktion auswirkt.
Abbildung 4.2 Definition einer RFC-Destination mit SM59
4.3
Zugriff auf R/3
erfolgt via DCOM
52
Windows-zu-R/3-Connectivity mit DCOM
Der Zugriff von Windows-Systemen aus nach R/3 via RFC bedient sich
einer Reihe von DLLs, die mit dem SAP GUI oder dem RFC-SoftwareDevelopment-Kit (RFCSDK) ausgeliefert werden. Diese DLLs basieren auf
SAP R/3 Remote Function Call
Kap04.fm Seite 53 Dienstag, 22. April 2003 2:31 14
DCOM, dem Distributed Common Object Protocol von Microsoft, mit dem
alle Kommunikationen zwischen Applikationen innerhalb einer Windows-Umgebung durchgeführt werden.
Für den Zugriff auf SAP R/3 müssen beim Aufbau der Connection immer
die richtigen Anmeldedaten (englisch Logon-Credentials) angegeben werden. Dies erledigen Sie normalerweise im SAP-Logon-Panel, das die
Daten wiederum in der Konfigurationsdatei SAPLOGON.INI abspeichert.
Abbildung 4.3 Angabe der Credentials in SM59
Befindet sich eine solche SAPLOGON.INI (normalerweise im WindowsSystem-Ordner, zum Beispiel C:\WINNT) auf Ihrem Rechner, können auch
die auf der librfc32.dll basierenden Libraries wie wdtlog.ocx oder der JavaConnector darauf zurückgreifen; es müssen nur noch UserID und Password explizit angegeben werden. Wollen Sie nicht auf die SAPLOGON.INI
zurückgreifen, müssen Sie alle Logon-Credentials selbst vollständig angeben. Abbildung 1.5 zeigt, wie die Credentials aus dem SAP Logon entnommen werden können.
Windows-zu-R/3-Connectivity mit DCOM
53
Kap04.fm Seite 54 Dienstag, 22. April 2003 2:31 14
Abbildung 4.4 Mapping der Logon-Credentials mit SAPLOGON.INI
4.3.1
Zugriff von Windows erfolgt über
ActiveX
R/3-Logon mit VBA
Das Logon von einer Windows-Applikation – also auch von VBA aus –
erfolgt grundsätzlich über die SAP.LogonCtrl (in wdtlog.ocx) oder auf
unterster Ebene durch die zentrale RFC-Library librfc32.dll. Wir beschränken uns hier immer auf das SAP.LogonCtrl.
Alle folgenden Beispiele für Windows wurden entweder mit Visual Basic
for Applications (VBA) oder Visual Basic Script (VBS) erstellt.
Aufruf eines BAPI
von VBA
Das Beispiel, das jetzt folgt, zeigt zunächst ein ganz einfaches VB-Programm, das einen Logon zu R/3 durchführt, und zwar ohne Verwendung
von Klassen. Das Programm beschafft sich ein Connection-Objekt zu R/3,
setzt die Parameter und führt den Logon durch. Anschließend ruft es
noch den Funktionsbaustein BAPI_EXCHRATE_GETCURRENTRATES mit
dem aktuellen Datum auf.
Listing 4.2 Logon zu R/3 und Aufruf des Funktionsbausteins BAPI_EXCHRATE_GETCURRENTRATES
' Example calling BAPI BAPI_EXCHRATE_GETCURRENTRATES
Option Explicit
Public Functions As SAPFunctionsOCX.SAPFunctions
54
SAP R/3 Remote Function Call
Kap04.fm Seite 55 Dienstag, 22. April 2003 2:31 14
Private LogonControl As SAPLogonCtrl.SAPLogonControl
Private R3Connection As SAPLogonCtrl.Connection
Dim Func As SAPFunctionsOCX.Function
Public iDATE As SAPFunctionsOCX.Parameter
Public tEXCH_RATE_LIST As SAPTableFactoryCtrl.Table
Private Sub Main()
Dim ix As Integer
Dim retcd As Boolean
Dim SilentLogon As Boolean
Set LogonControl =
CreateObject("SAP.LogonControl.1")
Set Functions = CreateObject("SAP.Functions")
Set R3Connection = LogonControl.NewConnection
R3Connection.Client = "000"
R3Connection.ApplicationServer = "192.168.69.111"
R3Connection.Language = "EN"
R3Connection.User = "DEVELOPER"
R3Connection.Password = "19920607"
R3Connection.System = "WAS"
R3Connection.SystemID = "$WebAS"
R3Connection.SystemNumber = "18"
R3Connection.UseSAPLogonIni = False
SilentLogon = True
retcd = R3Connection.Logon(0, SilentLogon)
If retcd <> True Then MsgBox "Logon failed": Exit
Sub
Functions.Connection = R3Connection
Set Func =
Functions.Add("BAPI_EXCHRATE_GETCURRENTRATES")
Set iDATE = Func.Exports("DATE")
Set tEXCH_RATE_LIST = Func.Tables("EXCH_RATE_LIST")
iDATE.Value = "20030101"
Func.Call
For ix = 1 To tEXCH_RATE_LIST.RowCount
Debug.Print tEXCH_RATE_LIST.Cell(ix, 2),
Debug.Print tEXCH_RATE_LIST(ix, 3), 'Different
ways to access matrix
Debug.Print tEXCH_RATE_LIST(ix, "EXCH_RATE")
Windows-zu-R/3-Connectivity mit DCOM
55
Kap04.fm Seite 56 Dienstag, 22. April 2003 2:31 14
Next
R3Connection.logoff
End Sub
4.3.2
Anatomie der RFC- und BAPI-Aufrufe von Windows
RFC-Aufruf mit
RFC_READ_TABLE
In diesem Abschnitt gehen wir noch einmal ins Detail und sezieren die
RFC-Aufrufe von einer Visual-Basic-Applikation aus. Dazu nehmen wir
dieses Mal den RFC-Baustein RFC_READ_TABLE, mit dem man den Inhalt
fast jeder beliebigen R/3-Tabelle via RFC lesen kann. Das verwendete Beispiel wird RFC_READ_TABLE von VBA aufrufen und den Inhalt der SAPMandantentabelle T000 lesen. Wenn Sie dieses Beispiel verstanden
haben, dürfte es Ihnen keine Schwierigkeit mehr bereiten, eine Anwendung mit Zugriff auf einen beliebigen anderen RFC-Baustein zu entwickeln.
Daten einer beliebigen SAP R/3Tabelle mit RFC_
READ_TABLE
lesen
Listing 4.3 Lesen einer beliebigen R/3-Tabelle via RFC
56
Sub R3RFC_READ_TABLE(pQueryTab)
'-----------------------------------------------------' Add the R/3 RFC function RFC_READ_TABLE to the collection
'-----------------------------------------------------Set RFC_READ_TABLE = funcControl.Add("RFC_READ_TABLE")
'-----------------------------------------------------' Create objects for each parameter
'-----------------------------------------------------Set eQUERY_TAB = RFC_READ_TABLE.Exports("QUERY_TABLE")
Set TOPTIONS = RFC_READ_TABLE.Tables("OPTIONS")
'
Set TDATA = RFC_READ_TABLE.Tables("DATA")
'
Set TFIELDS = RFC_READ_TABLE.Tables("FIELDS")
'
eQUERY_TAB.Value = pQueryTab ' pQueryTab is the R/3 name
of the table
TOPTIONS.AppendRow ' new item line
TOPTIONS(1, "TEXT") = "MANDT EQ '000'"
If RFC_READ_TABLE.Call = True Then
If TDATA.RowCount > 0 Then
MsgBox "Call to RFC_READ_TABLE successful! Data
found"
MsgBox TDATA(1, "WA")
Else
MsgBox "Call to RFC_READ_TABLE successful! No
SAP R/3 Remote Function Call
Kap04.fm Seite 57 Dienstag, 22. April 2003 2:31 14
data found"
End If
Else
MsgBox "Call to RFC_READ_TABLE failed!"
End If
End Sub
SAP stellt uns eine Anzahl von ActiveX-Controls und DLLs zur Verfügung,
die als intelligenter Proxy für die gesamte Kommunikation mit R/3 dienen. Ein ActiveX-Control ist ein DCOM-Objekt und deshalb auch kompatibel mit Visual Basic oder anderen DCOM-Anwendungen. Somit
erscheint SAP R/3 aus der Sicht eines ActiveX-Entwicklers wie jedes
andere DCOM-Objekt, wird also genauso behandelt wie etwa ein ADOoder ein DAO-Objekt. Mit anderen Worten ist aus der Sicht eines Entwicklers die SAP R/3-Instanz nichts weiter als ein Datenbankserver und
die Funktionsbausteine entsprechen aus dieser Sicht in etwa den Stored
Procedures eines Datenbanksystems.
DCOM ist das Zugriffsprotokoll von Windows für verteilte Objekte, im
Grunde das Gleiche wie RFC, aber für Windows.
DCOM ist das
RPC-Protokoll von
Windows
Sollte es dennoch Probleme geben, die ActiveX-Controls von SAP aufzurufen, liegt das Problem mit sehr großer Sicherheit bei der Installation der
Controls oder an einer mangelhaften Windows-Installation.
Hauptgrund für
Fehler: korrupte
Installation der
DLLs
Über SAP ActiveX-Controls brauchen Sie außer den Logon Credentials und
dem Namen des aufzurufenden Funktionsbausteins nichts weiter zu wissen. Die Controls bauen eine Session mit R/3 auf, und sobald Sie den
Funktionsbaustein dem lokalen Repository des ActiveX-Controls hinzufügen, können Sie alle Eigenschaften des Bausteins einschließlich der
Namen und Typen der Parameter abfragen.
Die folgenden kommentierten Code-Zeilen geben Ihnen Schritt für
Schritt einen Überblick über die einzelnen Methoden der RFC-Controls
am Beispiel eines einfachen Visual-Basic-Programms. Das Beispiel verzichtet auf die Typisierung der Variablen und ist somit auch unter Visual
Basic Script ausführbar. Dazu muss der Code nur in einer ASCII-Datei mit
der Dateierweiterung .vbs abgespeichert sein. Ein Doppelklick auf die
Datei vom Windows-Explorer aus führt das Script dann aus.
Windows-zu-R/3-Connectivity mit DCOM
Visual-Basic-Code
zum Lesen von
Tabelle T000 via
RFC
57
Kap04.fm Seite 58 Dienstag, 22. April 2003 2:31 14
Declarations
Zunächst deklarieren wir eine neue R/3-Logon-OCX-Komponente:
Dim LogonControl As SAPLogonCtrl.SAPLogonControl
Deklarieren eines
ConnectionObjekts
Das Connection-Objekt ist das Gateway zwischen lokaler Instanz und
R/3. Über die Connection wird zu Beginn eine Session durch Übermittlung der Anmeldedaten hergestellt. Grundsätzlich kann die Verbindung
von beliebig vielen Routinen gleichzeitig verwendet werden (Connection-Pooling):
Dim conn As SAPLogonCtrl.Connection
Deklarieren eines
Pointers auf ein
R/3 RFC-Repository-Objekt
Diesem Pointer wird später eine Referenz auf die Verwaltungsinformationen der gewünschten Funktionsbausteine zugewiesen. Die Eigenschaften
der Funktion werden demnach dynamisch bestimmt:
Dim funcControl As SAPFunctionsOCX.SAPFunctions
Dies ist der Pointer zum aktuellen R/3 RFC-Funktionsbaustein:
Dim RFC_READ_TABLE As SAPFunctionsOCX.Function
Als nächstes folgt die Deklaration eines Pointers für jeden Parameter:
Dim
Dim
Dim
Dim
eQUERY_TAB As SAPFunctionsOCX.Parameter
TOPTIONS As SAPFunctionsOCX.Table
TDATA As SAPFunctionsOCX.Table
TFIELDS As SAPFunctionsOCX.Table
Logon-Routine
Das Logon zu R/3 fassen wir in einer eigenen Unterroutine zusammen.
Darin legen wir eine neue Connection zu R/3 an, die die Verbindungsdaten über die ganze Programmlaufzeit hinweg hält und die Anmeldung an
R/3 zur Applikation hin abschottet.
Sub R3Logon()
Erzeugen einer
neuen Connection
Eine neue Connection muss mit der Methode NewConnection angelegt
werden. Das Anlegen eines Connection-Objekts mit CreateObject
funktioniert ausdrücklich nicht, weil es durch die fehlende Vererbung in
Visual Basic nicht möglich ist, das Objekt mit CreateObject sauber zu
initialisieren.
Set conn = LogonControl.NewConnection
58
SAP R/3 Remote Function Call
Kap04.fm Seite 59 Dienstag, 22. April 2003 2:31 14
Lediglich die Angabe von Applikationsserver und Systemnummer ist
zwingend, alle anderen Daten werden gegebenenfalls in einem Popup
abgefragt. Selbstverständlich ist dies in einer automatisierten Umgebung
nicht wünschenswert, weshalb Sie schließlich dann doch alle Angaben
machen oder in der SAPLOGON.INI auf dem Server hinterlegen müssen.
Angabe der
Logon-Credentials
conn.ApplicationServer = "R3Linux"' IP or DNS-Name of
the R/3 application server
conn.System = "00"
' System ID of the
instance, usually 00
conn.Client = "100"
' opt. Client number
to logon to
conn.Language = "EN"
' opt. Your login
language
conn.User = ""
' opt. Your user id
conn.Password = ""
' opt. Your password
Dann folgt der Aufruf der Logon-Methode:
retcd = conn.Logon(0, False)
Und schließlich die Prüfung, ob das Login erfolgreich war:
If retcd
MsgBox
MsgBox
Stop
else
MsgBox
End If
End Sub
<> True Then
" Cannot log on! "
retcd
" Logon OK."
Aufruf eines RFC-Funktionsbausteins
Der RFC-Funktionsbaustein wird über die Connection aufgerufen, die wir
im Logon-Schritt erzeugt haben. Das Coding lässt die lokalen Pointer auf
die Parameter des Funktionsbausteins verweisen. Das ist zwar nicht wirklich notwendig, macht aber das Programm lesbarer, als wenn immer der
ganze Parameterkontext angegeben werden muss. Hat ein RFC-Funktionsbaustein Tabellenparameter, erscheinen die in Visual Basic wie ADORecordsets und werden auch wie solche behandelt. Die Typisierung der
Recordsets erfolgt automatisch beim Hinzufügen des Funktionsbausteins
zum lokalen RFC-Repository:
Windows-zu-R/3-Connectivity mit DCOM
RFC-Aufruf
benutzt die zuvor
eröffnete Connection
59
Kap04.fm Seite 60 Dienstag, 22. April 2003 2:31 14
Sub R3RFC_READ_TABLE(pQueryTab)
Erzeugen einer
neuen Collection
für den Funktionsbaustein
Alle zu verwendenden Funktionsbausteine müssen einer lokalen Collection hinzugefügt werden, die als Cache für die Parameterinformation
dient:
Set RFC_READ_TABLE =
funcControl.Add("RFC_READ_TABLE")
Als Nächstes wird ein Pointer auf die Import- und Exportparameter
gesetzt:
Set eQUERY_TAB =
RFC_READ_TABLE.Exports("QUERY_TABLE")
Set TOPTIONS
= RFC_READ_TABLE.Tables("OPTIONS")
'
Set TDATA
= RFC_READ_TABLE.Tables("DATA")
'
Set TFIELDS
= RFC_READ_TABLE.Tables("FIELDS")
'
Import-, Export- und Tables-Parameter werden durch einen Visual-BasicPointer referenziert. Die function collection, die wir oben mit funcControl.Add erzeugt haben, stellt uns dynamisch einen Proxy für die Methoden und Pointer auf alle Parameter des Funktionsbausteins zur Verfügung.
Bevor wir den Funktionsbaustein aufrufen, müssen wir den Parametern
die gewünschten Werte zuweisen:
Lesen und
Schreiben der
Parameterwerte
eQUERY_TAB.Value = pQueryTab
' pQueryTab is the R/3 name of
the table
TOPTIONS.AppendRow
' new item line
TOPTIONS(1,"TEXT") = "MANDT EQ '000'"
Sobald den Parametern gültige Werte zugewiesen wurden, kann der
Funktionsbaustein aufgerufen werden. Der Aufruf retourniert TRUE oder
FALSE, je nachdem, ob der Aufruf erfolgreich war oder nicht:
If RFC_READ_TABLE.Call = True Then
Wenn der RFC-Aufruf erfolgreich war, können die Werte weiter verarbeitet werden. Im Beispiel hier zeigen wir jeweils die erste Zeile der Tabelle
in einer VB Messagebox an.
Ausgabe des
Ergebnisses
60
If TDATA.RowCount > 0 Then
MsgBox "Call to RFC_READ_TABLE successful! Data
found"
MsgBox TDATA(1, "WA")
SAP R/3 Remote Function Call
Kap04.fm Seite 61 Dienstag, 22. April 2003 2:31 14
Else
MsgBox "Call to RFC_READ_TABLE successful! No data
found"
End If
Else
MsgBox "Call to RFC_READ_TABLE failed!"
End If
End Sub
Hauptprogramm
Damit hätten wir den spannenden Teil des Codings auch schon hinter
uns. Im Folgenden packen wir dem Ganzen noch eine Main-Routine
hinzu:
Sub Main()
Main() procedure
Nun erzeugen wir noch eine Instanz der SAP.LogonControl-Klasse
(Version 1)
Set LogonControl = CreateObject("SAP.LogonControl.1")
Dieses Statement hat eine neue Instanz des Logon-Objekts erzeugt. Die
Nummer 1 am Ende des Klassennamens SAP.LogonControl.1 ist die
Versionsnummer der Klasse. Normalerweise gibt man die Version einer
Klasse nur an, wenn man wirklich explizit die Verwendung einer
bestimmten Version erzwingen will. Im Falle des SAP.LogonControl
gibt es nur die eine Version.
Nun erzeugen wir eine Instanz der SAP.Functions collection:
Set funcControl = CreateObject("SAP.Functions")
Als Nächstes erfolgt der Aufruf der Logon-Routine:
call R3Logon
Und dann die Zuweisung des Connection-Objekts:
funcControl.Connection = conn
Dann wird der RFC-Call ausgeführt und es folgt der Logoff:
call R3RFC_READ_TABLE("T000")
conn.Logoff
MsgBox " Logged off from R/3! "
End Sub
Windows-zu-R/3-Connectivity mit DCOM
61
Kap04.fm Seite 62 Dienstag, 22. April 2003 2:31 14
Start des Programms
Call Main()
Abhängig davon, welche Visual-Basic-Variante Sie verwenden, ist der
Aufruf leicht unterschiedlich. Im Falle von VBS müssen Sie dem ScriptFile noch das Statement Call Main() hinzufügen, um das Hauptprogramm explizit aufzurufen.
ASP
Call Main() in
einer ASP-Seite
Falls Sie das VBS-Script in eine ASP-Seite einbinden wollen, können Sie
das Coding in der VBS-Datei lassen und mit dem #include-Befehl von
ASP in die HTML-Seite einbinden:
<HTML>
<HEAD>
<#include RfcReadTable.vbs >
</HEAD>
<BODY><%>Call Main()<%></BODY>
Funktionsaufruf im Überblick
Das nachstehende Beispiel zeigt noch einmal den Aufruf eines Funktionsbaussteins im Überblick. Diesmal wurde ein anderer Funktionsbaustein
(RFC_GET_TABLE_ENTRIES) ausgewählt, der ebenfalls den Inhalt einer
beliebigen SAP R/3-Tabelle ausliest, jedoch etwas andere Parameter als
RFC_READ_TABLE hat.
Listing 4.4 Vollständiges Coding zum Aufruf der RFC-Funktion RFC_READ_TABLE
Dim LogonControl 'As SAPLogonCtrl.SAPLogonControl
Dim conn 'As SAPLogonCtrl.Connection
Dim funcControl 'As SAPFunctionsOCX.SAPFunctions
Dim TableFactoryCtrl 'As SAPTableFactoryCtrl.SAPTableFactory
'-----------------------------------------------------' Pointer to functions
'-----------------------------------------------------Dim RFC_READ_TABLE
'-----------------------------------------------------' Pointers to function parameters
'-----------------------------------------------------Dim eQUERY_TAB
Dim TOPTIONS
Dim TDATA
Dim TFIELDS
62
SAP R/3 Remote Function Call
Kap04.fm Seite 63 Dienstag, 22. April 2003 2:31 14
'******************************************************
' Main Program
'******************************************************
Call Main
'******************************************************
' Subroutines
'******************************************************
Sub Main()
Set LogonControl = CreateObject("SAP.LogonControl.1")
Set funcControl = CreateObject("SAP.Functions")
Set TableFactoryCtrl = CreateObject("SAP.TableFactory.1")
Call R3Logon
funcControl.Connection = conn
Call R3RFC_READ_TABLE("T000")
conn.Logoff
MsgBox " Logged off from R/3! "
End Sub
Sub R3Logon()
Set conn = LogonControl.NewConnection
conn.ApplicationServer = "r3dev" ' IP or DNS-Name of the
R/3 application server
conn.System = "00"
' System ID of the
instance, usually 00
conn.Client = "100"
' opt. Client number to
logon to
conn.Language = "EN"
' opt. Your login
language
conn.User = ""
' opt. Your user id
conn.Password = ""
' opt. Your password
retcd = conn.Logon(0, False)
If retcd <> True Then
MsgBox " Cannot log on! "
MsgBox retcd
Stop
Else
MsgBox " Logon OK."
End If
End Sub
Windows-zu-R/3-Connectivity mit DCOM
63
Kap04.fm Seite 64 Dienstag, 22. April 2003 2:31 14
Sub R3RFC_READ_TABLE(pQueryTab)
'-----------------------------------------------------' Add the R/3 RFC function RFC_READ_TABLE to the collection
'-----------------------------------------------------Set RFC_READ_TABLE = funcControl.Add("RFC_READ_TABLE")
'-----------------------------------------------------' Create objects for each parameter
'-----------------------------------------------------Set eQUERY_TAB = RFC_READ_TABLE.Exports("QUERY_TABLE")
Set TOPTIONS = RFC_READ_TABLE.Tables("OPTIONS")
'
Set TDATA = RFC_READ_TABLE.Tables("DATA")
'
Set TFIELDS = RFC_READ_TABLE.Tables("FIELDS")
'
eQUERY_TAB.Value = pQueryTab ' pQueryTab is the R/3 name
of the table
TOPTIONS.AppendRow ' new item line
TOPTIONS(1, "TEXT") = "MANDT EQ '000'"
If RFC_READ_TABLE.Call = True Then
If TDATA.RowCount > 0 Then
MsgBox "Call to RFC_READ_TABLE successful! Data
found"
MsgBox TDATA(1, "WA")
Else
MsgBox "Call to RFC_READ_TABLE successful! No
data found"
End If
Else
MsgBox "Call to RFC_READ_TABLE failed!"
End If
End Sub
Das nachstehende Programmbeispiel zeigt noch einmal den Aufruf eines
RFC-Bausteins an einem Stück. Um ein Vergleichsbeispiel zu haben, verwendet es diesmal den Aufruf des Bausteins RFC_GET_TABLE_ENTRIES.
Listing 4.5 Einfacher Aufruf von RFC_GET_TABLE_ENTRIES via RFC und VB
' Example calling BAPI RFC_GET_TABLE_ENTRIES
Option Explicit
Public Functions As SAPFunctionsOCX.SAPFunctions
Private LogonControl As SAPLogonCtrl.SAPLogonControl
Private R3Connection As SAPLogonCtrl.Connection
64
SAP R/3 Remote Function Call
Kap04.fm Seite 65 Dienstag, 22. April 2003 2:31 14
Dim Func As SAPFunctionsOCX.Function
Public iTABLE_NAME As SAPFunctionsOCX.Parameter
Public eNUMBER_OF_ENTRIES As SAPFunctionsOCX.Parameter
Public tENTRIES As SAPTableFactoryCtrl.Table
Private Sub Main()
Dim ix As Integer
Dim retcd As Boolean
Dim SilentLogon As Boolean
Set LogonControl =
CreateObject("SAP.LogonControl.1")
Set Functions = CreateObject("SAP.Functions")
Set TableFactory =
CreateObject("SAP.TableFactory.1")
Set R3Connection = LogonControl.NewConnection
R3Connection.Client = "000"
R3Connection.ApplicationServer = "192.168.69.111"
R3Connection.Language = "EN"
R3Connection.User = "DEVELOPER"
R3Connection.Password = "19920607"
R3Connection.System = "WAS"
R3Connection.SystemID = "$WebAS"
R3Connection.SystemNumber = "18"
R3Connection.UseSAPLogonIni = False
SilentLogon = True
retcd = R3Connection.Logon(0, SilentLogon)
If retcd <> True Then MsgBox "Logon failed": Exit
Sub
Functions.Connection = R3Connection
Set Func = Functions.Add("RFC_GET_TABLE_ENTRIES")
Set iTABLE_NAME = Func.Exports("TABLE_NAME")
Set eNUMBER_OF_ENTRIES =
Func.Imports("NUMBER_OF_ENTRIES")
Set tENTRIES = Func.Tables("ENTRIES")
iTABLE_NAME.Value = "TCURR"
Func.Call
Debug.Print eNUMBER_OF_ENTRIES
For ix = 1 To tENTRIES.RowCount
Windows-zu-R/3-Connectivity mit DCOM
65
Kap04.fm Seite 66 Dienstag, 22. April 2003 2:31 14
Debug.Print tENTRIES(ix, 1)
Next
R3Connection.logoff
End Sub
4.4
Hilfsklassen für
wiederkehrende
Arbeiten
Helper-Klassen für den Zugriff auf R/3 via
RFC
Um Programme klarer zu gestalten und von immer wiederkehrenden
Routinearbeiten zu säubern, macht es Sinn, sich eine Reihe von Hilfsklassen zu erstellen. Im Folgenden sind ein paar Ideen aufgezeigt, wie solche
Helper-Klassen aussehen können. Diese sind weniger dazu gedacht,
direkt und unverändert übernommen zu werden, vielmehr sollen sie
Anregungen geben, was man alles machen kann oder bedenken sollte.
4.4.1
Class R3LogonObj
Logon von VB
durch die Klasse
R3LogonObj
In unseren Beispielen führen wir das Logon zu SAP R/3 von Visual Basic
durchweg mit einer selbst geschriebenen Proxy-Klasse R3LogonObj
durch. Diese Klasse führt den Logon zu SAP R/3 zentral durch, so dass wir
uns nur an dieser Stelle um Logon-Daten wie Name des Applikationsservers, UserID, Passwort usw. kümmern müssen.
Referenz auf
ein Objekt
SAPFunctionsOCX.Functions
Die Klasse selbst exportiert dann im Wesentlichen das Objekt Functions
as SAPFunctionsOCX.Functions, das das zentrale Gateway zur RFCFunktionsbibliothek von SAP R/3 darstellt.
Listing 4.6 Class R3LogonObj
Public Functions As SAPFunctionsOCX.SAPFunctions
Public TableFactory As SAPTableFactoryCtrl.SAPTableFactory
Public SilentLogon As Boolean
'-----------------------------------------------------Private LogonControl As SAPLogonCtrl.SAPLogonControl
Private myCredentials As New R3Credentials
Private retcd
Private err As New ErrObject
Public Property Get R3Connection() As SAPLogonCtrl.connection
Set R3Connection = Me.Functions.connection
End Property
66
SAP R/3 Remote Function Call
Kap04.fm Seite 67 Dienstag, 22. April 2003 2:31 14
Private Property Set R3Connection(conn As SAPLogonCtrl.connection)
Set Functions.connection = conn
End Property
Public Sub R3Logon()
retcd = R3Connection.Logon(0, SilentLogon)
If retcd <> True Then
Exit Sub
Else
'
MsgBox " Logon OK."
End If
End Sub
Public Sub R3logoff()
R3Connection.logoff
End Sub
Private Sub Class_Initialize()
Set LogonControl =
CreateObject("SAP.LogonControl.1")
Set Functions = CreateObject("SAP.Functions")
Set TableFactory =
CreateObject("SAP.TableFactory.1")
Set R3Connection = LogonControl.NewConnection
myCredentials.Read R3Connection
Me.SilentLogon = False
End Sub
Private Sub Class_Terminate()
Me.R3logoff
End Sub
4.4.2 Class R3Credentials
Die eigentlichen Logon-Credentials sind noch einmal in einer eigenen
Klasse, den R3Credentials, realisiert. Das erlaubt uns, einen geheimen
Mechanismus zu implementieren, um die Logon-Daten zu verstecken.
Diese Klasse kann dann in den Verantwortungsbereich der Systemadministration gegeben werden, die ohnehin die Logon-Daten verwaltet,
ohne dass sie dem Anwendungsentwickler bekannt sind, denn der weist
die Daten durch die Methode READ automatisch dem Connection-Objekt
zu, ohne sie im Detail zu kennen.
Helper-Klassen für den Zugriff auf R/3 via RFC
Logon-Credentials stecken in
R3Credentials
67
Kap04.fm Seite 68 Dienstag, 22. April 2003 2:31 14
Listing 4.7 Class R3Credentials
Sub Read(ByRef oR3 As SAPLogonCtrl.Connection)
Set LogonDataWS = Excel.Worksheets("LogonData")
Set LogonData = LogonDataWS.Columns(2)
R3Connection.Client = "000"
R3Connection.ApplicationServer = "192.168.69.111"
R3Connection.Language = "EN"
R3Connection.User = "DEVELOPER"
R3Connection.Password = "06071992"
R3Connection.System = "WAS"
R3Connection.SystemID = "$WebAS"
R3Connection.SystemNumber = "18"
R3Connection.UseSAPLogonIni = False
Set LogonData = Nothing
Set LogonDataWS = Nothing
End Sub
Sub Class_Initialize()
End Sub
Sub Class_Terminate()
End Sub
4.4.3 Alternative R3Credentials-Class
Zugriff über
Excel-Sheet
Für den Zugriff von Visual Basic benutzen wir in unserer Entwicklungsumgebung ein Excel-Sheet, das wir einfach mit den Zugriffsdaten mehrerer
SAP R/3-Systeme füllen. So können wir unsere Anwendung ohne viel
Aufwand auf mehreren SAP R/3-Systemen testen.
Im folgenden Beispiel sehen Sie ein VBA-Programm, das die Daten aus
dem Excel-Sheet herausliest und den Parametern unserer Logon-Klasse
zuweist.
Listing 4.8 Class R3Credentials mit Daten aus Excel
Private LogonDataWS As Excel.Worksheet
Private LogonData As Excel.Range
Sub Read(ByRef oR3 As SAPLogonCtrl.Connection)
Set LogonDataWS = Excel.Worksheets("LogonData")
Set LogonData = LogonDataWS.Columns(2)
oR3.ApplicationServer = LogonData.Cells(2) ' IP or
DNS-Name of app server
oR3.System = LogonData.Cells(3)
' System
68
SAP R/3 Remote Function Call
Kap04.fm Seite 69 Dienstag, 22. April 2003 2:31 14
ID of the instance
oR3.SystemNumber = LogonData.Cells(4)
of Database instance
oR3.Client = LogonData.Cells(5)
Client number to logon to
oR3.Language = LogonData.Cells(6)
Your login language
oR3.User = LogonData.Cells(7)
Your user id
oR3.Password = LogonData.Cells(8)
Your password
oR3.SystemID = LogonData.Cells(9)
ID of the instance
oR3.UseSAPLogonIni = True
Set LogonData = Nothing
Set LogonDataWS = Nothing
End Sub
Sub Class_Initialize()
End Sub
Sub Class_Terminate()
End Sub
' Number
' opt.
' opt.
' opt.
' opt.
' System
Die Logon-Daten zu R/3 entsprechen denen aus der saplogon.ini.
Name
Wert
Application server
192.168.69.111
System ID
WAS
System Number
18
Client
000
Language
EN
User
DEVELOPER
Password
********
System
Web AS
Silent Login
FALSCH
Use SAPLOGON.INI
FALSCH
Gateway
Tabelle 4.1 Beispiel für Logon-Daten (für die Web AS-Testversion)
Helper-Klassen für den Zugriff auf R/3 via RFC
69
Kap04.fm Seite 70 Dienstag, 22. April 2003 2:31 14
4.5
R/3 Java Connectivity
4.5.1
SAP R/3 Java Connector JCo
Der Zugriff von Java auf SAP R/3 erfolgt über den Java Connector (JCo). Je
nach Plattform gibt es dafür eine kompatible Implementierung, so dass die
Aufrufe von Java auf SAP R/3 unabhängig von der Umgebung bleiben. In
einer Windows-Umgebung ist der Java Connector eine Java-Klassenbibliothek, die über das JNI (Java Native Interface) die Funktionen der RFCLibrary librfc32.dll aufruft.
JCo ist die einzige
empfohlene
RFC-Klasse
Der Java Connector ist die einzige unterstützte RFC-Schnittstelle von Java
nach SAP R/3. Alle früheren Java-Tools für RFC werden von SAP nicht
mehr unterstützt. Der Java Connector wurde ursprünglich von Thomas
Schüssler, http://arasoft.de, entwickelt und kann von Kunden und registrierten SAPNet-Usern über http://service.sap.com heruntergeladen werden. JCo ist derzeit für alle NT-Varianten verfügbar sowie für UNIX, AIX
und Linux. Die früher noch unterstützte Bibliothek jRFC wird von SAP
nicht mehr ausgeliefert und es wird empfohlen, Anwendungen auf JCo
umzustellen.
4.5.2
JCo unterstützt
XML-Konvertierung
SAP R/3-Logon mit Java
Im nachstehenden Listing erfolgt der Aufruf auf das BAPI BAPI_
EXCHRATE_GETCURRENTRATES von Java. Eine Besonderheit des JavaConnectors ist es, dass die Funktionsbausteinparameter bereits eine
intrinsische Konvertierung nach XML unterstützen und wir deshalb durch
Aufruf der Methode toXML() das Ergebnis sofort in XML ausgeben können:
System.out.println(myFunc.tEXCH_RATE_LIST.toXML());
Listing 4.9 Einfacher Aufruf von BAPI_EXCHRATE_GETCURRENTRATES via RFC und
Java
package R3;
import com.sap.mw.JCo.*;
public class R3Test extends Object {
public static BAPI_EXCHRATE_GETCURRENTRATES
myFunc;
public static void main (String args[]) {
R3RFCfunctions funcs = new R3RFCfunctions();
System.out.println("** SYS: Repository
created.");
70
SAP R/3 Remote Function Call
Kap04.fm Seite 71 Dienstag, 22. April 2003 2:31 14
funcs.Logon();
myFunc = new BAPI_EXCHRATE_GETCURRENTRATES
(funcs, "BAPI_EXCHRATE_GETCURRENTRATES");
myFunc.iDATE.setValue("20030101");
myFunc.Execute();
System.out.println(myFunc.tEXCH_RATE_LIST.
toXML());
}
}
package R3;
import com.sap.mw.JCo.*;
public class BAPI_EXCHRATE_GETCURRENTRATES // extends
R3RFCfunctions
{
public JCO.Function func;
private R3RFCfunctions functions;
public JCO.Field iDATE;
public JCO.Table tEXCH_RATE_LIST;
public BAPI_EXCHRATE_GETCURRENTRATES(
R3RFCfunctions funcRepository, String
funcname) {
functions = funcRepository;
func =
functions.add(funcname.toUpperCase());
//---Set vectors to the appropriate parameters
iDATE =
func.getImportParameterList()
.getField("DATE");
tEXCH_RATE_LIST =
func.getTableParameterList()
.getTable("EXCH_RATE_LIST");
try functions.add(funcname.
toUpperCase());
}
catch (Exception ex) {
}
}
public void Execute()
{functions.R3session.Connection.execute(func);}
}
package R3;
import com.sap.mw.JCo.*;
public class R3RFCfunctions extends R3RFCrepository
R/3 Java Connectivity
71
Kap04.fm Seite 72 Dienstag, 22. April 2003 2:31 14
{
public R3RFCfunctions()
{}
public JCO.Function add(String name)
{
try {
return super.R3session.Functions.getFunctionTemplate
(name.toUpperCase()).getFunction();}
catch (Exception ex) {}
return null; }
public class R3RFCrepository
{
public R3LogonObj R3session;
public R3RFCrepository()
{
R3session = new R3LogonObj(); }
public R3RFCrepository(R3LogonObj ActiveSession)
{
R3session = ActiveSession; }
public void Logon()
{
R3session.Connection.connect();}
public void Logoff()
{
R3session.Connection.disconnect();}
}
package R3;
import com.sap.mw.JCo.*;
public class R3LogonObj {
public JCO.Repository Functions;
public boolean SilentLogon;
public JCO.Client Connection;
public R3LogonObj() {
try {R3.R3Credentials myCred = new
R3.R3Credentials();
Connection =
myCred.Connect();
}
catch (Exception ex) {
ex.printStackTrace();System.exit(1);}
try {Functions = new
JCO.Repository("logosworld", Connection);}
catch (Exception ex) {
ex.printStackTrace();System.exit(1);}
}
}
72
SAP R/3 Remote Function Call
Kap04.fm Seite 73 Dienstag, 22. April 2003 2:31 14
4.6
Das SAP RFC-Gateway
Mit Hilfe des SAP RFC-Gateways können Sie einem externen Programm,
dem RFC-Listener, erlauben, sich selbst als Proxy-Server bei SAP R/3 anzubieten. Dadurch müssen in SAP R/3 selbst keine Verbindungsdaten zum
Listener gepflegt werden. SAP R/3 spricht den Listener über das Gateway
als eine RFC-Destination mit dem Namen an, unter dem der Listener sich
zuvor bei SAP R/3 registriert hat.
4.6.1
RFC-Listener
Registrierung eines RFC-Listeners beim SAP-Gateway
Folgendes ist ein Beispiel einer Registrierung am Gateway:
Srfcserv –aMYHOST.srfcserv –gSAPR3.logosworld.com –
xSAPGW00 –t
Das gezeigte Beispiel registriert sich selbst über Gateway SAPGW00 bei
der SAP R/3-Instanz mit dem Namen SAPR3.logosworld.com.
Der Name des SAP-Gateways ist von der Form SAPGWxx, wobei xx die
System-Nummer der zugehörigen SAP R/3-Instanz ist. SAPGW00 gehört
also zur Datenbank-Instanz »00«. Das Gateway des Demo-Web AS ist
SAPGW18, da dieses sich auf Datenbankinstanz 18 installiert.
Anstatt die Parameter in der Kommandozeile anzugeben, können diese
auch in der Datei saprfc.ini hinterlegt werden. saprfc.ini muss im selben
Verzeichnis wie der zu registrierende RFC-Server liegen.
Parameter können
auch in saprfc.ini
hinterlegt werden
Listing 4.10 Beispiel einer SAPRFC.INI
/*===================================================*/
/* Type R: Register a RFC server program at a SAP
gateway
*/
/*
or connect to an already registered RFC
server program */
/*===================================================*/
DEST=RFCEXT_LISTENER
TYPE=R
PROGID=SAPR3.srfcserv
GWHOST=SAPr3.logosworld.com
GWSERV=sapgw00
RFC_TRACE=0
Das SAP RFC-Gateway
73
Kap04.fm Seite 74 Dienstag, 22. April 2003 2:31 14
SMGW zeigt
registrierte
Gateway-Dienste
Eine Übersicht der aktuell angemeldeten Dienste am SAP-Gateway liefert
die Transaktion SMGW unter dem Menüpunkt Logged Systems.
Listing 4.11 Optionen der Registrierung eines RFC-Servers an einem SAP-Gateway
C:\Programme\sapgui46b\SAPGUI\RFCSDK\bin>srfcserv
Syntax for start and run in register mode:
srfcserv [options]
with
options = -D<destination with type 'R' in saprfc.ini>
= -t
RFC-Trace on
or
options = -a<program ID> e.g. <own host
name>.srfcserv
= -g<SAP gateway host name>
e.g.
hs0311
= -x<SAP gateway service>
e.g.
sapgw53
= -t
RFC-Trace on
= -L<SNC library, optional>
= -S<SNC myname, optional>
= -Q<SNC quality of protection, optional>
Option L, S and Q can be set if working with SNC
(Secure Network Communication).
4.6.2 Anlegen einer RFC-Destination für einen registrierten Listener
Um auf einen SAP-Gateway-Service zugreifen zu können, müssen Sie in
der rufenden Instanz das Gateway als Destination in Transaktion SM59
bekannt machen. An Stelle der festen IP-Adresse des zu rufenden Servers
geben Sie in diesem Fall den Namen an, unter dem sich das Gateway bei
seiner Registrierung bei SAP bekannt macht.
4.6.3 Eigene RFC-Listener erstellen
Kompletter Code
eines GatewayServers im
RFC-SDK
74
Das SAP RFCSDK listet den kompletten Sourcecode der in C geschriebenen RFC-Listener rfcexec und srfcserv. Die ausführliche Dokumentation zur Entwicklung eines Listeners findet sich in der Hilfe zum RFCSDK
in saprfc.hlp.
SAP R/3 Remote Function Call
Kap04.fm Seite 75 Dienstag, 22. April 2003 2:31 14
Listing 4.12 Abbildung 1.10Extrakte aus der Implementierung des rfcexec-Servers
static RFC_RC DLL_CALL_BACK_FUNCTION _loadds remote_
pipe( RFC_HANDLE handle );
static RFC_RC DLL_CALL_BACK_FUNCTION _loadds remote_
file( RFC_HANDLE handle );
static RFC_RC DLL_CALL_BACK_FUNCTION _loadds remote_
exec( RFC_HANDLE handle );
static RFC_RC DLL_CALL_BACK_FUNCTION _loadds mail
( RFC_HANDLE handle );
/* main function for an RFC server program */
/*ARGSUSED*/
main( int argc, char ** argv ){
/* initialized data */
static RFC_ENV
env;
RFC_HANDLE handle;
RFC_RC
rc;
if (argc == 1)
{ help();
return 0; }
/* install error handler */
env.errorhandler = myErrorhandler;
RfcEnvironment( &env );
/* accept connection
* (command line argv must be passed to RfcAccept) */
handle = RfcAccept( argv );
/* static function to install offered function modules
*/
rc = install(handle);
if( rc != RFC_OK )
{
/* if error occured, close connection with error message and exit */
RfcAbort( handle, "Initialization error" );
exit(1);
}
static RFC_RC DLL_CALL_BACK_FUNCTION _loadds remote_
pipe( RFC_HANDLE handle )
{
char
command[256];
RFC_PARAMETER parameter[4];
RFC_TABLE
table[2];
RFC_RC
rc;
Das SAP RFC-Gateway
75
Kap04.fm Seite 76 Dienstag, 22. April 2003 2:31 14
RFC_CHAR
read_flag = 0;
int
mode;
memset( command, 0, sizeof( command ) );
parameter[0].name = "COMMAND";
parameter[0].nlen = 7;
parameter[0].addr = (void *) command;
parameter[0].leng = sizeof(command);
parameter[0].type = RFCTYPE_CHAR;
parameter[1].name = "READ";
parameter[1].nlen = 4;
parameter[1].addr = (void *) &read_flag;
parameter[1].leng = sizeof(read_flag);
parameter[1].type = RFCTYPE_CHAR;
parameter[2].name = NULL;
table[0].name = "PIPEDATA";
table[0].nlen = 8;
table[0].type = RFCTYPE_CHAR;
table[0].leng = table_size;
table[0].itmode = RFC_ITMODE_BYREFERENCE;
table[1].name = NULL;
rc = RfcGetData( handle, parameter, table );
if( rc != RFC_OK ) return rc;
#ifdef SAPonWINDOWS
RfcAbort(handle, "Function RFC_REMOTE_PIPE is not
supported on Windows");
exit(1);
#endif
if( read_flag != 'X' )
mode = RUN_WAIT;
else
mode = RUN_READ;
rc = run( handle, command, sizeof(command),
table[0].ithandle, mode, (RFC_INT
*)0 );
if( rc != RFC_OK ) return rc;
parameter[0].name = NULL;
rc = RfcSendData( handle, parameter, table );
return rc;
} /* remote_pipe */
76
SAP R/3 Remote Function Call
Kap04.fm Seite 77 Dienstag, 22. April 2003 2:31 14
4.7
Troubleshooting RFC
Es existiert ein Standard-ABAP in SAP R/3, SRFCTEST, in dem die wichtigsten RFC-Möglichkeiten sehr gut demonstriert werden und auch gleich
getestet werden können.
SRFCTEST zum
Testen von RFC
Wenn ein Zugriff via SAP R/3 permanent versagt, testen Sie die
gewünschte Funktionalität immer zunächst lokal im Zielsystem. Zum Beispiel setzen die Aufrufe über LOCAL_EXEC voraus, dass rfcexec.exe sich
im Zugriffspfad des SAP GUI auf der Workstation befindet. In diesem Fall
sollten Sie auf der Arbeitsstation ein DOS-Fenster öffnen und versuchen,
rfcexec von einem beliebigen Verzeichnis auszuführen. Klappt dies
nicht, müssen Sie rfcexec.exe in eines der Verzeichnisse kopieren, die mit
dem PATH-Kommando angezeigt werden, oder Sie müssen den Suchpfad
entsprechend erweitern.
Lokaler Test
Abbildung 4.5 Aufruf von rfcexec.exe über eine DOS-Box
Klappt das lokale Ausführen der Programme, haben Sie vermutlich ein
Problem mit der RFC-Verbindung an sich. Denkbar sind folgende häufige
Störgründe:
왘 Bei Aufrufen über Frontend ist die Wahrscheinlichkeit groß, dass das
SAP GUI unvollständig oder fehlerhaft installiert wurde. Hier empfiehlt
sich immer eine Neuinstallation des SAP GUI, um zu sehen, ob das
vielleicht schon den Fehler behebt.
왘 Prüfen Sie auch die TCP/IP-Verbindungsstrecke vom SAP-Applikations-
server zur RFC-Destination. Das können Sie tun, indem Sie auf dem
Applikationsserver TELNET aufrufen, sich als SAP-Administrator anmelden (normalerweise USER=SAPsid, wobei sid die System-ID ist) und
von dort einen PING auf die IP-Adresse der RFC-Destination durchführen. Auch das TRACEROUTE-Utility zum Anzeigen aller Verbindungsknoten vom Aufrufer bis zum Ziel kann weitere Erkenntnisse geben
(Name in Windows: tracert.exe).
Troubleshooting RFC
77
Kap04.fm Seite 78 Dienstag, 22. April 2003 2:31 14
Abbildung 4.6 Erfolgreicher und nicht erfolgreicher PING eines Remote-Computers
Abbildung 4.7 TRACERT zum Finden eines IP-Hosts
4.8
Aufruf von Remote Programs aus R/3
Via RFC
4.8.1
RFC via Remote Shell
Um Programme auf einem entfernten Rechner auszuführen, muss dieser
zunächst dafür eingerichtet werden, Remote Program Calls zu akzeptieren. Dazu muss ein TCP/IP-Port auf dem Zielrechner so konfiguriert sein,
dass er ankommende Nachrichten als Programmaufruf akzeptiert.
UNIX unterstützt
standardmäßig
RPC-Aufrufe
78
Um von einem UNIX-Rechner ein Programm auf einem anderen UNIXRechner aufzurufen, können Sie das Programm RSH (manchmal auch
RSHELL) benutzen. RSH nimmt als Parameter die IP-Adresse des Zielrechners und einen String, der eine gültige Kommandozeile auf dem Zielrechner darstellen muss. Beachten Sie, dass RSH auf dem R/3-Applikationsserver ausgeführt wird, gegebenenfalls müssen Sie den Namen des
Zielrechners explizit spezifizieren.
SAP R/3 Remote Function Call
Kap04.fm Seite 79 Dienstag, 22. April 2003 2:31 14
Falls der Zielrechner ein Windows-Rechner ist, müssen Sie auf diesem ein
Utility installieren, das die RSH-Aufrufe entgegennimmt. Ein bewährtes
Tool ist der ATAMAN-Manager von ATAMAN.COM.
UNIX nach
Windows
Falls R/3 und die zu rufende Applikation beide auf einem Windows NT/
2000-System laufen, können Sie für den Aufruf auch DCOM verwenden.
Windows nach
Windows
Falls Sie wenig Erfahrung mit solchen Remote-Aufrufen haben, sollten Sie
die Aufrufe immer durch das SAP-Utility rfcexec durchführen. Dies ist
normalerweise als RFC-Destination SERVER_EXEC vordefiniert. Zuvor
testen Sie dann den Aufruf des Programms auf dem Remote-System von
der Kommandozeile des SAP-Applikationsservers aus. Denn die AufrufKette ist immer die folgende:
Rfcexec für
einfache
Anwendungen
1. R/3 bestimmt über die in Transaktion SM59 gegebene Definition, welches Programm aufgerufen werden soll, im Fall der Destination
SERVER_EXEC findet R/3 das Programm rfcexec.
2. Der R/3-Kernel führt jetzt das Programm rfcexec zusammen mit
eventuellen Parametern auf dem Rechner aus, dessen IP-Adresse in
SM59 angegeben wurde.
3. rfcexec ruft eine Command-Shell auf und übergibt dieser die Parameter zur Ausführung.
4. rfcexec fängt die Ergebnisse ab und gibt sie an das rufende R/3-System zurück.
4.8.2 RFC über Webserver
Im Zuge der Standardisierung von RPC-Aufrufen hat es sich heute
bewährt, Daten und Programmaufrufe ausschließlich über HTTP auszutauschen. Dazu wird auf allen potenziellen Zielrechnern für unsere
Remote-Aufrufe ein HTTP-Server installiert, sofern diese nicht ohnehin
schon eingerichtet sind, wie es bei fast allen modernen Windows NT/
2000-Systemen und den meisten Linux-Systemen der Fall ist.
Sicherheit durch
Gateway-Proxies
Alle Remote-Aufrufe sind fortan ausschließlich HTTP-GET- oder HTTPPOST-Requests, die vom HTTP-Server interpretiert werden. Die
gewünschte Aktion wird dann durch die aufgerufene ASP, JSP oder CGIPage durchgeführt. Damit reduziert sich die Installation der RFCs auf SAPSeite auf die Konfiguration der HTTP-Server.
Aufruf von Remote Programs aus R/3 Via RFC
79
Kap04.fm Seite 80 Dienstag, 22. April 2003 2:31 14
4.8.3 Aufruf eines Programms auf der Workstation mit
RFC
R/3 verwendet die klassische Client-Server-Technik, um Programme auf
einem Remote-Rechner aufzurufen, wobei die Applikation auf dem
Remote-Rechner den Server darstellt und R/3 in die Client-Rolle schlüpft.
Rfcexec.exe dient
als RFC-Server
für R/3
Dabei muss das zu rufende Programm den Konventionen des RFC-Protokolls entsprechen. Um Ihnen zu ersparen, jedes Mal dieses Protokoll in
Ihre Anwendung einzubinden, existiert ein Standard-RFC-Server rfcexec, der als Proxy zwischen R/3 und einem Betriebssystemkommando
dient.
rfcexec stellt feste
Funktionsaufrufe
bereit
Das rfcexec-Objekt stellt die in der folgenden Tabelle aufgelisteten
Methoden zur Verfügung. Diese erlauben im Wesentlichen, ein auszuführendes Betriebssystemkommando zu übergeben und je nach Methode
wahlweise den Ergebnisdatenstrom abzufangen und im rufenden Programm zur Verfügung zu stellen.
Methode
Beschreibung
RFC_REMOTE_PIPE
FUNCTION 'RFC_REMOTE_EXEC'
IMPORTING command
EXCEPTIONS
system_failure
communication_failure
Programm mit rfcexec ausführen.
RFC_REMOTE_PIPE
FUNCTION 'RFC_REMOTE_PIPE'
IMPORTING command
TABLES pipedata(80)
EXCEPTIONS
system_failure
communication_failure
Ein Programm ausführen, das Eingabedaten durch die Inputpipe übernimmt
und die Ergebnisse der Resultpipe
zurückgibt. Die Resultpipe ist gewöhnlich der Textdatenstrom, der von einer
UNIX- oder DOS-Box zurückgegeben
wird. Wenn Sie z.B. dir > mydata.txt ausführen, wird das Ergebnis in die Datei
mydata.txt umgeleitet. RFC_REMOTE_
PIPE fängt diesen Datenstrom ab und
tritt somit an die Stelle des Ausgabefiles.
file: = Name der Remote-Datei
pipedata: = Daten, die in die Inputpipe geschrieben werden
Tabelle 4.2 Vordefinierte Methoden des rfcexec.exe-Programms
80
SAP R/3 Remote Function Call
Kap04.fm Seite 81 Dienstag, 22. April 2003 2:31 14
Methode
Beschreibung
RFC_REMOTE_FILE
FUNCTION 'RFC_REMOTE_FILE'
IMPORTING
file(256)
Write(1)
TABLES filedata(80)
EXCEPTIONS
system_failure
Lesen und Schreiben einer Datei via
RFC.
file: = Name der Remote-Datei
write: = falls write=’X’, wird filedata in die Datei geschrieben, ansonsten wird die Datei gelesen und deren
Inhalt in filedata retourniert.
filedata: = Inhalt der Datei
communication_failure
Tabelle 4.2 Vordefinierte Methoden des rfcexec.exe-Programms
Für ABAP sieht der Aufruf von rfcexece wie jeder andere RFC-Funktionsbaustein aus. Dem ABAP-Programm können Sie also nicht ansehen,
dass der gerufene Funktionsbaustein kein R/3-Funktionsbaustein ist. Die
Destination des Aufrufs wird mit dem Parameter Destination angegeben und muss zuvor mit Transaktion SM59 definiert worden sein.
Syntaktisch sind
interne und
externe RFC gleich
In SAP R/3 ist standardmäßig eine RFC-Destination LOCAL_EXEC vordefiniert, die das Programm rfcexec auf der Workstation des aktuellen
Users aufruft. SAP R/3 kommuniziert dazu über das SAP GUI, das dann
über OLE die gewünschte Aktion ausführt. rfcexec ist ein RFC-Serverprogram, das ein als Parameter mitgegebenes Programm auf der Kommandozeile von Windows ausführt und den zurückerhaltenen Datenstrom an SAP R/3 zurückmeldet.
rfcexec.exe über
Destination
LOCAL_EXEC aufrufen
Listing 4.13 Ausführen eines Programms auf einer Workstation von R/3 aus mit RFC_
REMOTE_EXEC
DATA: command(256) DEFAULT 'echo Hello World. >> rfctest.dat'
DATA: rfc_mess(128).
CALL FUNCTION 'RFC_REMOTE_EXEC'
DESTINATION rfcdest
EXPORTING
command = command
EXCEPTIONS
system_failure
= 1 MESSAGE rfc_mess
communication_failure = 2 MESSAGE rfc_mess.
Aufruf von Remote Programs aus R/3 Via RFC
81
Kap04.fm Seite 82 Dienstag, 22. April 2003 2:31 14
Listing 4.14 Ausführen eines Programms auf einer Workstation von R/3 aus mit RFC_
REMOTE_PIPE
DATA: command(256) DEFAULT 'echo
test.dat'
DATA: rfc_mess(128).
DATA: pipedata(80) occurs 0 with
CALL FUNCTION 'RFC_REMOTE_PIPE'
DESTINATION rfcdest
EXPORTING
command = command
read
= 'X'
TABLES
pipedata = pipedata
EXCEPTIONS
system_failure
= 1
communication_failure = 2
Hello World. >> rfc-
header line.
MESSAGE rfc_mess
MESSAGE rfc_mess.
Listing 4.15 Lesen einer Datei von der Workstation von R/3 aus mit RFC_REMOTE_
FILE
DATA: command(256) DEFAULT 'echo Hello World. >> rfctest.dat'
DATA: rfc_mess(128).
DATA: pipedata(80) occurs 0 with header line.
CALL FUNCTION 'RFC_REMOTE_FILE'
DESTINATION rfcdest
EXPORTING
file = filename
write = write
"space: read the file; 'X': save
filedata to filename
TABLES
filedata = filedata
EXCEPTIONS
system_failure
= 1 MESSAGE rfc_mess
communication_failure = 2 MESSAGE rfc_mess.
82
SAP R/3 Remote Function Call
Kap04.fm Seite 83 Dienstag, 22. April 2003 2:31 14
Abbildung 4.8 Settings der vordefinierten RFC-Destination LOCAL_EXEC in SM59
Abbildung 4.9 Settings der vordefinierten RFC-Destination SERVER_EXEC in SM59
Aufruf von Remote Programs aus R/3 Via RFC
83
Kap04.fm Seite 84 Dienstag, 22. April 2003 2:31 14
4.8.4 Aufruf eines HTTP-Webservers von SAP R/3
Destination
SAPHTTPA
Um einen HTTP-Server aufzurufen, stellt SAP R/3 bereits geeignete RFCUtilities zur Verfügung. Dabei handelt es sich um ein Utility SAPHTTP, das
auf dem SAP R/3-Applikationsserver ausgeführt wird. Alternativ kann
SAPHTTP auch auf dem Frontend über SAP GUI ausgeführt werden.
Funktionen
HTTP_GET und
HTTP_POST
Standardmäßig ist eine RFC-Destination SAPHTTPA bereits mit Transaktion SM59 vordefiniert. Über diese können Sie dann HTTP-Anfragen versenden. Die beiden Funktionsbausteine HTTP_GET und HTTP_POST
erleichtern Ihnen dabei die Arbeit (siehe Listing ### und Listing ###).
Listing 4.16 Abruf einer URL mit ABAP
DATA: ABSOLUTE_URI(128) type c.
data: response_headers(80) occurs 0 with header line.
data: RESPONSE_ENTITY_BODY(120) occurs 0 with header
line.
ABSOLUTE_URI =
'http://xml.amazon.com/onca/xml2?t=webservices-20' &
'&tag=logosworldcom&dev-t=D2H3YO46KJJ615' &
'&AsinSearch=3528057297&type=lite&f=xml'.
CALL FUNCTION 'HTTP_GET'
EXPORTING
ABSOLUTE_URI
= ABSOLUTE_URI
RFC_DESTINATION
= 'SAPHTTPA'
PROXY
= '192.168.69.64:8080'
* IMPORTING
*
STATUS_CODE
=
*
STATUS_TEXT
=
*
RESPONSE_ENTITY_BODY_LENGTH
=
TABLES
*
REQUEST_ENTITY_BODY
=
RESPONSE_ENTITY_BODY
=
RESPONSE_ENTITY_BODY
RESPONSE_HEADERS
=
RESPONSE_HEADERS
*
REQUEST_HEADERS
=
EXCEPTIONS
CONNECT_FAILED
= 1
TIMEOUT
= 2
INTERNAL_ERROR
= 3
TCPIP_ERROR
= 4
84
SAP R/3 Remote Function Call
Kap04.fm Seite 85 Dienstag, 22. April 2003 2:31 14
DATA_ERROR
SYSTEM_FAILURE
COMMUNICATION_FAILURE
OTHERS
.
IF SY-SUBRC <> 0.
write: / sy-subrc.
ENDIF.
loop at response_entity_body.
write: / response_entity_body.
endloop.
=
=
=
=
5
6
7
8
Listing 4.17 Ergebnis der HTTP-Anfrage mit HTTP_GET
Test for function group
Function module
Upper/lower case
SFTP
HTTP_GET
Import parameters
ABSOLUTE_URI
http://localhost/postinfo.html
REQUEST_ENTITY_BODY_LENGTH
RFC_DESTINATION
PROXY
PROXY_USER
PROXY_PASSWORD
USER
PASSWORD
BLANKSTOCRLF
Value
0
SAPHTTP
Export parameters
STATUS_CODE
STATUS_TEXT
RESPONSE_ENTITY_BODY_LENGTH
Value
200
OK
2.651
Tables
REQUEST_ENTITY_BODY
Result:
RESPONSE_ENTITY_BODY
Result:
RESPONSE_HEADERS
Value
0 Entries
0 Entries
0 Entries
14 Entries
0 Entries
Aufruf von Remote Programs aus R/3 Via RFC
85
Kap04.fm Seite 86 Dienstag, 22. April 2003 2:31 14
Result:
REQUEST_HEADERS
Result:
11 Entries
0 Entries
0 Entries
Die HTTP-Header-Daten werden in genau der gleichen Form zurückgegeben, wie sie im HTTP-Datenstrom empfangen werden:
Listing 4.18 HTTP-Header in Tabelle RESPONSE_HEADERS
HTTP/1.1 200 OK
Server: Microsoft-IIS/5.0
Cache-Control: no-cache
Expires: Sat, 08 Sep 2001 12:36:33 GMT
Date: Sat, 08 Sep 2001 12:36:33 GMT
Content-Type: text/html
Accept-Ranges: bytes
Last-Modified: Sun, 21 Jan 2001 14:24:08 GMT
ETag: "0b4b1d0b583c01:96a"
Content-Length: 2651
<blank line>
4.8.5 Proxy-Settings in ABAP
Proxy-Settings in
Tabelle THTTP
Falls ABAP die HTTP-Aufrufe über einen HTTP-Proxy ausführen muss,
kann der Proxy für den ganzen Mandanten in der Tabelle THTTP vordefiniert werden. Dabei geht SAP davon aus, dass der erste Eintrag in THTTP
die Angaben des System-Proxy darstellt.
Listing 4.19 Standardcoding zum Bestimmen des Proxy für ABAP-HTTP-Requests
form set_http_proxy using uri proxy proxy_user proxy_
password.
data: proxyflag type c.
if proxy ne space. exit. endif.
select single * from thttp.
if thttp-exitfunc ne space.
call function thttp-exitfunc
exporting
absolute_uri = uri
importing
proxy
= proxyflag.
if proxyflag eq 'X'.
proxy = thttp-proxy.
86
SAP R/3 Remote Function Call
Kap04.fm Seite 87 Dienstag, 22. April 2003 2:31 14
proxy_user = thttp-puser.
proxy_password = thttp-ppassword.
endif.
endif.
endform.
Zum besseren Verständnis sehen Sie hier die Struktur der Tabelle THTTP:
MANDT
MANDT
CLNT
Client
PROXY
PROXY
CHAR
HTTP proxy host name
PUSER
PROXY_USER
CHAR
User name for HTTP proxy
PPASSWORD
PROXY_PWD
CHAR
Password for HTTP proxy
EXITFUNC
RS38L_FNAM
CHAR
Name of function module
Tabelle 4.3 Struktur der Tabelle THTTP
4.9
RFC von SAP R/3 auf Windows
4.9.1
Kommunikation mit Excel via OLE/2 und HTTP-Server
Eines der beliebtesten Tools im Enterprise-Computing ist die Tabellenkalkulation. Die einfache und einleuchtende Bedienung und die Möglichkeit, wiederkehrende Berechnungen in einer WYSIWYG-Umgebung ohne
Hilfe von EDV-Spezialisten vorzunehmen, ist etwas, das Sachbearbeiter in
hohem Maße schätzen.
Excel ist eines der
Akzeptanztools
für PCs
Da entsteht sehr rasch der Wunsch, die Daten in Excel zu erfassen, aber
doch sofort in SAP zur Verfügung zu haben, ohne diese mehrfach zu
erfassen. Zur Lösung dieses Problems gibt es wie so oft mehrere Ansätze.
SAP R/3 ist sehr wohl in der Lage, auf ein beliebiges DCOM-Objekt eines
Windows-Rechners zuzugreifen und darauf OLE-Befehle abzusetzen. Es
gibt auch hier die Möglichkeit eines 2-Tier- und eines 3-Tier-Ansatzes.
R/3 bietet eine RFC-zu-OLE-Brücke für ABAP an. Damit kann man über
das SAP GUI mit einem auf der Workstation des Benutzers befindlichen
OLE-Objekt kommunizieren. Hinreichende Beispiele für jemanden, der
ein wenig von VBA-Programmierung in MS Excel, MS Word und so weiter
versteht, finden sich in der Transaktion /nOLE2. Der Nachteil dieser
Lösung ist natürlich, dass das Arbeitsblatt von der Arbeitsstation des
angemeldeten SAP R/3-Benutzers aus zugreifbar sein muss. Dies kann
man allerdings leicht erreichen, indem man das Arbeitsblatt auf einem
von SAP R/3 zugreifbaren Netzwerk-Verzeichnis abspeichert.
RFC von SAP R/3 auf Windows
2-Tier: Direktzugriff via R/3OLE auf Excel
87
Kap04.fm Seite 88 Dienstag, 22. April 2003 2:31 14
3-Tier: Zugriff via
Middleware
Eine Alternative ist wiederum, die Kommunikation zwischen SAP R/3 und
Excel über einen Middleware-Broker durchzuführen. Dazu schickt SAP
R/3 seine Anfrage an den Broker, welcher die gewünschte Aufgabe mit
Excel aushandelt und das Ergebnis an SAP R/3 zurückmeldet. Diese
Lösung ist in aller Regel leichter zu realisieren und vor allem ist sie deutlich stabiler.
4.9.2 Zugriff auf ein Excel-Datenblatt von R/3
Beispiel zum
direkten Zugriff
In diesem Kapitel stellen wir eine Möglichkeit vor, direkt mit SAP R/3 auf
ein bestehendes Excel-Arbeitsblatt zuzugreifen, in diesem eine Kalkulation anzustoßen und die Ergebnisse in SAP R/3 zu importieren. Die
Kommunikation findet dabei über die OLE2-Bridge des SAP GUI der
Arbeitsstation des Benutzers statt. Diese Technik funktioniert in der
geschilderten Weise nicht, wenn die Transaktion nicht online ausgeführt
wird, weil dann kein SAP GUI im Zugriff ist.
Stücklistenkalkulation als
Beispiel
Für das Beispiel haben wir ein Spreadsheet definiert, in dem eine Stückliste aufgeführt ist. In dieser Stückliste kann man in einer Zelle eine
Menge eintragen. Es sind Formeln hinterlegt, die aus der Eingabe die
Mengen der Komponenten errechnen. Die einzelnen Sektionen sind in
Excel benannt, so dass wir es einfacher haben, auf die einzelnen Bereiche
zuzugreifen.
!
"
#$%$
#
" *+
,
-
/
/ )0 #
!
&'()
!'
(.'
&
Abbildung 4.10 Spreadsheet zur Berechnung der Stückliste (Bill of Material)
88
SAP R/3 Remote Function Call
Kap04.fm Seite 89 Dienstag, 22. April 2003 2:31 14
4&
0&&.&
"
"
"
" #$%$
#
*+
,
-
/
#
12()&3
13
&3
3
2)(3
3
&3
4&
Abbildung 4.11 Benannte Bereiche im Spreadsheet
$
(
/
$
2
/
!
%
32
$
.6
"
&
)*+*
)
0"1
4
)
#
'#
,-.
'#,
-5,
Abbildung 4.12 Formeln zur Berechnung
Testprogramm in VBA
Zum Zweck der Entwicklung entwerfen wir erst ein Testprogramm, das
die gewünschten Aktionen durch ein VBA-Programm simuliert. Die Entwicklungsumgebung von VBA hilft uns dabei, durch die Intellisense-Hilfe
die richtigen Befehle, Methoden und Properties der Excel-Objekte zu finden und im Debugger eine robuste Zugriffsform zu testen. Wenn wir die
Aufrufe später von SAP R/3 aus machen, wird uns der Debugger nicht
mehr zur Verfügung stehen, weshalb wir das Testen außerhalb von SAP
R/3 vornehmen.
Zugriff auf die
Daten durch ein
VBA-Programm
Listing 4.20 VBA-Routine zum Setzen und Auslesen der BOM-Werte
Sub Read_Values_From_EXCEL()
Dim ix As Integer
Dim cellvalue As String
Dim rowcount As Integer
Dim h_appl As Excel.Application
Dim h_book As Excel.Workbook
Dim h_books As Excel.Workbooks
RFC von SAP R/3 auf Windows
89
Kap04.fm Seite 90 Dienstag, 22. April 2003 2:31 14
Dim h_sheet As Excel.Worksheet
Dim h_sheets As Excel.Sheets
Dim h_range As Excel.Range
Dim h_rows As Excel.Range
Dim h_cell As Excel.Range
Dim h_name As Excel.Name
Set h_appl = New Excel.Application
h_appl.Visible = False
Set h_books = h_appl.Workbooks
Set h_book =
h_books.Open(FileName:="U:\_DEMO\BOM\BOM.XLS")
Set h_sheets = h_book.Worksheets
h_sheets.Select
Set h_sheet = h_sheets.Item("SUPERSAVER")
Set h_name = h_sheet.Names("QUANT")
Set h_range = h_name.RefersToRange
cellvalue = h_range(RowIndex:=1,
ColumnIndex:=1).Value
Debug.Print "Quant", cellvalue
cellvalue = cellvalue + 5
h_range(RowIndex:=1, ColumnIndex:=1).Value =
cellvalue
h_appl.CalculateFull
Set h_name = h_sheet.Names("RETURNS")
Set h_range = h_name.RefersToRange
Set h_rows = h_range.Rows
rowcount = h_rows.Count
For ix = 1 To rowcount
cellvalue = h_range(RowIndex:=ix,
ColumnIndex:=1).Value
Debug.Print ix, cellvalue
Next ix
h_book.Close savechanges:=False
h_appl.Quit
Set h_appl = Nothing
End Sub
90
SAP R/3 Remote Function Call
Kap04.fm Seite 91 Dienstag, 22. April 2003 2:31 14
Testprogramm in ASP
In einem nächsten Schritt versuchen wir, den Code aus einer anderen
Umgebung aufzurufen. Dazu erzeugen wir ein ASP-Script, um die Daten
als Webseite zu erhalten. Das gleiche Script können wir auch später von
SAP R/3 aufrufen und haben so bereits eine 3-Tier-Lösung für den Durchgriff von SAP R/3 auf Excel.
Aufruf als
ASP-Skript
Listing 4.21 ASP-Script zum Setzen und Auslesen der BOM-Werte via OLE
<%
Function Read_Values_From_EXCEL_VBS(myquant, filename)
Dim Resultstr
Dim ix
Dim cellvalue
Dim rowcount
Dim h_appl
Dim h_book
Dim h_books
Dim h_sheet
Dim h_sheets
Dim h_range
Dim h_rows
Dim h_cell
Dim h_name
resultstr = myquant & Chr(13) & Chr(10)
Set h_appl = CreateObject("Excel.Application")
'
h_appl.Visible = False
Set h_books = h_appl.Workbooks
Set h_book = h_books.Open(filename)
Set h_sheets = h_book.Worksheets
h_sheets.Select
Set h_sheet = h_sheets.Item("SUPERSAVER")
Set h_name = h_sheet.Names("QUANT")
Set h_range = h_name.RefersToRange
cellvalue = h_range(1, 1).Value
cellvalue = myquant
h_range(1, 1).Value = cellvalue
h_appl.CalculateFull
RFC von SAP R/3 auf Windows
91
Kap04.fm Seite 92 Dienstag, 22. April 2003 2:31 14
Set h_name = h_sheet.Names("RETURNS")
Set h_range = h_name.RefersToRange
Set h_rows = h_range.Rows
rowcount = h_rows.Count
For ix = 1 To rowcount
cellvalue = h_range(ix, 1).Value
resultstr = resultstr & CellValue
cellvalue = h_range(ix, 3).Value
resultstr = resultstr & "," & CellValue &
chr(13) & chr(10)
Next
'
h_book.Save
h_book.Close False
h_appl.Quit
Set h_appl = Nothing
Read_Values_From_EXCEL_VBS = resultstr
End Function
Response.write Read_Values_From_EXCEL_VBS(105,
"BOM.XLS")
%>
Direktzugriff von SAP R/3 auf Excel
Zugriff via
OLE-Brücke
Die Syntax zum Setzen und Aufrufen von COM-Objekten aus SAP R/3
heraus ist etwas von der in Visual Basic verschieden, weshalb wir das
Coding nicht 1:1 übernehmen können. In Listing ### ist die ABAP-Version zu sehen, die mit den VBA-Kommandos kommentiert ist.
Listing 4.22 ABAP-Routine zum Setzen und Auslesen der BOM-Werte via OLE
REPORT ydemo_excel_bom MESSAGE-ID sy.
INCLUDE ole2incl. "<-- Contains the types for OLEAccess
PARAMETER: filename LIKE rlgrap-filename
DEFAULT 'U:\_DEMO\BOM\BOM.xls'.
*
Dim h_appl As Excel.Application
DATA: h_appl TYPE ole2_object.
*
Dim h_books As Workbooks
DATA: h_books TYPE ole2_object.
*
Dim h_book As Workbook
DATA: h_book TYPE ole2_object.
92
SAP R/3 Remote Function Call
Kap04.fm Seite 93 Dienstag, 22. April 2003 2:31 14
*
Dim h_sheets As Excel.Sheets
DATA: h_sheets TYPE ole2_object.
*
Dim h_sheet As Worksheet
DATA: h_sheet TYPE ole2_object.
DATA: x_sheet TYPE ole2_object.
*
Dim h_name As Name
DATA: h_name TYPE ole2_object.
*
Dim h_range As Range
DATA: h_range TYPE ole2_object.
*
Dim h_rows As Range
DATA: h_rows TYPE ole2_object.
*
Dim h_cell As Range
DATA: h_cell TYPE ole2_object.
DATA: cellvalue(29).
DATA: rowcount TYPE i.
START-OF-SELECTION.
*
Set h_appl = New Excel.Application
CREATE OBJECT
h_appl 'EXCEL.APPLICATION'.
IF sy-subrc NE 0. MESSAGE i002 WITH sy-msgli. ENDIF.
*
h_appl.Visible = True
SET PROPERTY OF h_appl 'VISIBLE' = 1 .
*
Set h_books = h_appl.Workbooks
GET PROPERTY OF h_appl 'WORKBOOKS' = h_books .
*
Set h_book = h_books.Open(Filename:= "\BOM.*XLS")
CALL METHOD OF h_books 'OPEN' = h_book EXPORTING
#filename = filename.
* GET PROPERTY OF h_appl 'ACTIVEWORKBOOK' = h_book.
*
Set h_sheets = h_book.Worksheets
GET PROPERTY OF h_book 'WORKSHEETS' = h_sheets .
*
Set h_sheet = h_sheets.Item("SUPERSAVER")
* GET PROPERTY OF h_book 'ACTIVESHEET' = h_sheet.
CALL METHOD OF h_sheets 'ITEM' = h_sheet
EXPORTING #index = 'SUPERSAVER' .
****** Modify the Pivot Cell **************************
*
Set h_name = h_sheet.Names("QUANT")
CALL METHOD OF h_sheet 'NAMES' = h_name
EXPORTING #index ='QUANT' .
*
Set h_range = h_name.RefersToRange
GET PROPERTY OF h_name 'REFERSTORANGE' = h_range.
RFC von SAP R/3 auf Windows
93
Kap04.fm Seite 94 Dienstag, 22. April 2003 2:31 14
CALL METHOD OF h_range 'CELLS' = h_cell
EXPORTING #1 = 1 #2 = 1.
GET PROPERTY OF h_cell 'VALUE' = cellvalue.
WRITE: / 'Old value':, cellvalue.
cellvalue = cellvalue + 5.
WRITE: / 'New value':, cellvalue.
ULINE.
SET PROPERTY OF h_cell 'VALUE' = cellvalue.
CALL METHOD OF h_appl 'CALCULATEFULL'.
****** Now, Pick up results ***************************
*
Set h_name = h_sheet.Names("SUBQUANT")
CALL METHOD OF h_sheet 'NAMES' = h_name EXPORTING
#index ='RETURNS'.
*
Set h_range = h_name.RefersToRange
GET PROPERTY OF h_name 'REFERSTORANGE' = h_range.
* GET PROPERTY OF h_appl 'ACTIVECELL' = h_range.
*
cellvalue = h_cell.Value
CALL METHOD OF h_range 'ROWS' = h_rows.
*
Set h_rows = h_range.Rows
CALL METHOD OF h_rows 'COUNT' = rowcount.
*
*
*
*
*
94
DO rowcount TIMES.
CALL METHOD OF h_range 'CELLS' = h_cell
EXPORTING #1 = sy-index #2 = 1.
EXPORTING #rowindex = 1 #columnindex =
sy-index.
CALL METHOD OF h_cell 'VALUE' = cellvalue.
WRITE: / sy-index, cellvalue.
ENDDO.
h_book.Close false
CALL METHOD OF h_book 'SAVE'.
CALL METHOD OF h_book 'CLOSE' EXPORTING #1 = 0.
h_appl.Quit
CALL METHOD OF h_appl 'QUIT'.
Set h_appl = Nothing
FREE OBJECT h_appl.
SAP R/3 Remote Function Call
Kap04.fm Seite 95 Dienstag, 22. April 2003 2:31 14
4.10 Business-Objekte und BAPI
Eine der großen Stärken von SAP R/3 liegt darin, dass es Geschäftsprozesse de facto standardisiert. Solche Quasi-Standards werden als Business-Objekte bezeichnet. Um auf die Business-Objekte zugreifen zu können, wurden für diese Schnittstellen geschaffen, die als BAPI bezeichnet
werden.
Eines der Kernziele einer modernen Business-Software ist die Geschäftsprozessmodellierung mit Hilfe einer Programmiersprache. Damit soll eine
Standardisierung der Geschäftsprozesse möglich werden. SAP ist allein
durch seine Marktmacht dazu prädestiniert, solche Business-Modelle vorzugeben und zu vereinheitlichen. Business-Objekte sind solche Modellierungen von realen Geschäftsprozessen innerhalb von SAP-Systemen. Business-Objekte beschreiben und implementieren die Methoden, Properties
und Interfaces dieser Prozesse mit den Mitteln von ABAP Objects.
Business-Objekte
sind formale
Modelle von
realen Prozessen
Aus der Sicht eines Entwicklers besteht ein Geschäftsprozessmodell aus
den drei Elementen:
Geschäftsmodelle
aus Sicht eines
Entwicklers
왘 Database
Hier werden die Daten in proprietärer Form abgespeichert.
왘 Business-Objekt
Eine abstrakte Projektion der Realität mit den Mitteln der Programmiersprache.
왘 Application Programming Interface (API)
Schnittstelle für den Zugriff auf die Business-Objekte von einer Programmiersprache aus.
Der Zugriff auf die Business-Objekte erfolgt über eine öffentlich bekannte
Business-API – das Business Application Programming Interface, kurz
BAPI – und ist technisch eine Untermenge der RFC-fähigen Funktionsbausteine in R/3. BAPIs sind die offizielle Außenschnittstelle, mit der
Zugriffe von Fremdsystemen auf R/3 erfolgen sollen.
Zugriff über
Business-API
4.10.1 Business-Objekte und Modellsichten
Business-Objekte sind die technische Beschreibung einer der Modellsichten auf einen Prozess. In einfachen Fällen kommen wir mit den folgenden
Modellsichten aus:
Business-Objekte und BAPI
95
Kap04.fm Seite 96 Dienstag, 22. April 2003 2:31 14
왘 Technische Sicht (Komponentensicht)
In der Technischen Sicht werden die Objekte beschrieben, wie sie tatsächlich auf dem Computer realisiert werden. Hier bestimmen wir also,
welche Tabellen in der Datenbank angelegt werden, welche Datenbank-Engine überhaupt verwendet wird, welche Protokolle zum Austausch der Daten benutzt werden, und in welcher Programmiersprache wir arbeiten.
왘 Anwendungsfall (Use Case)
Die Anwendungsfälle beschreiben die Operationen, die wir auf den
Daten durchführen wollen, etwa einen Logon, Aufträge speichern,
nach Aufträgen suchen und so weiter.
왘 Business View (Logische Sicht)
Der Business View ist die abstrakte Ebene, die versucht, unbelastet von
den technischen Details die logischen Komponenten einer Applikation
zu beschreiben. Dabei denken wir an die Organisation in Stammdaten,
an Kundenaufträge oder einen Internetshop. Wichtig dabei ist, dass
die Logische Sicht zunächst frei von Restriktionen formuliert werden
darf, also so nah wie möglich dem Denken bei der realen Arbeit entsprechen soll.
(!,
!
$%&
"#
'(
(
)**
)
)+'"
-+)
)
09)7*&
;*
;*
;)
7*&
8*
&4+<11
Abbildung 4.13 Beispiel für Modellsichten
96
SAP R/3 Remote Function Call
*7*&
)
:4*
17*&
:4*
;*
;)
Kap04.fm Seite 97 Dienstag, 22. April 2003 2:31 14
Ein Business-Objekt ist nun eine formale Beschreibung eines Business
Views. Demnach gibt es Business Views für jede logische Entität, zum Beispiel für den Materialstamm, Kundenstamm, Kundenaufträge oder für
eine ganze Shopping-Cart-Applikation. Materialstamm, Kundenstamm
und Kundenaufträge sind als Business-Objekte schon in SAP R/3 definiert
und dafür gibt es auch schon die passenden BAPIs.
Formale Beschreibung eines
Business-View
Alle öffentlichen Business-Objekte sind im SAP R/3 Business Object Repository (BOR) registriert. Dieses mit den Transaktionen BAPI und SWO1
(Business Object Builder) zugängliche Verzeichnis zeigt die vorhandenen
Business-Objekte, deren Methoden und die Implementierung an.
Business Object
Repository – BOR
Die Shopping-Cart-Applikation als Business-Objekt ist eine Sonderentwicklung von Logos! Informatik GmbH und Casabac GmbH. Näheres und
einen Download der neuesten Versionen finden Sie unter shoppingcart.logosworld.com.
!"
#!"$
%!&
%
'
(& !"
(&#!"$
(&%!&
!
"
#
#$
) !"
)#!"$
)%!&
+ !"
+ #!"$
+ %!&
#$#
'$
*
'$
*
Abbildung 4.14 Business-Sichten in SAP R/3
Business-Objekte und BAPI
97
Kap04.fm Seite 98 Dienstag, 22. April 2003 2:31 14
#$%%%&'%()*+
!
"
#$
%&
!'"
"
! #$
#$#$(
!
Abbildung 4.15 Business-Objekte in SAP R/3-SD
Abbildung 4.16 Business-Objekt BUS1093 (ExchangeRate) in Transaktion BAPI
98
SAP R/3 Remote Function Call
Kap04.fm Seite 99 Dienstag, 22. April 2003 2:31 14
Abbildung 4.17 Business-Objekt BUS1093 (ExchangeRate) in Transaktion SWO1
4.10.2 Technische Kriterien eines BAPI
Ein BAPI ist eine Implementierung eines Business-Objekts, die öffentliche
Methoden zur Verfügung stellt. In der Realisierung verbirgt sich hinter
jeder Methode ein Funktionsbaustein. Zusätzlich erhält aber jede
Methode noch eine zum SAP Business Workflow kompatible Objektschnittstelle in SWO1. Wenn von BAPI die Rede ist, ist selten das Business-Objekt selbst gemeint, sondern meistens der BAPI-Funktionsbaustein, der eine der vielen Methoden eines BAPI implementiert. So ist
beispielsweise das BAPI zum Kundenauftragsmodell BUS2032, und BAPI_
SALESORDER_CREATEFROMDAT2 ist der BAPI-Funktionsbaustein zur
Methode CreateFromDat2.
BAPI ist die
Implementierung
eines BusinessObjekts
Aus technischer Sicht besteht kein Unterschied zwischen einem BAPIFunktionsbaustein und gewöhnlichen RFC-Bausteinen. Allerdings unterwirft SAP ein BAPI gewissen Konventionen, die jeder beachten sollte, der
standardkonforme BAPIs entwickeln möchte:
Technisch ist eine
BAPI-Funktion ein
RFC-Funktionsbaustein
왘 Ein BAPI führt niemals ein
COMMIT WORK oder einen ROLLBACK WORK
aus. Der Sinn davon ist, dass eine externe Applikation eigene Transaktionen als Sequenzen von BAPI-Methoden ausführen kann.
왘 Das Ende einer Transaktion wird durch die speziellen BAPI-Funktions-
bausteine BAPI_TRANSACTION_COMMIT
ROLLBACK erreicht.
und BAPI_TRANSACTION_
왘 Alle Schnittstellenparameter sollen einen aussagekräftigen, englischen
Namen haben.
Business-Objekte und BAPI
99
Kap04.fm Seite 100 Dienstag, 22. April 2003 2:31 14
4.10.3 Anwendungsbeispiel: Das Sales-Order-BAPI
Kundenaufträge
sind zentral für SD
Wir haben als Beispiel für die Anwendung eines BAPI das Sales-OrderObjekt ausgewählt, das ein ganz zentrales Business-Objekt in SAP ist.
Dieses wird verwendet für das Anlegen, Ändern und Anzeigen von
왘 Kundenaufträgen
왘 Angebotsanfragen (Request for quotation – RFQ)
왘 Gut- und Lastschriftenanforderungen
왘 Auslieferungsaufträgen
Auslieferungsaufträge sind Aufträge, die automatisch eine Lieferung
erzeugen. Man verwendet sie unter anderem zum Ausliefern in mehreren Einzellieferungen. Dabei wird der Auslieferungsauftrag mit Bezug
zum Originalauftrag angelegt. Der Auslieferungsauftrag ist so eingestellt, dass automatisch eine Auslieferung (Objekt LIKP) erstellt wird,
gegebenenfalls mit anschließendem automatischen Versand.
왘 Anstoßen von Auslieferungen
Das Business-Objekt-Konzept von SAP R/3 sieht es nicht vor, Auslieferungen direkt durch eine Schnittstelle anzulegen. Der zentrale Einstiegspunkt für jede SD-Transaktion ist das Sales-Order-BAPI. Dazu muss der
Kundenauftrag bestimmte Customizing-Anforderungen erfüllen:
왘 Der Kundenauftragstyp (TVAK-AUART) muss auf automatisches
Anlegen einer Auslieferung eingestellt sein.
왘 Das Anlegen der Auslieferung muss vom Status des Kundenauftrags
abhängig sein, zum Beispiel durch Setzen des Feldes Liefersperre im
Kopf (VBAK-LIFSK) oder Position (VBAP-LIFSP).
왘 Anstoßen von Fakturen.
왘 Der Kundenauftragstyp (TVAK-AUART) muss auf automatisches
Anlegen einer Faktura eingestellt sein.
왘 Das Anlegen der Faktura muss vom Status des Kundenauftrags
abhängig sein, zum Beispiel durch Setzen des Feldes Fakturasperre
im Kopf (VBAK-FAKSK) oder Position (VBAP-FAKSP)
Kundenauftragsbestand abfragen
왘 Methode:
SalesOrder.GetList
왘 Funktion: BAPI_SALESORDER_GETLIST
Die BAPI-Methode gibt eine Liste aller Kundenaufträge eines bestimmten
Kunden zurück. Die Liste kann auf Materialnummern und bestimmte
Zeiträume eingeschränkt werden.
100
SAP R/3 Remote Function Call
Kap04.fm Seite 101 Dienstag, 22. April 2003 2:31 14
Kundenauftrag anlegen
왘 Methode:
SalesOrder.CreateFromDat2
왘 Funktion: BAPI_SALESORDER_CREATEFROMDAT2
Diese BAPI-Methode legt einen Kundenauftrag komplett neu an und verwendet dazu die übergebenen Daten. Die Methode kann alle businessrelevanten Daten aufnehmen und erlaubt es, einen Kundenauftrag auf
einen Schlag anzulegen.
In unseren Beispielen weiter unten zeigen wir einen Mehrschritt-Ansatz,
indem wir zunächst den Auftragskopf (also nur VBAK) ohne Verkaufspositionen (VBAP) anlegen. Später fügen wir die Positionen mit der
Methode BAPI_SALESORDER_CHANGE hinzu.
Erst Kopf, dann
Position anlegen
Kundenauftrag ändern
왘 Methode:
SalesOrder.Change
왘 Funktion: BAPI_SALESORDER_CHANGE
Diese BAPI-Methode ermöglicht es, einen bestehenden Kundenauftrag in
allen Einzelheiten zu ändern, also insbesondere auch Positionen oder Einteilungsdaten hinzuzufügen oder zu löschen und selbstverständlich alle
bereits bestehenden Werte einzeln zu ändern.
Einzelnes Ändern
von Feldwerten
Kundenauftrag oder Kundenauftragspositionen löschen
Löschen ist wie in jeder professionellen Datenbank oder Transaktionsumgebung nur eine Variante des Änderns. Dazu muss lediglich das
Updateflag = "D" für Delete gesetzt werden.
Löschen:
Updateflag = »D«
4.10.4 Beispiel: BAPI_SALESORDER_GETLIST
Im Folgenden sehen Sie ein fertiges Rahmenprogramm zum Aufruf des
BAPIs, das eine Liste aller Kundenaufträge zu einem Kunden zurückgibt.
Liste aller Kundenaufträge
Listing 4.23 ABAP: Call BAPI_SALESORDER_GETLIST
'**** Functions in Library
Public func As SAPFunctionsOCX.Function
Public XMLDOC As New MSXML2.DOMDocument
Private myR3 As R3LogonObj
Private XMLhelp As New XMLhelper
'**** Parameters
Public iCUSTOMER_NUMBER As SAPFunctionsOCX.Parameter
Business-Objekte und BAPI
101
Kap04.fm Seite 102 Dienstag, 22. April 2003 2:31 14
Public
Public
Public
Public
Public
meter
Public
Public
Public
Public
iDOCUMENT_DATE As SAPFunctionsOCX.Parameter
iDOCUMENT_DATE_TO As SAPFunctionsOCX.Parameter
iMATERIAL As SAPFunctionsOCX.Parameter
iPURCHASE_ORDER As SAPFunctionsOCX.Parameter
iPURCHASE_ORDER_NUMBER As SAPFunctionsOCX.ParaiSALES_ORGANIZATION As SAPFunctionsOCX.Parameter
iTRANSACTION_GROUP As SAPFunctionsOCX.Parameter
eRETURN As SAPFunctionsOCX.Structure
tSALES_ORDERS As SAPTableFactoryCtrl.Table
Public Sub Class_Initialize()
Set myR3 = New R3LogonObj
myR3.R3Logon
'*************** Creating the object reference for the
RFC Functions
'====================================================
Set func =
myR3.Functions.Add("BAPI_SALESORDER_GETLIST")
'*************** Creating the object reference for the
Parameters
'==================================================
'**** Importing Parameters
Set iCUSTOMER_NUMBER =
func.Exports("CUSTOMER_NUMBER")
Set iDOCUMENT_DATE = func.Exports("DOCUMENT_DATE")
Set iDOCUMENT_DATE_TO =
func.Exports("DOCUMENT_DATE_TO")
Set iMATERIAL = func.Exports("MATERIAL")
Set iPURCHASE_ORDER =
func.Exports("PURCHASE_ORDER")
Set iPURCHASE_ORDER_NUMBER =
func.Exports("PURCHASE_ORDER_NUMBER")
Set iSALES_ORGANIZATION =
func.Exports("SALES_ORGANIZATION")
Set iTRANSACTION_GROUP =
func.Exports("TRANSACTION_GROUP")
'**** Exporting Parameters
Set eRETURN = func.Imports("RETURN")
'**** Table Parameters
102
SAP R/3 Remote Function Call
Kap04.fm Seite 103 Dienstag, 22. April 2003 2:31 14
Set tSALES_ORDERS = func.Tables("SALES_ORDERS")
End Sub ' Class_Initialize()
Public Sub Class_Terminate()
Set func = Nothing
Set myR3 = Nothing
End Sub ' Class_Terminate()
Public Sub Execute()
func.Call
End Sub ' Class_Initialize()
Public Sub Connect()
End Sub ' Connect
Public Function toXMLDoc() As MSXML2.DOMDocument
Set toXMLDoc = XMLhelp.toXMLDoc(func)
End Function
Public Function toXML() As String
toXML = toXMLDoc.XML
End Function
Listing 4.24 ABAP: Anlegen eines Auftragskopfs mit BAPI_SALESORDER_
CREATEFROMDAT2
*&----------------------------------------------------*
*& Report YDEMO_BAPI_2032_CREATE_HEADER
*&----------------------------------------------------*
*& This routines demonstrates the use of the BAPI
*
*& BAPI_SALESORDER_CREATEFROMDAT2
*& It calls the BAPI and creates the header of a sales
*& orders
*& w/o creating any items so far.
*&----------------------------------------------------*
REPORT YDEMO_BAPI_2032_CREATE_HEADER.
TYPE-POOLS: SYDES.
PARAMETERS: VBELN LIKE VBCOM-VBELN OBLIGATORY MEMORY ID
AUN.
PARAMETERS: AUART LIKE VBCOM-AUART OBLIGATORY MEMORY ID
AUA.
Business-Objekte und BAPI
103
Kap04.fm Seite 104 Dienstag, 22. April 2003 2:31 14
PARAMETERS:
KUN.
PARAMETERS:
WEM.
PARAMETERS:
VKO.
PARAMETERS:
VTW.
PARAMETERS:
SPA.
PARAMETERS:
AUD.
PARAMETERS:
PARAMETERS:
KUNAG LIKE VBCO2-KUNNR OBLIGATORY MEMORY ID
KUNWE LIKE VBCO2-KUNWE OBLIGATORY MEMORY ID
VKORG LIKE VBCOM-VKORG OBLIGATORY MEMORY ID
VTWEG LIKE VBCOM-VTWEG OBLIGATORY MEMORY ID
SPART LIKE VBCOM-SPART OBLIGATORY MEMORY ID
AUDAT LIKE VBCOM-AUDAT OBLIGATORY MEMORY ID
REFVBELN LIKE VBCOM-VBELN MEMORY ID AUB.
REFVGTYP LIKE VBAK-VGTYP DEFAULT 'C'.
DATA: ORDER_HEADER_IN LIKE BAPISDHD1.
DATA: ORDER_HEADER_OUT LIKE BAPISDHD1.
DATA: SALESDOCUMENT LIKE BAPIVBELN-VBELN.
DATA: RETURN
LIKE STANDARD TABLE OF BAPIRET2
WITH HEADER LINE.
DATA: ORDER_ITEMS_IN LIKE STANDARD TABLE OF BAPISDITM
WITH HEADER LINE.
DATA: ORDER_PARTNERS LIKE STANDARD TABLE OF BAPIPARNR
WITH HEADER LINE.
START-OF-SELECTION.
PERFORM BAPI_SALESORDER_CREATE
USING VBELN AUART KUNAG KUNWE
VKORG VTWEG SPART AUDAT REFVBELN REFVGTYP.
*ERFORM bapi_salesorder_getcreate
WRITE: / 'Returned sales order number:'
, SALESDOCUMENT COLOR COL_TOTAL.
ULINE.
LOOP AT RETURN.
CALL FUNCTION 'MESSAGE_TEXT_BUILD'
EXPORTING
MSGID
= RETURN-ID
MSGNR
= RETURN-NUMBER
MSGV1
= RETURN-MESSAGE_V1
MSGV2
= RETURN-MESSAGE_V2
104
SAP R/3 Remote Function Call
Kap04.fm Seite 105 Dienstag, 22. April 2003 2:31 14
MSGV3
= RETURN-MESSAGE_V3
MSGV4
= RETURN-MESSAGE_V4
IMPORTING
MESSAGE_TEXT_OUTPUT = SY-LISEL
EXCEPTIONS
OTHERS
= 1.
WRITE: / SY-LISEL COLOR COL_NORMAL..
ENDLOOP.
*-----------------------------------------------------*
FORM BAPI_SALESORDER_CREATE
USING VALUE(DOCNO) LIKE VBCOM-VBELN
VALUE(DOC_TYPE) LIKE VBCOM-AUART
VALUE(SOLDTO) LIKE VBCOM-KUNNR
VALUE(SHIPTO) LIKE VBCOM-KUNNR
VALUE(SALESORG) LIKE VBCOM-VKORG
VALUE(DISTRCHANNEL) LIKE VBAK-VTWEG
VALUE(DIVISION) LIKE VBCOM-SPART
VALUE(ORDERDATE) LIKE VBCOM-AUDAT
VALUE(REFDOCNO) LIKE VBCOM-VBELN
VALUE(REFDOC_TYPE) LIKE VBAK-VGTYP.
REFRESH ORDER_ITEMS_IN.
REFRESH ORDER_PARTNERS.
CLEAR ORDER_HEADER_IN.
CLEAR RETURN.
CLEAR SALESDOCUMENT.
SALESDOCUMENT = VBELN.
IF NOT REFDOCNO IS INITIAL.
ULINE. FORMAT RESET COLOR COL_NEGATIVE.
WRITE:/ 'The reference does not work in 40B HP65 due
to an error when'.
WRITE:/ 'calling SD_SALES_DOCU_SAVE from
SD_SALES_DOCUMENT_MAINTAIN. '.
ULINE. FORMAT RESET.
ENDIF.
ORDER_HEADER_IN-REFOBJTYPE = 'BUS2032'.
ORDER_HEADER_IN-REFOBJKEY = REFDOCNO.
ORDER_HEADER_IN-REFDOCTYPE = REFDOC_TYPE.
ORDER_HEADER_IN-DOC_TYPE = AUART.
Business-Objekte und BAPI
105
Kap04.fm Seite 106 Dienstag, 22. April 2003 2:31 14
ORDER_HEADER_IN-SALES_ORG = SALESORG.
ORDER_HEADER_IN-DISTR_CHAN = DISTRCHANNEL.
ORDER_HEADER_IN-DIVISION = DIVISION.
ORDER_HEADER_IN-REQ_DATE_H = ORDERDATE.
ORDER_PARTNERS-PARTN_ROLE
ORDER_PARTNERS-PARTN_NUMB
APPEND ORDER_PARTNERS.
ORDER_PARTNERS-PARTN_ROLE
ORDER_PARTNERS-PARTN_NUMB
APPEND ORDER_PARTNERS.
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
106
= 'AG'.
= SOLDTO.
= 'WE'.
= SHIPTO.
CALL FUNCTION 'BAPI_SALESORDER_CREATEFROMDAT2'
EXPORTING
SALESDOCUMENT
= SALESDOCUMENT
ORDER_HEADER_IN
= ORDER_HEADER_IN
ORDER_HEADER_INX
=
SENDER
=
BINARY_RELATIONSHIPTYPE = ' '
INT_NUMBER_ASSIGNMENT
= ' '
BEHAVE_WHEN_ERROR
= ' '
LOGIC_SWITCH
= ' '
TESTRUN
= ' '
CONVERT
= ' '
IMPORTING
SALESDOCUMENT_EX
= SALESDOCUMENT
TABLES
RETURN
= RETURN
order_items_in
= order_items_in
ORDER_ITEMS_INX
=
ORDER_PARTNERS
= ORDER_PARTNERS
ORDER_SCHEDULES_IN
=
ORDER_SCHEDULES_INX
=
ORDER_CONDITIONS_IN
=
ORDER_CFGS_REF
=
ORDER_CFGS_INST
=
ORDER_CFGS_PART_OF
=
ORDER_CFGS_VALUE
=
ORDER_CFGS_BLOB
=
ORDER_CFGS_VK
=
SAP R/3 Remote Function Call
Kap04.fm Seite 107 Dienstag, 22. April 2003 2:31 14
*
*
*
*
*
*
ORDER_CFGS_REFINST
ORDER_CCARD
ORDER_TEXT
ORDER_KEYS
EXTENSIONIN
PARTNERADDRESSES
EXCEPTIONS
OTHERS
COMMIT WORK.
=
=
=
=
=
=
= 1.
ENDFORM.
Die Auftragspositionen können jederzeit an einen bestehenden Auftrag
angefügt werden. Das wird genau wie das Ändern eines Auftrags durch
den BAPI BAPI_SALESORDER_CHANGE erledigt:
Listing 4.25 ABAP: Zufügen von Auftragspositionen mit BAPI_SALESORDER_CHANGE
TYPE-POOLS: SYDES.
FORM BAPI_SALESITEM_ADD
USING VALUE(DOCNO) LIKE VBCOM-VBELN VALUE(POSNR)
LIKE VBAP-POSNR
VALUE(MATNR) LIKE VBAP-MATNR VALUE(QUANT)
LIKE VBAP-KWMENG
VALUE(VRKME) LIKE VBAP-VRKME VALUE(CONDI)
LIKE KONV-KSCHL
VALUE(NETPR) LIKE VBAP-NETPR
VALUE(CURR_ISO) LIKE BAPISDITM-CURR_ISO.
DATA: ORDER_HEADER_IN LIKE BAPISDH1.
DATA: ORDER_HEADER_INX LIKE BAPISDH1X.
DATA: ORDER_HEADER_OUT LIKE BAPISDHD1.
DATA: SALESDOCUMENT
LIKE BAPIVBELN-VBELN.
DATA: ORDER_ITEMS_IN
LIKE STANDARD TABLE OF
BAPISDITM WITH HEADER LINE.
DATA: ORDER_ITEMS_INX LIKE STANDARD TABLE OF
BAPISDITMX WITH HEADER LINE.
DATA: SCHEDULE_LINES
LIKE STANDARD TABLE OF
BAPISCHDL WITH HEADER LINE.
DATA: SCHEDULE_LINESX LIKE STANDARD TABLE OF
BAPISCHDLX WITH HEADER LINE.
DATA: CONDITIONS_IN
LIKE STANDARD TABLE OF
Business-Objekte und BAPI
107
Kap04.fm Seite 108 Dienstag, 22. April 2003 2:31 14
BAPICOND
WITH HEADER LINE.
DATA: CONDITIONS_INX
LIKE STANDARD TABLE OF
BAPICONDX WITH HEADER LINE.
DATA: RETURN
LIKE STANDARD TABLE OF
BAPIRET2
WITH HEADER LINE.
REFRESH: ORDER_ITEMS_IN, ORDER_ITEMS_INX.
REFRESH: SCHEDULE_LINES, SCHEDULE_LINESX.
CLEAR: ORDER_HEADER_IN, ORDER_HEADER_INX.
CLEAR: SCHEDULE_LINES, SCHEDULE_LINESX.
CLEAR: RETURN, SALESDOCUMENT.
SALESDOCUMENT = DOCNO.
ORDER_HEADER_INX-UPDATEFLAG = 'U'.
ORDER_ITEMS_IN-ITM_NUMBER = POSNR.
ORDER_ITEMS_IN-MATERIAL
= MATNR.
ORDER_ITEMS_IN-TARGET_QTY = QUANT.
ORDER_ITEMS_IN-TARGET_QU = VRKME.
ORDER_ITEMS_IN-SALES_UNIT = VRKME.
ORDER_ITEMS_IN-TARGET_VAL = PRICE.
ORDER_ITEMS_IN-CURR_ISO = CURR_ISO.
ORDER_ITEMS_INX-ITM_NUMBER = ORDER_ITEMS_INITM_NUMBER.
ORDER_ITEMS_INX-UPDATEFLAG = 'I'.
APPEND ORDER_ITEMS_IN.
*-----------------------------------------------------*
SCHEDULE_LINES-ITM_NUMBER = ORDER_ITEMS_INITM_NUMBER.
SCHEDULE_LINES-REQ_DATE = SY-DATUM + 7.
SCHEDULE_LINES-REQ_QTY = QUANT.
APPEND SCHEDULE_LINES.
SCHEDULE_LINESX-ITM_NUMBER = SCHEDULE_LINESITM_NUMBER.
SCHEDULE_LINESX-UPDATEFLAG = 'I'.
APPEND SCHEDULE_LINESX.
*-----------------------------------------------------*
IF NOT ( PRICE IS INITIAL OR CONDI IS INITIAL ).
CONDITIONS_IN-ITM_NUMBER = ORDER_ITEMS_INITM_NUMBER.
CONDITIONS_IN-COND_TYPE = CONDI.
CONDITIONS_IN-COND_VALUE = PRICE.
CONDITIONS_IN-CURR_ISO = CURR_ISO.
108
SAP R/3 Remote Function Call
Kap04.fm Seite 109 Dienstag, 22. April 2003 2:31 14
APPEND CONDITIONS_IN.
CONDITIONS_INX-ITM_NUMBER = CONDITIONS_INITM_NUMBER.
CONDITIONS_INX-UPDATEFLAG = 'I'.
APPEND CONDITIONS_INX.
ENDIF.
*-----------------------------------------------------*
CALL FUNCTION 'BAPI_SALESORDER_CHANGE'
EXPORTING
SALESDOCUMENT
= SALESDOCUMENT
ORDER_HEADER_IN
= ORDER_HEADER_IN
ORDER_HEADER_INX
= ORDER_HEADER_INX
TABLES
RETURN
= RETURN
ORDER_ITEM_IN
= ORDER_ITEMS_IN
SCHEDULE_LINES
= SCHEDULE_LINES
SCHEDULE_LINESX
= SCHEDULE_LINESX
CONDITIONS_IN
= CONDITIONS_IN
CONDITIONS_INX
= CONDITIONS_INX.
ENDFORM.
4.10.5 VBA-Beispiel zu BAPI_SALESORDER_GETLIST
Hier folgt nun zum Vergleich die Auflistung der Kundenaufträge mit Hilfe
eines VBA-Programms.
Liste aller
Kundenaufträge
Listing 4.26 VBA: Call BAPI_SALESORDER_GETLIST
'**** Functions in Library
Public func As SAPFunctionsOCX.Function
Public XMLDOC As New MSXML2.DOMDocument
Private myR3 As R3LogonObj
Private XMLhelp As New XMLhelper
'**** Parameters
Public iCUSTOMER_NUMBER As SAPFunctionsOCX.Parameter
Public iDOCUMENT_DATE As SAPFunctionsOCX.Parameter
Public iDOCUMENT_DATE_TO As SAPFunctionsOCX.Parameter
Public iMATERIAL As SAPFunctionsOCX.Parameter
Public iPURCHASE_ORDER As SAPFunctionsOCX.Parameter
Public iPURCHASE_ORDER_NUMBER As SAPFunctionsOCX.Parameter
Public iSALES_ORGANIZATION As SAPFunctionsOCX.Parameter
Business-Objekte und BAPI
109
Kap04.fm Seite 110 Dienstag, 22. April 2003 2:31 14
Public iTRANSACTION_GROUP As SAPFunctionsOCX.Parameter
Public eRETURN As SAPFunctionsOCX.Structure
Public tSALES_ORDERS As SAPTableFactoryCtrl.Table
Public Sub Class_Initialize()
Set myR3 = New R3LogonObj
myR3.R3Logon
'*************** Creating the object reference for the
RFC Functions
'====================================================
Set func =
myR3.Functions.Add("BAPI_SALESORDER_GETLIST")
'*************** Creating the object reference for the
Parameters
'==================================================
'**** Importing Parameters
Set iCUSTOMER_NUMBER =
func.Exports("CUSTOMER_NUMBER")
Set iDOCUMENT_DATE = func.Exports("DOCUMENT_DATE")
Set iDOCUMENT_DATE_TO =
func.Exports("DOCUMENT_DATE_TO")
Set iMATERIAL = func.Exports("MATERIAL")
Set iPURCHASE_ORDER =
func.Exports("PURCHASE_ORDER")
Set iPURCHASE_ORDER_NUMBER =
func.Exports("PURCHASE_ORDER_NUMBER")
Set iSALES_ORGANIZATION =
func.Exports("SALES_ORGANIZATION")
Set iTRANSACTION_GROUP =
func.Exports("TRANSACTION_GROUP")
'**** Exporting Parameters
Set eRETURN = func.Imports("RETURN")
'**** Table Parameters
Set tSALES_ORDERS = func.Tables("SALES_ORDERS")
End Sub ' Class_Initialize()
Public Sub Class_Terminate()
Set func = Nothing
Set myR3 = Nothing
End Sub ' Class_Terminate()
110
SAP R/3 Remote Function Call
Kap04.fm Seite 111 Dienstag, 22. April 2003 2:31 14
Public Sub Execute()
func.Call
End Sub ' Class_Initialize()
Public Sub Connect()
End Sub ' Connect
Public Function toXMLDoc() As MSXML2.DOMDocument
Set toXMLDoc = XMLhelp.toXMLDoc(func)
End Function
Public Function toXML() As String
toXML = toXMLDoc.XML
End Function
4.11
SAP Interface Repository
Alle offiziell von SAP freigegebenen BAPIs, IDocs und RFC-Bausteine sind
im Interface Repository von SAP dokumentiert, das unter der URL http:/
/ifr.sap.com abrufbar ist. Es ist für jedermann zugänglich und gibt die
Struktur der BAPIs sowohl in Textform als auch als formales XML-Dokument zurück.
Alle BAPIs sind im
IFR dokumentiert
Zum Abrufen der Information verwendet SAP so genannte Canonical
URLs, die im Wesentlichen eine vom W3C abgesegnete Variante der CGISpezifikation zur Codierung von Parametern in eine URI sind. Eine Version des IFR kann auch mit der Transaktion BAPI in einer SAP R/3-Instanz
aufgerufen werden.
Anfrage in Form
einer Canonical
URL
Das nachstehende Beispiel ist eine typische Anfrage an das IFR, die uns
ein XML-Schema für die GetList-Methode des Sales-Order-BAPIs
zurückgibt.
Typische Anfrage
an das IFR
Listing 4.27 Eine typische Anfrage an das IFR
http://ifr.sap.com/catalog/query.asp?
namespace=urn:sap-com:ifr:LO:46C
&type=bapi&name=SalesOrder.GetList
&xml=schema.w3c-2000-04&xdir=response
Tabelle 4.4 erläutert die Bestandteile der Canonical URLs, Tabelle 4.5 listet die möglichen Werte für die einzelnen Elemente auf, und Tabelle 4.6
die verwendeten Objekttypen.
SAP Interface Repository
111
Kap04.fm Seite 112 Dienstag, 22. April 2003 2:31 14
Element
Bedeutung
http://ifr.sap.com/catalog/query.asp?
Einstiegs-URL ins IFR
namespace=urn:sapcom:ifr:LO:46C
Namespace für das XML-Dokument
&type=bapi
Anfrage nach einem BAPI
&name=SalesOrder.GetList
Name des BAPI
&xml=schema.w3c-2000-04
Anfrage nach XML-Schema gemäß W3C-Spezifikation
&xdir=response
Anfrage nach Schema für die Antwort
Tabelle 4.4 Objekt-Typen, die in den Canonical URLs von SAP verwendet werden
Element
Erlaubte Werte
type=
bobj | bapi | rfc | imsg | idoc | iseg | area | docu
name=
Name des Objekts
key=
Schlüssel des Dokuments, zum Beispiel Auftragsnummer
param=
Parameter, die kein Schlüsselfeld sind, zum Beispiel Auftragsdatum
language=
Sprache des Ergebnisdokuments, falls sinnvoll
xml=
schema | template [W3C-Version]
xdir=
send | response
Tabelle 4.5 Mögliche Werte innerhalb der Canonical URL
type=
Bedeutung
area
Area
bapi
BAPI
bobj
Business Object
idoc
Intermediate Document (IDoc)
imsg
IDoc message type
iseg
IDoc segment
Rfc
Remote Function Call
Tabelle 4.6 Objekt-Typen, die in den Canonical URLs von SAP
verwendet werden
112
SAP R/3 Remote Function Call
Kap04.fm Seite 113 Dienstag, 22. April 2003 2:31 14
type=
Bedeutung
Name
Name
Param
Parameter
docu
Documentation
Tabelle 4.6 Objekt-Typen, die in den Canonical URLs von SAP
verwendet werden (Forts.)
Folgendermaßen gestaltet sich die Abfrage des XSD-Schemas für RFC
IDOCTYPE_READ-COMPLETE:
http://ifr.sap.com/catalog/query.asp?namespace=urn:sapcom:ifr:BASIS:46C&type=rfc&name=IDOCTYPE_READ_COMPLETE&xml=SCHEMA&xdir=SEND
<?xml version="1.0" encoding="utf-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="urn:sap-com:document:sap:rfc:functions"
targetNamespace="urn:sap-com:document:sap:rfc:functions" version="1.0">
<xsd:element name="IDOCTYPE_READ_COMPLETE">
<xsd:annotation>
<xsd:documentation>Read IDoc type with segments
(RFC-compatible)</xsd:documentation>
</xsd:annotation>
<xsd:complexType>
<xsd:all>
<xsd:element name="PI_IDOCTYP">
<xsd:annotation>
<xsd:documentation>Basic type</xsd:documentation>
</xsd:annotation>
<xsd:simpleType>
<xsd:restriction base="xsd:string">
<xsd:maxLength value="30"/>
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
<xsd:element name="PI_CIMTYP" minOccurs="0">
...
SAP Interface Repository
113
Kap04.fm Seite 114 Dienstag, 22. April 2003 2:31 14