Have you ever needed to integrate your rails Web application or API to a SAP backend server?
Have you tried to optimize some process workflow or even expose some relevant information to an internal or external website?
There have been so many occasions when I had to integrate the SAP server to the outter world... and I've been used virtually all available options out there.
This project is a way to return to the community what I have needed and built along the way.
This Gem simplifies that process of calling SAP RFC (Remote Function Call) functions, making it quick to get information back from SAP into a Ruby/Rails apps.
The following function calls are available:
RFC | Function | Status |
---|---|---|
RFC_READ_TABLE | Reads an SAP table, returning the requested columns | stable |
BAPI_REQUISITION_GETDETAIL | Obtains information from a Purchase Requisition | stable |
BAPI_REQUISITION_GETRELINFO | Gets information from a P.Req. release strategy | stable |
BAPI_TRANSACTION_COMMIT | Commits work | stable |
BAPI_TRANSACTION_ROLLBACK | Rolls back work | stable |
AUTHORITY_CHECK | Checks if an user has authorization for some object | stable |
BAPI_REQUISITION_RELEASE_GEN | Purchase Requisition Release (strategy) header level | stable |
BAPI_REQUISITION_RELEASE | Purchase Requisition Release (strategy) item level | stable |
This is the list of RFCs to be added here:
RFC | Function | Status |
---|---|---|
BAPI_PO_GETDETAIL1 | Gets details from a Purchase Order | WIP |
BAPI_PO_GETRELINFO | Gets Release information for a PO | WIP |
BAPI_PO_RELEASE | Releases a Purchase Order (Release Strategy) | pipeline |
BAPI_GOODSMVT_CREATE | Posts Goods Movement | pipeline |
WIP: Work in progress Pipeline: planned to be done
The NetWeaver SAP RFC framework allows for C/C++ calls to SAP Remote Function Call routines, called Function Modules.
There are always some concerns when doing lib calls, as requirements are not always thought to be the same way as in Ruby.
In some scenarios, we need to have the return as class instances.
This gem carries the calls, returning Ruby-like class instances as return, that you can than use in your projects
This project depends on the 'nwrfc' gem, which in turn depends on Ruby ffi to make library calls.
This project also depends on the SAP NW RFC library, which is only available through the SAP connectors, which can be found at their homepage https://support.sap.com/en/product/connectors/nwrfcsdk.html.
Unfortunatelly, it's required to have SAP access and authorization to download this file.
I'm in a early stage development and I would deeply appreciate support from the community to implement the functionalities foreseen for this gem, as well as propose fixes to issues.
For this matter, this gem licence is MIT, therefore you can use and modify it as much as you want, as long as you do the proper reference to my gem.
When you know where to look for, SAP will provide almost all its information through
table reading. the method read_table
will read the SAP table and return it
as an array of objects.
The code below:
- Carries a SAP Table reading, returning the fields requested in an array of objects with the name of that table
- fields: array with SAP field names
- read_table: takes the SAP table name and which fields as arguments. The 'where' clause isn't implemented yet
- list: returns an array of Lfa1 objects, containing an attribute for each SAP field requested
Connecting to SAP
Although this example shows 'open' user, password and connection options, keep in mind
you can use (since Rails 5.2) the Secrets option to securelly store data.
# declare SAP logon info and creates the connection
logon_info = { 'user' => 'user',
'passwd' => 'password',
# 'trace' => 2,
'client' => '100',
'ashost' => 'server.com',
'sysnr' => '00' }
conn = RnSap::Sap.new(logon_info)
Reading the entire content of a table
In this example the table LFA1 (Vendor's A segment - cross company view)
is read entirely, retreaving the vendor Name, its code and its country.
# declare which fields will be read from SAP
fields = %w[NAME1 LIFNR LAND1]
# list returns an array of Lfa1 objects
list = conn.read_table('lfa1', fields, [])
puts "-------- LFA1 - lista final ---------"
puts "Count: #{list.count}"
list.each do |item|
puts( "Vendor: #{item.lifnr} / #{item.land1} / #{item.name1}")
end
Reading with filters
In this example the table MARA (Material general view) is read
with the filter for Material Type (MTART) being "Raw Material" (ROH)
fields = %w[MATNR MTART MEINS]
list = conn.read_table('mara', fields, ['MATNR = "ROH"'])
puts "-------- MARA - lista final ---------"
puts "Count: #{list.count}"
list.each do |item|
puts( "Material: #{item.matnr} / #{item.mtart} / #{item.meins}")
end
Passing additional parameters via Hash
From version 0.3.0 onwards, it's now possible to pass Hash parameters as well.
The method now assumes that the entire result should be returned, but now also
allows to inform from which row the result is expected (Row Skip) and
how many result rows (if available) are expected (Row Count).
# ================= Reading tables - hash parameters ====================
# The 'where' clauses are passed as an array of strings
@list3 = conn.read_table({ name: 'MARA', fields: fields, clauses: ["MTART = 'ROH'"], row_skip: 1, row_count: 2 })
puts '-------- MARA - Filtered for Raw Materials - Skip: 1 row; Count: 2 rows ---------'
puts "Count: #{@list3.count}"
@list3.each do |item|
puts("Material: #{item.matnr} / Creator: #{item.ernam}")
end
When the Purchase requisition number is already known (ex: you obtained it through reading
table EBAN), the method preq_detail
will provide all information related
to it, including descriptions, account assignment objects (ex: cost center) and texts.