
Fiori für ABAP - Änderungsbelege
Wie können wir eigentlich die Änderungsbelege in unsere Anwendung einblenden, die aktuell nur auf der Datenbank vorhanden sind? Dazu schauen wir uns eine weitere Re-Use Komponente an.
Inhaltsverzeichnis
In diesem Artikel schauen wir uns an, wie wir die Änderungsdokumente in unsere bestehende Fiori-Anwendung integrieren können. Dabei verwenden wir eine Reuse-Komponente.
Einleitung
Bisher hatten wir uns in verschiedenen Artikeln mit dem Thema Änderungsbelege auseinandergesetzt. Dabei hatten wir im ersten Schritt die Änderungsbelege implementiert und sie im zweiten Schritt innerhalb einer ABAP-Anwendung zur Verfügung gestellt und auch in unserer Anwendung getestet. Daher wird es Zeit, in unserer Sales-App die Änderungsbelege anzuzeigen, sodass auch der User sie sieht. Dafür stellt SAP aktuell eine Reuse-Komponente zur Verfügung, die wir, wie auch die Application Logs, in unsere Fiori-Anwendung integrieren können.
Erweiterung
Die Schritte sind allerdings nicht so einfach wie beim Application Log. Hier müssen wir auch eine neue Custom Section anlegen, um diese über ein Fragment und eine Controller Extension einbinden zu können.
Bibliothek
Im ersten Schritt erweitern wir die manifest.json Datei und fügen eine neue Bibliothek unter dem Knoten "libs" hinzu. Ähnlich wie bei den Application Logs wird hier auch für die Change Documents eine Komponente hinzugefügt.
"libs": {
"sap.nw.core.changedocs.lib.reuse": {
"lazy": true
}
}
Custom Section
Als nächsten Schritt müssen wir eine Custom Section hinzufügen. Diese können wir über die Page Map hinzufügen, wie wir das bereits in einem älteren Artikel gemacht haben. Dazu wechseln wir auf die Page Map und fügen eine Custom Section hinzu, in diesem Fall direkt nach dem Admin-Bereich.
Im Anschluss öffnen wir das Fragment und können dort eine Anpassung vornehmen. Hierzu übernehmen wir den ComponentContainer und geben diesem eine entsprechende ID. Diese ID kannst du vergeben, wie du möchtest, du solltest sie dir nur für später merken. Ansonsten müssen wir hier keine weiteren Anpassungen vornehmen.
<core:FragmentDefinition xmlns:core="sap.ui.core" xmlns="sap.m" xmlns:macros="sap.fe.macros">
<core:ComponentContainer id="idChangeContainer"/>
</core:FragmentDefinition>
Controller Extension
Als Nächstes müssen wir eine Controller Extension für die Object Page implementieren. Der einfachste Weg, dies zu tun, ohne es manuell machen zu müssen, ist wieder über die Page Map. Dazu öffnest du die Page Map und bleibst auf der obersten Ebene. Auf der rechten Seite findest du dann im Menü einen Eintrag, um die Controller Extension anzulegen. Dabei wird die Extension, also eine Datei, angelegt und der entsprechende Controller registriert.
Im Controller geben wir der Extension einen Namen. Dieser Name wird dann für die Datei verwendet, die implementiert wird. Entsprechend wollen wir einen neuen Controller anlegen und nicht einen bestehenden wiederverwenden, außerdem haben wir aktuell keinen zusätzlichen im Projekt.
Implementierung
Auch in der offiziellen SAP-Dokumentation findest du dieses riesige Code-Snippet. Dabei handelt es sich um die komplette Implementierung des Controllers in der entsprechenden Erweiterung. Ein Kopieren wird hier allerdings relativ schwerfallen, da wir sehr viele Punkte anpassen müssen, um den Controller auf unsere Spezifikation und unsere Anwendung anpassen zu können. Solltest du den Code als Vorlage nehmen, solltest du dir auf jeden Fall den Pfad innerhalb des "Extend" speichern, denn da ist die Controller-Extension unter dem entsprechenden Namen, den wir vergeben haben, verlinkt.
sap.ui.define(['sap/ui/core/mvc/ControllerExtension', 'sap/ui/core/Core'], function (ControllerExtension, Core) {
'use strict';
return ControllerExtension.extend('swh.test.zbsglobalsales.ext.controller.ChangeDocumentExtension', {
_chdContainer: "swh.test.zbsglobalsales::SASaleObjectPage--fe::CustomSubSection::ChangeDocument--idChangeContainer",
override: {
/**
* Called when a controller is instantiated and its View controls
* (if available) are already created.
* Can be used to modify the View before it is displayed, to bind
* event handlers and do other one-time initialization.
* @memberOf chdbookproject.ext.controller.ChdControllerExt
*/
onInit: function () {
var that = this;
var oViewId = this.getView().getId();
if (oViewId === "swh.test.zbsglobalsales::SASaleObjectPage") {
this._oComp = Core.createComponent({
name: "sap.nw.core.changedocs.lib.reuse.changedocscomponent",
id: "ChangeDocReuseComponent",
settings: {
"objectClass": ["ZBS_CO_SALES"],
"startDate": "2026-01-01T00:00:00.0000",
"stIsAreaVisible": true
}
});
var oChdContainer = Core.byId(this._chdContainer);
if (oChdContainer !== undefined) {
oChdContainer.setComponent(this._oComp);
}
this._oComp.setStIsAreaVisible(true);
this._oComp.stRefresh();
}
},
editFlow: {
onAfterSave: function () {
var that = this;
this._oComp.stRefresh();
}
},
routing: {
onAfterBinding: function (oBindingContext) {
var that = this;
oBindingContext.requestProperty("RawChangeID").then(function (sObject) {
if (sObject) {
that._oComp.setObjectId([sObject]);
}
that._oComp.stRefresh();
});
}
},
}
});
});
Dazu haben wir die folgenden Punkte innerhalb des Codes angepasst:
- Containername (_chdContainer) - Der Name des Containers muss neu vergeben werden und auf deine Anwendung angepasst werden. Der erste Teil setzt sich aus dem Namespace und dem Namen der Anwendung zusammen. Danach folgt der Name der Object Page, auf der der Container implementiert ist, dann entsprechend der Name der Custom Section und der Name des eigentlichen Controls. Dahinter befindet sich dann die ID unseres ComponentContainers, den wir im Fragment angelegt haben.
- ViewID - Als Nächstes müssen wir die View-ID auf unsere Anwendung anpassen. Diese wird wieder zusammengesetzt aus dem Namespace und der ID unserer Anwendung sowie der Object Page, auf der die Extension implementiert wurde.
- Einstellungen - Im unteren Teil müssen wir dann die Einstellungen anpassen. Dort geben wir als Object Class unser eigentliches Änderungsobjekt an, unter dem die Änderungen später zu finden sind. Wir geben ein Startdatum an, ab dem selektiert werden soll. Ist eine Anwendung relativ neu in der Tabelle, dann kannst du das Datum auch entsprechend auf den heutigen Tag setzen, ansonsten auf den Tag, von wo an deine Änderungen selektiert werden sollen.
- Attribut - Im unteren Teil müssen wir im Request Property unser Attribut aus dem OData-Service eingeben, welches für die Identifikation des Change Documents verwendet wird. Eigentlich müssten wir hier die UUID angeben. Durch die Prüfung, die später beim Debuggen durchgeführt wurde, haben wir allerdings festgestellt, dass diese nicht so übergeben wird, wie wir sie benötigen (Format). Daher übergeben wir hier ein neues Feld, was wir einen Schritt später dann anlegen. Über "RawChangeID" übergeben wir die eigentliche UUID im richtigen Format an den Service, um die Daten später lesen zu können.
ABAP Environment
Ein Test der Anwendung im Preview ist leider nicht möglich, hier erhalten wir beim Laden der Object Page einen Fehler und können nicht weiterarbeiten. Daher müssen wir ebenfalls zuvor die Anwendung erst auf das ABAP-System deployen und können dann die weiteren Schritte vornehmen.
Deplyoment
Führen wir nun das eigentliche Deployment durch und stellen die Anwendung wieder im ABAP Environment zur Verfügung. Starten wir die Anwendung nun im Testlauf, sollte das Control das erste Mal geladen werden, allerdings noch ohne Daten. Hier fehlen uns noch die Berechtigungen, die wir im nächsten Schritt vergeben.
Berechtigungen
Entsprechend müssen wir unsere IAM-App wieder erweitern und den Service für die Änderungsbelege aufnehmen. Dabei müssen wir einen OData-v2-Service hinzufügen. Und nicht vergessen, die entsprechende Anzahl Leerzeichen zwischen Service und Version zu haben. Als Code-Beispiel findest du den Service zum Kopieren hier noch einmal:
APS_CHANGE_DOCUMENTS_SRV 0001
Nachdem du die IAM-App erweitert hast, um die Berechtigungen anzupassen, solltest du den "Publish" Button klicken, um die Änderungen im Launchpad zur Verfügung zu stellen.
RawChangeID
Wie bereits oben erwähnt, haben wir aktuell ein Problem: Würden wir die UUID angeben, würde diese als Identifier keine Informationen liefern. Das liegt daran, dass die UUID in der Fiori-Anwendung falsch dargestellt wird, zumindest nicht in dem Format, das der Service benötigt, um sie aus dem System zu lesen. Daher müssen wir ein zusätzliches virtuelles Feld im Service implementieren, welches die rohe ID ohne Aufbereitung zur Verfügung stellt; das heißt, komplett großgeschrieben und ohne Bindestriche. Diese Information benötigen wir dann im Service, um die entsprechenden Daten abzurufen.
@ObjectModel.virtualElementCalculatedBy: 'ABAP:ZCL_BS_DEMO_RAP_SALES_VE'
virtual RawChangeID : abap.char(32),
Die Implementierung ist hier recht einfach: Wir übernehmen die UUID in das neue Feld und sind damit schon fertig. Alle Änderungen, die wir am Service und der Implementierung vorgenommen haben, findest du im Commit unten noch einmal, wenn du dir diese im Detail anschauen möchtest.
Zum Hintergrund der eigentlichen Änderung schauen wir uns den HTTP-Request im Browser an. Dort sehen wir, dass der Service mit der UUID aufgerufen wird und entsprechend das falsche Format übergeben wird. Als Ergebnis erhalten wir keine Änderungsbelege aus dem Service zurück. Tauschen wir allerdings die UUID gegen unsere eigentliche ID aus, die wir auch auf der Datenbank finden, dann erhalten wir aus dem Service ein entsprechendes Ergebnis. Daher haben wir festgestellt, dass wir hier die übergebene ID anpassen müssen und das Format ändern.
" UUID
604aadc-c1e5-1fe1-84df-751c01c1157d
" RawChangeID
0604AADCC1E51FE184DF751C01C1157D
Test
Sind nun alle Änderungen vorhanden, können wir den eigentlichen Test noch einmal durchführen. Dafür rufen wir unsere Anwendung auf und gehen in einen Datensatz. Hier können wir entsprechende Änderungen vornehmen und sehen dann, dass entsprechende Änderungsbelege geschrieben werden. Wir sehen hier auch den Änderer, das Datum, die Uhrzeit und welche Feldinformationen sich geändert haben. Damit ist das Control nun erfolgreich in unserer Anwendung implementiert, und wir sollten keine Fehler mehr haben.
Ausblick
Für das Release 2608 wurde bereits angekündigt, dass die Core Data Services für die Change Documents offiziell freigegeben werden und damit einen C1-Kontrakt für die Nutzung in ABAP Cloud erhalten. Damit sollte das Thema Komplexität bei der Einführung etwas reduziert werden. Wir können dann später die Core Data Services direkt in unserem RAP-Objekt mitmodellieren und über eine Annotation anzeigen, ohne den Umweg über die Reuse-Komponente zu gehen, die aktuell sehr kompliziert in der Implementierung ist.
Vollständiges Beispiel
Die gespeicherten Ressourcen zu unserer Anwendung findest du in unserem GitHub Repository. Damit kannst du in Zukunft alle Anpassungen an der Fiori App mit nachvollziehen oder die Ressourcen für ein Deployment nutzen. Die aktuellen Änderungen findest du in diesem Commit wieder. Die Änderungen auf der ABAP Seite, findest du in diesem Commit.
Fazit
Die Implementierung der Komponente ist nicht wirklich leicht, hier gibt es viele Punkte zu beachten, damit die Anwendung im Nachgang immer noch sauber lädt und auch die Inhalte anzeigt, die wir sehen wollen. Grundsätzlich war dies die schwerste Komponente bisher und es mussten sehr viele Punkte angepasst und beachtet werden.
Weitere Informationen:
SAP Help - Reuse Library for Change Documents
SAP Help - Fiori Elements Integration OData v4





