Homelab, Linux, JS & ABAP (~˘▾˘)~
 

[JavaScript] Subtract month from date in format yyyyMMdd

//Input String yyyymmdd
var date_string = '20200101'

//Create date object
var oDate = new Date(date_string.substr(0, 4), date_string.substr(4, 2), date_string.substr(6, 2))

oDate.setMonth(oDate.getMonth() - 1)

var year = oDate.getFullYear().toString()
var month = oDate.getMonth().toString()
var day = oDate.getDay().toString()

//Add leading zero's
if (month.length === 1 ) {
	month = '0' + month
}
if (day.length === 1 ) {
	day = '0' + day
}

//Return string: 20191201
var sDate =  year + month + day

[SAPUI5] MyInbox: Integration of Detail View – EmbedIntoDetail

https://launchpad.support.sap.com/#/notes/2305401 (App to App Navigation CookBook.pdf)

https://blogs.sap.com/2020/07/31/fiori-my-inbox-integration-of-custom-detail-page/

Target:

Go to /n/ui2/fpld_cust and define a second target for your App, i.e. approve.

The approve target needs the “emdedIntoDetails” parameter:

SWFVISU:

Add the new target for your WF Task. Here you have access to all attributes of your Workitem-Container. Pass all your mandatory fields you’ve defined in your oData Entity.

Some examples: https://blogs.sap.com/2016/05/31/my-inbox-open-task-swfvisu-configuration/

If your missing some parameters, just add them in your Workitem Task and pass the values directly into it right from your Workflow Container. This looks much better.

Manifest:

