This wiki explains how to create web service from function modules (tcode SE37) and consume it in .NET (C#). This method usually is used when a non-SAP system (such as .NET) wants to interact with SAP. For example : for posting to FI. Let's follow the steps :
1. Create Function modules in SE 37. Go to tcode SE37. Enter the name of function modules and click button Create
2. Enter description for this function module and Set the attributes to "Remote Enabled Module". if you want to generate web service, you must set the processing type to "Remote Enabled Module"
3. Go to the next tab. Click "Import" Tab. Enter Import parameter needed. You must tick "Pass by value" check box in function modules that will be used as web service. In this case the associated type for Header is ZUST_AGRI_POST_CH_VAL_HEADER.
here is the structure of ZUST_AGRI_POST_CH_VAL_HEADER.
4. Go to next tab. Click "Export" tab. Don't forget to tick "Pass by value" checkbox like step 3
5. "Changing" tab is empty. Go to next tab. Click "Tables" tab.
Here is the structure of ZUST_AGRI_POST_CH_VAL_ITEM
6. Go to the last tab. Click "Source code" tab. Copy these codes.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 |
FUNCTION ZUAGRICH_POST_AMOUNT. *"---------------------------------------------------------------------- *"*"Local Interface: *" IMPORTING *" VALUE(HEADER) TYPE ZUST_AGRI_POST_CH_VAL_HEADER *" EXPORTING *" VALUE(COMMIT_RETURN) LIKE BAPIRET2 STRUCTURE BAPIRET2 *" TABLES *" GL_ACCOUNT STRUCTURE ZUST_AGRI_POST_CH_VAL_ITEM *" AMOUNT TYPE RE_T_BAPIACCR09 *" RETURN STRUCTURE BAPIRET2 *" ACC_PAYABLE TYPE RE_T_BAPIACAP09 *"---------------------------------------------------------------------- DATA : lt_gl_account TYPE re_t_bapiacgl09, ld_gl_account TYPE bapiacgl09, ld_gl_account2 TYPE bapiacgl09, lt_accountreceivable TYPE re_t_bapiacar09, lt_accountpayable TYPE re_t_bapiacap09, lt_currencyamount TYPE re_t_bapiaccr09, ld_currencyamount TYPE bapiaccr09, ld_currencyamount2 TYPE bapiaccr09,
* ld_currencyamount3 TYPE bapiaccr09, * lt_return TYPE /eacc/t_bapiret2, * lt_criteria TYPE bapiackec9_tab, ld_account TYPE ZUST_AGRI_POST_CH_VAL_ITEM,"zust_agri_post_bkm_val_item, * ld_account2 TYPE zust_agri_post_bkm_val_item, ld_amount TYPE bapiaccr09, ld_header TYPE bapiache09, ld_ap TYPE bapiacap09, intLine type POSNR_ACC.
intLine = 1.
MOVE-CORRESPONDING header TO ld_header. ld_header-bus_act = 'RFBU'. LOOP AT gl_account INTO ld_account. MOVE-CORRESPONDING ld_account TO ld_gl_account. APPEND ld_gl_account TO lt_gl_account. intLine = intLine + 1. ENDLOOP. * LOOP AT acc_payable INTO ld_ap. APPEND ld_ap TO lt_accountpayable. ENDLOOP.
* intLine = 1.
loop at amount into ld_currencyamount. * ld_currencyamount-ITEMNO_ACC = intLine. APPEND ld_currencyamount TO lt_currencyamount. * intLine = intLine + 1. endloop.
refresh return. clear commit_return. CALL FUNCTION 'BAPI_ACC_DOCUMENT_POST' EXPORTING documentheader = ld_header TABLES accountgl = lt_gl_account accountreceivable = lt_accountreceivable accountpayable = lt_accountpayable currencyamount = lt_currencyamount return = return.
CALL FUNCTION 'BAPI_TRANSACTION_COMMIT' EXPORTING wait = 'X' IMPORTING return = commit_return.
ENDFUNCTION.
|
7. Save the codes, assign to package and new Transport request number, then activate the function modules.
8. Next steps are generating the web service. Click "Utilities" -> "More Utilities" -> "Create web service" -> "From Function module"
9. Then "Provide Service Definition details" shows up. Enter web service name and its description, then click Continue. Usually I add "WS" to the prefix to differentiate the web service name and function module name.
10. On step "Choose Endpoint", just leave as it is. Click continue.
11. Next, on step "Configure service", don't forget to tick "Deploy Service", then click continue
12. On step "Enter package/request", Enter your package and transport request no, then click continue
13. Done. Your web service is activated.
14. Next step, create endpoint via tcode SOAMANAGER. This tcode will open web configuration tools via your web browser. Remember your browser must be Internet Explorer , otherwise the system won't run well
14b. If you face any issues regarding cannot open the web configuration tools, read this step. If you have don't have any issues opening the web configuration tools, you can skip this step and please read step 15. The URL will be like this (http://devecc.indofood.co.id:8080/sap/bc/webdynpro/sap/appl_soap_management?sap-client=530&sap-language=EN) :
Usually the problem is your computer cannot recognize the domain such as devecc.indofood.co.id , to resolve this issue, you must open your hosts file on C:\Windows\System32\drivers\etc\hosts , Enter your [SAP IP][space][domainname] under the last line of the hosts file (example : 172.30.52.102 devecc.indofood.co.id) like this picture and don't forget to save
You can get your SAP IP via SAP GUI :
To test the connection , open command prompt, press [Windows]+R , type cmd
Enter this command to the command prompt : ping[space][yourdomainname] ,example : ping devecc.indofood.co.id . The result will return result similar like this if your computer successfully recognize the SAP server IP:
Refresh your page in internet explorer.
15. The web configuration tools will be shown like this.
16. Enter your SAP username and password
17. The web configuration tools will be shown. Click "Business Administration" tab, then click "Web service administration" link
18. Web Administration menu shows up. First, click dropdown "Search by", choose "Service". Second, enter your search pattern, example : ZUAGRICHWS*POST*. Last, click button "Go"
19. The result will be shown on the Search results table below. Usually only 5 results are shown. If the results is more that that, you can click up or down arrow on the bottom of the search results table (marked by blue circle). Choose your web service by clicking the left column of chosen row. The row will be highlighted like image below. Then click "Apply selection" button.
20. After that, "Detail of service definition" window will be shown. Usually there are two conditions:
- if the dropdown in the right most is empty, then it means the service endpoint hasn't been created. you have to create service first. It will be explain in the next steps.
- if the dropdown in the right most isn't empty, then it means the service endpoint has been created. Just click "Open WSDL document for selected binding" link to open your WSDL document. (or skip to step 25)
21. To create service endpoint, click "Configuration" tab, then click "Create service"
22. Enter new service name (I give the same name as web service name, ex: ZUAGRICHWS_POST_AMOUNT), enter description , and enter new binding name (ex : ZUAGRICHWS_POST_AMOUNT). Then click apply settings
23. "Configuration of Web service" window shows up below the "Detail of service definition" window. Tick "User ID/Password" on HTTP Authentication box until "Collected Authentication method" have one row in its table. Then click Save button.
24. Notice that one new row appear on the "Detail of Service definition" table. Click "Overview" tab
25. Notice that the right most dropdown is not empty anymore. You have successfully created your endpoint. Click "Open WSDL for selected binding" link to open your WSDL document
26. The WSDL document URL will be similar like this : http://devecc.indofood.co.id:8080/sap/bc/srt/wsdl/bndg_4C73AADA27CC02CCE1008000AC1E3466/wsdl11/allinone/ws_policy/document?sap-client=530 , the content will be similar like image below.
27. Because there is some bugs from SAP , we cannot directly consume this web service. We have to save this WSDL document to local file (with *.wsdl extension) and fix it. Click "File" - "Save as" in IE Menu Bar, enter file name D530_ZUAGRICHWS_POST_AMOUNT.wsdl. Usually I use naming convention like this [SAPType]_[WebServiceName].wsdl to indicate that this is web service on Development server client 530.
28. Change some parts of the wsdl file to fix the bugs before it's consumed by .NET (by using text editors like notepad/ Textpad / Visual Studio).
- First, change "parameters" to "parameter".
result:
- Second, if you are using BAPI, change "System" to "SYSTEM" (we have to change it to uppercase because in .NET will conflict with .NET System namespace).
result:
- Third we have to change domain name to IP and fix its corresponding port, if you haven't applied SAP note 1263112, whatever your SAP port settings, it will always show 443 instead of correct port, in this case 8080. There are some people have issues with this problem in
http://forums.sdn.sap.com/thread.jspa?threadID=1419721&start=0&tstart=0 (example : devecc.indofood.co.id:443 -> change it to 172.30.52.102:8080).
result:
Why you should change domain to IP ? becase not all web service consumer recognize the domain (devecc.indofood.co.id) as 172.30.52.102. (except you have a good DNS server). If the consumer don't know this domain, when they call this web service, they will throw exception / error.
Don't forget to save the document.
29. Next step is to place this WSDL document to virtual direcory in order to be able to be accessed by other computers. You can place this document at your computer (
http://localhost/services) or on server (ex:
http://10.126.140.46/services) . The steps to create virtual directory is not covered this tutorial. You can create it in Internet Information Services (IIS) Manager (command : inetmgr)
You can test the web service by entering the URL on your browser. If successful, it will return result similar like this
31. Your web service has been successfully deployed :D Now Open your visual studio 2008. Add web reference from this web service
Enter your web service URL, click Go, then enter your web reference name that will be used in the code (ex : SAPWSD530POST), Click "Add reference"
32. Use this code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 |
SAPWSD530POST.ZUAGRICHWS_POST_AMOUNT4 s = new SAPWSD530POST.ZUAGRICHWS_POST_AMOUNT4(); s.Credentials = nc;
SAPWSD530POST.ZuagrichPostAmount param = new SAPWSD530POST.ZuagrichPostAmount(); #region header SAPWSD530POST.ZustAgriPostChValHeader h = new SAPWSD530POST.ZustAgriPostChValHeader(); h.Username = data.Header.Username; h.HeaderTxt = data.Header.HeaderText; h.CompCode = data.Header.CompanyCode; h.DocDate = string.Format("{0}-{1}-{2}", data.Header.DocumentDate.Year, data.Header.DocumentDate.Month.ToString("00"), data.Header.DocumentDate.Day.ToString("00")); h.PstngDate = string.Format("{0}-{1}-{2}", data.Header.PostingDate.Year, data.Header.PostingDate.Month.ToString("00"), data.Header.PostingDate.Day.ToString("00")); //h.TransDate = string.Format("{0}-{1}-{2}", data.Header.TranslationDate.Year, data.Header.TranslationDate.Month, data.Header.TranslationDate.Day); h.TransDate = ""; h.FiscYear = data.Header.FiscalYear.ToString(); h.FisPeriod = data.Header.FiscalPeriod.ToString("00"); h.DocType = data.Header.DocumentType; #endregion //assign header to param param.Header = h;
//GL Account table //SAPWSQ615POST4.ZustAgriPostChValItem[] g = new SAPWSQ615POST4.ZustAgriPostChValItem[data.Details.Count]; List<SAPWSD530POST.ZustAgriPostChValItem> glaccs = new List<SAPWSD530POST.ZustAgriPostChValItem>(); //Amount table //SAPWSQ615POST4.Bapiaccr09[] a = new SAPWSQ615POST4.Bapiaccr09[data.Details.Count]; List<SAPWSD530POST.Bapiaccr09> amounts = new List<SAPWSD530POST.Bapiaccr09>(); //Account payable table List<SAPWSD530POST.Bapiacap09> aps = new List<SAPWSD530POST.Bapiacap09>();
// int idx = 0;
foreach (PostingJournal detail in data.Details) { if (string.IsNullOrEmpty(detail.VendorNo)) { SAPWSD530POST.ZustAgriPostChValItem obj = new SAPWSD530POST.ZustAgriPostChValItem(); //g[idx] = new SAPWSQ615POST4.ZustAgriPostChValItem(); obj.ItemnoAcc = detail.AccountingDocLineItemNo.ToString("0000000000"); obj.GlAccount = detail.GLAccount; obj.ItemText = detail.ItemText; obj.DocType = detail.DocumentType; obj.CompCode = detail.CompanyCode; obj.BusArea = detail.BusinessArea; obj.FisPeriod = detail.FiscalPeriod.ToString("00"); obj.FiscYear = detail.FiscalYear.ToString(); obj.PstngDate = string.Format("{0}-{1}-{2}", detail.PostingDate.Year, detail.PostingDate.Month.ToString("00"), detail.PostingDate.Day.ToString("00")); obj.AllocNmbr = detail.AssignmentNo; //g[idx].ProfitCtr = detail.ProfitCenter; obj.ProfitCtr = ""; obj.Costcenter = detail.CostCenter; obj.WbsElement = detail.WbsElement; //added to accommodate jamsostek posting //g[idx].VendorNo = detail.VendorNo; glaccs.Add(obj); } else { SAPWSD530POST.Bapiacap09 obj3 = new SAPWSD530POST.Bapiacap09(); obj3.ItemnoAcc = detail.AccountingDocLineItemNo.ToString("0000000000"); obj3.VendorNo = detail.VendorNo; obj3.CompCode = detail.CompanyCode; obj3.BusArea = detail.BusinessArea; obj3.AllocNmbr = detail.AssignmentNo; obj3.ItemText = detail.ItemText; aps.Add(obj3);
} SAPWSD530POST.Bapiaccr09 obj2 = new SAPWSD530POST.Bapiaccr09(); //a[idx] = new SAPWSQ615POST4.Bapiaccr09(); obj2.ItemnoAcc = detail.AccountingDocLineItemNo.ToString("0000000000"); obj2.Currency = "IDR"; obj2.AmtDoccur = detail.AmountDocumentCurrency; amounts.Add(obj2); //idx++; } //assign amount and GL account to param param.GlAccount = glaccs.ToArray(); param.Amount = amounts.ToArray(); param.AccPayable = aps.ToArray(); //result table //just fill with zero, even though no parameters is needed //assign to param's inner variable param.Return = new SAPWSD530POST.Bapiret2[0]; SAPWSD530POST.ZuagrichPostAmountResponse result; try { result = s.ZuagrichPostAmount(param); foreach (SAPWSD530POST.Bapiret2 item in result.Return) { if (item.Type == "S") //success { List<SapPostingError> errors = new List<SapPostingError>(); foreach (SAPWSD530POST.Bapiret2 item2 in result.Return) { errors.Add(new SapPostingError(item2.Type, item2.Message)); } //lblStrSuccess.Text = "Posting sukses. No dokumen : " + item.MessageV2.Substring(0, 10); return new PostingResult(PostingResultType.Success, item.MessageV2.Substring(0, 10), errors); //break; } else if (item.Type == "E") //error { List<SapPostingError> errors = new List<SapPostingError>(); foreach (SAPWSD530POST.Bapiret2 item2 in result.Return) { errors.Add(new SapPostingError(item2.Type, item2.Message)); } //ltStrErr.Text = ltStrErr.Text + "Posting error. Error message : " + item.Message + "<br />"; return new PostingResult(PostingResultType.Error, item.Message, errors); } }
} catch (Exception ex) { throw ex; }
|
33. That's it. Just test using above codes. Customize the codes according to your needs. It works well in my system. Hope this tutorial helps.
No comments:
Post a Comment