Skip to Content
Author's profile photo Gregor Wolf

SDN Contest: SAP on Rails in a real Business Application

Update Oct, 18th 2006: Functions are now also avaliable as a Web Service. You can download the WSDL and then start developing using the Web Service. Username and Password for HTTP Basic Authentication is SDNCONTEST. Piers Harding provided already a Ruby, Ruby on Rails, and SAP Web Services Integration how to do that.

Siteco currently provides its customers access to online price, availability and order information through an ITS Flow Logic application. We currently integrate this application into our corporate website. It is based on the Open Source web content management system Typo3 written in PHP. We write our own extensions for Typo3 to access SAP using SOAP Web Services.

Playing around with Ruby on Rails I thought wouldn’t it be better to do it or at least Prototypes for new Features to directly show them our Sales people. We can benefit from Rails advantages: Clear Model View Controller Concept, Don’t Repeat Yourself (DRY) and AJAX awareness. Using Piers Harding’s saprfc and sap4rails this should be possible.

To start developing the Rails application you can use Craig Cmehil’s great Scripting in a Box v0.1 Package which already includes Ruby on Rails. To make it work correctly with the Eclipse RadRails Perspective you have to apply the Patches described in URL for the Ruby on Rails example in Scripting in a Box Version 0.1.0.


This is the prize for the best implementation in the Contest – a Siteco Vistosa task light:


Business Case


Navigation after Login:

Welcome Screen:

Availability check and price information:

Sales Order Status:

Sales Order Details:

PDF of Delivery Note:

Change Password:

Test Environment

To allow everyone to compete to this contest I’ve opened an ERP 2004 system to the public with a special User having only authorizations for the needed functionality. You find the login information in the Ruby Unit Test.

Used BAPI’s:

This BAPI’s are used to achieve the functionality shown in the Business case:

Create Internet User in Transaction SU05

The User I’ve created has the Contact Person ID 111 the Type is BUS1006001 which is a Business partner employee. The password is set to test1.

Ruby Unit Test

Here is the code of the Ruby Unit Test:

