Enterprise Resource Planning Blogs by SAP
Get insights and updates about cloud ERP and RISE with SAP, SAP S/4HANA and SAP S/4HANA Cloud, and more enterprise management capabilities with SAP blog posts.
cancel
Showing results for 
Search instead for 
Did you mean: 
Vincent_Zhu
Product and Topic Expert
Product and Topic Expert

紧随这篇博客,今天我们将再次逐步详细地介绍一个利用SAP S/4HANA Cloud三系统来做开发扩展的案例。

 

1. 案例背景

我们经常听到启用批次管理的客户在问是否有对临近效期物料的提醒、是否有对临近效期物料的批量查询报表,在标准产品中要查询相关信息需要检索多张报表,比如库存报表、批次信息等。通过利用开发人员可扩展性,我们开发了一个定制的物料临期管理App,并嵌入到SAP S/4HANA Cloud系统中。旨在帮助企业智能化地管理物料效期,提高供应链管理效率。关于业务上该自开发案例的价值,可参考此博客

shelf1.png

 

每个企业由于不同业务管理需要,可能对临近效期的提醒范围定义不同,我们还开发了警示灯自定义阈值配置app,用户可以自定义设置效期多少范围需显示为红灯,多少范围需显示为黄灯,多少范围需显示为绿灯,自定义设置满足不同企业客制化效期管理需求。

shelf2.png

 

2. 后台服务开发

2.1 创建CDS数据模型

创建数据定义YCDS_DUE_MAT_LIST

 

 

@AbapCatalog.sqlViewName: 'YDUEMATMANGE'
@AbapCatalog.compiler.compareFilter: true
//@AbapCatalog.preserveKey: true
@AccessControl.authorizationCheck: #CHECK
@EndUserText.label: 'Material Due Date List'
define view YCDS_DUE_MAT_LIST as select from I_Batch
inner join YCDS_SUM_STOCK_01 on YCDS_SUM_STOCK_01.Material = I_Batch.Material
                                       and YCDS_SUM_STOCK_01.Plant = I_Batch.Plant
                                       and YCDS_SUM_STOCK_01.Batch = I_Batch.Batch
association [1..1] to I_Product on I_Product.Product = I_Batch.Material
association [1..1] to I_ProductDescription on I_ProductDescription.Product = I_Batch.Material
                                          and I_ProductDescription.Language = $session.system_language
association [1..1] to I_Plant on I_Plant.Plant = I_Batch.Plant
                              and I_Plant.Language = $session.system_language
association [1..1] to I_Supplier on I_Supplier.Supplier = I_Batch.Supplier                           
{
  key I_Batch.Material,
  key I_Batch.Batch,
  key I_Batch.Plant,
  key I_Batch.Supplier,
  key I_Batch.BatchBySupplier,
//  key YCDS_SUM_STOCK_01.InventoryStockType,
//  key YCDS_SUM_STOCK_01.MatlDocLatestPostgDate,
  YCDS_SUM_STOCK_01.StorageLocation,
  YCDS_SUM_STOCK_01.MatlWrhsStkQtyInMatlBaseUnit,
  I_Batch.MatlBatchIsInRstrcdUseStock,
  I_Batch.ShelfLifeExpirationDate,
  I_Batch.ManufactureDate,
  I_Product.BaseUnit,
  I_ProductDescription.ProductDescription,
  I_Plant.PlantName,
  I_Supplier.SupplierName,
  case when I_Batch.MatlBatchIsInRstrcdUseStock = 'X' then 'Restricted' else 'Unrestricted' end as BatchStatus,
  $session.system_date as curr_date
}
where I_Batch.ShelfLifeExpirationDate is not initial
  and YCDS_SUM_STOCK_01.MatlWrhsStkQtyInMatlBaseUnit <> 0

 

 

 

创建数据定义YCDS_DUE_MAT_LIST2

 

 

