SAP CRM Fiori端到端的字段扩展教程_UI


Jerry Wang在他的公众号文章 ​SAP产品的Field Extensibility​里介绍了SAP CRM WebClient的Application Enhancement Tool, 以及S/4HANA Fiori UI的Custom Field Extension Tool,这两个工具都提供了很好的端到端的扩展性。所谓端到端扩展,就是从最底层的数据库层,到连接数据库层和UI层的服务层,到最上层和用户打交道的UI层,都会自动被SAP提供的标准工具所扩展。


那么,有的朋友工作的SAP Fiori UI,比如SAP CRM Fiori UI,并没有开箱即用的扩展工具。这种情况下,如果我们想给用户在Fiori UI上提供一些新的字段可供输入,应该如何实现呢?本文就介绍Partner在实施SAP CRM Fiori时,如何人工实现端到端的字段扩展。

01


本文选择的CRM Fiori应用是My Opportunity,如果没有用过的朋友,可以访问SAP官网这个链接,点击“免费试用”后进行体验:


​https://www.sap.com/china/products/fiori.html​


SAP CRM Fiori端到端的字段扩展教程_字段_02


假设客户需要在My Opportunity的Fiori UI上增加一个可以输入的字段:Created By,用来维护一个商机的创建者。


总体扩展思路很清晰,分别是:


  • OData模型的扩展
  • Fiori UI对扩展字段读操作场景的扩展
  • Fiori UI对扩展字段写操作场景的扩展


下面是端到端扩展的详细步骤。


1. OData模型的增强


在事务码SEGW里创建一个新的Gateway项目,假设名称叫ZJERRY_DEMO.


SAP CRM Fiori端到端的字段扩展教程_SAP_03


我们要通过这个项目对SAP标准的Opportunity OData模型做增强,因此通过菜单Data Model->Redefine->OData Service来导入标准OData模型:


SAP CRM Fiori端到端的字段扩展教程_字段_04


从F4帮助对话框中选择SAP标准的OData模型CRM_OPPORTUNITY:


SAP CRM Fiori端到端的字段扩展教程_字段_05


导入成功后,从右键菜单选择Generate Runtime, 自动生成OData模型的数据提供类DPC(Data Provider Class)以及元数据提供类MPC(Metadata Prodiver Class)。


SAP CRM Fiori端到端的字段扩展教程_UI_06


关于DPC和MPC的详细用途,请参阅Jerry Wang的文章:​SAP OData编程指南​


02


现在我们已经有了一个可以用于做增强的OData模型了。需要扩展的字段从业务上说,应该做在Opportunity的抬头结构上。

找到抬头结构的DDIC结构名称:CRMT_ODATA_OPPT_HEADER


SAP CRM Fiori端到端的字段扩展教程_SAP_07


在SE11里使用传统的ABAP Append技术给这个结构增强一个字段:EXT_CREATED_BY


SAP CRM Fiori端到端的字段扩展教程_字段_08


在我们自己用于增强的OData模型里,在Opportunity下面同样创建一个新的字段:


SAP CRM Fiori端到端的字段扩展教程_字段_09


假设我们新建的模型字段名称为extCreatedBy,绑定到DDIC字段EXT_CREATED_BY上。


SAP CRM Fiori端到端的字段扩展教程_字段_10


打开SEGW自动生成的DPC类,重定义它的GET_ENTITY方法:


SAP CRM Fiori端到端的字段扩展教程_UI_11


METHOD /iwbep/if_mgw_appl_srv_runtime~get_entity.
CALL METHOD super->/iwbep/if_mgw_appl_srv_runtime~get_entity EXPORTING
iv_entity_name = iv_entity_name
iv_entity_set_name = iv_entity_set_name
iv_source_name = iv_source_name
it_key_tab = it_key_tab
it_navigation_path = it_navigation_path
io_tech_request_context = io_tech_request_context IMPORTING
er_entity = er_entity
es_response_context = es_response_context.* Customer extension could be put here
CASE iv_entity_name.
WHEN 'Opportunity'.* Extension logic on Opportunity header
CALL METHOD fill_created_by EXPORTING
it_key_tab = it_key_tab CHANGING
cr_entity = er_entity.
WHEN OTHERS.
ENDCASE.
ENDMETHOD.


