OData ABAP Entwicklung: Lesen Domänenfestwerte

Eine häufige Anforderung bei der SAPUI5 Entwicklung ist der Umgang mit den zahlreichen Schlüsseln, die im ERP Backend verwendet werden. Zu so einem Schlüssel muss durch die SAPUI5 App die Bedeutung angezeigt werden. In diesem Blog-Artikel entwickeln wir einen Function Import, welcher die NameValue-Paare für Dömänenfestwerte an die SAPUI5 App zurückliefert.

Domänenfestwerte im SAP DDIC

Ein Beispiel für Domänenfestwerte ist der Lebenszyklusstatus einer SalesOrder im EPM Model. Dies ist das Tabellenfeld SNWD_SO-LIFECYCLE_STATUS.

SalesOrder Header Tabelle

Die möglichen Werte des Status sind definiert durch die Domäne D_SO_LC.

Sicht auf eine Domäne

Im SAP DDIC sind diese Werte sprachabhängig in Tabelle DD07T gespeichert.

Tabelle DD07T

Starten wir mit der Implementierung. Die Implementierung besteht aus den folgenden Schritten:

  1. Modellierung des komplexen Typen NameValue
  2. Modellierung des Function Imports getDomFixValues
  3. Implementierung des Function Imports getDomFixValues
  4. Test des Function Imports im Gateway Client
  5. Integration in die Fiori App

1. Modellierung des komplexen Typen NameValue

Der komplexe Typ NameValue besteht aus den beiden String-Feldern Name und Value. Diese Struktur enthält den Schlüssel aus DD07T~DOMVALUE_L sowie die Bedeutung des Schlüssels aus DD07T~DDTEXT. Zur Typisierung benutze ich die ABAP-Struktur /IWBEP/S_MGW_NAME_VALUE_PAIR.

Komplexer Typ NameValue

2. Modellierung des Function Imports getDomFixValues

Der Function Import getDomFixValues erhält als Url Parameter den Namen der Domäne und liefert eine Tabelle des komplexen Typ NameValue zurück.

Function Import getDomFixValue

3. Implementierung des Function Imports getDomFixValues

Nach der Generierung der Laufzeitobjekte kann der Function Import implementiert werden. Das Gateway Projekt habe ich in diesem Beispiel ZRL_DOMFIXVALUE genannt. Die generierte Data Provider Class heißt also ZCL_ZRL_DOMFIXVALUE_DPC_EXT. Für die Implementierung des Function Imports reimplementiere ich die Methode /IWBEP/IF_MGW_APPL_SRV_RUNTIME~EXECUTE_ACTION.

Zur besseren Strukturierung des Codes deligiere ich die Ausführung an die private Methode FCT_GET_DOM_FIX_VALUES.

Implementierung der Execute Action

Die Methode FCT_GET_DOM_FIX_VALUES enthält die eigentliche Logik. Mit dem Namen der Domäne lese ich die Tabelle DD07T. Der Parameter des Function Imports ist über die Struktur zcl_zrl_domfixvalue_mpc=>ts_getdomfixvalues benutzbar. Für den Complex Type NameValue wird in der der Model Provider Class der Typ zcl_zrl_domfixvalue_mpc=>NameValue generiert.

* ---------------------------------------------------------------------------------------+
* | Instance Private Method ZCL_ZRL_DOMFIXVALUE_DPC_EXT->FCT_GET_DOM_FIX_VALUES
* +-------------------------------------------------------------------------------------------------+
* | [--->] IR_FUNC_IMPORT                 TYPE REF TO /IWBEP/IF_MGW_REQ_FUNC_IMPORT
* | [<---] ER_DATA                        TYPE REF TO DATA
* | [!CX!] /IWBEP/CX_MGW_BUSI_EXCEPTION
* +--------------------------------------------------------------------------------------
  METHOD fct_get_dom_fix_values.
    DATA lt_keyvalue TYPE TABLE OF zcl_zrl_domfixvalue_mpc=>keyvalue.
    DATA ls_param TYPE zcl_zrl_domfixvalue_mpc=>ts_getdomfixvalues.

    ir_func_import->get_converted_parameters(
      IMPORTING
        es_parameter_values = ls_param ).

    SELECT
       dd07t~domvalue_l AS key
       dd07t~ddtext AS value
      FROM dd07t
      INTO TABLE lt_keyvalue
      WHERE
        dd07t~domname = ls_param-domname AND
        dd07t~ddlanguage = sy-langu AND
        dd07t~as4local = 'A' AND
        dd07t~as4vers = '0000'.

    IF sy-subrc <> 0.
      RAISE EXCEPTION TYPE /iwbep/cx_mgw_busi_exception
        EXPORTING
          message = |FCT_GET_DOM_FIX_VALUES: No domain fix values found for { ls_param-domname } |.
    ENDIF.

    copy_data_to_ref(
      EXPORTING
        is_data = lt_keyvalue
      CHANGING
        cr_data = er_data ).

  ENDMETHOD.