@AbapCatalog.sqlViewName: 'YDUEMATMANGE2'
@AbapCatalog.compiler.compareFilter: true
@AbapCatalog.preserveKey: true
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'Material Due Date List'
define view YCDS_DUE_MAT_LIST2 as select from YCDS_DUE_MAT_LIST
association [1..1] to I_StorageLocation on I_StorageLocation.StorageLocation = YCDS_DUE_MAT_LIST.StorageLocation
                                       and I_StorageLocation.Plant           = YCDS_DUE_MAT_LIST.Plant
{
  key YCDS_DUE_MAT_LIST.Material,
  key YCDS_DUE_MAT_LIST.Plant,
  key YCDS_DUE_MAT_LIST.StorageLocation,
  key YCDS_DUE_MAT_LIST.Batch,
  key YCDS_DUE_MAT_LIST.Supplier,
//  key YCDS_DUE_MAT_LIST.InventoryStockType,
//  key YCDS_DUE_MAT_LIST.MatlDocLatestPostgDate,
  YCDS_DUE_MAT_LIST.ProductDescription,
  YCDS_DUE_MAT_LIST.PlantName,
  I_StorageLocation.StorageLocationName,
  YCDS_DUE_MAT_LIST.BatchBySupplier,
  YCDS_DUE_MAT_LIST.SupplierName,
  MatlWrhsStkQtyInMatlBaseUnit,
  YCDS_DUE_MAT_LIST.BaseUnit,
  YCDS_DUE_MAT_LIST.ShelfLifeExpirationDate,
  YCDS_DUE_MAT_LIST.ManufactureDate,
  YCDS_DUE_MAT_LIST.BatchStatus,
  dats_days_between(YCDS_DUE_MAT_LIST.curr_date,YCDS_DUE_MAT_LIST.ShelfLifeExpirationDate) as remaining_days
} 

 

 

 

创建数据定义YCDS_SUM_STOCK_01

 

 

