Skip to Content
Technical Articles

Extend SAP AIN Equipment Creation process using SCP Workflow Service – Part 2/2

This blog is a continuation of my previous blog post, where I gave an overview on how we can leverage SCP Workflow to extend the Equipment Creation process in SAP Asset Intelligence Network with data quality and governance.

In this blog, I will take you through the technical implementation details in 6 Steps. Let’s get started:

Step 1 : Set up Authorizations for Equipment Data Reviewer and Equipment Data Creator (Manager) in SCP

Create 2 groups AIN_Equipment_Reviewers and AIN_Equipment_Managers and assign users to these groups.

Step 2 : Set up organizational units and user authorizations in AIN User Authorization App.

You can use the User Authorization application to define a granular access to asset modeling business objects like for eg., Equipments for users in your organization.

I have created two organizational units here “Reviewers” and “Managers” and assigned the groups i created in Step 1 to the corresponding organizational units with ‘Read’ access to Reviewers and ‘Delete’ authorization for Managers. I have deliberately not assigned any business objects(equipments) here. I will be doing that dynamically from within my workflow using the AIN User Authorization APIs. You will see this further in Step 5.

Step 3 : Create a destination to access the AIN APIs inside the workflow.

Lets at this point take a look at the AIN API that we are going to use.

We will use one of the User Authorization APIs provided by AIN to dynamically add/remove business objects to an organizational unit. Here’s the documentation.

Briefly recall that we created two organizational units in Step 2 and assigned relevant authorizations to User groups. We will now use this API to add the specific equipment under approval process to the Reviewer and the Manager organizational unit from within the workflow. In order to consume this API inside the workflow, I have created a destination configuration for the APIs.

Step 4 : Extend Equipments application for usage inside Fiori My Inbox as custom Task UI.

There are multiple resources out there explaining how to create a custom Task UI. For the most part you can follow the SCP Workflow documentation or this tutorial by DJ Adams on SAP Developer Center. Let me get into specifics of some of the things that I did for this scenario.

Note: I did implement some workarounds which may not be required in all cases. Also, some of the workarounds may not be best suited for productive use cases.

I extended the standard Equipment application once to act as a custom Task UI for both Reviewer task and Creator task. I reused the extended application in both cases.The following table describes the behavior expected of the task application,

 Reviewer Custom UI Manager Custom UI Where is the implementation?
1.  Action Buttons Approve (Positive) , Reject (Negative) Complete(Positive) Logic implemented inside the Custom Task UI application
2. Context Display the data for the equipment which triggered the workflow Display the data for the equipment which triggered the workflow Logic implemented inside the Custom Task UI application
3. Data Read-only Editable Standard Equipment application takes care of this based on User Authorizations defined in Step 2. (Further see Step 5.c and Step 5.e to know how the equipment is added to the org units defined in the User Authorization app)

Step 4.a. In order to create action buttons based on whether the UI is rendered for a reviewer task or a manager/creator task, I pass a parameter as an identifier from the user task configuration in the workflow. (Described in Step 5.d and 5.f. ) This parameter can be accessed using the component startup parameters. I use this value to either create the Approve/Reject button or the Complete button.

