Technical Articles
Build SAP Overview Page using SAP HANA Cloud & SAP CAP service annotations in Visual (VS) Code
Hi Everyone,
This blog will help you to create SAP Overview Page (SAP Fiori Elements) using SAP CAP service in Visual Studio Code.
Pre-requisites
- Node >= 14
- UI5 Tooling – npm install –global @ui5/cli
- Cloud Foundry CLI
- VS Code & SAP Fiori tools Extension Pack – Installing Visual Studio Code and Configuring SAP Extensions in Visual Studio Code
- cds development kit by using cds v in the terminal – npm i -g @sap/cds-dk
- SAP BTP Trial Account – Get a Free Account on SAP BTP Trial
- SAP HANA Cloud
Project development
Step 5: After initializing the project, you should see the following empty folders:
- app: for UI artifacts
- db: for the database level schema model
- srv: for the service definition layer
namespace capsrv;
using
{
Currency,
managed
}
from '@sap/cds/common';
entity SalesOrderType : managed
{
key salesOrder : String(5) @title: 'Sales Order ID';
customerCompanyName : String(40) @title : 'Company Name';
revenueInLocalCurrency : String(30) @title : 'Gross Amount';
localCurrency : String(30) @title : 'Currency Code';
numberOfItems : String(60) @title : 'Number of Items';
}
entity SalesPerSupplierType : managed
{
key ID : UUID @(Core.Computed:true) @title: 'Supplier';
supplier : String(10) @title : 'Business Partner ID';
supplierName : String(80) @title : 'Supplier';
grossAmountInCompanyCurrency : Decimal(16, 3) @title : 'Revenue';
netUnitPriceInCompanyCurrency : Decimal(16, 3) @title : 'Average Item Price';
quantity : Decimal(13, 3) @title : 'Number of Sold Items';
companyCurrency : String(5) @Common.Label : 'ISO Currency Code' @Common.IsUpperCase: true;
quantityUnit : String(3) @Common.Label : 'Unit of Measure';
companyCurrencyShortName : String(15) @Common.Label : 'Short text';
quantityUnitName : String(10) @Common.Label : 'Measuremt unit text' @Common.QuickInfo : 'Unit of Measurement Text (Maximum 10 Characters)'
}
entity SalesHistoryType : managed
{
key ID : UUID @(Core.Computed:true);
creationMonthAsDate : DateTime;
creationMonth : String(2);
creationMonth_Text : String(10);
grossAmountInCompanyCurrency : Decimal(16, 3) @title : 'Revenue';
companyCurrency : String(5);
companyCurrency_Text : String(40) @Common.Label : 'Long text';
referenceAmount : Integer;
}
using capsrv as cp from '../db/schema';
@path : 'service/cap'
service capService {
entity SalesOrder as select from cp.SalesOrderType;
@readonly
entity SalesHistory as select from cp.SalesHistoryType excluding {
createdAt,
createdBy,
modifiedAt,
modifiedBy
};
entity SalesPerSupplier as select from cp.SalesPerSupplierType;
}
using {capsrv} from './capfesrv';
//Filters
annotate capService.SalesOrder with @(UI : {
SelectionFields : [
salesOrder,
customerCompanyName,
numberOfItems
],
SelectionVariant : {
$Type : 'UI.SelectionVariantType',
SelectOptions : [{
$Type : 'UI.SelectOptionType',
PropertyName : localCurrency,
}],
},
});
annotate capService.SalesOrder with {
modifiedAt @UI.Hidden;
modifiedBy @UI.Hidden;
createdAt @UI.Hidden;
createdBy @UI.Hidden ;
};
//Donut Chart
annotate capService.SalesPerSupplier with @(UI : {
Chart #donut : {
$Type : 'UI.ChartDefinitionType',
ChartType : #Donut,
Description : 'Donut Chart',
Measures : [grossAmountInCompanyCurrency],
MeasureAttributes : [{
$Type : 'UI.ChartMeasureAttributeType',
Measure : grossAmountInCompanyCurrency,
Role : #Axis1,
DataPoint : '@UI.DataPoint#GrossAmountInCompanyCurrency'
}],
Dimensions : [supplier],
DimensionAttributes : [{
$Type : 'UI.ChartDimensionAttributeType',
Dimension : supplier,
Role : #Category
}]
},
PresentationVariant #donutPreVar : {
$Type : 'UI.PresentationVariantType',
Visualizations : ['@UI.Chart#donut'],
MaxItems : 3,
IncludeGrandTotal : true,
SortOrder : [{
$Type : 'Common.SortOrderType',
Descending : true,
Property : grossAmountInCompanyCurrency
}]
},
DataPoint #GrossAmountInCompanyCurrency : {
$Type : 'UI.DataPointType',
Value : grossAmountInCompanyCurrency,
Title : 'Revenue',
CriticalityCalculation : {
$Type : 'UI.CriticalityCalculationType',
ImprovementDirection : #Maximize,
DeviationRangeHighValue : 1000000,
DeviationRangeLowValue : 3000000
},
TrendCalculation : {
$Type : 'UI.TrendCalculationType',
ReferenceValue : 1000,
UpDifference : 10,
StrongUpDifference : 100,
DownDifference : -10,
StrongDownDifference : -100
},
},
Identification : [{
$Type : 'UI.DataField',
Value : grossAmountInCompanyCurrency
}]
});
annotate capService.SalesHistory with {
modifiedAt @UI.Hidden;
modifiedBy @UI.Hidden;
createdAt @UI.Hidden;
createdBy @UI.Hidden;
companyCurrency @title : 'Currency' @Measures.ISOCurrency : 'Currency';
companyCurrency_Text @title : '';
creationMonthAsDate @title : 'Creation Date';
creationMonth @title : 'Month';
creationMonth_Text @title : 'Month' @Common.QuickInfo : 'Month Long text';
referenceAmount @title : 'Amount' ;
};
//Line Chart
annotate capService.SalesHistory with @(
UI.Chart #Line : {
$Type : 'UI.ChartDefinitionType',
ChartType : #Line,
Description : 'Line Chart',
Measures : [grossAmountInCompanyCurrency],
MeasureAttributes : [{
$Type : 'UI.ChartMeasureAttributeType',
Measure : grossAmountInCompanyCurrency,
Role : #Axis1,
DataPoint : '@UI.DataPoint#GrossAmountInCompanyCurrency'
}],
Dimensions : [creationMonth],
DimensionAttributes : [{
$Type : 'UI.ChartDimensionAttributeType',
Dimension : creationMonth,
Role : #Category
}]
},
UI.PresentationVariant #Line : {
$Type : 'UI.PresentationVariantType',
Visualizations : ['@UI.Chart#Line'],
MaxItems : 3,
IncludeGrandTotal : true,
SortOrder : [{
$Type : 'Common.SortOrderType',
Descending : true,
Property : creationMonthAsDate
}]
},
UI.DataPoint #GrossAmountInCompanyCurrency : {
$Type : 'UI.DataPointType',
Value : grossAmountInCompanyCurrency,
Title : 'Revenue',
CriticalityCalculation : {
$Type : 'UI.CriticalityCalculationType',
ImprovementDirection : #Maximize,
DeviationRangeHighValue : 1000000,
DeviationRangeLowValue : 3000000
},
TrendCalculation : {
$Type : 'UI.TrendCalculationType',
ReferenceValue : referenceAmount,
UpDifference : 10,
StrongUpDifference : 100,
DownDifference : -10,
StrongDownDifference : -100
}
}
);
Step 13: Add csv files under db/csv naming as namespace-entity.csv
Step 15: CAP by default create V4 service. To create V2 will add cds odata v2 proxy using npm i @sap/cds-odata-v2-adapter-proxy
Also add server.js under srv layer to enable v2 version of the service & run cds watch.
Step 16: As we are developing the CAP app using Node.js, we need to mention the version in the package.json before deploying to SAP BTP.
Step 17: Now generate and mta file using cds add mta. By executing the command, mta.yaml will be created which has all the resources, modules and other service details which are required to deploy to SAP BTP.
Step 22: Now we can see the cap service is available to use both in v4 & v2 version
Step 23: Now let us create SAP Fiori Elements. Press Ctrl+Shft+P and start typing and select >Fiori: Open Application Generator. Choose Overview Page and click Next.
Step 24: Choose Connect to an OData Service under Data Source & Service Selection
Step 26: Select the SalesOrder for Filter entity and click on Next.
Step 28: You can see empty screen with filters.
Step 29: Lets add cards now in manifest.json and change enableLiveFilter to false. So that Go action will get enabled.
"enableLiveFilter": false,
{
"donutCard": {
"model": "mainService",
"template": "sap.ovp.cards.charts.analytical",
"settings": {
"title": "Donut Chart",
"entitySet": "SalesPerSupplier",
"chartAnnotationPath": "com.sap.vocabularies.UI.v1.Chart#donut",
"presentationAnnotationPath": "com.sap.vocabularies.UI.v1.PresentationVariant",
"dataPointAnnotationPath": "com.sap.vocabularies.UI.v1.DataPoint#GrossAmountInCompanyCurrency",
"idenfiticationAnnotationPath": "com.sap.vocabularies.UI.v1.Identification",
"chartProperties": {
"plotArea": {
"dataLabel": {
"type": "percentage"
}
}
}
}
},
"lineCard": {
"model": "mainService",
"template": "sap.ovp.cards.charts.analytical",
"settings": {
"title": "Line Chart",
"entitySet": "SalesHistory",
"chartAnnotationPath": "com.sap.vocabularies.UI.v1.Chart#Line",
"presentationAnnotationPath": "com.sap.vocabularies.UI.v1.PresentationVariant",
"dataPointAnnotationPath": "com.sap.vocabularies.UI.v1.DataPoint#GrossAmountInCompanyCurrency",
"idenfiticationAnnotationPath": "com.sap.vocabularies.UI.v1.Identification"
}
}
}
Hope this blog is helpful.
Git Repo: https://github.com/SaiNithesh/ovpcapfe
Feel free to comment
Regards,
Sai Nithesh Gajula
Great work SaiNithesh Gajula ! It looks good
Keep sharing more lot of different innovative ways to do..
Thanks @Yogananda Muthaiah.
Great Job @Sainithesh, Please keep it up.
Thanks Mohit 🙂
Hi Sainithesh, It would be really great if you can add the git repository / csv files to hands on quickly.
I have updated the Git Repo as well.
Hi Sainithesh, the app folder is missing in the repository, can you please add it as well?
Hi, @Sainithesh there is a mistake in step 9 in naming the CDS! It is not "ovpcap.cds" it should be "capfesrv.cds".
Great job, keep it up!
Thanks Nikola. I have corrected it.
Nice Blog, SaiNithesh
HI @SaiNithesh Gajula,
thank you for this great tutorial! The overview page should also run with OData V4. Is that correct? When trying to run it with V4 after generating the app in BAS, I cannot see the cards. Only the filters appear. I also adapted the manifest.json accordingly. Can you possibly import the app itself in git as well?
Thank you.
BR
Rufat
Hi Rufat Gadirov,
The Overview Page should work with OData V4 service as well. Hope you have added cards in the manifest.json file as explained in Step 29 of this tutorial.
Regards,
Sai Nithesh
Hi SaiNithesh Gajula,
thank you for your quick response. Ok, I am using OData V4 and I also tried out with V2. Yes, I did add those cards in manifest.json but they are not being rendered. Is there no other adaptation necessary, like in component.js - like adding jQuery.sap.require("sap.ovp.app.Component") for example? I guess something is missing and since that the git repo does not contain your web app I am not sure on that behalf. Maybe you could upload the other relevant files as well? In console the flex settings are marked as error...but in code I don´t see anything wrong...the code matches your example.
Btw, with OData V4, I am getting the same error as described here:
https://answers.sap.com/questions/13753276/sap-fiori-elements-overview-page.html
BR & Thanks
Rufat
Hi. Mine has an error inPromise with model unassigned.
I'm also trying.