方法的逻辑就是,首先调用SAP标准的GET_ENTITY方法,然后调用我们自己的方法FILL_CREATED_BY。


method FILL_CREATED_BY.

FIELD-SYMBOLS: <s_guid> LIKE LINE OF it_key_tab,

<opp_header> TYPE cl_crm_opportunity_mpc=>ts_opportunity,

<created_by> TYPE sy-uname.

DATA: lv_created_by TYPE crmd_orderadm_h-created_by.

ASSIGN cr_entity->* TO <opp_header>.

ASSIGN COMPONENT 'EXT_CREATED_BY' of STRUCTURE <opp_header> TO <created_by>.

CHECK sy-subrc = 0.

READ TABLE it_key_tab ASSIGNING <s_guid> WITH KEY name = 'Guid'.

CHECK sy-subrc = 0.

SELECT SINGLE created_by INTO lv_created_by FROM crmd_orderadm_h WHERE guid = <s_guid>-value.

IF sy-subrc = 0.

<created_by> = lv_created_by.

ENDIF.

endmethod.


在方法FILL_CREATED_BY里,从数据库表CRMD_ORDERADM_H里将Opportunity的创建者读取出来,赋给GET_ENTITY的返回结构。


这一切做完后,在SAP Gateway Client里测试,确保在返回结果里,能看到我们扩展的字段extCreatedBy,并且被填充上了对应的值。OData模型的增强步骤就完成了。


SAP CRM Fiori端到端的字段扩展教程_字段_12


2. Fiori UI增强


增强前的Fiori UI,假设我们希望把扩展字段放在Opportunity明细页面的Info标签下。这是增强前的UI:


SAP CRM Fiori端到端的字段扩展教程_字段_13


这是增强后的UI,可以看到增强字段出现在所有标准字段的底部:


SAP CRM Fiori端到端的字段扩展教程_SAP_14


在Opporunity页面对应的XML视图中找到可以存放增强字段的位置,Fiori UI里这些位置有个术语:ExtensionPoint,类似ABAP后台的BAdI Enhancement Spot。因为我们是在Opportunity Info标签页的底部添加字段,所以ExtensionPoint是下图的opportunityInfoTabContentBottomExtension:


SAP CRM Fiori端到端的字段扩展教程_UI_15


新建一个Fiori扩展项目,在Component.js里声明一个View Extension,代码如下图红色方框内所示,注意第41行使用了我们前面找到的Extension Point opportunityInfoTabContentBottomExtension,第43行定义了放到这个Extension Point里去的XML Fragment名称:extCreatedBy。


SAP CRM Fiori端到端的字段扩展教程_SAP_16


新建一个文件:extCreatedBy.fragment.xml,在这个文件里定义需要在Fiori UI上显示的Created By字段的标签和输入框:


<core:FragmentDefinition xmlns="sap.m" xmlns:core="sap.ui.core" xmlns:ui="sap.ui.layout">
<ui:form.SimpleForm id="opportunityExtension"> <ui:content>
<Label id="opportunityCreatedByLbael" text="Created By">
</Label>
<Text id="opportunityCreatedByValue" text="{json>/extCreatedBy}"></Text>
</ui:content>
</ui:form.SimpleForm></core:FragmentDefinition>


至此,Fiori UI的扩展也完成了。但是,因为我们第一步只重定义了DPC的GET_ENTITY方法,因此只实现了扩展字段的读场景。如果用户在扩展字段里填写了值,点保存,输入值是无法存储到后台数据库的,为此,我们还需要基于写场景也完成需要的增强。


3. Fiori UI对于写场景的增强


Opportunity标准的Fiori UI,当客户点了保存之后,会有一个脏检查,判断是否当前是否真的有字段发生改动,只有当needsUpdate标志位为true时,才把最新的改动发送到后台,进行数据库持久化。


在引入扩展字段后,如果标准字段没有发生变化,但是扩展字段发生了变化,这种情况同样需要将变化刷新到后台数据库去。标准代码的ExtensionHook,如下图933行所示,就是SAP在Fiori UI JavaScript实现里针对这种场景留下的增强出口。


SAP CRM Fiori端到端的字段扩展教程_SAP_17