require 'test/unit' require 'test/unit/assertions' require 'rubygems' require_gem 'saprfc'   class SAPTest < Test::Unit::TestCase # Login Data @@partneremployeeid = "111" @@password = "test1" @@newpassword = "test2" # Product Data @@material = 'P-100' @@unit = '' # Values set during Test @@customer = '' @@salesorg = '' @@subtotal1 = '' @@subtotal2 = '' def setup SAP::Rfc.useCache = true @rfc = :ashost => "", :sysnr => 00, :lang => "EN", :client => "800", :user => "SDNCONTEST", :passwd => "SDNCONTEST", :trace => 0 ) end def test_CSC_00005_Login # Check Password pwcheck ="BAPI_PAR_EMPLOYEE_CHECKPASSWOR") pwcheck.PARTNEREMPLOYEEID.value = @@partneremployeeid pwcheck.PASSWORD.value = @@password ret = pwcheck.RETURN.value assert(ret['TYPE'] == 'S') # Get Customer Number excheck ="BAPI_PAR_EMPLOYEE_CHECKEXISTEN") excheck.PARTNEREMPLOYEEID.value = @@partneremployeeid @@customer = excheck.CUSTOMER.value assert( @@customer != nil) #puts "
Customer Number: " + @@customer # Get Sales Areas getsalesareas ="BAPI_CUSTOMER_GETSALESAREAS") getsalesareas.CUSTOMERNO.value = @@customer ret = getsalesareas.RETURN.value assert(ret['TYPE'] == 'S') getsalesareas.SALESAREAS.hashRows {|x| @@salesorg = x['SALESORG'] } assert(@@salesorg == '1000') end   def test_CSC_00010_CustomerDetail customerdetail ="BAPI_CUSTOMER_GETDETAIL2") customerdetail.CUSTOMERNO.value = @@customer ret = customerdetail.RETURN.value assert(ret['TYPE'] != 'E') address = customerdetail.CUSTOMERADDRESS.value puts "
Customer Name: " + address['NAME'] assert( address['NAME'] != nil ) end   def test_CSC_00012_ContactDetail contactdetail ="BAPI_BUSPARTNEREMPLOYE_GETLIST") idrange = contactdetail.IDRANGE.structure idrange.SIGN.value = 'I' idrange.OPTION.value = 'EQ' idrange.LOW.value = @@partneremployeeid contactdetail.IDRANGE.value = [ idrange.value ] contactdetail.ADDRESSDATA.hashRows { |x| assert( x['LASTNAME'] != nil ) puts "
Contact last name: " + x['LASTNAME'] } end   def test_CSC_00015_ChangePassword # Change Password changepassword ="BAPI_PAR_EMPLOYEE_CHANGEPASSWO") changepassword.PARTNEREMPLOYEEID.value = @@partneremployeeid changepassword.PASSWORD.value = @@password changepassword.NEW_PASSWORD.value = @@newpassword changepassword.VERIFY_PASSWORD.value = @@newpassword ret = changepassword.RETURN.value assert(ret['TYPE'] == 'S') # Back to default changepassword.PASSWORD.value = @@newpassword changepassword.NEW_PASSWORD.value = @@password changepassword.VERIFY_PASSWORD.value = @@password ret = changepassword.RETURN.value assert(ret['TYPE'] == 'S') end def test_CSC_00020_Salesorders # Salesorder List salesorderlist ="BAPI_SALESORDER_GETLIST") salesorderlist.CUSTOMER_NUMBER.value = @@customer salesorderlist.SALES_ORGANIZATION.value = @@salesorg salesorderlist.TRANSACTION_GROUP.value = 0 ret = salesorderlist.RETURN.value assert(ret['TYPE'] != 'E') salesorderlist.SALES_ORDERS.hashRows {|x| @sddoc = x['SD_DOC'] } assert( @sddoc != nil) puts "
Sales Document Number: " + @sddoc # Salesorder salesorder ="BAPISDORDER_GETDETAILEDLIST") view = salesorder.I_BAPI_VIEW.structure view.HEADER.value = 'X' view.ITEM.value = 'X' salesorder.I_BAPI_VIEW.value = view.value salesdocs = salesorder.SALES_DOCUMENTS.structure salesdocs.VBELN.value = @sddoc salesorder.SALES_DOCUMENTS.value = [ salesdocs.value ] salesorder.ORDER_ITEMS_OUT.hashRows {|x| @doc_number = x['DOC_NUMBER'] } assert( @sddoc == @doc_number ) end def test_CSC_00030_MaterialDetails # Material Detail materialdetail ="BAPI_MATERIAL_GET_DETAIL") materialdetail.MATERIAL.value = @@material ret = materialdetail.RETURN.value assert(ret['TYPE'] == 'S') materialgeneral = materialdetail.MATERIAL_GENERAL_DATA.value @@unit = materialgeneral['BASE_UOM'] assert( @@unit != nil) puts "
Material Unit: " + @@unit end   def test_CSC_00040_Availability materialavailability ="BAPI_MATERIAL_AVAILABILITY") materialavailability.MATERIAL.value = @@material materialavailability.UNIT.value = @@unit # Read Plants of Material materialplants ="MATERIAL_READ_PLANTS") materialplants.MATNR.value = @@material # Check Availability for every Plant totalavailability = 0.0 materialplants.PLANTS.hashRows { |x| @plant = x['WERKS'] materialavailability.PLANT.value = x['WERKS'] assert( materialavailability.AV_QTY_PLT.value != nil) totalavailability = totalavailability + materialavailability.AV_QTY_PLT.value.to_f } assert( totalavailability >= 0) puts "
Availability total: " + totalavailability.to_s end def test_CSC_00050_Price salesordersimulate ="BAPI_SALESORDER_SIMULATE") # Order Header orderheader = salesordersimulate.ORDER_HEADER_IN.structure orderheader.DOC_TYPE.value = 'AG' orderheader.SALES_ORG.value = @@salesorg # This is needed because of an error in saprf-0.18 orderheader.REQ_DATE_H.value = '00000000' orderheader.PURCH_DATE.value = '00000000' orderheader.PRICE_DATE.value = '00000000' orderheader.QT_VALID_F.value = '00000000' orderheader.QT_VALID_T.value = '00000000' orderheader.CT_VALID_F.value = '00000000' orderheader.CT_VALID_T.value = '00000000' salesordersimulate.ORDER_HEADER_IN.value = orderheader.value # Order Items orderitems = salesordersimulate.ORDER_ITEMS_IN.structure orderitems.MATERIAL.value = @@material orderitems.REQ_QTY.value = '0000000001000' salesordersimulate.ORDER_ITEMS_IN.value = [ orderitems.value ] # Order Partners orderpartners = salesordersimulate.ORDER_PARTNERS.structure orderpartners.PARTN_ROLE.value = 'AG' orderpartners.PARTN_NUMB.value = @@customer salesordersimulate.ORDER_PARTNERS.value = [ orderpartners.value ] # Call Function ret = salesordersimulate.RETURN.value puts "
Return Message: " + ret['MESSAGE'] salesordersimulate.ORDER_ITEMS_OUT.hashRows { |x| @@subtotal1 = x['SUBTOTAL1'].to_f @@subtotal2 = x['SUBTOTAL2'].to_f assert( 0 < @@subtotal1) assert( 0 < @@subtotal2 ) assert( @@subtotal1 >= @@subtotal2 ) } puts "
List Price: " + @@subtotal1.to_s puts "Net Price: " + @@subtotal2.to_s end def teardown @rfc.close() end end

How to participate to the contest?

Publish your Application as a Blog or Article here in SDN. If you don’t have a Blogger account it’s a good reason to become a Blogger now. Deadline is November, 30th 2006, 19 p.m. CET. For discussions please use the Topic SDN Contest: SAP on Rails in a real Business Application in the Scripting Languages Forum.

Assigned tags

      Be the first to leave a comment
      You must be Logged on to comment or reply to a post.