Add a route to navigate via Inbox. The pattern has to match your inbox url.

			"routes": [
				{
					"pattern": "",
					"name": "master",
					"target": "master"
				},
				{
					"pattern": "DataSet/{Pernr},{Datum},{Infty}",
					"name": "object",
					"target": [
						"master",
						"object"
					]
				},
				{
					"pattern": "detail/LOCAL_INBOX/{wfInstanceId}/{taskPath}",
					"name": "wfobject",
					"target": "object"
				}

Detail.Controller:

	onInit: function () {
			// Model used to manipulate control states. The chosen values make sure,
			// detail page is busy indication immediately so there is no break in
			// between the busy indication for loading the view's meta data
			var oViewModel = new JSONModel({
				busy: false,
				delay: 0
			});

			this.getRouter().getRoute("object").attachPatternMatched(this._onObjectMatched, this);

			//My Inbox Integration
			this.getRouter().getRoute("wfobject").attachPatternMatched(this._onWFObjectMatched, this);

			this.setModel(oViewModel, "detailView");

			this.getOwnerComponent().getModel().metadataLoaded().then(this._onMetadataLoaded.bind(this));

		},


		_onWFObjectMatched: function (oEvent) {
			this.getModel("appView").setProperty("/layout", "MidColumnFullScreen");
			var compData = this.getOwnerComponent().getComponentData();

			if (compData && compData.startupParameters && compData.startupParameters.PERNR && Array.isArray(compData.startupParameters.PERNR) &&
				compData.startupParameters.PERNR[0]) {

				var sPernr = compData.startupParameters.PERNR[0];
				var sDatum = compData.startupParameters.DATUM[0];
				var sInfty = compData.startupParameters.INFTY[0];

				this.byId("detailPage").addStyleClass("myInboxPage");

				this.getModel().metadataLoaded().then(function () {
					var sObjectPath = this.getModel().createKey("/DataSet", {
						Pernr: sPernr,
						Datum: sDatum,
                                          Infty: sInfty
					});
					this._bindView(sObjectPath);

				}.bind(this));
			}
		},

[SAPUI5] uncheck checkbox if another one is selected

XML

<Checkbox id="Checkbox1" selected="{ path:'oModel>CB1' }" select="handleOrderSelected"></Checkbox>	
<Checkbox id="Checkbox2" selected="{ path:'oModel>CB2' }" select="handleRejectSelected"></Checkbox>

controller.js

	handleOrderSelected: function (oEvent) {
		//Wenn Checkbox1 selektiert, setze Checkbox2 auf false.
		var bSelected = oEvent.getParameter("selected");
		if (bSelected) {
			var bindingContext = oEvent.getSource().getBindingContext("oModel");
			this.oModelTemplate.setProperty("CB2", "", bindingContext, false);
		}
	},

	handleRejectSelected: function (oEvent) {
		//Wenn Checkbox2 selektiert, setze Checkbox1 auf false.
		var bSelected = oEvent.getParameter("selected");
		if (bSelected) {
			var bindingContext = oEvent.getSource().getBindingContext("oModel");
			this.oModelTemplate.setProperty("CB1", "", bindingContext, false);
		}
	}

[SAPUI5] Copy Table Row

Button für das Kopieren einer Zeile hinzufügen.

<Table id="itemsTable" items="{oModel>/ITEMS}">
<columns>
      <Column id="splitColumn" hAlign="Center" demandPopin="false">
            <Text text="{i18n>SPLIT}"/>
      </Column>
</columns>
<items>
      <ColumnListItem>
            <cells>
                  <Button press="onSplitPressed" id="SPLIT_ROW" icon="{= ${oModel>CUSTOM_ITEM} === true ? 'sap-icon://delete' : 'sap-icon://add'}"/>
            </cells>
      </ColumnListItem>
</items>
</Table>

Nur neu hinzugefügte Zeilen sollen auch wieder gelöscht werden dürfen, daher werden manuell hinzugefügte Zeilen markiert mit CUSTOM_ITEM = True;
Via Expression Binding wird dann das erforderliche Icon bestimmt.

onSplitPressed: function (oEvent) {
		var oContext = oEvent.getSource().getBindingContext("oModel");
		var path = oContext.getPath();
		var oModel = oContext.getModel();
		var oItems = oModel.getProperty("/ITEMS");
		var index = path.substr(path.length - 1);

		//selektiertes Item lesen
		var oItem = oModel.getProperty(path);

		//was soll passieren? Zeile hinzufügen oder entfernen?
		if (oItem.CUSTOM_ITEM !== true) {

			//Neues Item anlegen
			var oNewItem = JSON.parse(JSON.stringify(oItem));
			//Markiere neue Zeile, da nur diese auch wieder gelöscht werden darf
			oNewItem.CUSTOM_ITEM = true;
			// +1 weil Zeile soll ja nach der Aktuellen einfügt werden
			index++; 
			oItems.splice(index, 0, oNewItem);

		} else {
			// Item löschen
			oItems.splice(index, 1);
		}

		oModel.setProperty("/ITEMS", oItems);
	},

[Fiori] Debug deployed Fiori App

When opening the Dev-Tools for a deployed Fiori App, it will look like this:

You won’t see any controller.js to debug.
What to do? Close the Debugger-Tools and hit CTRL+ALT+SHIFT+P to open the Technical Information Dialog

Check the Checkbox (or choose a specific controller) and reload the app.

It reloads with a new URL parameter and if you open the Dev-Tools, you will now see the controller.js.

Other options to debug or at least to collect some information about your app are the UI5 Diagnostics (hit CTRL+ALT+SHIFT+S) and the UI5 Inspector which is a Brower Addon.

[SAPUI5] Formatting numbers

https://experience.sap.com/fiori-design-web/formatting-numbers/#usage
https://sapui5.netweaver.ondemand.com/sdk/#/topic/91f3145e6f4d1014b6dd926db0e91070
a few examples: https://github.com/brooklynb7/HTML5/blob/master/sapui5-dist-static/test-resources/sap/ca/ui/demokit/explored/views/type/number.view.xml

<ObjectListItem 
title="{income>Month}" 
number="{ model : 'income', path : 'Cost', type: 'sap.ui.model.type.Integer', formatOptions: {groupingEnabled: true} }"
numberUnit="EUR" />

[SAPUI5] Deploying the ui5 sample app on debian

I’m deploying the openui5-sample-app to a Linux Container running Debian Buster. First update the packages and install Node.js.

apt update && apt upgrade -y
apt install curl -y
curl -sL https://deb.nodesource.com/setup_12.x | bash -
apt install nodejs -y
nodejs --version

Install PM2 (process manager to manage Node.js applications) and the UI5 Tooling

npm install pm2 -g
npm install --global @ui5/cli

Now clone the openui5-sample-app and build it

apt install git
git clone https://github.com/SAP/openui5-sample-app.git
cd openui5-sample-app/
ui5 build -a
cd ..

Run your project on port 8000. With “startup” it will automatically create a systemd script.

pm2 serve openui5-sample-app/dist/ 8000
pm2 startup
pm2 save
systemctl start pm2-root
systemctl status pm2-root

[SAPUI5] local ui5 development

1. Install node.js

2. Install UI5 Tooling

npm install --global @ui5/cli

3. Install Easy UI5 Generator, create a project and run it on your localhost

npm install -g yo generator-easy-ui5
yo easy-ui5
cd <your project name> 
npm start

4. Set up a Github project and do your initial push

git add .
git commit -m "Initial commit"
git remote add origin https://github.com/user/myUI5App.git 
git push origin master

5. Install your favorite Editor, e.g. Visual Studio Code or Atom, and open your project to edit it