@AbapCatalog.viewEnhancementCategory: [#NONE]
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'Sum of Stock 01'
@Metadata.ignorePropagatedAnnotations: true
@ObjectModel.usageType:{
  serviceQuality: #X,
  sizeCategory: #S,
  dataClass: #MIXED
}
define view entity YCDS_SUM_STOCK_01 as select from I_MaterialStock_2
{
  key Material,
  key Plant,
  key StorageLocation,
  key Batch,
  key MaterialBaseUnit,
  @Semantics.quantity.unitOfMeasure: 'MaterialBaseUnit'
  @Aggregation.default: #SUM
  sum( MatlWrhsStkQtyInMatlBaseUnit ) as MatlWrhsStkQtyInMatlBaseUnit
}
where InventoryStockType = '01'
group by Material, Plant, StorageLocation, Batch, MaterialBaseUnit

 

 

 

2.2 创建Metadata Extensions

创建新的Metadata Extension:YC_DUE_MAT_LIST

 

 

@Metadata.layer: #CUSTOMER

@UI.headerInfo.title.type: #STANDARD
@UI.headerInfo.title.label: 'Material Shelf Life Management'
@UI.headerInfo.description.type: #STANDARD
@UI.headerInfo.typeName: 'Material Due List'
@UI.headerInfo.typeNamePlural: 'Material Shelf Life Management'

annotate view YC_DUE_MAT_LIST with
{

  @UI.facet: [{ id: 'Material',
                purpose: #STANDARD,
                type: #IDENTIFICATION_REFERENCE,
                label: 'Material',
                position: 10}
                 ]

  @UI:{ lineItem: [{ position: 10 }],
        lineItem: [{label: 'Material'}],
        identification: [{ position: 10 }],
        selectionField: [{ position: 20 }]
        }
  Material;
  @UI:{ lineItem: [{ position: 20 }],
        lineItem: [{label: 'Material Description'} ],
        identification: [{ position: 20 }]
        }
  @UI.lineItem: [{exclude: true}]
  ProductDescription;
  @UI:{ lineItem: [{ position: 30 }],
        lineItem: [{label: 'Plant'}],
        identification: [{ position: 30 }],
        selectionField: [{ position: 10 }]
        }
  Plant;
  @UI:{ lineItem: [{ position: 40 }],
        lineItem: [{label: 'Plant Name'}],
        identification: [{ position: 40 }]
        }
  @UI.lineItem: [{exclude: true}]
  PlantName;
  @UI.lineItem: [{ position: 50 }]
  @UI.lineItem: [{label: 'Storage Location'}]
  @UI.identification: [{ position: 50 }]
  @UI.selectionField: [{position: 50}]
  StorageLocation;
  @UI.lineItem: [{ position: 60 }]
  @UI.lineItem: [{label: 'Storage Location Name'}]
  @UI.identification: [{ position: 60 }]
  @UI.lineItem: [{exclude: true}]
  StorageLocationName;
  @UI.lineItem: [{ position: 70 }]
  @UI.lineItem: [{label: 'Batch'}]
  @UI.identification: [{ position: 70 }]
  @UI.selectionField: [{position: 70}]
  Batch;
  @UI.lineItem: [{ position: 80 }]
  @UI.lineItem: [{label: 'Supplier Batch'}]
  @UI.identification: [{ position: 80 }]
  @UI.selectionField: [{position: 80}]
  BatchBySupplier;
  @UI.lineItem: [{ position: 90 }]
  @UI.lineItem: [{label: 'Supplier'}]
  @UI.identification: [{ position: 90 }]
  Supplier;
  @UI.lineItem: [{ position: 100 }]
  @UI.lineItem: [{label: 'Supplier Name'}]
  @UI.identification: [{ position: 100 }]
  @UI.lineItem: [{exclude: true}]
  SupplierName;
  @UI.lineItem: [{ position: 110 }]
  @UI.lineItem: [{label: 'Unrestricted Inventory Qty'}]
  @UI.identification: [{ position: 110 }]
  MatlWrhsStkQtyInMatlBaseUnit;
  @UI.lineItem: [{ position: 120 }]
  @UI.lineItem: [{label: 'Unit'}]
  @UI.identification: [{ position: 120 }]
//  @UI.lineItem: [{exclude: true}]
  @UI.hidden: true
  BaseUnit;
  @UI.lineItem: [{ position: 130 }]
  @UI.lineItem: [{label: 'Expiration Date'}]
  @UI.identification: [{ position: 130 }]
  ShelfLifeExpirationDate;
  @UI.lineItem: [{ position: 140 }]
  @UI.lineItem: [{label: 'Manufacture Date'}]
  @UI.identification: [{ position: 140 }]
  @UI.lineItem: [{exclude: true}]
  ManufactureDate;
  @UI.lineItem: [{ position: 150 }]
  @UI.lineItem: [{label: 'Batch Status'}]
  @UI.identification: [{ position: 150 }]
  @UI.lineItem: [{exclude: true}]
  BatchStatus;
  @UI.lineItem: [{ position: 160, importance: #HIGH }]
  @UI.lineItem: [{label: 'Remaining Days'}]
  @UI.identification: [{ position: 160 }]
  remaining_days;
  @UI.lineItem: [{ position: 170, value: 'due_range', criticality: 'Criticality' }]
  @UI.lineItem: [{label: 'Due Date Range'}]
  @UI.identification: [{ position: 170 }]
  due_range;    
//  @UI.hidden: true
//  InventoryStockType;
//  @UI.hidden: true
//  MatlDocLatestPostgDate;
  @UI.hidden: true
  Criticality;
}

 

 

 

2.3 创建Service Definition和Service Binding

shelf3.png

 shelf4.png

 我们可以通过预览的方式查看发布的服务:

shelf5.png

 

3. 前台应用开发

首先在BTP创建Destination:

shelf6.png

 

然后打开BAS服务,选择SAP Fiori Worklist Application:

shelf7.png

 

发布完成,部署完权限之后,就可以看到App:

shelf8.png

 

以上是该案例——物料临期管理自开发应用的步骤介绍。希望通过此案例的介绍能让您了解到三系统开发能实现的常见功能。