SAP学习笔记 - 开发57 - RAP开发 Managed App RAP action 之 Accept Travel 和 Reject Travel

上一章讲了RAP action 指 Copy Travel。

SAP学习笔记 - 开发56 - RAP开发 Managed App RAP action: Processor/ Approver,Copy Travel 功能实现-CSDN博客

本章继续将RAP action的相关内容。

目录

1,需求说明

[2,New Projection View](#2,New Projection View)

2-1,Z04_PV_Travel_M_Approver

2-2,Z04_PV_Booking_M_Approver

[2-3,设定Project View之间的父子关系](#2-3,设定Project View之间的父子关系)

[2-4,设定Metadata - Z04_PV_Travel_M_Approver](#2-4,设定Metadata - Z04_PV_Travel_M_Approver)

[2-5,设定Metadata - Z04_PV_Booking_M_Approver](#2-5,设定Metadata - Z04_PV_Booking_M_Approver)

[3,New Behavior Definition - Z04_PV_Travel_M_Approver](#3,New Behavior Definition - Z04_PV_Travel_M_Approver)

[4,New Service Definition](#4,New Service Definition)

[5,New Service Binding](#5,New Service Binding)

6,测试一下Layout

[7,Accept Travel 功能实现](#7,Accept Travel 功能实现)

a),修改实体数据

b),读取更新后的数据

c),构建返回结果

d),总结

[8,Reject Travel 功能实现](#8,Reject Travel 功能实现)

[9,测试 Accept Travel 和 Reject Travel 功能](#9,测试 Accept Travel 和 Reject Travel 功能)

[9-1,Accept Travel](#9-1,Accept Travel)

[9-2,Reject Travel](#9-2,Reject Travel)

[9-3,Accept Travel - Object Page](#9-3,Accept Travel - Object Page)

[9-4,Reject Travel - Object Page](#9-4,Reject Travel - Object Page)


下面是详细内容。

1,需求说明

本章要做 Accept Travel,Reject Travel 两个更新操作。

设定的背景是该用户不能看到Create,Delete功能,只能做Accept,Reject,以及部分编集。

另外,该用户不需要看到 Booking Supplement,只需要看到 Travel,Booking两个表的数据。

为了实现这个功能,咱们需要新做一个 Projection View,并在其基础上,做 Behavior,Service。

下面来实操,看系统上怎么实现。

2,New Projection View

2-1,Z04_PV_Travel_M_Approver

右键 Data View,点 New Data Definition

输入Name,Description,点Next

选中ProjectionView模板,点Finish

这样就做好了,注意Currency Code,以及provider contract 设定

同样,把Booking 的Projection View也做了

2-2,Z04_PV_Booking_M_Approver

2-3,设定Project View之间的父子关系

2-4,设定Metadata - Z04_PV_Travel_M_Approver

推荐还是要使用单独的Metadata文件,这里就偷懒给放到 Projection View里面

复制代码
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'Data Definition for Z04_PV_Travel_M_Approver - Projection V'
@Metadata.ignorePropagatedAnnotations: true
@UI.headerInfo: {
    typeName: 'Travel',
    typeNamePlural: 'Travels',
    title: {
        type: #STANDARD,
        label: 'Travel',
        value: 'TravelId'
    }
}
define root view entity Z04_PV_Travel_M_Approver
  provider contract transactional_query
  as projection on Z04_DV_Travel_M

{
      @UI.facet: [
      {
          id: 'TravelDetail',
          purpose: #STANDARD,
          parentId: '',
          position: 10,
          label: 'Travel Detail',
          type: #IDENTIFICATION_REFERENCE
      },
      {
          id: 'Booking',
          purpose: #STANDARD,
          parentId: '',
          position: 20,
          label: 'Bookings',
          targetElement: '_Booking',
          type: #LINEITEM_REFERENCE
      }
      ]
      @UI:{ lineItem:[{ position: 10 }],
            identification: [{ position: 10 }]
          }
      @Search.defaultSearchElement: true
  key TravelId,
      @UI:{ lineItem:[{ position: 20, importance: #HIGH }],
            selectionField: [{ position: 20 }],
            identification: [{ position: 20 }]
          }
      @Search.defaultSearchElement: true
      @Consumption.valueHelpDefinition: [{ entity: {
                  name: '/DMO/I_Agency',
                  element: 'AgencyID'
              },
              label: 'Agency'
      }]
      @ObjectModel.text.element: [ 'AgencyName' ]
      AgencyId,
      _Agency.Name       as AgencyName,
      @UI:{ lineItem:[{ position: 30 }],
          selectionField: [{ position: 30 }],
          identification: [{ position: 30 }]
        }
      @Search.defaultSearchElement: true
      @Consumption.valueHelpDefinition: [{
              entity: {
                  name: '/DMO/I_Customer',
                  element: 'CustomerID'
              },
              label: 'Customer'
      }]
      @ObjectModel.text.element: [ 'CustomerName' ]
      CustomerId,
      _Customer.LastName as CustomerName,
      @UI:{ lineItem:[{ position: 40 }],
          identification: [{ position: 40 }]
        }
      BeginDate,
      @UI:{ lineItem:[{ position: 50 }],
          identification: [{ position: 50 }]
        }
      EndDate,
      @Semantics.amount.currencyCode: 'CurrencyCode'
      @UI:{ lineItem:[{ position: 55 }],
            identification: [{ position: 55 }]
        }
      BookingFee,
      @Semantics.amount.currencyCode: 'CurrencyCode'
      @UI:{ lineItem:[{ position: 60 }],
          identification: [{ position: 60 }]
        }
      TotalPrice,
      @Consumption.valueHelpDefinition: [{
        entity: {
            name: 'I_Currency',
            element: 'Currency'
        },
        label: 'Currency'
      }]
      CurrencyCode,
      @UI:{ lineItem:[{ position: 60 }],
            identification: [{ position: 65 }]
        }
      Description,
      @UI:{ lineItem:[{ position: 70 },
                      { type:#FOR_ACTION, dataAction: 'acceptTravel', label: 'Accept Travel' },
                      { type:#FOR_ACTION, dataAction: 'rejectTravel', label: 'Reject Travel' }],
          selectionField: [{ position: 70 }],
          identification: [{ position: 70 },
                           { type:#FOR_ACTION, dataAction: 'acceptTravel', label: 'Accept Travel' },
                           { type:#FOR_ACTION, dataAction: 'rejectTravel', label: 'Reject Travel' }],
          textArrangement: #TEXT_ONLY
        }
      @Search.defaultSearchElement: true
      @Consumption.valueHelpDefinition: [{
          entity: {
              name: '/DMO/I_Overall_Status_VH',
              element: 'OverallStatus'
          },
          label: 'Overall Status'
      }]
      @ObjectModel.text.element: [ 'OverallStatusText' ]
      OverallStatus,
      @UI.hidden: true
      _Status._Text.Text as OverallStatusText : localized,
      @UI.hidden: true
      CreatedBy,
      @UI.hidden: true
      CreatedAt,
      @UI.hidden: true
      LastChangedBy,
      @UI.hidden: true
      LastChangedAt,
      /* Associations */
      _Agency,
      _Booking : redirected to composition child Z04_PV_Booking_M_Approver,
      _Currency,
      _Customer,
      _Status
}

2-5,设定Metadata - Z04_PV_Booking_M_Approver

复制代码
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'Data Definition for Z04_PV_Booking_M_Approver - Projection V'
@Metadata.ignorePropagatedAnnotations: true
@UI.headerInfo: {
    typeName: 'Booking',
    typeNamePlural: 'Bookings',
    title: {
        type: #STANDARD,
        label: 'Booking',
        value: 'BookingId'
    }
}
@Search.searchable: true
define view entity Z04_PV_Booking_M_Approver
  as projection on Z04_DV_Booking_M
{
      @UI.facet: [
      {
          id: 'BookingDetail',
          purpose: #STANDARD,
          parentId: '',
          position: 10,
          label: 'Booking Detail',
          type: #IDENTIFICATION_REFERENCE
      }]
      @Search.defaultSearchElement: true
  key TravelId,
      @UI:{ lineItem:[{ position: 20 }],
          identification: [{ position: 20 }]
        }
      @Search.defaultSearchElement: true
  key BookingId,
      @UI:{ lineItem:[{ position: 30 }],
          identification: [{ position: 30 }]
        }
      BookingDate,
      @UI:{ lineItem:[{ position: 40 }],
          identification: [{ position: 40 }]
        }
      @Search.defaultSearchElement: true
      @Consumption.valueHelpDefinition: [{ entity: {
          name: '/DMO/I_Customer',
          element: 'CustomerID'
      }  }]
      @ObjectModel.text.element: [ 'CustomerName' ]
      CustomerId,
      _Customer.LastName         as CustomerName,
      @UI:{ lineItem:[{ position: 50 }],
          identification: [{ position: 50 }]
        }
      @Consumption.valueHelpDefinition: [{ entity: {
          name: '/DMO/I_Carrier',
          element: 'AirlineID'
      }  }]
      @ObjectModel.text.element: [ 'CarrierName' ]
      CarrierId,
      _Carrier.Name              as CarrierName,
      @UI:{ lineItem:[{ position: 60 }],
          identification: [{ position: 60 }]
        }
      ConnectionId,
      @UI:{ lineItem:[{ position: 70 }],
          identification: [{ position: 70 }]
        }
      FlightDate,
      @Semantics.amount.currencyCode: 'CurrencyCode'
      @UI:{ lineItem:[{ position: 80 }],
          identification: [{ position: 80 }]
        }
      FlightPrice,

      CurrencyCode,
      @UI:{ lineItem:[{ position: 90 }],
          identification: [{ position: 90 }],
          textArrangement: #TEXT_ONLY
        }
      @Consumption.valueHelpDefinition: [{ entity: {
          name: '/DMO/I_Booking_Status_VH',
          element: 'BookingStatus'
      } }]
      @ObjectModel.text.element: [ 'BookingStatusText' ]
      BookingStatus,
      @UI.hidden: true
      _Booking_Status._Text.Text as BookingStatusText : localized,
      @UI.hidden: true
      LastChangedAt,
      /* Associations */
      _BookingSupplement,
      _Booking_Status,
      _Carrier,
      _Connection,
      _Customer,
      _Travel : redirected to parent Z04_PV_Travel_M_Approver
}

3,New Behavior Definition - Z04_PV_Travel_M_Approver

右键 Projection View,然后点 New Behavior Definition

输入Name,Description,点Next

然后点Finish,就建好了

但是注意我们这里不需要Create,Delete,所以都去掉

Booking方面,也不需要Update,Delete,也去掉,就变成下面这个样子的

复制代码
projection;
strict ( 2 );

define behavior for Z04_PV_Travel_M_Approver //alias <alias_name>
use etag
{
//  use create;
  use update;
//  use delete;

  use action acceptTravel;
  use action rejectTravel;
//  use action copyTravel;

//  use association _Booking { create; }
}
//
//define behavior for Z04_PV_Booking_M_Approver //alias <alias_name>
//{
//  use update;
//  use delete;
//
//  use association _Travel;
//}

4,New Service Definition

右键 Projection View,点 New Service Definition

输入Name,Description,点Next

再点Next,然后点Finish,这样就完成了

将 Booking 也暴露,然后点 Alt+F3,激活

5,New Service Binding

右键 Service Definition,然后点 New Service Binding

输入Name,Description,Binding Type,然后点Next

再点Finish 就建好了

按 Ctrl+F3激活,然后点Publish,发布

6,测试一下Layout

Layout基本上没啥问题。

List Report

Object Page

按钮位置好像不对,这个也可以通过Position设定

刷新一下,就OK了

万事具备,就剩下实现具体功能了。

7,Accept Travel 功能实现

复制代码
  METHOD acceptTravel.

    MODIFY ENTITIES OF Z04_DV_Travel_M IN LOCAL MODE
    ENTITY Z04_DV_Travel_M
    UPDATE FIELDS ( OverallStatus )
    WITH VALUE #( FOR ls_keys IN keys ( %tky = ls_keys-%tky
                                        OverallStatus = 'A' ) ).
    READ ENTITIES OF Z04_DV_Travel_M IN LOCAL MODE
    ENTITY Z04_DV_Travel_M
    ALL FIELDS WITH CORRESPONDING #( keys )
    RESULT DATA(lt_result).

    result = VALUE #( FOR ls_result IN lt_result ( %tky = ls_result-%tky
                                                   %param = ls_result ) ).

  ENDMETHOD.

下面来看一下代码解释。

这段代码是一个RAP (Restful ABAP Programming) action的实现,用于将旅行记录的状态更新为"已接受"(A)。以下是代码的详细解释:

a),修改实体数据

abap

复制代码
MODIFY ENTITIES OF Z04_DV_Travel_M IN LOCAL MODE
  ENTITY Z04_DV_Travel_M
  UPDATE FIELDS ( OverallStatus )
  WITH VALUE #( FOR ls_keys IN keys ( %tky = ls_keys-%tky
                                      OverallStatus = 'A' ) ).

这部分代码执行以下操作:

  1. MODIFY ENTITIES - 修改实体数据

  2. OF Z04_DV_Travel_M - 操作的是名为Z04_DV_Travel_M的CDS视图实体

  3. IN LOCAL MODE - 在本地模式下运行(不触发到数据库的直接修改)

  4. 更新Z04_DV_Travel_M实体的OverallStatus字段

  5. 使用VALUE #(...)构造器为每个传入的key设置新值:

    • %tky - 技术key(包含业务对象的key字段)

    • OverallStatus = 'A' - 将状态设置为'A'(表示"已接受")

b),读取更新后的数据

abap

复制代码
READ ENTITIES OF Z04_DV_Travel_M IN LOCAL MODE
  ENTITY Z04_DV_Travel_M
  ALL FIELDS WITH CORRESPONDING #( keys )
  RESULT DATA(lt_result).

这部分代码读取刚刚更新后的数据:

  1. 从同一个实体Z04_DV_Travel_M中读取数据

  2. 读取所有字段(ALL FIELDS)

  3. 使用传入的keys作为筛选条件

  4. 将结果存储在内部表lt_result

c),构建返回结果

abap

复制代码
result = VALUE #( FOR ls_result IN lt_result ( %tky = ls_result-%tky
                                               %param = ls_result ) ).

这部分构建方法的返回结果:

  1. 使用VALUE #(...)构造器为每个结果记录创建条目

  2. 每个条目包含:

    • %tky - 技术key

    • %param - 完整的实体数据(作为参数返回)

d),总结

这个acceptTravel action的主要功能是:

  1. 接收一组旅行记录的key

  2. 将这些记录的OverallStatus字段更新为'A'(表示接受)

  3. 读取并返回更新后的完整记录数据

这是RAP中处理业务对象状态变更的标准模式,遵循ABAP RESTful Application Programming Model的规范。

Reject Travel 和 Accept Travel 功能基本相同,唯一不同的就是设定的值不同。

8,Reject Travel 功能实现

  • OverallStatus = 'X'

    复制代码
    METHOD rejectTravel.
      MODIFY ENTITIES OF Z04_DV_Travel_M IN LOCAL MODE
        ENTITY Z04_DV_Travel_M
        UPDATE FIELDS ( OverallStatus )
        WITH VALUE #( FOR ls_keys IN keys ( %tky = ls_keys-%tky
                                        OverallStatus = 'X' ) ).
      READ ENTITIES OF Z04_DV_Travel_M IN LOCAL MODE
        ENTITY Z04_DV_Travel_M
        ALL FIELDS WITH CORRESPONDING #( keys )
        RESULT DATA(lt_result).
    
      result = VALUE #( FOR ls_result IN lt_result ( %tky = ls_result-%tky
                                                     %param = ls_result ) ).
    ENDMETHOD.

OverallStatus 的值有 3个,O:Open/ A:Accepted/ X:Rejected

9,测试 Accept Travel 和 Reject Travel 功能

9-1,Accept Travel

选中一条,然后点 Accept Travel 按钮

状态已经变为了 A:Accepted(受入)

9-2,Reject Travel

选中一条,然后点 Reject Travel 按钮

状态已经变为了 X:Rejected(拒否)

看一下数据库,Accept Travel/ Reject Travel 都已经写到数据库里面去了。

9-3,Accept Travel - Object Page

点 Accept Travel

修改成功

9-4,Reject Travel - Object Page

点 Reject Travel

修改成功

数据也更新了

Accept Travel,Reject Travel 本身功能就是更新一个字段,所以代码也比较少。

但是因为功能所限,所以要单独开一个App,重新做一遍 Projection View,Service,Binding。

以上就是本篇的全部内容。

如果大家觉得还行,希望大家多点赞,收藏,转发,感谢!

更多SAP顾问业务知识请点击下面目录链接或东京老树根的博客主页

https://blog.csdn.net/shi_ly/category_12216766.html

东京老树根-CSDN博客