Example ITS Flow Logic - Sales Order Creation (© 2002 Computerservice Wolf - all rights reserved.) STEP 1 - Requirements Company A has a product catalog on the internet, which is implemented in PHP and mySQL. This catalog should be extended with the option to create a sales order. SAP ITS can be used to achieve this as long as the back-end ERP system is SAP. STEP 2 - Preparation Download and install the ITS (www.saplabs.com) Install SAP@Web Studio (www.saplabs.com). Starting from release 4.6C you can use the Web Application Builder in the ABAP workbench to achieve the same functionality as web studio.
STEP 3 -Implementation You should consider using this implementation model for applications that offer many application functions on one page, and the dialog flow is not fixed in advance. Such applications have simple point-and-click user interfaces, limited manual data input, and reduced data formatting requirements. They are often used in e-commerce scenarios. Data transfer from the product catalog We use an HTML form (and HTTP POST) as the interface between the product catalog and the ITS flow logic application. <form ACTION="http://its.domain.com/scripts/wgate/z_order_in/!?~language=en" METHOD="POST"> Qty: <input type="text" name="ORDER_ITEMS_IN-REQ_QTY[1]"><br> Material: <input type="text" name="ORDER_ITEMS_IN-MATERIAL[1]"><br> <input type="submit" name="Place Order" value="ORDER"> </form> The form looks like this: Definition of the ITS Service The ITS service is called z_order_in and has the following content: | ~ZGateway | sapxginet | implies flow logic application | | ~language | | this value will be set in the URL | | ~initialTemplate | login | startup page | | ~theme | 99 | sets the look and feel of the web app |
|
Log-on to SAP as an internet user 1.1. LOGIN.HTML The login page asks the customer to enter his customer number and the password. You maintain these 2 values in SAP using SU05 (object for customer) and XD01 (create customer master record). <html> <head> <title>`#order_in_login`</title>
</head> <body> <form method=post action=`wgateURL()`> <table> <tr> <td>`#KUNNR`</td> <td><input type=text name="CUSTOMERNO" value="`CUSTOMERNO`"></td>
</tr> <tr> <td>`#PASSWORD`</td> <td><input type=password name="PASSWORD"></td>
</tr> <tr> <td> <input type="hidden" name="SALES_ORGANIZATION" value ="1000"> <input type="hidden" name="DISTRIBUTION_CHANNEL" value ="10"> <input type="hidden" name="DIVISION" value ="10"> `repeat with i from 1 to ORDER_ITEMS_IN-MATERIAL.dim` <input type="hidden" name="ORDER_ITEMS_IN-MATERIAL[`i`]" value ="`ORDER_ITEMS_IN-MATERIAL[i]`"> <input type="hidden" name="ORDER_ITEMS_IN-REQ_QTY[`i`]" value ="`ORDER_ITEMS_IN-REQ_QTY[i]`">
`end` <input type="submit" name="~event=login" value=`#login`">
</td>
</tr> </table? </form> <h2>`#Messages`</h2> `RETURN-MESSAGE`<br> </body> </html> 1.2. LOGIN FLOW FILE <flow> <event name="login" next_state="checkCustomerNumber"> </event> <state name="checkCustomerNumber"> <module name="BAPI_CUSTOMER_CHECKEXISTENCE" stateful="0" type="RFC"> <result next_state="checkPassword"> <expr> RETURN-TYPE==""
</expr> </result> <persistent name="CUSTOMER_NUMBER_OUT"/> <persistent name="SALES_ORGANIZATION"/> <persistent name="DISTRIBUTION_CHANNEL"/> <persistent name="DIVISION"/> <persistent name="lang"/> <persistent name="javascript"/> <persistent name="session"/>
</module>
</state> <state name="checkPassword"> <module name="BAPI_CUSTOMER_CHECKPASSWORD" stateful="0" type="RFC"> <result next_template="simulate"> <expr> RETURN-TYPE==""
</expr> </result> </module>
</state> </flow> First the BAPI_CUSTOMER_CHECKEXISTENCE is called in order to check whether the customer number exists. If this is true then the password is checked with BAPI_CUSTOMER_CHECKPASSWORD. If this is true then the template "simulate" is called. In all other cases the error message is displayed through the structure RETURN referencing field MESSAGE. Simulate the order 2.1. SIMULATE.HTML <html> <head> <title>`#simulate_order`</title> </head> <body> RETURN-TYPE: `RETURN-TYPE`<br> RETURN-MESSAGE: `RETURN-MESSAGE`<br> RETURN-CODE: `RETURN-CODE`<br> <table border="1"> <tr> <td>`#material`</td> <td>`#quantity`</td> <td>`#price`</td>
</tr> `repeat with i from 1 to ORDER_ITEMS_OUT-MATERIAL.dim` <tr> <td>`ORDER_ITEMS_OUT-MATERIALS[i]`</td> <td>`ORDER_ITEMS_OUT-REQ_QTY[i]`</td> <td>`ORDER_ITEMS_OUT-SUBTOTAL_2[i]/1000`</td>
</tr>
`end` </table> <form action="`wgateURL()`" method="POST"> `repeat with i from 1 to ORDER_ITEMS_IN-MATERIAL.dim` <input type="hidden" name="ORDER_ITEMS_IN-MATERIAL[`i`]" value="`ORDER_ITEMS_IN-MATERIAL[i]`"> <input type="hidden" name="ORDER_ITEMS_IN-REQ_QTY[`i`]" value="`ORDER_ITEMS_IN-REQ_QTY[i]`">
`end` <input type="submit" name="~event=shipto" value="`#shipto`"> <input type="submit" name="~event=order" value="`#order`"> </form> </body> </html> 2.1.1. GET DATE TIME FUNCTION MODULE To start the simulation with BAPI_SALESORDER_SIMULATE many other additional fields in the structure ORDER_HEADER_IN and the tables ORDER_PARTNERS and ORDER_ITEMS_IN must be filled. Some fields must contain the current date. To get the current date use the custom RFC Z_GET_DATE: function z_get_date * importing * value(dayspast) like mara-matnr default 0 * value(timepast) like mara-matnr default 0 * exporting * value(date) like sy-datum * value(time) like sy-uzeit date = sy-datum - dayspast. time = sy-uzeit - timepast. endfunction. 2.1.2. HTML Business Script INIT The table and structures are filled through the HTML Business script init: ` ORDER_HEADER_IN-DOC_TYPE = 'ZOR'; ORDER_HEADER_IN-SALES_ORG = SALES_ORGANIZATION; ORDER_HEADER_IN-DISTR_CHAN = DISTRIBUTION_CHANNEL; ORDER_HEADER_IN-DIVISION = DIVISION; ORDER_HEADER_IN-CD_VALUE1 = "0.00"; ORDER_HEADER_IN-CD_VALUE2 = "0.00"; ORDER_HEADER_IN-CD_VALUE3 = "0.00"; ORDER_HEADER_IN-CD_VALUE4 = "0.00"; ORDER_HEADER_IN-PRICE_DATE = DATE; ORDER_HEADER_IN-QT_VAILD_F = DATE; ORDER_HEADER_IN-QT_VAILD_T = DATE; ORDER_HEADER_IN-CT_VAILD_F = DATE; ORDER_HEADER_IN-CT_VAILD_T = DATE; ORDER_PARTNERS-PARTN_ROLE[1] = "AG"; ORDER_PARTNERS-PARTN_NUMB[1] = CUSTOMER_NUMBER_OUT; ORDER_PARTNERS-ITM_NUMBER[1] = "000000"; if (ORDER_PARTNERS-NAME[2] != "") ORDER_PARTNERS-PARTN_ROLE[2] = "WE"; ORDER_PARTNERS-PARTN_NUMB[2] = CUSTOMER_NUMBER_OUT; ORDER_PARTNERS-ITM_NUMBER[2] = "000000";
end; repeat with i from 1 to ORDER_ITEMS_IN-MATERIAL.dim ORDER_ITEMS_IN-COND_VALUE[i] = "0.00"; ORDER_ITEMS_IN-COND_VAL1[i] = "0.00"; ORDER_ITEMS_IN-CD_VALUE1[i] = "0.00"; ORDER_ITEMS_IN-CD_VALUE2[i] = "0.00"; ORDER_ITEMS_IN-CD_VALUE3[i] = "0.00"; ORDER_ITEMS_IN-CD_VALUE4[i] = "0.00";
end; ` 2.2. SIMULATE FLOW FILE After the successful simulation of the sales order the customer has the option to order either directly or to set a different ship-to address. <flow> <state name="simulate"> <module name="BAPI_SALESORDER_SIMULATE" stateful="0" type="RFC"> </module>
</state> <state name="init"> <module name="init" stateful="0" type="SCRIPT"> <default next_state="simulate"> </default> </module>
</state> <event name="ontouch" next_state="dateget"> </event> <state name="dateget"> <module name="Z_GET_DATE" stateful="0" type="RFC"> <default next_state="init"> </default> </module>
</state> <event name="order" next_template="order"> </event> <event name="shipto" next_template="shipto"> </event> </flow> Change the ship to address 3.1. SHIPTO.HTML Through this template a different ship-to address can be set. The material number and quantity are again transferred in hidden fields. <html> <head> <title>`#shipto`</title> </head> <body> <form action="`wgateURL()`" method="POST"> `repeat with i from 1 to ORDER_ITEMS_IN-MATERIAL.dim` <input type="hidden" name="ORDER_ITEMS_IN-MATERIAL[`i`]" value="`ORDER_ITEMS_IN-MATERIAL[i]`"> <input type="hidden" name="ORDER_ITEMS_IN-REQ_QTY[`i`]" value="`ORDER_ITEMS_IN-REQ_QTY[i]`">
`end` <table> <tr> <td>Name1:</td> <td><input type=text name="ORDERS_PARTNERS-NAME[2]" maxlength=35></td>
</tr> <tr> <td>Name2:</td> <td><input type=text name="ORDERS_PARTNERS-NAME_2[2]" maxlength=35></td>
</tr> <tr> <td>Name3:</td> <td><input type=text name="ORDERS_PARTNERS-NAME_3[2]" maxlength=35></td>
</tr> <tr> <td>Name4:</td> <td><input type=text name="ORDERS_PARTNERS-NAME_4[2]" maxlength=35></td>
</tr> <tr> <td>Street:</td> <td><input type=text name="ORDERS_PARTNERS-STREET[2]" maxlength=35></td>
</tr> <tr> <td>ZIP:</td> <td><input type=text name="ORDERS_PARTNERS-POSTL_CODE[2]" maxlength=35></td>
</tr> <tr> <td>City:</td> <td><input type=text name="ORDERS_PARTNERS-CITY[2]" maxlength=35></td>
</tr> <tr> <td>Country:</td> <td><input type=text name="ORDERS_PARTNERS-LAND[2]" maxlength=35></td>
</tr> </table> <input type="submit" name="~event=order" value="`#order`"> </form> </body> </html> 3.2. SHIPTO FLOW FILE <flow> <event name="order" next_template="order"> <!--*FlowDesigner bounds (-100, 8, 100, 10)*--> </event> </flow> Show the order confirmation 4.1. ORDER.HTML After the successful posting of the sales order, the data and order number need to be displayed. <html> <head> <title>`#order`</title> </head> <body> <pre> `#Soldtoname`: `SOLD_TO_PARTY-NAME` `#Soldtostreet`: `SOLD_TO_PARTY-STREET` `#SoldtoZIP`: `SOLD_TO_PARTY-POSTL_CODE` `#Soldtocity`: `SOLD_TO_PARTY-CITY` `#Shiptoname`: `SHIP_TO_PARTY-NAME` `#Shiptostreet`: `SHIP_TO_PARTY-STREET` `#ShiptoZIP`: `SHIP_TO_PARTY-POSTL_CODE` `#Shiptocity`: `SHIP_TO_PARTY-CITY` <table border="1"> <tr> <td>`#role`</td> <td>`#kunnr`</td> <td>`#item_numb`</td> <td>`#name`</td> <td>`#street`</td> <td>`#zip`</td> <td>`#city`</td>
</tr> `repeat with i from 1 to ORDER_PARTNERS-NAME.dim` <tr> <td>`ORDER_PARTNERS-PARTN_ROLE[i]`</td> <td>`ORDER_PARTNERS-PARTN_NUMB[i]`</td> <td>`ORDER_PARTNERS-ITM_NUMBER[i]`</td> <td>`ORDER_PARTNERS-NAME[i]`</td> <td>`ORDER_PARTNERS-STREET[i]`</td> <td>`ORDER_PARTNERS-POSTL_CODE[i]`</td> <td>`ORDER_PARTNERS-CITY[i]`</td>
</tr> `end` </table> RETURN-TYPE: `RETURN-TYPE` RETURN-MESSAGE: `RETURN-MESSAGE` RETURN-CODE: `RETURN-CODE` `#salesdocument`: `SALESDOCUMENT` </pre> </body> </html> 4.2. ORDER FLOW FILE To create the sales order the BAPI BAPI_SALESORDER_CREATEFROMDATA is called. This RFC has the same interface as the BAPI_SALESORDER_SIMULATE so we need to call the script "init". In the script there is a check to see if a different ship to was entered, which must be supplied with additional values accordingly. <flow> <state name="simulate"> <module name="BAPI_SALESORDER_CREATEFROMDATA" stateful="0" type="RFC"> </module>
</state> <state name="init"> <module name="init" stateful="0" type="SCRIPT"> <default next_state="simulate"> </default> </module>
</state> <event name="ontouch" next_state="getdate"> </event> <state name="getdate"> <module name="Z_GET_DATE" stateful="0" type="RFC"> <default next_state="init"> </default> </module>
</state> </flow> Note: In 4.0B the BAPI BAPI_SALESORDER_CREATEFROMDATA has as error when a different ship to address is entered. The ZIP is not transferred. To correct this apply OSS note 0441210) |