创建一个新的contoller extension,实现代码如下:


sap.ui.controller("cus.crm.opportunity.CRM_OPPRTNTYExtension.view.extS4", {
onInit : function () {
//Execute onInit for the base class BaseMasterController
sap.ca.scfld.md.controller.BaseDetailController.prototype.onInit.call(this);
},extHookAddCustomHeaderFields : function(oEntry) {// "createdByInput" is the id for extension UI element defined in extS4CreatedBy.fragment.xml
var oExtensionControl = this.byId("createdByInput");// get the current value that end user has entered in extension field in detail view
var extensionValue = oExtensionControl.getValue();
oEntry.extCreatedBy = extensionValue;}});


这一步完成后,用户在Fiori UI输入的扩展字段的值,能够被HTTP请求传到Fiori 后台。可以做个测试,在UI上随便输入一个值,比如Jerry88,点击保存。在Chrome开发者工具里能观察到这个值被传到了后台:


SAP CRM Fiori端到端的字段扩展教程_UI_18


剩下最后一步,就是重定义后台DPC_EXT类的PATCH_ENTITY方法,把Fiori UI上传入的扩展字段值保存到后台数据库。


代码如下:


METHOD /iwbep/if_mgw_appl_srv_runtime~patch_entity.
CALL METHOD super->/iwbep/if_mgw_appl_srv_runtime~patch_entity EXPORTING
iv_entity_name = iv_entity_name
iv_entity_set_name = iv_entity_set_name
iv_source_name = iv_source_name
io_data_provider = io_data_provider
it_key_tab = it_key_tab
it_navigation_path = it_navigation_path
io_tech_request_context = io_tech_request_context IMPORTING
er_entity = er_entity.
FIELD-SYMBOLS: <header_from_ui> TYPE crmt_odata_oppt_header,
<header_buffer> TYPE crmt_opport_h_com,
<value_ui> TYPE crmt_odata_oppt_header-ext_created_by,
<value_db> TYPE crmt_opport_h_com-fld00008b,
<input_fields> LIKE LINE OF cl_crm_opportunity_impl=>gt_input_fields.
DATA: ls_input TYPE crmt_input_field_names.
CHECK iv_entity_name = 'Opportunity'.
ASSIGN er_entity->* TO <header_from_ui>.
CHECK sy-subrc = 0.
READ TABLE cl_crm_opportunity_impl=>gt_opport_h ASSIGNING <header_buffer> INDEX 1.
CHECK sy-subrc = 0.
ASSIGN COMPONENT 'EXT_CREATED_BY' OF STRUCTURE <header_from_ui> TO <value_ui>.
CHECK sy-subrc = 0.
ASSIGN COMPONENT 'FLD00008B' OF STRUCTURE <header_buffer> TO <value_db>.
CHECK sy-subrc = 0.
<value_db> = <value_ui>.
READ TABLE cl_crm_opportunity_impl=>gt_input_fields ASSIGNING <input_fields> WITH KEY objectname = 'OPPORT_H'.
CHECK sy-subrc = 0.* Notify One order function module that we want to persist the value of this field
ls_input-fieldname = 'FLD00008B'.
INSERT ls_input INTO TABLE <input_fields>-field_names.
ENDMETHOD.


这里的思路是重用CRM One Order框架里专门为扩展字段预留的字段FLD00008B来存储扩展字段的值。


PATCH_ENTITY方法的重定义实现完毕后,在UI上为扩展字段维护一个值:


SAP CRM Fiori端到端的字段扩展教程_SAP_19


点击保存按钮,观察到扩展字段的值正确地被写入数据库表了。


SAP CRM Fiori端到端的字段扩展教程_UI_20


至此,SAP CRM Fiori端到端的扩展步骤就讲解完毕了。对于SAP CRM顾问来说,希望对大家的实际工作有所帮助。对于工作于SAP其他产品的顾问来说,或许您有开箱即用的扩展工具可以使用,不必人工去执行本文介绍的步骤,然而了解这些步骤,对您理解SAP产品扩展策略的设计也是有帮助的。


SAP CRM Fiori端到端的字段扩展教程_字段_21

SAP CRM Fiori端到端的字段扩展教程_UI_22