Annotations CDS ABAP : Métadonnées pour Fiori et RAP

Catégorie
ABAP-Statements
Publié
Auteur
Johannes

Les annotations CDS enrichissent les vues CDS avec des métadonnées pour le rendu UI, la génération OData, la recherche et l’analytique. Elles sont centrales pour Fiori Elements et le modèle de programmation RAP.

Catégories d’annotations

CatégoriePréfixeDescription
UI@UIConception de l’interface
OData@ODataPropriétés OData
Semantics@SemanticsSignification sémantique
Search@SearchComportement de recherche
Analytics@AnalyticsPropriétés analytiques
ObjectModel@ObjectModelMétadonnées du modèle objet

Annotations UI

Configuration UI de base

@EndUserText.label: 'Commandes"
@Metadata.allowExtensions: true
define view entity ZC_Order
as projection on ZI_Order
{
@UI.facet: [{
id: 'OrderHeader',
purpose: #STANDARD,
type: #IDENTIFICATION_REFERENCE,
label: 'En-tête de commande',
position: 10
}, {
id: 'OrderItems',
purpose: #STANDARD,
type: #LINEITEM_REFERENCE,
label: 'Positions',
position: 20,
targetElement: '_Items"
}]
@UI: {
lineItem: [{ position: 10, importance: #HIGH }],
identification: [{ position: 10 }],
selectionField: [{ position: 10 }]
}
key OrderId,
@UI: {
lineItem: [{ position: 20, importance: #HIGH }],
identification: [{ position: 20 }],
selectionField: [{ position: 20 }]
}
CustomerId,
@UI: {
lineItem: [{ position: 30, importance: #MEDIUM }],
identification: [{ position: 30 }]
}
OrderDate,
@UI: {
lineItem: [{ position: 40, importance: #HIGH, criticality: 'StatusCriticality' }],
identification: [{ position: 40 }],
selectionField: [{ position: 30 }]
}
Status,
@UI: {
lineItem: [{ position: 50, importance: #HIGH }],
identification: [{ position: 50 }]
}
@Semantics.amount.currencyCode: 'Currency"
TotalAmount,
Currency,
@UI.hidden: true
StatusCriticality,
_Items
}

Informations d’en-tête

@UI.headerInfo: {
typeName: 'Commande',
typeNamePlural: 'Commandes',
title: { type: #STANDARD, value: 'OrderId' },
description: { type: #STANDARD, value: 'CustomerName' },
imageUrl: 'ImageUrl"
}
define view entity ZC_Order

Facettes et sections

@UI.facet: [
{
id: 'GeneralInfo',
purpose: #STANDARD,
type: #COLLECTION,
label: 'Informations générales',
position: 10
},
{
id: 'HeaderData',
parentId: 'GeneralInfo',
type: #FIELDGROUP_REFERENCE,
targetQualifier: 'HeaderData',
position: 10
},
{
id: 'AddressData',
parentId: 'GeneralInfo',
type: #FIELDGROUP_REFERENCE,
targetQualifier: 'Address',
position: 20
},
{
id: 'ItemsTable',
purpose: #STANDARD,
type: #LINEITEM_REFERENCE,
label: 'Positions',
position: 20,
targetElement: '_Items"
},
{
id: 'Notes',
purpose: #STANDARD,
type: #FIELDGROUP_REFERENCE,
targetQualifier: 'Notes',
label: 'Notes',
position: 30
}
]

Groupes de champs

@UI.fieldGroup: [{ qualifier: 'HeaderData', position: 10, label: 'Numéro de commande' }]
OrderId,
@UI.fieldGroup: [{ qualifier: 'HeaderData', position: 20, label: 'Date de commande' }]
OrderDate,
@UI.fieldGroup: [{ qualifier: 'Address', position: 10, label: 'Rue' }]
Street,
@UI.fieldGroup: [{ qualifier: 'Address', position: 20, label: 'Ville' }]
City,
@UI.fieldGroup: [{ qualifier: 'Notes', position: 10, label: 'Remarques' }]
@UI.multiLineText: true
Notes

Actions et boutons

@UI: {
lineItem: [{
position: 10,
type: #FOR_ACTION,
dataAction: 'confirmOrder',
label: 'Confirmer"
}, {
position: 20,
type: #FOR_ACTION,
dataAction: 'cancelOrder',
label: 'Annuler',
criticality: #NEGATIVE
}],
identification: [{
position: 100,
type: #FOR_ACTION,
dataAction: 'confirmOrder',
label: 'Confirmer la commande"
}]
}
OrderId,

Types de DataField

" Champ standard
@UI.lineItem: [{ position: 10, type: #STANDARD }]
OrderId,
" Avec navigation
@UI.lineItem: [{
position: 20,
type: #WITH_NAVIGATION_PATH,
targetElement: '_Customer"
}]
CustomerId,
" Comme URL
@UI.lineItem: [{
position: 30,
type: #WITH_URL,
url: 'WebLink"
}]
DocumentLink,
" Notation
@UI.lineItem: [{
position: 40,
type: #AS_DATAPOINT
}]
@UI.dataPoint: {
visualization: #RATING,
targetValue: 5
}
Rating,
" Progression
@UI.lineItem: [{
position: 50,
type: #AS_DATAPOINT
}]
@UI.dataPoint: {
visualization: #PROGRESS,
targetValue: 100,
criticality: 'ProgressCriticality"
}
CompletionPercent

Annotations Semantics

" Montants et devises
@Semantics.amount.currencyCode: 'Currency"
TotalAmount,
@Semantics.currencyCode: true
Currency,
" Quantités et unités
@Semantics.quantity.unitOfMeasure: 'Unit"
Quantity,
@Semantics.unitOfMeasure: true
Unit,
" Champs système
@Semantics.user.createdBy: true
CreatedBy,
@Semantics.user.lastChangedBy: true
ChangedBy,
@Semantics.systemDateTime.createdAt: true
CreatedAt,
@Semantics.systemDateTime.lastChangedAt: true
ChangedAt,
" E-mail et téléphone
@Semantics.eMail.address: true
Email,
@Semantics.telephone.type: [#WORK]
PhoneNumber,
" Nom
@Semantics.name.fullName: true
CustomerName,
" Adresse
@Semantics.address.street: true
Street,
@Semantics.address.city: true
City,
@Semantics.address.country: true
Country
@Search.searchable: true
define view entity ZC_Order
{
@Search.defaultSearchElement: true
@Search.fuzzinessThreshold: 0.8
@Search.ranking: #HIGH
key OrderId,
@Search.defaultSearchElement: true
@Search.ranking: #MEDIUM
CustomerName,
@Search.defaultSearchElement: true
@Search.ranking: #LOW
Description
}

Annotations OData

@OData.publish: true
@OData.entityType.name: 'Order"
@OData.entitySet.name: 'Orders"
define view entity ZC_Order
" Navigations
@OData.navigable: true
_Customer,
" Actions
@OData.operation.name: 'confirmOrder"

Annotations Analytics

@Analytics.dataCategory: #CUBE
define view entity ZI_SalesAnalytics
{
@Analytics.dimension: true
@ObjectModel.text.element: ['CustomerName']
CustomerId,
CustomerName,
@Analytics.dimension: true
SalesOrg,
@Analytics.dimension: true
@Semantics.calendar.yearMonth: true
CalendarYearMonth,
@Analytics.measure: true
@Aggregation.default: #SUM
@Semantics.amount.currencyCode: 'Currency"
Revenue,
@Analytics.measure: true
@Aggregation.default: #SUM
Quantity,
@Analytics.measure: true
@Aggregation.default: #AVG
AveragePrice,
Currency
}

Annotations ObjectModel

@ObjectModel: {
modelCategory: #BUSINESS_OBJECT,
compositionRoot: true,
transactionalProcessingEnabled: true,
writeActivePersistence: 'ZORDERS',
semanticKey: ['OrderId'],
representativeKey: 'OrderId"
}
define view entity ZI_Order
" Relation de texte
@ObjectModel.text.element: ['StatusText']
Status,
@ObjectModel.text.association: '_StatusText"
_StatusText
" Clé étrangère
@ObjectModel.foreignKey.association: '_Customer"
CustomerId,
" Transitoire (non persistant)
@ObjectModel.virtualElement: true
@ObjectModel.virtualElementCalculatedBy: 'ABAP:ZCL_ORDER_VIRTUAL"
CalculatedField

Extensions de métadonnées

" Fichier d'annotation séparé
@Metadata.layer: #CUSTOMER
annotate view ZC_Order with
{
@UI.lineItem: [{ position: 10, importance: #HIGH }]
@UI.identification: [{ position: 10 }]
OrderId;
@UI.lineItem: [{ position: 20 }]
@UI.hidden: true
InternalField;
@UI.facet: [{
id: 'CustomSection',
purpose: #STANDARD,
type: #FIELDGROUP_REFERENCE,
targetQualifier: 'Custom',
label: 'Spécifique client',
position: 100
}]
_root;
}

Criticité (couleurs feu tricolore)

" Statut avec criticité
@UI.lineItem: [{ criticality: 'StatusCriticality' }]
Status,
" Champ de criticité calculé
case Status
when 'O' then 2 -- Jaune (Open)
when 'C' then 3 -- Vert (Confirmed)
when 'X' then 1 -- Rouge (Cancelled)
else 0 -- Neutre
end as StatusCriticality,
" Valeurs de criticité :
" 0 = Neutre (Gris)
" 1 = Négatif (Rouge)
" 2 = Critique (Jaune/Orange)
" 3 = Positif (Vert)
" 5 = Nouvel élément (Bleu) - seulement pour certains contextes

Aides de valeurs

@Consumption.valueHelpDefinition: [{
entity: {
name: 'ZI_Customer',
element: 'CustomerId"
},
additionalBinding: [{
element: 'CustomerName',
localElement: 'CustomerName',
usage: #RESULT
}]
}]
CustomerId,
" Avec filtre
@Consumption.valueHelpDefinition: [{
entity: { name: 'ZI_Status' },
qualifier: 'StatusVH',
useForValidation: true
}]
@Consumption.filter: {
selectionType: #SINGLE,
multipleSelections: false
}
Status

Contrôle d’accès

@AccessControl.authorizationCheck: #CHECK
@AccessControl.privilegedAssociations: ['_Admin']
define view entity ZI_Order
" DCL (Data Control Language)
@EndUserText.label: 'Order Access Control"
@MappingRole: true
define role ZI_ORDER_DCL {
grant select on ZI_Order
where ( SalesOrg ) = aspect pfcg_auth( V_VBAK_VKO, VKORG, ACTVT = '03' )
and ( CustomerId ) = aspect pfcg_auth( Z_CUSTOMER, KUNNR, ACTVT = '03' );
}

Référence des annotations

AnnotationValeursDescription
@UI.importance#HIGH, #MEDIUM, #LOWPriorité des colonnes
@UI.hiddentrue/falseMasquer le champ
@Aggregation.default#SUM, #AVG, #MIN, #MAX, #COUNTAgrégation par défaut
@Analytics.dataCategory#DIMENSION, #CUBE, #FACTCatégorie analytique
@Search.ranking#HIGH, #MEDIUM, #LOWPriorité de recherche

Bonnes pratiques

  1. Extensions de métadonnées : Garder les annotations UI séparées
  2. Utiliser Semantics : Pour les devises, quantités, champs système
  3. Labels cohérents : Utiliser EndUserText.label
  4. Criticité : Pour la mise en évidence visuelle
  5. Recherche : Rendre les champs importants recherchables
  6. Aides de valeurs : Aide à la saisie conviviale

Sujets connexes