Technical Articles
AI Powered Invoice Management with SAP RAP and ABAP on Cloud – Part 3
All Blogs in this Series –
AI Powered Invoice Management with SAP RAP and ABAP on Cloud
AI Powered Invoice Management with SAP RAP and ABAP on Cloud – Part 1
AI Powered Invoice Management with SAP RAP and ABAP on Cloud – Part 2
AI Powered Invoice Management with SAP RAP and ABAP on Cloud – Part 3
If you want to know the reference of this blog, please go through the Part 1 & Part 2 sections of this AI Powered Invoice Management Series.
This is going to be the last part of the AI Powered Invoice Management Series. What we are focusing here is –
- Creating a Unmanaged scenario
- Creation of a ABAP Workflow
- Creation of a NodeJS based Wrapper on top of the ABAP Unmanaged API
Process Flow
On-premise developments ( Create RAP Unmanaged API )
Create a custom table –
Create CDS Entity
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'Interface of WF Trigger'
define root view entity Z_I_INV_PO_WF
as select from
// zinv_po_status
ekko left outer join
zinv_po_status on ekko.ebeln = zinv_po_status.ebeln
{
// key ekko.ebeln,
key zinv_po_status.ebeln,
zinv_po_status.amount,
zinv_po_status.status
}
Create a Projection view –
@EndUserText.label: 'Peojection view for INV PO WF'
@AccessControl.authorizationCheck: #NOT_REQUIRED
define root view entity Z_P_INV_PO_WF
provider contract transactional_query
as projection on Z_I_INV_PO_WF {
key ebeln,
amount,
status
}
Create Behavior Definition –
unmanaged
implementation in class zbp_i_inv_po_wf unique;
define behavior for Z_I_INV_PO_WF
{
create;
}
projection;
//strict;
define behavior for Z_P_INV_PO_WF //alias <alias_name>
{
use create;
// use update;
// use delete;
}
Implement the Behavior class
CLASS lhc_z_i_inv_po_wf DEFINITION INHERITING FROM
cl_abap_behavior_handler.
PRIVATE SECTION.
METHODS create FOR MODIFY
IMPORTING entities FOR CREATE z_i_inv_po_wf.
METHODS read FOR READ
IMPORTING keys FOR READ z_i_inv_po_wf RESULT result.
ENDCLASS.
CLASS lhc_z_i_inv_po_wf IMPLEMENTATION.
METHOD create.
DATA: ls_line TYPE zinv_po_status,
lt_lines TYPE TABLE OF zinv_po_status.
LOOP AT entities ASSIGNING FIELD-SYMBOL(<ls_entity>).
ls_line = CORRESPONDING #( <ls_entity> ).
APPEND ls_line TO lt_lines.
DATA : lv_objectkey TYPE swr_struct-object_key.
DATA: lt_input_container TYPE TABLE OF swr_cont,
lv_subrc TYPE sy-subrc,
lv_value TYPE swe_evtid,
lt_msglns TYPE TABLE OF swr_messag,
lt_msgstr TYPE TABLE OF swr_mstruc.
lv_objectkey = ls_line-ebeln.
lt_input_container = VALUE #( ( element = 'PurchasingDocument'
value = ls_line-ebeln ) ( element = 'TargetValue' value = ls_lineamount ) ).
CALL FUNCTION 'SAP_WAPI_CREATE_EVENT' STARTING NEW TASK
lv_objectkey
EXPORTING
object_type = 'ZINV_PUORD'
object_key = lv_objectkey
event = 'PROCESS_PAY_FOR_INV'
TABLES
input_container = lt_input_container
message_lines = lt_msglns
message_struct = lt_msgstr.
ENDLOOP.
zcl_inv_payment=>update_table( it_table = lt_lines ).
ENDMETHOD.
METHOD read.
ENDMETHOD.
ENDCLASS.
CLASS lsc_z_i_inv_po_wf DEFINITION INHERITING FROM
cl_abap_behavior_saver.
PROTECTED SECTION.
METHODS finalize REDEFINITION.
METHODS check_before_save REDEFINITION.
METHODS save REDEFINITION.
METHODS cleanup REDEFINITION.
METHODS cleanup_finalize REDEFINITION.
ENDCLASS.
CLASS lsc_z_i_inv_po_wf IMPLEMENTATION.
METHOD finalize.
ENDMETHOD.
METHOD check_before_save.
ENDMETHOD.
METHOD save.
ENDMETHOD.
METHOD cleanup.
ENDMETHOD.
METHOD cleanup_finalize.
ENDMETHOD.
ENDCLASS.
On-premise developments ( Workflow Developments )
Create a basic workflow –
Now implement global variables –
Add decisions Approve and Reject in the Workflow
Configure the bindings
Create Events in SWo1 and set the parameters –
Here are the parameter lists of the workflow –
SAP CF NodeJS Express server to trigger the Workflow
Create a NPM package and create index.js
var express = require('express');
var app = express();
var PORT = 8080;
var lib = require('./lib');
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.post('/trigger_wf', async function (req, res) {
await lib.trigger_wf(req, res);
});
app.get('/', async function (req, res) {
await lib.base(req, res);
});
app.listen(PORT, function (err) {
if (err) console.log(err);
console.log("Server listening on PORT", PORT);
});
Now create the lib.js file
const SapCfAxios = require('sap-cf-axios').default;
const xsenv = require('@sap/xsenv');
module.exports = {
base: async function base(req, res) {
res.send(JSON.stringify({ 'uri': '/trigger_wf' }));
},
trigger_wf: async function trigger_wf(req, res) {
var custurl = process.env['MURL'];
console.log('I am here');
// var data = req.body;
console.log('--------------------')
console.log(req.body);
var data = req.body;
var post_body = {
"ebeln": data.ebeln,
"amount": data.amount,
"status": data.status
}
console.log(post_body);
try {
console.log('--------------------')
const axios_DUMMY_GET = SapCfAxios('DUMMY_GET');
const response = await axios_DUMMY_GET({
method: 'post',
url: custurl,
headers:{
"X-Requested-With" : "X"
},
data: post_body
});
console.log('--------------------')
console.log(JSON.stringify(response.data.d))
res.json({ "STATUS": "Post Successful" });
} catch (error) {
console.log(JSON.stringify(error));
res.json({ "STATUS": "Error in Post", "MES":
JSON.stringify(error) });
}
}
}
and use manifest.yml file to deploy your nodejs to cloud foundry environment
Note – Here sap-cf-axios is used to create a secure communication tunnel to call the on-premise destination through the SAP BTP destination and Cloud Connectors.
Thanks for having patience reading out the blog till the end. Hope to hear from you….
Hi Sabarna
Thank you for the series.
Very interesting
Emmanuel
Thank you for reading 🙏🙏.