Connector for SAP Business Suite - Developer's Manual part 3 - Integration scenario: Scripting
The Connector for SAP Business Suite provides various functions for Velocity
scripts. The script API of the connector must be
registered in order to this.
Within the script API, the connector provides various functions, the
"simpleRFC API" which can be used for
calling BAPI/RFC functions in Velocity scripts.
The main focus of the scripting function of the Connector for SAP Business
Suite is on Groovy. In conjunction with the integration on SAP systems,
Groovy can be used to call SAP BAPI/RFC functions. These can be
used, for example, to generate or manipulate SAP data (e.g. orders).
SAP processes (e.g. workflows) can be initiated with this functionality.
A configured Connector for SAP Business Suite with an active
View & Write or Developer API license is required to use the Groovy
functionality.
1. Scenario overview - SAP sales order
Using the example of an SAP sales order, this document will demonstrate
how a typical integration project should be carried out. SAP sales orders
can be triggered by internet shops when a customer saves their order compiled
as a backet, for example.
2. Requirements
In this scenario, it is assumed that an SAP R/3 System with a configured
SD order recording is available. SAP R/3 is the leading system and defines
the framework conditions. Conversely, this also means that a specific
result - the SAP SD order - is expected in the SAP world. The sales
order can be generated with SAP transactions using SAP-typical user interfaces
(the SAPGUI). For the sales order, the orders would be recorded using
transaction "VA01". If this is not the case, that is, if SAP is not yet
able to implement the basic requirements using its own means,
it is still too early for an integration scenario with Intrexx.
Here, the functional prerequisites in SAP (an SAP implementation project,
SAP Customizing) need to be created first. This is not part of this
documentation but standard SAP business. The functional requirements
for the SAP sales order can be formulated as follows for this example:
The customer logs in to the Intrexx portal. They can record an order from the
menu. There he compiles an order that is then sent to the SAP System.
If this is successful, the order number needs to be send to the customer
immediately after their submission. The order should be available in
SAP R/3 as an SD sales order (transaction "VA01") without any manual
intermediate steps. Put simply, this example scenario expects that
The customer master data is already available both in SAP
and in the Intrexx portal (with a reference to the SAP customer number).
To begin with, only one item should be generated per order for the
sake of simplicity.
The customer nows the article number and enters the desired amount.
3. Process simulation in SAP
As a fully configured SAP system is assumed here, it needs to be possible
to record an SAP sales order as if it the customer will receive it
via an alternative interface. There, this should be simulated in
SAP via SAP standard transactions. This is the transaction "VA01"
for the SAP SD sales order.
Only identifying the most necessary entries for recording an order correctly
has proven itself as wise. For the SAP SD sales order,
this is the following information:
Information
Example
Source
Sales order type
YTA
Constant, predefined by the SAP side
Sales organization
1000
Constant, predefined by the SAP side
Distribution channel
10
Constant, predefined by the SAP side
Division
10
Constant, predefined by the SAP side
Sold-to party
10000
Context of the logged-in user, Customer number
Sales order number
TEST0001
Customer entry, from the user interface
Sales order date
20.08.2008
Customer entry, from the user interface
Material
B100000
Customer entry, from the user interface
Amount
10
Customer entry, from the user interface
Depending on the Customizing settings in the SAP system, additional information
may also be required.
After the order is saved, a check is performed by the SAP department
as to whether the order's content is correct and sufficient.
The latter should definitely already be checked at this stage. For example,
the SAP order could be correct based on the configured SAP Customizing.
Because a sales order is followed by processes such as delivery and
invoicing, the entire processes needs to also be correctly handleable.
Assessing this is the job of the respective department.
4. Analysis of available SAP BAPI functions
In the last step, the SAP standard transaction and the information required to
simulate the required SAP process was determined. This step analyzes which
functions SAP provides to the external systems in order to generate the
same result - an identical-looking sales order. The SAP system contains
a number of functions with API character that can and should be used by SAP
itself and by external functions. In most cases, these are the so-called
function modules. Some of these function modules can be used for external
systems. These then have an additional property: they can be called remotely.
These are referred to as Remote Function Calls (RFC for short), some of these
have BusinessObject character. This means that they are specially flagged
and represent object-oriented access to an SAP BusinessObject. SAP AG
calls the total set of BusinessObjects and their access routines
"Business API" (BAPI). The individual function module is also referred to
here as a "BAPI". SAP recommends the Business API with all its BAPI function
modules for external access to SAP objects and their processes.
Every integration project should therefore go via the BAPI functions.
4.1. Transaction BAPI
In many cases, the SAP transaction "BAPI" helps identify the BAPI functions for the
desired result. Here, you can research whether official BAPI functions
are provided for the desired SAP object. You will find what you're
looking for very quickly for the SD sales order example.
For the example of creating an SD sales order, the SAP BusinessObject
"BUS2032" and the object method (the BAPI function module "BAPI_SALESORDER_CREATEFROMDAT2")
are available.
4.2 Business Object Repository (BOR)
The Business Object Repository is primarily used for the SAP business workflow
functionality. All of the SAP objects important for the SAP workflow
have a defined BusinessObject here.
The provided search aids should help you find the BusinessObject
you're looking for quickly.
Once you've found the BusinessObject, you can identify the usable BAPI
functions very quickly in the methods. Click on the
button to navigate
directly to the corresponding function module.
4.3 Search for function modules callable per remote
If the previous steps proved unsuccessful, you have the ability to
enter terms to search through all of the function modules callable per remote.
The function module "RFC_FUNCTION_SEARCH" is well-suited for this and
can be called via the transaction "SE37".
Using the entry parameters, you can search for *ORDER*, for example.
The results list then contains every function module that
can be called by an external component - whether this fulfills
the desired purpose of course needs to be checked.
4.4 Proxy function modules
If all previous attempts to achieve the desired result in the SAP system
were unsuccessful, there is one final way: individual programming.
To do this, you must create at least one function module shell, that is
classified as RFC-enabled. The function module must pass calls on to other
function modules that may not be flagged as remotely callable. The
customer-specific RFC function module then only acts as a proxy.
Alternatively, this function module can also call other functions
available in ABAP (for example, subroutines) or generate and process batch
input maps. The latter naturally requires extensive ABAP knowhow.
Furthermore, it should be noted that this procedure is not recommended by SAP
and therefore no support is provided for this. This form of implementation
should be chosen if there are no alternatives and the customer is aware
of the risk involved and can be held responsible for it. For reasons of
simplification, it can sometimes be useful to use your own proxy function
modules, although official BAPI function modules exist for the required
requirement. Especially for external systems, the call is much clearer if
only the absolutely required parameters have to be filled instead of
the sometimes very extensive parameters. Proxy function modules can then
link different BAPI calls and, if necessary, extend the parameters
to SAP Customizing (for example, determine the correct sales
organization in SAP).
5. Parameter concept
Once it is clear which function modules - preferably BAPI function modules -
can be called remotely, an external call must be simulated. The system
confirms whether the previously determined information is actually sufficient
to generate the required SAP object. All function modules offer a test
option via transaction "SE37", you can use this to check the functions
and their parameters. Here, you can simulate the view of an external system.
The parameters available in the function module interface must be populated
in the same way as identified in the simulation.
The mimimum information from the previous steps must be entered into the
corresponding parameter fields here. The test workbench via transaction "SE37"
supports simple parameters, structures and table parameters. Documentation
for the function module can be of great help for identifying the right fields.
Because entering the parameters can be a lot of work, these entries can be
saved. You can access your entries again later via "Test data".
Once all of the parameters have been entered, the function module
can be started with F8.
The function modules usually report the success of a call using export
parameters, for example, a document number generated by the system
(see area highlighted in red). BAPI functions must often be confirmed by
additionally calling the function module "BAPI_TRANSACTION_COMMIT".
Otherwise, a document number or similar is generated but the document
is not found in the system. If you want to test this type of BAPI function,
you must either be satisfied with the successful generation of a document
number or program the function module call from an SAP report (transaction "SE38")
in the SAP system with a subsequent commit. In most cases, however,
the document number generated is already sufficient to assume that the
SAP object was successfully created. BAPI functions also usually have a
property that documents messages about the success or failure of internal
processes, documented in a table of the structure "BAPIRET2"
(the parameter "RETURN" in this case). Here, all lines with the type
E, A or X are evaluated as errors. In these cases, the document number
should also be missing in the export. The messages often contain detailed
information as to why the function could not be processed successfully,
for example, mandatory fields could not be populated.
6. Designing the user interface
The next step involves creating a first draft of a user interface
for the integration scenario. In this case, the user should enter
all of the parameters required for the SAP function, or be able
to identify them from the context. The potentially available
constant templates (e.g. Order type) can be supplemented in the script
later. For test cases, this information can also come from predefined edited
fields.
6.1 Create the application
Create a
new application
based on the application template
Basic application.
Create the following edit fields on the edit page.
Each time, select the option
"New data field" and
select the stated data type in the subsequent dialog in each case:
Order type
Data type: Text, Input required, Custom default: YTA,
Maximum number of characters available: 4 characters
Sales organization
Data type: Text
Distribution channel
Data type: Text
Division
Data type: Text
Customer number
Data type: Text, Read-only,
Default from user data: "BIASAP-KUNNR"
With these settings, the customer number stored in the user manager
is entered automatically when a new data set is created.
The "Read-only" setting prevents manually entry.
Click
here for a description of how to create the additional attribute
"BIASAP-KUNNR" in the user manager.
Order number
Data type: Text
Order date
Data type: Date, Create date picker
Article number
Data type: Text
Amount
Data type: Integer
SAP order number
Data type: Text, Read-only
Once all of the edit pages have been created, the edit page should look
something like this:
The application title can be changed to "Create SAP sales order with Groovy"
by double-clicking on the
application structure.
6.2 Overview table on the start page
On the start page "All Entries", delete all elements apart
from the table.
Select the following fields as table columns:
Change date
Customer number
Order number
Order date
Article number
Amount
SAP order number
Save the application and publish it in the portal menu structure.
6.3. The application in the browser
On the edit page, you will see the created edit fields with the
default entries. Enter test data in the empty fields that
aren't read-only. Click on "OK".
The new data set is now shown in the table on the start page.
6.4. Summary
The created application enables you to record all data required
for further processing in SAP. For the sake of simplification,
only one order item can be recorded.
7. Process integration
This section contains the actual integration of an SAP system with the
goal of generating an SAP sales order from the data entered via a process.
The SAP sales order is generated with Groovy script using an SAP
function module.
7.1 Generate the Groovy script
SAP function modules can provide very complex parameters.
To avoid errors while creating the script, a script generator
is provided with Intrexx. The complete description of this can be found
here.
7.2. Create the process
In the
Processes module, create
a new process.
As the source of the new process, select
"Event initiated by change of a record".
Click on "Next".
Select the application created in this part of the Developer's Manual.
Select the record event "Insert" and click on "OK".
7.3. Groovy action
When a new record is added in the application, an SAP sales order
should be created with a Groovy script. To do this, connect a
Groovy script action with the previously created data group event handler.
Open the properties dialog of the
Groovy script action by double-clicking on it.
Click on "Next".
Open the Intrexx editor.
The Groovy script generated earlier can be inserted here.
7.4. Identify fields from the data group
The script now needs to be modified.
Please note that United Planet assumes no liability for any
errors caused by incorrect modifications.
To begin with, the data fields from the Intrexx application need to be
identified.
To do this, we will add a section to the script where the Intrexx data fields
are referenced. After the variable definition, you can open a list
of the data group's data fields by right-clicking. If a data field is selected
from this list, the corresponding script is inserted at the position of the
cursor.
Here is a complete list of the data field references:
The data field variables now need to be assigned to the correct parameters of
the function module. In the script, the parameters are pre-generated. The empty
value "l_value" is assigned to the parameters.
Example:
g_sap.setImpStrucParField(l_function, "ORDER_HEADER_IN","DOC_TYPE", l_value); // ABAP Type C: 4,0
These should now be replace. The value "l_value" is replaced
by the variable "l_auart" in this example. Generated coding
for tables can be modified as follows:
// Imported Table ORDER_PARTNERS (ABAP Structure: BAPIPARNR) - Belegpartner
l_table = g_sap.getTable(l_function,"ORDER_PARTNERS");
for(int i = 0; i < 1; i++){
l_table.appendRow();
g_sap.setTableField(l_table, "PARTN_ROLE", "AG"); // ABAP Type C: 2,0
g_sap.setTableField(l_table, "PARTN_NUMB", l_kunnr); // ABAP Type C: 10,0
} // Table ORDER_PARTNERS end
Generally, a FOR loop is generated for tables. If only one table row
is required (as is the case in this simplified example), the 0 needs
to be replaced by a 1. Unrequired parameters can be deleted to keep the script
small and manageable. If they are needed later, then they can be copied
individually from the generated coding of the SAP groovy generator.
7.6. Evaluate SAP call
An SAP call is performed at this point in the generated script.
// Execute SAP function
if(g_sap.executeSapFunction(l_client, l_function)) {
if(l_trace) g_log.info(l_logprefix + "Fill export parameters")
// ---- get and check results
l_value = g_sap.getExpPar(l_function,"SALESDOCUMENT") // ABAP Type: C 20,0 - Number of Generated Document
The following script starts the SAP function module, analyzes
the returned order number and writes this to the current
data set in the Intrexx data group. A rollback is performed
in the case of errors.
//==========> EXECUTE SAP FUNCTION
if(g_sap.executeSapFunction(l_client, l_function)){
// SALESDOCUMENT (ABAP Type: C 10,0) - Number of the generated document
String l_vbeln = g_sap.getExpPar(l_function,"SALESDOCUMENT");
if(l_vbeln.equals("")){
g_sap.BapiRollback(l_client);
return null;
}
// save vbeln to datagroup
l_conn = g_dbConnections.systemConnection;
l_lid = g_record["66B1F38BA125C4C22444D27AC9108B91A208EE16"].getValue(); // datafield (PK) (S) ID
l_stmtOrderUpdate = g_dbQuery.prepare(l_conn, "UPDATE XTABLE9EB02DDB SET SAP_VBELN = ? WHERE LID = ?");
l_stmtOrderUpdate.setString(1, l_vbeln);
l_stmtOrderUpdate.setInt(2, l_lid);
l_stmtOrderUpdate.executeUpdate();
// final commit
g_sap.BapiCommit(l_client, false); // set to true if commit should wait
}else{
g_sap.BapiRollback(l_client);
return null;
};
The following coding is well-suited for finding errors by writing
notifications from the BAPIRET2 messages to the log file.
In the application
created earlier, you can now create a test data set. The order number
is write-protected and is empty. When you click on "OK", the data
set is added and this triggers the process with the Groovy script
action.
The data set just created is now supplemented by the SAP order number.
If an error occurs or the SAP order number isn't entered, please
check the log file.
8.2. View SAP order
With the SAP order number, the correspdonding order can be viewed
in SAP with the transaction "VA03".
8.3. Check completeness
Now, the department now needs to check and confirm whether the order
in SAP is identical to the data set created in the Intrexx application.
Additionally, subsequent processes such as delivery or invoicing
need to be checked.
9. Possible extensions
9.1. RFC functions with item data
In our example, we have deliberately avoided processing multiple order items.
This doesn't correspond to the reality of many scenarios. Therefore, this
section will look at the steps required when multiple positions should be
processed with Groovy script. For this purpose, the data group, which
saves the data for the order header, is seen as the parent data group.
Beneath this parent data group, child data groups, also known as
subordinate data groups,
are used that contain the order items to the header datasets. The child data
group contains the ID of the parent dataset in the data field "FKLID".
You can see a very simplified sales processing here. The data group
"Order items" has been created as a child data group of the
"Sales orders" data group; this contains the header data.
Now, a change to a dataset from the "Sales orders" data group could
trigger the Groovy script in a corresponding process. But with this, there
should be a check that the entire order is complete. The dataset for the
sales order is saved in Intrexx before the first order item is created.
The process from Intrexx's side will therefore look something like this:
Enter and confirm header data in the application
Enter items in the application
Complete entire order in the application, e.g. with a manually or
automatically set checkbox
Further processing with a Groovy script action
// get db connection
def l_conn = g_dbConnections.systemConnection
// get Lid for parent record
def l_fkLid = g_record["BBCAC884A9397E98BD683B76386D58A39A8B56BC"].getValue(); // datafield (PK) (S) ID
// db query postions
def l_stmtPositions = g_dbQuery.prepare(l_conn, "SELECT LID, STR_BARCODEDERPOSITIO_616DDB16 FROM XDATAGROUP12A091EF WHERE FKLID = ?")
l_stmtPositions.setInt(1, l_fkLid)
def l_rsPositions = l_stmtPositions.executeQuery()
// loop all positions
l_rsPositions.each
{
g_log.info("Record: " + it.value(1) + " = " + it.value(2))
}
The Groovy script requires the actual technical names of the data group
"Order times" and the data field "Barcode". These can be identified
on the
Application structure tab and then inserted into the example script
at the corresponding postions. The script outputs the order item
information in the log file. Once a complete dataset with items
has been recorded, the following information is available there.
INFO 2008-08-24 14:31:59,203 - de.uplanet.lucy.server.workflow.GroovySkriptCall[WebConnectorWorker-localhost:8102-8]
Record: 34 = 1000
INFO 2008-08-24 14:31:59,203 - de.uplanet.lucy.server.workflow.GroovySkriptCall[WebConnectorWorker-localhost:8102-8]
Record: 35 = 2000
If the item data should be entered into a table of an SAP function module,
as in the previous example, the script for the loop needs to be changed
slightly.
The methods of the Groovy API are implemented in the business logic
of the Connector for SAP Business Suite as the Java class
"net.initall.ixapi.groovy.IxSapGroovyAPI". The available methods
can be found in the
Appendix.
To be able to use the methods in Velocity as well, the Groovy API needs
to be registered as a "callable". Callables are an expansion concept
for integrating any Java classes. These Java classes can be registered in the
portal configuration file "customcallables.cfg".
To use the Groovy API of the Connector for SAP Business Suite, you
should use the context name "GSAP".
As of Business Logic 2010, a fast-track configuration is available which
takes over these settings automatically.
9.3. Using the simpleRFC functionality
The simpleRFC API provides functions for calling BAPI/RFC functions in Velocity
sripts. Velocity scripts can be integrated into Intrexx view pages, for example.
Please note that Velocity scripts are performed on the server while the delivered
HTML pages are being generated. Parameters need to be transferred via
request values or via the sessions. The license "View & Write" is the
minimum requirement for this. However, with the license "View Only",
a simple call can be used that can call a simple remote-capable function
module with an import and export parameter.
The complete API is described in the
Appendix. Notes on its usage are provided in the following
sections.
9.3.1. VUsing the trigger functionality (simple call)
For simple calls of RFC functions, a special function of the simpleRFC API is
available. This can be used for typical triggers sich as calculating current
data in SAP or similar. With this, an import parameter with the string
type can be populated and an export parameter can be requested. The RFC
functions require a special interface:
function z_demo_trigger_simplerfc .
*"----------------------------------------------------------------------
*"*"Local interface:
*" IMPORTING
*" VALUE(INPUT) TYPE STRING OPTIONAL
*" EXPORTING
*" VALUE(RESULT) TYPE STRING
*"----------------------------------------------------------------------
concatenate 'Reply from SAP. Input value was:'
input
into result separated by ' '.
endfunction.
As the import parameter, the parameter "INPUT" with a character data type
(e.g. string) is expected. If a result should be written back, this needs
to be done via the export parameter "RESULT".
This function module can then be started from a view page, where a
static text element
with the option "Programming, only default language" has been created.
The call is specified via the simpleRFC API as programming text:
Loading the view page will now always call the function module
and displays the result of the export parameter "RESULT" as text.
In Intrexx, you can access the displayed value of the static text field
with JavaScript (Attribute *.textContent). By integrating request values,
a conditional execution can be implemented in the Velocity script.
This simple call of BAPI/RFC functions is available in the license "View Only".
9.3.2. Using the entire simpleRFC API
The following example demonstrates the use of the simpleRFC API on
view pages for complex function modules. The complete API is described in the
Appendix.
The majority of API methods' have "boolean" results. With this, the SAP
Connector shows whether the last call of an API method was successful or not.
The error handling needs to take place in its own Velocity script.
A typical simpleRFC script has the following structure:
Open connection to SAP
Load BAPI/RFC function
Populate import parameter of the function
Start function
Read export parameter of the function
Close function
Close connection
As an example, a simple function will be used. This provides the
stock levels of promotional gifts in the export table "ET_STOCK".
This table needs to be populated accordingly:
The export structure has a simple structure and contains the material number,
material abbreviation and the stock as an integer value.
This SAP function is used on a view page.
The script for calling the SAP function module via the simpleRFC API
is entered in the static text
element. The result is an HTML output of the returned table.
This is transferred to the request parameter "sapstock".
This first text field can also be moved to the
hidden area.
A second static text element displays the current request value and
thus the currently identified HTML output of the stock as text.
The script of the first static text field displays the usage
of the simpleRFC methods as an example:
## open connection
Open Connection: $GSAP.simpleRfcConnect("saperp","system")
## function open
<br>Load Function: $GSAP.simpleRfcFunctionLoad("/IATL/MESSE_IPHONE_GET_STOCK")
## execute without commit
<br>Execute: $GSAP.simpleRfcFunctionExecute(false)
## loop export table
<br>Set Focus Table: $GSAP.simpleRfcSetFocusTable("ET_STOCK")
<br>Records found: $GSAP.simpleRfcTableGetCount()
#set($strOutput = "<table>")
#foreach($line in $GSAP.simpleRfcTableGetEntries())
<br> List Item: $line
Set Table Line: $GSAP.simpleRfcTableSetLine($line)
#if($GSAP.simpleRfcSetFocusTableField("MATNR"))
#set($strMatnr = $GSAP.simpleRfcGetParameterValue())
#end
#if($GSAP.simpleRfcSetFocusTableField("MAKTX"))
#set($strText = $GSAP.simpleRfcGetParameterValue())
#end
#if($GSAP.simpleRfcSetFocusTableField("COUNT"))
#set($strCount = $GSAP.simpleRfcGetParameterValue())
#end
#set($strOutput = $strOutput + "<tr><td>" + $strMatnr + "</td><td>" + $strText + "</td><td>" + $strCount + "</td></tr>")
#end
#set($strOutput = $strOutput + "</table>")
## function close
<br>Close Function: $GSAP.simpleRfcFunctionClose(false)
## close Connection
<br>Close Connection: $GSAP.simpleRfcClose()
## set output
$strOutput
$Request.put("sapstock",$strOutput)
Especially the populating and reading of parameters from the function module interface
can be complex here. Each parameter needs to be focussed first before
it can be read and set. Structures and tables require a doubled focussing -
to begin with the table / structure is put in focus, then the column (the field).
The simpleRFC API allows access to tables via special API methods, e.g. to
identify the amount, or to position or added new rows. In short,
the following VM code loops over all available table lines: