Skip to Content
Technical Articles

Creating a draft enabled Sales Order Fiori App using the new ABAP Programming Model – Part 3: Defining the UI & Creating the Fiori Elements App

Defining the UI using Metadata Extensions

In the previous part we’ve defined the data model for our app. Now it’s time to define how our app should look like. We’ll do this by adding UI annotations to our consumption views using Metadata Extensions.

Within the next few subsections I’ll try to explain how the different annotations determine how the UI will look like.

UI annotations for List Report

Annotation Usage
@UI.typeNamePlural Title above the list
@UI.selectionField Default position of the field within the selection criteria
@UI.lineItem Default position of the field within the table

 

UI annotations for Object Page facets

Annotation Usage
@UI.facet Used to group fields as desired
@UI.facet.type Type of facet (CollectionFacet, ReferenceFacet or ReferenceURLFacet)
@UI.facet.label Description (title) for facet
@UI.facet.parentId Reference to parent facet (for nested facets)

Sales Order Header consumption view Metadata Extension

@Metadata.layer: #CUSTOMER

@UI: {
    headerInfo: {
    typeName: 'Sales Order',
    typeNamePlural: 'Sales Orders',
    title: { type: #STANDARD, label: 'Sales Order' }
    }
}

annotate view ZSD_C_SOHEADER
    with 
{
    @UI.facet: [
        { 
            label: 'Header data',
            id: 'Header',
            type: #COLLECTION
        },
        {
            label: 'Document Information',
            id : 'HeaderData',
            parentId : 'Header',
            type : #FIELDGROUP_REFERENCE,
            targetQualifier : 'HeaderData'
        },
        {
            label: 'Organizational Information',
            id : 'OrgInfo',
            parentId : 'Header',
            type : #FIELDGROUP_REFERENCE,
            targetQualifier : 'OrgInfo'
        },
        {
            label: 'Customer Information',
            id : 'CustomerInfo',
            parentId : 'Header',
            type : #FIELDGROUP_REFERENCE,
            targetQualifier : 'CustomerInfo'
        },
        {
            label: 'Internal Information',
            id : 'InternalInfo',
            parentId : 'Header',
            type : #FIELDGROUP_REFERENCE,
            targetQualifier : 'InternalInfo'
        },
        {
            label: 'Items',
            purpose: #STANDARD,
            id: 'Items',
            type: #LINEITEM_REFERENCE,
            targetElement: '_items'
            
        }
        
    ]
    
    @UI: {
      lineItem: [ { position: 10, label: 'Sales Order', importance: #HIGH } ],
      selectionField: [ { position: 10 } ],
      identification:[ { position: 10, label: 'Sales Order' } ],
      fieldGroup: [{ qualifier: 'HeaderData', position: 10 }]
    }
    orderNumber; 
    @UI: {
      lineItem: [ { position: 20, label: 'Order Type', importance: #HIGH } ],
      selectionField: [ { position: 20 } ],
      identification:[ { position: 20, label: 'Order Type' } ],
      fieldGroup: [{ qualifier: 'HeaderData', position: 20 }]
    }
    orderType;
    @UI: {
      lineItem: [ { position: 110, label: 'Net Value', importance: #HIGH } ],
      selectionField: [ { position: 150 } ],
      identification:[ { position: 150, label: 'Net Value' } ],
      fieldGroup: [{ qualifier: 'HeaderData', position: 30 }]
    } 
    netValue; 
    @UI: {
      selectionField: [ { position: 160 } ],
      identification:[ { position: 160, label: 'Currency' } ]
    } 
    currency;   
    @UI: {
      lineItem: [ { position: 30, label: 'Sales Organization', importance: #HIGH } ],
      selectionField: [ { position: 30 } ],
      identification:[ { position: 30, label: 'Sales Organization' } ],
      fieldGroup: [{ qualifier: 'OrgInfo', position: 10 }]
    }
    salesOrganization;
    @UI: {
      selectionField: [ { position: 40 } ],
      identification:[ { position: 40, label: 'Distribution Channel' } ],
      fieldGroup: [{ qualifier: 'OrgInfo', position: 20 }]
    } 
    distributionChannel; 
    @UI: {
      selectionField: [ { position: 50 } ],
      identification:[ { position: 50, label: 'Division' } ],
      fieldGroup: [{ qualifier: 'OrgInfo', position: 30 }]
    } 
    division;
    @UI: {
      selectionField: [ { position: 60 } ],
      identification:[ { position: 60, label: 'Sales Office' } ],
      fieldGroup: [{ qualifier: 'OrgInfo', position: 40 }]
    } 
    salesOffice; 
    @UI: {
      selectionField: [ { position: 70 } ],
      identification:[ { position: 70, label: 'Sales Group' } ],
      fieldGroup: [{ qualifier: 'OrgInfo', position: 50 }]
    } 
    salesGroup; 
    @UI: {
      lineItem: [ { position: 80, label: 'Sold-to', importance: #HIGH } ],
      selectionField: [ { position: 80 } ],
      identification:[ { position: 80, label: 'Sold-to' } ],
      fieldGroup: [{ qualifier: 'CustomerInfo', position: 10 }]
    } 
    soldTo;
    @UI: {
      lineItem: [ { position: 90, label: 'Ship-to', importance: #HIGH } ],
      selectionField: [ { position: 90 } ],
      identification:[ { position: 90, label: 'Ship-to' } ],
      fieldGroup: [{ qualifier: 'CustomerInfo', position: 20 }]
    } 
    shipTo; 
    @UI: {
      lineItem: [ { position: 100, label: 'Customer Reference', importance: #LOW } ],
      selectionField: [ { position: 100 } ],
      identification:[ { position: 100, label: 'Customer Reference' } ],
      fieldGroup: [{ qualifier: 'CustomerInfo', position: 30 }]
    } 
    customerReference;
    
    @UI: {
      lineItem: [ { position: 130, label: 'Created By', importance: #LOW } ],
      selectionField: [ { position: 110 } ],
      identification:[ { position: 110, label: 'Created By' } ],
      fieldGroup: [{ qualifier: 'InternalInfo', position: 10 }]
    } 
    createdBy;
    @UI: {
      lineItem: [ { position: 140, label: 'Created On', importance: #LOW } ],
      selectionField: [ { position: 120 } ],
      identification:[ { position: 120, label: 'Created On' } ],
      fieldGroup: [{ qualifier: 'InternalInfo', position: 20 }]
    }  
    createdOn;
    @UI: {
      selectionField: [ { position: 130 } ],
      identification:[ { position: 130, label: 'Created At' } ],
      fieldGroup: [{ qualifier: 'InternalInfo', position: 30 }]
    }  
    createdAt; 
    @UI: {
      selectionField: [ { position: 140 } ],
      identification:[ { position: 140, label: 'Changed On' } ],
      fieldGroup: [{ qualifier: 'InternalInfo', position: 40 }]
    } 
    changedOn; 
}

 

Sales Order Item consumption view Metadata Extension

@Metadata.layer: #CUSTOMER

@UI: {
    headerInfo: {
    typeName: 'Sales Order Item',
    typeNamePlural: 'Sales Order Items',
    
    title: { type: #STANDARD, label: 'Sales Order Item' }
    }
}

annotate view ZSD_C_SOITEM
    with 
{
    @UI.facet: [
        {
            label: 'Item Information',
            id : 'ItemData',
            //parentId : 'Header',
            type : #FIELDGROUP_REFERENCE,
            targetQualifier : 'ItemData'
        },
        {
            label: 'Internal Information',
            id : 'InternalInfo',
            //parentId : 'Header',
            type : #FIELDGROUP_REFERENCE,
            targetQualifier : 'InternalInfo'
        }
    ]

    @UI: {
      hidden: true,
      lineItem: [ { position: 10, label: 'Sales Order', importance: #HIGH } ],
      selectionField: [ { position: 10 } ],
      identification:[ { position: 10, label: 'Sales Order' } ],
      fieldGroup: [{ qualifier: 'ItemData', position: 10 }]
    } 
    orderNumber;
    @UI: {
      lineItem: [ { position: 20, label: 'Item', importance: #HIGH } ],
      selectionField: [ { position: 20 } ],
      identification:[ { position: 20, label: 'Item' } ],
      fieldGroup: [{ qualifier: 'ItemData', position: 20 }]
    } 
    orderItem; 
    @UI: {
      lineItem: [ { position: 30, label: 'Material', importance: #HIGH } ],
      selectionField: [ { position: 30 } ],
      identification:[ { position: 30, label: 'Material' } ],
      fieldGroup: [{ qualifier: 'ItemData', position: 30 }]
    } 
    material;
    @UI: {
      lineItem: [ { position: 40, label: 'Description', importance: #HIGH } ],
      selectionField: [ { position: 40 } ],
      identification:[ { position: 40, label: 'Description' } ],
      fieldGroup: [{ qualifier: 'ItemData', position: 40 }]
    }  
    itemDescription; 
    @UI: {
      lineItem: [ { position: 50, label: 'Quantity', importance: #HIGH } ],
      selectionField: [ { position: 50 } ],
      identification:[ { position: 50, label: 'Quantity' } ],
      fieldGroup: [{ qualifier: 'ItemData', position: 50 }]
    } 
    orderQuantity;
    @UI: {
      selectionField: [ { position: 60 } ],
      identification:[ { position: 60, label: 'Sales Unit' } ]
    }  
    salesUnit;
    @UI: {
      lineItem: [ { position: 70, label: 'Net Value', importance: #HIGH } ],
      selectionField: [ { position: 70 } ],
      identification:[ { position: 70, label: 'Net Value' } ],
      fieldGroup: [{ qualifier: 'ItemData', position: 70 }]
    }  
    netValue; 
    @UI: {
      selectionField: [ { position: 80 } ],
      identification:[ { position: 80, label: 'Currency' } ]
    } 
    currency; 
    @UI: {
      lineItem: [ { position: 90, label: 'Created By', importance: #LOW } ],
      selectionField: [ { position: 90 } ],
      identification:[ { position: 90, label: 'Created By' } ],
      fieldGroup: [{ qualifier: 'InternalInfo', position: 10 }]
    } 
    createdBy;
    @UI: {
      lineItem: [ { position: 100, label: 'Created On', importance: #LOW } ],
      selectionField: [ { position: 100 } ],
      identification:[ { position: 100, label: 'Created On' } ],
      fieldGroup: [{ qualifier: 'InternalInfo', position: 20 }]
    } 
    createdOn;
    @UI: {
      lineItem: [ { position: 110, label: 'Created At', importance: #LOW } ],
      selectionField: [ { position: 110 } ],
      identification:[ { position: 110, label: 'Created At' } ],
      fieldGroup: [{ qualifier: 'InternalInfo', position: 30 }]
    } 
    createdAt;
    @UI: {
      lineItem: [ { position: 120, label: 'Changed On', importance: #LOW } ],
      selectionField: [ { position: 120 } ],
      identification:[ { position: 120, label: 'Changed On' } ],
      fieldGroup: [{ qualifier: 'InternalInfo', position: 40 }]
    } 
    changedOn; 
}

 

Exposing the Business Object consumption CDS view as oData service

Open transaction /IWFND/MAINT_SERVICE and add the generated service to the list of activated services. This can either be co-deployed or routing-based, depending on your system setup.

 

Generating the Fiori Elements App

Open up SAP Web IDE and create a new project from template. Choose for “List Report Application” and click Next.

Enter following details (you can choose your own):

  • Project Name: ZSD_SO_DEMO_V1
  • Title: Manage Sales Orders
  • Namespace: be.thevaluechain
  • Description: Manage Sales Orders

Click “Next

In the next screen choose your desired backend system from the service catalog and select your previously activated oData service. Click “Next“.

Select all remote annotations and click “Next“.

Enter following details:

  • OData Collection: ZSD_C_SOHEADER
  • OData Navigation: to_items

Click “Finish“.

Select the newly created project and click the “play” button in the toolbar.

Select “flpSandbox.html” and click “OK“.

Open the app by clicking the generated tile.

Result:

Our app now has basic functionality:

  • Search
  • Result list report
  • Search helps
  • Detail screens (display)

In the next parts we’ll implement the required logic to enable:

  • Changing existing Sales Orders
  • Deleting existing Sales Orders
  • Creating new Sales Orders
  • Locking Sales Orders when a Draft instance is created

 

1 Comment
You must be Logged on to comment or reply to a post.
  • Hello Geert-Jan Klaps,

     

    Thanks for this blog post. I was searching for such materials. Actually, I’m new to ABAP programming model and I’m following this tutorial

    https://help.sap.com/viewer/cc0c305d2fab47bd808adcad3ca7ee9d/201809.001/en-US/a1243bff462b4ee3a03e2bb6fc30e015.html

    I have a question and hope you can assist me:

    I defined annotations for UI.facet exactly as you did, but I didn’t get them displayed on the Object Page.

    Actually, I have defined the annotations for the list report view (home view) and the object view (detail view) in the same CDS view. is that right? or I have to split the code (CDS view for each of the home and detail view) ?

     

    Here is part of the code:

    ……..

    @UI.headerInfo: {
    typeName: ‘Sales Order Item’,
    typeNamePlural: ‘Sales Orders Items’,
    title: {value: ‘My Sales Order List’},
    description.value: ‘List Report Sales Orders’

    }
    @Search.searchable: true
    define view ZDEMO_CDS_SalesOrderItem_M as select from SEPM_I_SalesOrderItem_E as Item {

    @UI.selectionField.position: 10
    @UI.lineItem: {importance: #HIGH,label: ‘Sales Order’, position: 10}
    @UI.facet: [
    {
    label: ‘General Information’,
    id:’GeneralInformation’,
    //isSummary: true,
    type: #COLLECTION,
    position: 10
    },
    {
    label: ‘Customer Info’,
    id: ‘CustomerInfo’,
    parentId: ‘GeneralInformation’,
    type: #FIELDGROUP_REFERENCE,
    position: 20,
    targetQualifier: ‘Company’
    }
    ]
    key Item.SalesOrder as SalesOrderID,

    //@UI.hidden: true
    key Item.SalesOrderItem as ItemPosition,

    @UI.fieldGroup: [{
    qualifier: ‘Company’,
    position: 10
    }]
    @UI.selectionField.position: 20
    @Search: {defaultSearchElement: true, fuzzinessThreshold: 0.7} // The search will work even if you provide part of the company name
    //@Search.defaultSearchElement: true // You have to provide the complete company name, then the search will work(When choosing the default filter)
    @UI.lineItem.position: 20
    Item._SalesOrder._Customer.CompanyName as CompanyName,

    …….