* ---------------------------------------------------------------------------------------+
* | Instance Public Method ZCL_ZRL_DOMFIXVALUE_DPC_EXT->/IWBEP/IF_MGW_APPL_SRV_RUNTIME~EXECUTE_ACTION
* +-------------------------------------------------------------------------------------------------+
* | [--->] IV_ACTION_NAME                 TYPE        STRING(optional)
* | [--->] IT_PARAMETER                   TYPE        /IWBEP/T_MGW_NAME_VALUE_PAIR(optional)
* | [--->] IO_TECH_REQUEST_CONTEXT        TYPE REF TO /IWBEP/IF_MGW_REQ_FUNC_IMPORT(optional)
* | [<---] ER_DATA                        TYPE REF TO DATA
* | [!CX!] /IWBEP/CX_MGW_BUSI_EXCEPTION
* | [!CX!] /IWBEP/CX_MGW_TECH_EXCEPTION
* +--------------------------------------------------------------------------------------
  METHOD /iwbep/if_mgw_appl_srv_runtime~execute_action.
    CASE iv_action_name.

      WHEN 'getDomFixValues'.

        fct_get_dom_fix_values(
          EXPORTING
            ir_func_import               = io_tech_request_context
          IMPORTING
            er_data                      =  er_data ).

      WHEN OTHERS.
        RAISE EXCEPTION TYPE /iwbep/cx_mgw_busi_exception
          EXPORTING
            message = |EXECUTE_ACTION: Function import { iv_action_name } not implemented|.
    ENDCASE.
  ENDMETHOD.

4. Test Function Import im Gateway Client

Jetzt ein kurzer Test im Gateway Client (Transaktion /IWFND/GW_CLIENT), ob das Ganze auch wie gewünscht funktioniert. Die URL ist /sap/opu/odata/sap/ZRL_DOMFIXVALUE_SRV/getDomFixValues?domname=’D_SO_LC’

SAP Gateway Client

Voilà! Der Service liefert für die Domäne D_SO_LC die NameValue-Paare zurück.

5. Integration in die Fiori App

Jetzt bauen wir eine SAPUI5, die diesen Service konsumiert. Das gehört inhaltlich eigentlich nicht in einen ABAP Blog. Ich persönlich finde jedoch, dass der Aufruf eines Function Imports in den diversen Forumsbeiträgen und Blogs immer nur partiell beschrieben ist. Deshalb an dieser Stelle einmal eine Schritt für Schritt Anleitung.

5.1 manifest.json

In der manifest.json unter sap.app den OData Service als dataSource registrieren und diese an ein Model binden. Hier wird das Default-Model verwendet.

	"sap.app": {
		"id": "cgi.DomFixValue",
		"dataSources": {
			"mainService": {
				"uri": "/sap/opu/odata/sap/ZRL_DOMFIXVALUE_SRV",
				"type": "OData",
				"settings": {
					"odataVersion": "2.0"
				}
			}
		}		
	}	

	"models": {
			"": {
				"dataSource": "mainService",
				"preload": true,
				"settings": {
					"defaultBindingMode": "TwoWay",
					"defaultOperationMode": "Server"
				}
			}
		}

5.2 neo-app.json

Für die Ausführung in der WebIDE muss folgender Eintrag in der neo-app.json stehen:

	{
		"path": "/sap/opu/odata",
		"target": {
			"type": "destination",
			"name": "cgigwy",
			"entryPath": "/sap/opu/odata"
		},
		"description": "cgigwy"
	}

5.3 Component.js

Das Ausführen des Function Imports ist an die models-Datei ausgelagert.
In der Component.js erfolgt der Aufruf models.createLifecycleStatusModel(this) hinzufügen.

sap.ui.define([
	"sap/ui/core/UIComponent",
	"cgi/DomFixValue/model/models"
], function (UIComponent, models) {
	"use strict";

	return UIComponent.extend("cgi.DomFixValue.Component", {

		metadata: {
			manifest: "json"
		},

		/**
		 * The component is initialized by UI5 automatically during the startup of the app and calls the init method once.
		 * @public
		 * @override
		 */
		init: function () {
			// call the base component's init function
			UIComponent.prototype.init.apply(this, arguments);

			// enable routing
			this.getRouter().initialize();
			
			models.createLifecycleStatusModel(this);
		}

	});
});

5.4 models.js

In models.js wird dann die Methode createLifecycleStatusModel implementieren. Sie erzeugt ein JSON Model mit Namen lifecycleStatus, mit dessen Hilfe das Ergebnis des Function Imports in der App verwendet werden kann.

sap.ui.define([
	"sap/ui/model/json/JSONModel",
	"sap/ui/Device"
], function (JSONModel, Device) {
	"use strict";

	return {

		createDeviceModel: function () {
			var oModel = new JSONModel(Device);
			oModel.setDefaultBindingMode("OneWay");
			return oModel;
		},

		createLifecycleStatusModel: function (oComponent) {
			var mOptions = {
				method: "GET",
				urlParameters: {
					"domname": "D_SO_LC"
				},
				success: function (oData) {
					oComponent.setModel(new JSONModel(oData.results), "lifecycleStatus");
				},
				error: function () {
					oComponent.setModel(new JSONModel({}), "lifecycleStatus");
				}
			};

			oComponent.getModel().callFunction("/getDomFixValues", mOptions);
		}

	};
});

 

Du programmierst, bist ABAP-interessiert und hast Lust coole Projekte mit uns zu machen? Wir suchen dich! Schau doch mal in unserer Stellenbeschreibung vorbei.

Veröffentlicht in ABAP

Über den Autor

Rüdiger Lühr

Kommentar verfassen