Hello Community,
Introduction:
Managing production deployments can be challenging when multiple teams and tools are involved. Our IT team relied on Excel sheets to track approved JIRA items for weekly bug fixes and monthly enhancements. This manual process was time-consuming and error-prone.
To simplify this, I developed an application using SAP RAP that automates the collection and management of JIRA items for deployment.
Challenges:
Tracking weekly and monthly changes across multiple teamsManual Excel-based communication for access requests, JIRA closure, and stakeholder notificationsDifficulty in auditing past deployments
Solution Overview:
I built an application leveraging RAP draft functionality to manage deployment data efficiently.
Key Features:
Centralized collection of JIRA itemsSupport for attachmentsChange HistoryDraft-enabled functionality for smooth user experienceIntegration with number ranges for unique identifiers
Technical Objects Used:
DomainData ElementDatabase TablesMain Object (Collection of JIRA Items)Sub Object (Attachments)Message ClassData Definition (CDS View)Service Definition & Service Binding (OData V4)Behavior Definition & ImplementationNumber Range
Benefits:
Eliminates manual Excel trackingProvides real-time visibility of deployment itemsImproves collaboration between IT and business stakeholders
Next Steps:
I plan to enhance the application with:
Workflow integration for approvalsEmail notifications for stakeholdersAnalytics dashboard for deployment history
Database Table
1. ZRELEASE_ITEMS – For main object
@EndUserText.label : ‘Release Items’
@AbapCatalog.enhancement.category : #EXTENSIBLE_ANY
@AbapCatalog.tableCategory : #TRANSPARENT
@AbapCatalog.deliveryClass : #A
@AbapCatalog.dataMaintenance : #RESTRICTED
define table zrelease_items {
key client : abap.clnt not null;
key id : abap.char(10) not null;
key defect : zdefectid not null;
description : abap.char(300);
projecttype : zproject_typ;
region : zregio;
releasetype : zreltype;
changetype : zchange_typ;
releasedate : abap.dats;
ffidused : abap.char(50);
jiraurl : abap.char(500);
createdon : abap.dats;
createdby : abp_creation_user;
isdeployed : abap_boolean;
}
2. ZRELATTACH – For attachment
@EndUserText.label : ‘Release Items Attachments’
@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE
@AbapCatalog.tableCategory : #TRANSPARENT
@AbapCatalog.deliveryClass : #A
@AbapCatalog.dataMaintenance : #RESTRICTED
define table zrelattach {
key client : abap.clnt not null;
key zrelid : abap.char(10) not null;
key zdefect : zdefectid not null;
key zid : uuid not null;
attachment : zrawstr;
mimetype : abap.char(128);
filename : abap.char(255);
crtby : abp_creation_user;
crton : abp_creation_date;
}
ZREL_CHANGELOG – For Change History
@EndUserText.label : ‘release item scenario: log changes to release entity’
@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE
@AbapCatalog.tableCategory : #TRANSPARENT
@AbapCatalog.deliveryClass : #A
@AbapCatalog.dataMaintenance : #RESTRICTED
define table zrel_changelog {
key client : abap.clnt not null;
key change_id : abap.raw(16) not null;
id : abap.char(10) not null;
changing_operation : abap.char(10);
changed_field_name : abap.char(32);
changed_from : abap.char(255);
changed_value : abap.char(255);
created_at : timestampl;
changed_by : abp_creation_user;
}
CDS – Basic View(Header)
@AbapCatalog.viewEnhancementCategory: [ #NONE ]
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: ‘Basic View For Release Items’
@Metadata.ignorePropagatedAnnotations: true
@Metadata.allowExtensions: true
@ObjectModel.usageType: { serviceQuality: #X, sizeCategory: #S, dataClass: #MIXED }
define root view entity ZI_RELEASE
as select from zrelease_items
composition [0..*] of ZI_ATTACH as _Attach
association [1] to ZI_PROJECT_FV as _ProjectText on $projection.Projecttype = _ProjectText.ProjType
association [1] to ZI_REGION_FV as _RegionText on $projection.Region = _RegionText.Staging
association [1] to ZI_RELTYP_FV as _ReleaseText on $projection.ReleaseType = _ReleaseText.RelType
association [1] to ZI_CHANGE_FV as _ChangeText on $projection.ChangeType = _ChangeText.ChangeTyp
association [0..*] to ZC_CHANGELOG as _ChangeLog on $projection.Id = _ChangeLog.Id
{
key id as Id,
key defect as Defect,
description as Description,
@ObjectModel.text.association: ‘_ProjectText’
projecttype as Projecttype,
@ObjectModel.text.association: ‘_RegionText’
region as Region,
@ObjectModel.text.association: ‘_ReleaseText’
releasetype as ReleaseType,
@ObjectModel.text.association: ‘_ChangeText’
changetype as ChangeType,
releasedate as ReleaseDate,
ffidused as FFID,
jiraurl as JiraUrl,
createdon as CreatedOn,
createdby as CreatedBy,
isdeployed as IsDeployed,
_Attach,
_ProjectText,
_RegionText,
_ReleaseText,
_ChangeText,
_ChangeLog
}
CDS – Projection(Header)
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: ‘Consumption View For Release Item’
@Metadata.ignorePropagatedAnnotations: true
@Metadata.allowExtensions: true
@Search.searchable: true
@ObjectModel.semanticKey: [ ‘Id’,’Defect’ ]
define root view entity ZC_RELEASE provider contract transactional_query as projection on ZI_RELEASE
{
key Id,
@ObjectModel.sort.enabled: true
key Defect,
Description,
@ObjectModel.text.element: [ ‘ProjectText’ ]
Projecttype,
_ProjectText.Description as ProjectText,
@ObjectModel.text.element: [ ‘RegionText’ ]
Region,
_RegionText.Description as RegionText,
@ObjectModel.text.element: [ ‘ReleaseText’ ]
ReleaseType,
_ReleaseText.Description as ReleaseText,
@ObjectModel.text.element: [ ‘ChangeText’ ]
ChangeType,
_ChangeText.Description as ChangeText,
ReleaseDate,
FFID,
JiraUrl,
CreatedOn,
@Semantics.user.createdBy: true
CreatedBy,
IsDeployed,
_Attach : redirected to composition child ZC_ATTACH,
_ProjectText,
_RegionText,
_ReleaseText,
_ChangeText,
_ChangeLog
}
CDS – Basic(Attachment)
@AbapCatalog.viewEnhancementCategory: [#NONE]
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: ‘Basic View For Attachment’
@Metadata.ignorePropagatedAnnotations: true
@Metadata.allowExtensions: true
@ObjectModel.usageType:{
serviceQuality: #X,
sizeCategory: #S,
dataClass: #MIXED
}
define view entity ZI_ATTACH as select from zrelattach
association to parent ZI_RELEASE as _RELEASE on $projection.Zrelid = _RELEASE.Id and
$projection.Zdefect = _RELEASE.Defect
{
key zrelattach.zrelid as Zrelid,
key zrelattach.zdefect as Zdefect,
key zrelattach.zid as Zid,
zrelattach.attachment as Attachment,
zrelattach.mimetype as Mimetype,
zrelattach.filename as Filename,
zrelattach.crtby as Crtby,
zrelattach.crton as Crton,
_RELEASE
}
CDS – Projection(Attachment)
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: ‘Consumption View For Attachment’
@Metadata.ignorePropagatedAnnotations: true
@Metadata.allowExtensions: true
define view entity ZC_ATTACH as projection on ZI_ATTACH
{
key Zrelid,
key Zdefect,
key Zid,
@Semantics.largeObject:{
fileName: ‘Filename’,
mimeType: ‘Mimetype’,
contentDispositionPreference: #INLINE
}
Attachment,
@Semantics.mimeType: true
Mimetype,
Filename,
@Semantics.user.createdBy: true
Crtby,
Crton,
/* Associations */
_RELEASE : redirected to parent ZC_RELEASE
}
CDS – Basic view(Change History)
@AbapCatalog.viewEnhancementCategory: [#NONE]
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: ‘Basic View For Change Log’
@Metadata.ignorePropagatedAnnotations: true
@ObjectModel.usageType:{
serviceQuality: #X,
sizeCategory: #S,
dataClass: #MIXED
}
define view entity ZI_CHANGELOG as select from zrel_changelog
{
key change_id as ChangeId,
id as Id,
changing_operation as ChangingOperation,
changed_field_name as ChangedFieldName,
changed_from as ChangedFrom,
changed_value as ChangedValue,
created_at as CreatedAt,
changed_by as ChangedBy
}
CDS – Metadata extension(Header)
@Metadata.layer: #CORE
@Search.searchable: true
annotate view ZC_RELEASE with
{
@EndUserText.label: ‘ID’
.defaultSearchElement: true
.fuzzinessThreshold: 0.7
.facet: [ //{ id: ‘HeaderInfo’, label: ‘Header Info’, type: #COLLECTION, targetQualifier: ‘Header’ },
{ id: ‘GeneralInfo’,
label: ‘General’,
targetQualifier: ‘General’,
type: #IDENTIFICATION_REFERENCE,
purpose: #STANDARD,
position: 10
//parentId: ‘HeaderInfo’
},
{ id: ‘Attach’,
label: ‘Attachments’,
targetQualifier: ‘Attach’,
type: #LINEITEM_REFERENCE,
targetElement: ‘_Attach’,
//parentId: ‘HeaderInfo’,
position: 20 },
{
id: ‘ChangeLog’,
label: ‘Changes’,
targetQualifier: ‘ChangeLog’,
type: #LINEITEM_REFERENCE,
targetElement: ‘_ChangeLog’,
position: 30
} ]
.identification: [ { position: 10, qualifier: ‘General’ } ]
.lineItem: [ { position: 10, label: ‘Mark As Deployed’,type: #FOR_ACTION , dataAction: ‘MrkDep’ } ]
.selectionField: [ { position: 10 } ]
Id;
.defaultSearchElement: true
.fuzzinessThreshold: 0.7
.identification: [ { position: 20, qualifier: ‘General’ } ]
.lineItem: [ { position: 20, label: ‘Defect’ } ]
.selectionField: [ { position: 20 } ]
Defect;
@EndUserText.label: ‘Description’
.defaultSearchElement: true
.fuzzinessThreshold: 0.7
.identification: [ { position: 30, qualifier: ‘General’ } ]
.lineItem: [ { position: 30, label: ‘Description’ } ]
Description;
@Consumption.valueHelpDefinition: [ { entity: { element: ‘Staging’, name: ‘ZI_REGION_FV’ } } ]
@Consumption.filter.selectionType: #SINGLE
@EndUserText.label: ‘Region’
.identification: [ { position: 40, qualifier: ‘General’ } ]
.lineItem: [ { position: 40, label: ‘Region’ } ]
.selectionField: [ { position: 30 } ]
.textArrangement: #TEXT_ONLY
Region;
@Consumption.valueHelpDefinition: [ { entity: { element: ‘ProjType’, name: ‘ZI_PROJECT_FV’ } } ]
.textArrangement: #TEXT_ONLY
@Consumption.filter.selectionType: #SINGLE
.identification: [ { position: 50, qualifier: ‘General’ } ]
.lineItem: [ { position: 50, label: ‘Project Type’ } ]
.selectionField: [ { position: 40 } ]
Projecttype;
@Consumption.valueHelpDefinition: [ { entity: { element: ‘RelType’, name: ‘ZI_RELTYP_FV’ } } ]
@Consumption.filter.selectionType: #SINGLE
.textArrangement: #TEXT_ONLY
.identification: [ { position: 60, qualifier: ‘General’ } ]
.lineItem: [ { position: 60, label: ‘Release Type’ } ]
.selectionField: [ { position: 50 } ]
ReleaseType;
@Consumption.valueHelpDefinition: [ { entity: { element: ‘ChangeTyp’, name: ‘ZI_CHANGE_FV’ } } ]
@Consumption.filter.selectionType: #SINGLE
.textArrangement: #TEXT_ONLY
.identification: [ { position: 70, qualifier: ‘General’ } ]
.lineItem: [ { position: 70, label: ‘Change Type’ } ]
.selectionField: [ { position: 60 } ]
ChangeType;
@EndUserText.label: ‘FF ID’
.identification: [ { position: 80, qualifier: ‘General’ } ]
.lineItem: [ { position: 100, label: ‘FF ID’ } ]
FFID;
@EndUserText.label: ‘JIRA Link’
.identification: [ { position: 100, qualifier: ‘General’ } ]
JiraUrl;
@EndUserText.label: ‘Release Date’
.identification: [ { position: 90, qualifier: ‘General’ } ]
.lineItem: [ { position: 100, label: ‘Release Date’ } ]
.selectionField: [ { position: 70 } ]
@Consumption.filter.selectionType: #SINGLE
ReleaseDate;
@EndUserText.label: ‘Created On’
.identification: [ { position: 110, qualifier: ‘General’ } ]
.selectionField: [ { position: 80 } ]
@Consumption.filter.selectionType: #SINGLE
CreatedOn;
@EndUserText.label: ‘Created By’
.identification: [{ position: 120, qualifier: ‘General’ }]
.selectionField: [ { position: 90 } ]
CreatedBy;
@EndUserText.label: ‘IsDeployed’
.identification: [{ position: 130, qualifier: ‘General’ }]
.lineItem: [{ position: 130, label: ‘IsDeployed’,emphasized: true }]
.selectionField: [ { position: 100 } ]
IsDeployed;
}
CDS – Metadata extension(Attachment)
@Metadata.layer: #CORE
annotate entity ZC_ATTACH
with
{
.hidden: true
Zrelid;
.hidden: true
Zdefect;
.hidden: true
Zid;
.textArrangement: #TEXT_FIRST
.lineItem: [{ position: 10,label: ‘Attachment’ ,qualifier: ‘Attach’}]
.identification: [{position: 10}]
Attachment;
.hidden: true
Mimetype;
.textArrangement: #TEXT_FIRST
.lineItem: [{ position: 20,label: ‘Description’ , qualifier: ‘Attach’}]
.identification: [{position: 20}]
Filename;
.lineItem: [{ position: 30,label: ‘CreatedBy’ ,qualifier: ‘Attach’}]
.identification: [{position: 30}]
Crtby;
.lineItem: [{ position: 40,label: ‘CreatedOn’ ,qualifier: ‘Attach’}]
.identification: [{position: 40}]
Crton;
/* Associations */
//_RELEASE;
}
CDS – Metadata Extension(Change History)
@Metadata.layer: #CORE
annotate entity ZC_CHANGELOG
with
{
.hidden: true
ChangeId;
.hidden: true
Id;
.lineItem: [{ position: 10,label: ‘Operation’,qualifier: ‘ChangeLog’ }]
ChangingOperation;
.lineItem: [{ position: 20,label: ‘Field’ , qualifier: ‘ChangeLog’}]
ChangedFieldName;
.lineItem: [{ position: 30,label: ‘Old Value’ , qualifier: ‘ChangeLog’}]
ChangedFrom;
.lineItem: [{ position: 40,label: ‘New Value’ ,qualifier: ‘ChangeLog’}]
ChangedValue;
.hidden: true
CreatedAt;
.lineItem: [{ position: 60,label: ‘Change By’ ,qualifier: ‘ChangeLog’}]
ChangedBy;
}
Service Definition
@EndUserText.label: ‘Service definition for release item’
define service ZSD_RELEASE {
expose ZC_RELEASE;
expose ZC_ATTACH;
expose ZC_CHANGELOG;
}
Service Binding
Number Range
Behavior Definition
managed implementation in class zbp_i_release unique;
strict ( 2 );
with draft;
define behavior for ZI_RELEASE //alias <alias_name>
persistent table zrelease_items
draft table ZDRAFT_RELEASE
lock master
authorization master ( instance,global )
late numbering
etag master CreatedOn
{
create ( authorization : global );
update(features : instance);
delete(features : instance);
field ( readonly ) Id;
field ( readonly : update) Defect;
field ( mandatory : create ) Defect; // ChangeType,Description,Region,Projecttype,ffid,ReleaseDate,ReleaseType;
field ( features : instance ) ChangeType,Description,Region,Projecttype,ffid,ReleaseDate,ReleaseType,IsDeployed;
association _Attach {create;with draft;}
action ( features : instance ) MrkDep;
draft action Edit;
draft action Resume;
draft action Activate optimized;
draft action Discard;
draft determine action Prepare
{
validation ValidateDD;
}
validation ValidateDD on save {create;update;}
side effects
{
field Defect affects field JiraUrl;
}
determination BuildURL on modify { field Defect; }
mapping for zrelease_items {
Id = id;
Defect = defect;
ffid = ffidused;
ChangeType = changetype;
Description = description;
JiraUrl = jiraurl;
Projecttype = projecttype;
Region = region;
ReleaseDate = releasedate;
ReleaseType = releasetype;
CreatedOn = createdon;
CreatedBy = createdby;
IsDeployed = isdeployed;
}
}
define behavior for ZI_ATTACH
implementation in class zimpl_attach unique
persistent table zrelattach
draft table zdraft_attach
lock dependent by _RELEASE
authorization dependent by _RELEASE
late numbering
etag dependent by _RELEASE
{
update;
delete;
field ( readonly:update ) Zdefect,Zrelid,Zid;
association _RELEASE {with draft;}
mapping for zrelattach{
Zrelid = zrelid;
Zdefect = zdefect;
Zid = zid;
Filename = filename;
Attachment = attachment;
Crtby = crtby;
Crton = crton;
Mimetype = mimetype;
}
}
Behavior Implementation
1. Number Assignment
LOOP AT mapped-zi_release REFERENCE INTO DATA(map).
IF map->Id IS NOT INITIAL.
CONTINUE.
ENDIF.
TRY.
cl_numberrange_runtime=>number_get( EXPORTING object = ‘ZRELEASEID’
nr_range_nr = ’01’
IMPORTING number = DATA(lv_id) ).
CATCH cx_nr_object_not_found.
CATCH cx_number_ranges.
ENDTRY.
map->Id = |{ lv_id ALPHA = OUT }|.
map->Defect = map->%tmp-Defect.
ENDLOOP.
2. URL generation,
READ ENTITIES OF zi_release IN LOCAL MODE
ENTITY zi_release ALL FIELDS WITH CORRESPONDING #( keys )
RESULT DATA(lt_results).
LOOP AT lt_results ASSIGNING FIELD-SYMBOL(<ls_result>).
IF <ls_result>-JiraUrl IS INITIAL.
<ls_result>-JiraUrl = |https://Jira.company.com/browse/{ <ls_result>-Defect }|.
ENDIF.
IF <ls_result>-CreatedOn IS INITIAL.
<ls_result>-CreatedOn = cl_abap_context_info=>get_system_date( ).
ENDIF.
IF <ls_result>-CreatedBy IS INITIAL.
TRY.
<ls_result>-CreatedBy = cl_abap_context_info=>get_user_technical_name( ).
CATCH cx_abap_context_info_error.
ENDTRY.
ENDIF.
ENDLOOP.
MODIFY ENTITIES OF zi_release IN LOCAL MODE
ENTITY zi_release
UPDATE FIELDS ( JiraUrl CreatedOn CreatedBy )
WITH CORRESPONDING #( lt_results ).
ENDMETHOD.
assignment of created on/created by
Video Snip
Hello Community,Introduction:Managing production deployments can be challenging when multiple teams and tools are involved. Our IT team relied on Excel sheets to track approved JIRA items for weekly bug fixes and monthly enhancements. This manual process was time-consuming and error-prone.To simplify this, I developed an application using SAP RAP that automates the collection and management of JIRA items for deployment.Challenges:Tracking weekly and monthly changes across multiple teamsManual Excel-based communication for access requests, JIRA closure, and stakeholder notificationsDifficulty in auditing past deploymentsSolution Overview:I built an application leveraging RAP draft functionality to manage deployment data efficiently.Key Features:Centralized collection of JIRA itemsSupport for attachmentsChange HistoryDraft-enabled functionality for smooth user experienceIntegration with number ranges for unique identifiersTechnical Objects Used:DomainData ElementDatabase TablesMain Object (Collection of JIRA Items)Sub Object (Attachments)Message ClassData Definition (CDS View)Service Definition & Service Binding (OData V4)Behavior Definition & ImplementationNumber RangeBenefits:Eliminates manual Excel trackingProvides real-time visibility of deployment itemsImproves collaboration between IT and business stakeholdersNext Steps:I plan to enhance the application with:Workflow integration for approvalsEmail notifications for stakeholdersAnalytics dashboard for deployment history⚠️Important DisclaimerThe content shared in this blog represents a conceptual idea and a demonstration only. It has not been implemented in a live environment and should not be considered as a production-ready solution. Any steps or configurations mentioned are for illustrative purposes only. Please validate and test thoroughly before applying in your SAP landscape. NoteAll code snippets and logic referenced in this blog will be published in the coming days on a dedicated GitHub repository. Once available, I will update this post with the repository link for your reference.Database Table 1. ZRELEASE_ITEMS – For main object@EndUserText.label : ‘Release Items’
@AbapCatalog.enhancement.category : #EXTENSIBLE_ANY
@AbapCatalog.tableCategory : #TRANSPARENT
@AbapCatalog.deliveryClass : #A
@AbapCatalog.dataMaintenance : #RESTRICTED
define table zrelease_items {
key client : abap.clnt not null;
key id : abap.char(10) not null;
key defect : zdefectid not null;
description : abap.char(300);
projecttype : zproject_typ;
region : zregio;
releasetype : zreltype;
changetype : zchange_typ;
releasedate : abap.dats;
ffidused : abap.char(50);
jiraurl : abap.char(500);
createdon : abap.dats;
createdby : abp_creation_user;
isdeployed : abap_boolean;
}2. ZRELATTACH – For attachment@EndUserText.label : ‘Release Items Attachments’
@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE
@AbapCatalog.tableCategory : #TRANSPARENT
@AbapCatalog.deliveryClass : #A
@AbapCatalog.dataMaintenance : #RESTRICTED
define table zrelattach {
key client : abap.clnt not null;
key zrelid : abap.char(10) not null;
key zdefect : zdefectid not null;
key zid : uuid not null;
attachment : zrawstr;
mimetype : abap.char(128);
filename : abap.char(255);
crtby : abp_creation_user;
crton : abp_creation_date;
}ZREL_CHANGELOG – For Change History@EndUserText.label : ‘release item scenario: log changes to release entity’
@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE
@AbapCatalog.tableCategory : #TRANSPARENT
@AbapCatalog.deliveryClass : #A
@AbapCatalog.dataMaintenance : #RESTRICTED
define table zrel_changelog {
key client : abap.clnt not null;
key change_id : abap.raw(16) not null;
id : abap.char(10) not null;
changing_operation : abap.char(10);
changed_field_name : abap.char(32);
changed_from : abap.char(255);
changed_value : abap.char(255);
created_at : timestampl;
changed_by : abp_creation_user;
} CDS – Basic View(Header)@AbapCatalog.viewEnhancementCategory: [ #NONE ]
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: ‘Basic View For Release Items’
@Metadata.ignorePropagatedAnnotations: true
@Metadata.allowExtensions: true
@ObjectModel.usageType: { serviceQuality: #X, sizeCategory: #S, dataClass: #MIXED }
define root view entity ZI_RELEASE
as select from zrelease_items
composition [0..*] of ZI_ATTACH as _Attach
association [1] to ZI_PROJECT_FV as _ProjectText on $projection.Projecttype = _ProjectText.ProjType
association [1] to ZI_REGION_FV as _RegionText on $projection.Region = _RegionText.Staging
association [1] to ZI_RELTYP_FV as _ReleaseText on $projection.ReleaseType = _ReleaseText.RelType
association [1] to ZI_CHANGE_FV as _ChangeText on $projection.ChangeType = _ChangeText.ChangeTyp
association [0..*] to ZC_CHANGELOG as _ChangeLog on $projection.Id = _ChangeLog.Id
{
key id as Id,
key defect as Defect,
description as Description,
@ObjectModel.text.association: ‘_ProjectText’
projecttype as Projecttype,
@ObjectModel.text.association: ‘_RegionText’
region as Region,
@ObjectModel.text.association: ‘_ReleaseText’
releasetype as ReleaseType,
@ObjectModel.text.association: ‘_ChangeText’
changetype as ChangeType,
releasedate as ReleaseDate,
ffidused as FFID,
jiraurl as JiraUrl,
createdon as CreatedOn,
createdby as CreatedBy,
isdeployed as IsDeployed,
_Attach,
_ProjectText,
_RegionText,
_ReleaseText,
_ChangeText,
_ChangeLog
} CDS – Projection(Header) @AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: ‘Consumption View For Release Item’
@Metadata.ignorePropagatedAnnotations: true
@Metadata.allowExtensions: true
@Search.searchable: true
@ObjectModel.semanticKey: [ ‘Id’,’Defect’ ]
define root view entity ZC_RELEASE provider contract transactional_query as projection on ZI_RELEASE
{
key Id,
@ObjectModel.sort.enabled: true
key Defect,
Description,
@ObjectModel.text.element: [ ‘ProjectText’ ]
Projecttype,
_ProjectText.Description as ProjectText,
@ObjectModel.text.element: [ ‘RegionText’ ]
Region,
_RegionText.Description as RegionText,
@ObjectModel.text.element: [ ‘ReleaseText’ ]
ReleaseType,
_ReleaseText.Description as ReleaseText,
@ObjectModel.text.element: [ ‘ChangeText’ ]
ChangeType,
_ChangeText.Description as ChangeText,
ReleaseDate,
FFID,
JiraUrl,
CreatedOn,
@Semantics.user.createdBy: true
CreatedBy,
IsDeployed,
_Attach : redirected to composition child ZC_ATTACH,
_ProjectText,
_RegionText,
_ReleaseText,
_ChangeText,
_ChangeLog
}CDS – Basic(Attachment)@AbapCatalog.viewEnhancementCategory: [#NONE]
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: ‘Basic View For Attachment’
@Metadata.ignorePropagatedAnnotations: true
@Metadata.allowExtensions: true
@ObjectModel.usageType:{
serviceQuality: #X,
sizeCategory: #S,
dataClass: #MIXED
}
define view entity ZI_ATTACH as select from zrelattach
association to parent ZI_RELEASE as _RELEASE on $projection.Zrelid = _RELEASE.Id and
$projection.Zdefect = _RELEASE.Defect
{
key zrelattach.zrelid as Zrelid,
key zrelattach.zdefect as Zdefect,
key zrelattach.zid as Zid,
zrelattach.attachment as Attachment,
zrelattach.mimetype as Mimetype,
zrelattach.filename as Filename,
zrelattach.crtby as Crtby,
zrelattach.crton as Crton,
_RELEASE
}CDS – Projection(Attachment)@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: ‘Consumption View For Attachment’
@Metadata.ignorePropagatedAnnotations: true
@Metadata.allowExtensions: true
define view entity ZC_ATTACH as projection on ZI_ATTACH
{
key Zrelid,
key Zdefect,
key Zid,
@Semantics.largeObject:{
fileName: ‘Filename’,
mimeType: ‘Mimetype’,
contentDispositionPreference: #INLINE
}
Attachment,
@Semantics.mimeType: true
Mimetype,
Filename,
@Semantics.user.createdBy: true
Crtby,
Crton,
/* Associations */
_RELEASE : redirected to parent ZC_RELEASE
}CDS – Basic view(Change History)@AbapCatalog.viewEnhancementCategory: [#NONE]
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: ‘Basic View For Change Log’
@Metadata.ignorePropagatedAnnotations: true
@ObjectModel.usageType:{
serviceQuality: #X,
sizeCategory: #S,
dataClass: #MIXED
}
define view entity ZI_CHANGELOG as select from zrel_changelog
{
key change_id as ChangeId,
id as Id,
changing_operation as ChangingOperation,
changed_field_name as ChangedFieldName,
changed_from as ChangedFrom,
changed_value as ChangedValue,
created_at as CreatedAt,
changed_by as ChangedBy
}CDS – Metadata extension(Header)@Metadata.layer: #CORE
@Search.searchable: true
annotate view ZC_RELEASE with
{
@EndUserText.label: ‘ID’
.defaultSearchElement: true
.fuzzinessThreshold: 0.7
.facet: [ //{ id: ‘HeaderInfo’, label: ‘Header Info’, type: #COLLECTION, targetQualifier: ‘Header’ },
{ id: ‘GeneralInfo’,
label: ‘General’,
targetQualifier: ‘General’,
type: #IDENTIFICATION_REFERENCE,
purpose: #STANDARD,
position: 10
//parentId: ‘HeaderInfo’
},
{ id: ‘Attach’,
label: ‘Attachments’,
targetQualifier: ‘Attach’,
type: #LINEITEM_REFERENCE,
targetElement: ‘_Attach’,
//parentId: ‘HeaderInfo’,
position: 20 },
{
id: ‘ChangeLog’,
label: ‘Changes’,
targetQualifier: ‘ChangeLog’,
type: #LINEITEM_REFERENCE,
targetElement: ‘_ChangeLog’,
position: 30
} ]
.identification: [ { position: 10, qualifier: ‘General’ } ]
.lineItem: [ { position: 10, label: ‘Mark As Deployed’,type: #FOR_ACTION , dataAction: ‘MrkDep’ } ]
.selectionField: [ { position: 10 } ]
Id;
.defaultSearchElement: true
.fuzzinessThreshold: 0.7
.identification: [ { position: 20, qualifier: ‘General’ } ]
.lineItem: [ { position: 20, label: ‘Defect’ } ]
.selectionField: [ { position: 20 } ]
Defect;
@EndUserText.label: ‘Description’
.defaultSearchElement: true
.fuzzinessThreshold: 0.7
.identification: [ { position: 30, qualifier: ‘General’ } ]
.lineItem: [ { position: 30, label: ‘Description’ } ]
Description;
@Consumption.valueHelpDefinition: [ { entity: { element: ‘Staging’, name: ‘ZI_REGION_FV’ } } ]
@Consumption.filter.selectionType: #SINGLE
@EndUserText.label: ‘Region’
.identification: [ { position: 40, qualifier: ‘General’ } ]
.lineItem: [ { position: 40, label: ‘Region’ } ]
.selectionField: [ { position: 30 } ]
.textArrangement: #TEXT_ONLY
Region;
@Consumption.valueHelpDefinition: [ { entity: { element: ‘ProjType’, name: ‘ZI_PROJECT_FV’ } } ]
.textArrangement: #TEXT_ONLY
@Consumption.filter.selectionType: #SINGLE
.identification: [ { position: 50, qualifier: ‘General’ } ]
.lineItem: [ { position: 50, label: ‘Project Type’ } ]
.selectionField: [ { position: 40 } ]
Projecttype;
@Consumption.valueHelpDefinition: [ { entity: { element: ‘RelType’, name: ‘ZI_RELTYP_FV’ } } ]
@Consumption.filter.selectionType: #SINGLE
.textArrangement: #TEXT_ONLY
.identification: [ { position: 60, qualifier: ‘General’ } ]
.lineItem: [ { position: 60, label: ‘Release Type’ } ]
.selectionField: [ { position: 50 } ]
ReleaseType;
@Consumption.valueHelpDefinition: [ { entity: { element: ‘ChangeTyp’, name: ‘ZI_CHANGE_FV’ } } ]
@Consumption.filter.selectionType: #SINGLE
.textArrangement: #TEXT_ONLY
.identification: [ { position: 70, qualifier: ‘General’ } ]
.lineItem: [ { position: 70, label: ‘Change Type’ } ]
.selectionField: [ { position: 60 } ]
ChangeType;
@EndUserText.label: ‘FF ID’
.identification: [ { position: 80, qualifier: ‘General’ } ]
.lineItem: [ { position: 100, label: ‘FF ID’ } ]
FFID;
@EndUserText.label: ‘JIRA Link’
.identification: [ { position: 100, qualifier: ‘General’ } ]
JiraUrl;
@EndUserText.label: ‘Release Date’
.identification: [ { position: 90, qualifier: ‘General’ } ]
.lineItem: [ { position: 100, label: ‘Release Date’ } ]
.selectionField: [ { position: 70 } ]
@Consumption.filter.selectionType: #SINGLE
ReleaseDate;
@EndUserText.label: ‘Created On’
.identification: [ { position: 110, qualifier: ‘General’ } ]
.selectionField: [ { position: 80 } ]
@Consumption.filter.selectionType: #SINGLE
CreatedOn;
@EndUserText.label: ‘Created By’
.identification: [{ position: 120, qualifier: ‘General’ }]
.selectionField: [ { position: 90 } ]
CreatedBy;
@EndUserText.label: ‘IsDeployed’
.identification: [{ position: 130, qualifier: ‘General’ }]
.lineItem: [{ position: 130, label: ‘IsDeployed’,emphasized: true }]
.selectionField: [ { position: 100 } ]
IsDeployed;
}CDS – Metadata extension(Attachment)@Metadata.layer: #CORE
annotate entity ZC_ATTACH
with
{
.hidden: true
Zrelid;
.hidden: true
Zdefect;
.hidden: true
Zid;
.textArrangement: #TEXT_FIRST
.lineItem: [{ position: 10,label: ‘Attachment’ ,qualifier: ‘Attach’}]
.identification: [{position: 10}]
Attachment;
.hidden: true
Mimetype;
.textArrangement: #TEXT_FIRST
.lineItem: [{ position: 20,label: ‘Description’ , qualifier: ‘Attach’}]
.identification: [{position: 20}]
Filename;
.lineItem: [{ position: 30,label: ‘CreatedBy’ ,qualifier: ‘Attach’}]
.identification: [{position: 30}]
Crtby;
.lineItem: [{ position: 40,label: ‘CreatedOn’ ,qualifier: ‘Attach’}]
.identification: [{position: 40}]
Crton;
/* Associations */
//_RELEASE;
}CDS – Metadata Extension(Change History)@Metadata.layer: #CORE
annotate entity ZC_CHANGELOG
with
{
.hidden: true
ChangeId;
.hidden: true
Id;
.lineItem: [{ position: 10,label: ‘Operation’,qualifier: ‘ChangeLog’ }]
ChangingOperation;
.lineItem: [{ position: 20,label: ‘Field’ , qualifier: ‘ChangeLog’}]
ChangedFieldName;
.lineItem: [{ position: 30,label: ‘Old Value’ , qualifier: ‘ChangeLog’}]
ChangedFrom;
.lineItem: [{ position: 40,label: ‘New Value’ ,qualifier: ‘ChangeLog’}]
ChangedValue;
.hidden: true
CreatedAt;
.lineItem: [{ position: 60,label: ‘Change By’ ,qualifier: ‘ChangeLog’}]
ChangedBy;
}Service Definition@EndUserText.label: ‘Service definition for release item’
define service ZSD_RELEASE {
expose ZC_RELEASE;
expose ZC_ATTACH;
expose ZC_CHANGELOG;
}Service BindingNumber RangeBehavior Definitionmanaged implementation in class zbp_i_release unique;
strict ( 2 );
with draft;
define behavior for ZI_RELEASE //alias <alias_name>
persistent table zrelease_items
draft table ZDRAFT_RELEASE
lock master
authorization master ( instance,global )
late numbering
etag master CreatedOn
{
create ( authorization : global );
update(features : instance);
delete(features : instance);
field ( readonly ) Id;
field ( readonly : update) Defect;
field ( mandatory : create ) Defect; // ChangeType,Description,Region,Projecttype,ffid,ReleaseDate,ReleaseType;
field ( features : instance ) ChangeType,Description,Region,Projecttype,ffid,ReleaseDate,ReleaseType,IsDeployed;
association _Attach {create;with draft;}
action ( features : instance ) MrkDep;
draft action Edit;
draft action Resume;
draft action Activate optimized;
draft action Discard;
draft determine action Prepare
{
validation ValidateDD;
}
validation ValidateDD on save {create;update;}
side effects
{
field Defect affects field JiraUrl;
}
determination BuildURL on modify { field Defect; }
mapping for zrelease_items {
Id = id;
Defect = defect;
ffid = ffidused;
ChangeType = changetype;
Description = description;
JiraUrl = jiraurl;
Projecttype = projecttype;
Region = region;
ReleaseDate = releasedate;
ReleaseType = releasetype;
CreatedOn = createdon;
CreatedBy = createdby;
IsDeployed = isdeployed;
}
}
define behavior for ZI_ATTACH
implementation in class zimpl_attach unique
persistent table zrelattach
draft table zdraft_attach
lock dependent by _RELEASE
authorization dependent by _RELEASE
late numbering
etag dependent by _RELEASE
{
update;
delete;
field ( readonly:update ) Zdefect,Zrelid,Zid;
association _RELEASE {with draft;}
mapping for zrelattach{
Zrelid = zrelid;
Zdefect = zdefect;
Zid = zid;
Filename = filename;
Attachment = attachment;
Crtby = crtby;
Crton = crton;
Mimetype = mimetype;
}
}Behavior Implementation1. Number Assignment LOOP AT mapped-zi_release REFERENCE INTO DATA(map).
IF map->Id IS NOT INITIAL.
CONTINUE.
ENDIF.
TRY.
cl_numberrange_runtime=>number_get( EXPORTING object = ‘ZRELEASEID’
nr_range_nr = ’01’
IMPORTING number = DATA(lv_id) ).
CATCH cx_nr_object_not_found.
CATCH cx_number_ranges.
ENDTRY.
map->Id = |{ lv_id ALPHA = OUT }|.
map->Defect = map->%tmp-Defect.
ENDLOOP.2. URL generation, READ ENTITIES OF zi_release IN LOCAL MODE
ENTITY zi_release ALL FIELDS WITH CORRESPONDING #( keys )
RESULT DATA(lt_results).
LOOP AT lt_results ASSIGNING FIELD-SYMBOL(<ls_result>).
IF <ls_result>-JiraUrl IS INITIAL.
<ls_result>-JiraUrl = |https://Jira.company.com/browse/{ <ls_result>-Defect }|.
ENDIF.
IF <ls_result>-CreatedOn IS INITIAL.
<ls_result>-CreatedOn = cl_abap_context_info=>get_system_date( ).
ENDIF.
IF <ls_result>-CreatedBy IS INITIAL.
TRY.
<ls_result>-CreatedBy = cl_abap_context_info=>get_user_technical_name( ).
CATCH cx_abap_context_info_error.
ENDTRY.
ENDIF.
ENDLOOP.
MODIFY ENTITIES OF zi_release IN LOCAL MODE
ENTITY zi_release
UPDATE FIELDS ( JiraUrl CreatedOn CreatedBy )
WITH CORRESPONDING #( lt_results ).
ENDMETHOD. assignment of created on/created by Video Snip Read More Technology Blog Posts by Members articles
#SAP
#SAPTechnologyblog