this.sap.iot.ain.manageequipments.Component.extend("sap.iot.ain.manageequipments.manageequipmentsExtension.Component", {
	metadata: {
		manifest: "json"
	},

	init: function () {
          
          //other code
          ..........
          ..............
          sap.iot.ain.manageequipments.Component.prototype.init.apply(
			this, arguments);

	 // get parameter value from startupParameters
	var startupParameters = this
		.getComponentData().startupParameters;
	var sMode = startupParameters.oParameters.oQueryParameters.operation[0];

        //other code
        ..........
        ..............

       //Create Action buttons
       // Reject
	var oNegativeAction = {
		sBtnTxt: "Reject",
		onBtnPressed: function () {
			that._triggerComplete(
				     that.oComponentData.inboxHandle.attachmentHandle.detailModel
						.getData().InstanceID,
						false,
						jQuery
						.proxy(
							that._refreshTask,
							that));
		}
	};

	// Accept
	var oPositiveAction = {
		sBtnTxt: "Approve",
		onBtnPressed: function () {
			that._triggerComplete(
				that.oComponentData.inboxHandle.attachmentHandle.detailModel
						.getData().InstanceID,
						true,
						jQuery
						.proxy(
							that._refreshTask,
							that));
		}
	};

	//Complete
	var oCompleteAction = {
		sBtnTxt: "Complete",
		onBtnPressed: function () {
			that._triggerComplete(
				that.oComponentData.inboxHandle.attachmentHandle.detailModel
						.getData().InstanceID,
						true,
						jQuery
						.proxy(
							that._refreshTask,
							that));
			}
	};

        //create action buttons based on the value of the parameter sent from workflow
	if (sMode !== 'change') {
		// Add the Accept & Reject buttons
		startupParameters.inboxAPI
			.addAction({
					action: oPositiveAction.sBtnTxt,
					label: oPositiveAction.sBtnTxt,
					type: "Accept"
				},oPositiveAction.onBtnPressed);

		startupParameters.inboxAPI
			.addAction({
					action: oNegativeAction.sBtnTxt,
					label: oNegativeAction.sBtnTxt,
					type: "Reject"
				},oNegativeAction.onBtnPressed);
	} else {
		startupParameters.inboxAPI
			.addAction({
					action: oCompleteAction.sBtnTxt,
					label: oCompleteAction.sBtnTxt,
					type: "Accept"
				},oCompleteAction.onBtnPressed);
		}
      
        //other functions
        ..........
        ..............
});

Step 4.b. In order to load data for a single equipment record for a specific equipment in context, I did the following :

  • Pass the equipment id as a parameter from workflow into the component startup parameters of the extended application component. See Step 5.d and 5.f.
  • I defined a new route in the manifest.json file of the extended application to handle the detailed view route for My Inbox and load the Equipment Detail view instead of the Equipment List view.
    "routing": {
    			"routes": {
    				"detail": {
    					"pattern": "detail/{SAP__Origin}/{InstanceID}/{contextPath}",
    					"view": "sap.iot.ain.manageequipments.view.EquipmentComponentPage"
    				}
    			}
    		}​
  • I had to override one of the internal methods to handle the route when the application is rendered inside My Inbox, get the equipment id from the startup parameters , prepare the navigation context object and trigger the corresponding route (in the standard Equipment application) for displaying equipment details
    sap.iot.ain.lib.reusable.view.component.ComponentBaseController.prototype.mHandleNavigation = function (oEvent) {
    	var sRoute = oEvent.getParameter("name");
    	var oParams = oEvent.getParameter("arguments");
    	var oObjectPageParams;
    	if (sRoute === "detailsWithQueryParam") {
    		oParams = {
    			id: jQuery.sap.getUriParameters().get("id") //Might change to an argument if 1880004348 can be resolved
    		};
    	} else if (sRoute === "detail") {
    		var sId = this.getOwnerComponent().getComponentData().startupParameters.oParameters.oQueryParameters.id[0];
    		oParams = {
    			id: sId
    		};
    	}
    	oObjectPageParams = this.fnGetObjectPageParams(oParams);
    	if (sRoute === "componentHierarchyPage" || sRoute === "detailsWithQueryParam" || sRoute === "detail") {
    		
    
                   //other code
                   ..............................................
                   ....................................
    						
    		this._oRouter.fireRoutePatternMatched({
    			name: this.sDETAILSPAGE,
    			arguments: oObjectPageParams
    		});
    	}
    };​

There is another thing that I want to talk about which seems to be a question asked a few times on SCN – Why do service calls or calls to external URL’s from my custom task UI task UI fail when rendered inside My Inbox while they work standalone?                             So, here’s the answer : My Inbox dynamically instantiates the custom task UI component and hence the task UI component is now a child component to the parent “My Inbox” component. All the calls to load the custom task UI resources(js files/images/services etc) are relative to the parent and routed through a specially defined route within the neo-app.json of My Inbox for the purpose of proper routing. Now, for this reason, to access them from inside the custom task UI ,one has to define these calls with /html5apps/<taskui_application_name>/ prepended to the actual path. See blog. However in my case, as i was extending a standard application it was not possible for me to redefine the paths as suggested. So, i intercepted the backend service calls and rerouted the calls relative to the extended application.

$.ajaxSetup({
	beforeSend: function (xhr, settings) {
		if (((settings.url).indexOf("\/ain\/") === 0) || ((settings.url).indexOf("\/ac\/") === 0) || (((settings.url).indexOf("\/aspm\/") > -1) && ((settings.url).indexOf("sap\/fiori\/manageequipmentsrad") !== 0))) {
			settings.url = "sap/fiori/manageequipmentsrad" + settings.url;
		}
	}
});

Note: As I was trying to embed an extension of a standard application, i also had to do a couple of small workarounds by overriding some internal methods. I did it using monkey patching in javascript. This may not be necessary in other cases.

Step 5 : Implement the workflow model

Let’s take a quick look at the workflow model snapshot in the Workflow Editor. For simplicity, I have only implemented the logic for “Approve” action by the Reviewer.

Let’s now take a look at the steps that I executed for creating this model.

5.a. Define a payload which accepts the equipment data for the workflow and assign it to the Start Event.

What you see below is the json structure I created for the payload. In here. I have created a structure so that the complete equipment data is passed into the workflow from the Equipments application, upon triggering the workflow. However, in this specific scenario we are interested only in the equipment id.

5.b. Create request payload for calling the AIN API

Notice that the json structure highlighted in Red is the exact payload expected by the User Authorization API to add/remove a business object to an organizational Unit. See eg in the API documentation linked in Step 3. Also, the equipment Id is read from the workflow context which contains data that is passed from the Equipments application on trigger of the workflow. You will see this in Step 6.

5.c. Call AIN User Authorization API to add equipment into the Reviewer organizational unit.

As discussed earlier we will in this step add the equipment object to the Reviewer organizational unit. Here, the first step is to get the ID of the organization unit that we created. In order to do this let us use another API to get the organizational unit structure. Just a quick example of the actual response on calling this API /ain/rest/api/v1/user-auth/organization/units/structure?uomsystem=metric

Add a service task to call the API.

.

5.d. Add Approval step for Reviewer

Add a user task for the approval step.

Notice the configurations above. The most important points to not are (1) the usage of the workflow context within the configurations. (2) The User Interface configuration which points to the extended version of the Equipments application defined in Step 4. (3) Parameters which are passed into the Equipments application (extended) component instantiated for the purpose of embedding into My Inbox.

Note: Ideally I would add an exclusive gateway at this point to handle Approve / Reject. For simplicity irrespective of the action the reviewer takes I go the next step in my model.
5.e. Call AIN User Authorization API to add equipment into the Manager organizational unit.

Here the steps are exactly the same as Step 5.c , the only change being you use the Manager organization unit ID instead of the reviewer.

5.f. Add manual completion of the workflow by Manager/Creator on publishing the record.

Here the steps are exactly the similar to what is defined in Step 5.d , other than the following change : assign the user task to AIN_Equipment_Managers group. Also the value of the parameter passed to the task UI operation should be ‘change’. As for the details of the application presented to the Manager and its implementation details we have looked at it in Step 4.

This brings us to the end of the implementation and also to the end of this blog.Hope you all got to take something away from here. Cheers!

1 Comment
You must be Logged on to comment or reply to a post.
  • Hello Radhika,

     

    thanks a lot for this blog series!

    Please correct me if I am wrong but as far as I understand all details this was developed on Neo Platform?

    If corerct I have the question if this also works with SAP Cloud Foundry or what has to be changed that it works?

     

    BR

    Reiner