**TITLE**: Stack Cards — Configure OVP Stack Card and Object Stream

**INTRODUCTION**: Configure a Fiori Elements (OVP) stack card that aggregates up to 20 quick view cards in an object stream. This guide shows the manifest configuration keys (manifest.json) and required OData metadata (EDMX) relationships to enable navigation between primary and secondary entity sets and to control object stream behavior (placeholder, footer actions, item text).

**TAGS**: fiori-elements-framework, ovp, stack-card, object-stream, manifest.json, edmx, OData, quick-view

STEP: 1 — Add Stack Card to manifest.json

DESCRIPTION: Add a stack card entry under "sap.ovp" → "cards" in manifest.json. Configure title, subtitle, entitySet for the dominant entity, identificationAnnotationPath for quick view content, itemText for placeholder text, and objectStreamCardsSettings to control footer behavior. Keep requireAppAuthorization if navigation requires app-level authorization.

LANGUAGE: JSON

CODE:
```JSON
"sap.ovp": {
    ...
    "cards": {
        "card00": {
            "model": "salesOrder",
            "template": "sap.ovp.cards.stack",
            "settings": {
                "title": "Stack Card Title",
                "subTitle": "Stack Card",
                "requireAppAuthorization": "#Action-toappnavsample",
                "itemText": "items awaiting approval",
                "entitySet": "SalesOrderSet",
                "identificationAnnotationPath": "com.sap.vocabularies.UI.v1.Identification,com.sap.vocabularies.UI.v1.Identification#item2",
                "objectStreamCardsSettings": {
                    "showFirstActionInFooter": false
                }
            }
        },
        ...
    }
}
```

STEP: 2 — Keys and Behavior for Object Stream (Actionable Summary)

DESCRIPTION: Ensure these keys are set and understand their effects when implementing the stack card:
- entitySet: dominant entity set used to fetch stack items (e.g., SalesOrderSet).
- objectStreamCardsNavigationProperty: navigation property to fetch object-stream items from a secondary entity set (e.g., SalesOrder). Not relevant for quick view cards.
- objectStreamCardsSettings.showFirstActionInFooter (boolean, default false):
  - true → first footer action on quick view card becomes a navigation action.
  - false → navigation action on footer is not shown; other actions are shown instead.
- itemText: custom text appended to placeholder card message.
- Placeholder card: appears only when the object stream has 20 quick view cards (it is not counted in the 20). Object stream displays up to 20 quick view cards; clicking the stack card header or "View All" opens the app or object stream.

LANGUAGE: JSON

CODE:
```JSON
{
  "entitySet": "SalesOrderSet",
  "objectStreamCardsNavigationProperty": "SalesOrder",  // not used for quick view cards
  "objectStreamCardsSettings": {
    "showFirstActionInFooter": false
  },
  "itemText": "items awaiting approval"
}
```

STEP: 3 — Quick View Cards: Actions and Navigation

DESCRIPTION: Configure quick view cards (object stream cards) so they can include actions (confirm, reject, etc.) and a navigation link. The object stream header is navigable and navigates to the same destination as the stack card header. If showFirstActionInFooter = true, the first footer action is a navigation action; otherwise the navigation action is omitted from footer.

LANGUAGE: JSON

CODE:
```JSON
{
  "objectStreamCardsSettings": {
    "showFirstActionInFooter": true   // set to true to surface navigation as first footer action
  }
}
```

STEP: 4 — Ensure OData Metadata: Navigation Property and Association

DESCRIPTION: Confirm your service metadata (EDMX) declares navigation properties and associations between entity types used by the stack card. Example metadata below demonstrates BusinessPartner -> SalesOrder via ToSalesOrders navigation property, an association Assoc_BusinessPartner_SalesOrders, and an association set Assoc_BusinessPartner_SalesOrders_AssocS. Include these definitions in your service metadata so object stream navigation and expanded queries function.

LANGUAGE: XML

CODE:
```XML
<EntityType Name="BusinessPartner" sap:content-version="1">
    <Key>
        <PropertyRef Name="BusinessPartnerID"/>
    </Key>
    <Property Name="Address" Type="GWSAMPLE_BASIC.CT_Address" Nullable="false"/>
    <Property Name="BusinessPartnerID" Type="Edm.String" Nullable="false" MaxLength="10" sap:label="Bus. Part. ID" sap:creatable="false" sap:updatable="false"/>
    <Property Name="CompanyName" Type="Edm.String" MaxLength="80" sap:label="Company Name"/>
    <Property Name="WebAddress" Type="Edm.String" sap:label="Web Address" sap:sortable="false" sap:filterable="false" sap:semantics="url"/>
    <Property Name="EmailAddress" Type="Edm.String" MaxLength="255" sap:label="E-Mail Address" sap:semantics="email"/>
    <Property Name="PhoneNumber" Type="Edm.String" MaxLength="30" sap:label="Phone No." sap:semantics="tel"/>
    <Property Name="FaxNumber" Type="Edm.String" MaxLength="30" sap:label="Fax Number"/>
    <Property Name="LegalForm" Type="Edm.String" MaxLength="10" sap:label="Legal Form"/>
    <Property Name="CurrencyCode" Type="Edm.String" MaxLength="5" sap:label="Currency" sap:semantics="currency-code"/>
    <Property Name="BusinessPartnerRole" Type="Edm.String" MaxLength="3" sap:label="Bus. Part. Role"/>
    <Property Name="CreatedAt" Type="Edm.DateTime" Precision="7" sap:label="Time Stamp" sap:creatable="false" sap:updatable="false"/>
    <Property Name="ChangedAt" Type="Edm.DateTime" Precision="7" ConcurrencyMode="Fixed" sap:label="Time Stamp" sap:creatable="false" sap:updatable="false"/>
    <NavigationProperty Name="ToSalesOrders" Relationship="GWSAMPLE_BASIC.Assoc_BusinessPartner_SalesOrders" FromRole="FromRole_Assoc_BusinessPartner_SalesOrders" ToRole="ToRole_Assoc_BusinessPartner_SalesOrders"/>
    <NavigationProperty Name="ToContacts" Relationship="GWSAMPLE_BASIC.Assoc_BusinessPartner_Contacts" FromRole="FromRole_Assoc_BusinessPartner_Contacts" ToRole="ToRole_Assoc_BusinessPartner_Contacts"/>
    <NavigationProperty Name="ToProducts" Relationship="GWSAMPLE_BASIC.Assoc_BusinessPartner_Products" FromRole="FromRole_Assoc_BusinessPartner_Products" ToRole="ToRole_Assoc_BusinessPartner_Products"/>
</EntityType>
<EntityType Name="SalesOrder" sap:content-version="1">
    <Key>
        <PropertyRef Name="SalesOrderID"/>
    </Key>
    <Property Name="SalesOrderID" Type="Edm.String" Nullable="false" MaxLength="10" sap:label="Sa. Ord. ID" sap:creatable="false" sap:updatable="false"/>
    <Property Name="SalesOrderGuid" Type="Edm.Guid" Nullable="false" sap:label="SalesOrder GUID" sap:creatable="false" sap:updatable="false"/>
    <Property Name="Note" Type="Edm.String" MaxLength="255" sap:label="Description" sap:updatable="false" sap:sortable="false" sap:filterable="false"/>
    <Property Name="NoteLanguage" Type="Edm.String" MaxLength="1" sap:label="Language" sap:creatable="false" sap:updatable="false" sap:sortable="false" sap:filterable="false"/>
    <Property Name="CustomerID" Type="Edm.String" MaxLength="10" sap:label="Bus. Part. ID" sap:updatable="false"/>
    <Property Name="CustomerName" Type="Edm.String" MaxLength="80" sap:label="Company Name" sap:creatable="false" sap:updatable="false"/>
    <Property Name="CurrencyCode" Type="Edm.String" MaxLength="5" sap:label="Currency" sap:updatable="false" sap:semantics="currency-code"/>
    <Property Name="GrossAmount" Type="Edm.Decimal" Precision="16" Scale="3" sap:unit="CurrencyCode" sap:label="Gross Amt." sap:creatable="false" sap:updatable="false"/>
    <Property Name="NetAmount" Type="Edm.Decimal" Precision="16" Scale="3" sap:unit="CurrencyCode" sap:label="Net Amt." sap:creatable="false" sap:updatable="false"/>
    <Property Name="TaxAmount" Type="Edm.Decimal" Precision="16" Scale="3" sap:unit="CurrencyCode" sap:label="Tax Amt." sap:creatable="false" sap:updatable="false"/>
    <Property Name="LifecycleStatus" Type="Edm.String" MaxLength="1" sap:label="PO Lifecycle" sap:creatable="false" sap:updatable="false"/>
    <Property Name="LifecycleStatusDescription" Type="Edm.String" MaxLength="60" sap:label="Lifecycle Descript." sap:creatable="false" sap:updatable="false" sap:sortable="false" sap:filterable="false"/>
    <Property Name="BillingStatus" Type="Edm.String" MaxLength="1" sap:label="PO Confirmation" sap:creatable="false" sap:updatable="false"/>
    <Property Name="BillingStatusDescription" Type="Edm.String" MaxLength="60" sap:label="Billing Description" sap:creatable="false" sap:updatable="false" sap:sortable="false" sap:filterable="false"/>
    <Property Name="DeliveryStatus" Type="Edm.String" MaxLength="1" sap:label="PO Ordering" sap:creatable="false" sap:updatable="false"/>
    <Property Name="DeliveryStatusDescription" Type="Edm.String" MaxLength="60" sap:label="Delivery Description" sap:creatable="false" sap:updatable="false" sap:sortable="false" sap:filterable="false"/>
    <Property Name="CreatedAt" Type="Edm.DateTime" Precision="7" sap:label="Time Stamp" sap:creatable="false" sap:updatable="false"/>
    <Property Name="ChangedAt" Type="Edm.DateTime" Precision="7" sap:label="Time Stamp" sap:creatable="false" sap:updatable="false"/>
    <NavigationProperty Name="ToBusinessPartner" Relationship="GWSAMPLE_BASIC.Assoc_BusinessPartner_SalesOrders" FromRole="ToRole_Assoc_BusinessPartner_SalesOrders" ToRole="FromRole_Assoc_BusinessPartner_SalesOrders"/>
    <NavigationProperty Name="ToLineItems" Relationship="GWSAMPLE_BASIC.Assoc_SalesOrder_SalesOrderLineItems" FromRole="FromRole_Assoc_SalesOrder_SalesOrderLineItems" ToRole="ToRole_Assoc_SalesOrder_SalesOrderLineItems"/>
</EntityType>
<Association Name="Assoc_BusinessPartner_SalesOrders" sap:content-version="1">
    <End Type="GWSAMPLE_BASIC.BusinessPartner" Multiplicity="1" Role="FromRole_Assoc_BusinessPartner_SalesOrders"/>
    <End Type="GWSAMPLE_BASIC.SalesOrder" Multiplicity="*" Role="ToRole_Assoc_BusinessPartner_SalesOrders"/>
    <ReferentialConstraint>
        <Principal Role="FromRole_Assoc_BusinessPartner_SalesOrders">
            <PropertyRef Name="BusinessPartnerID"/>
        </Principal>
        <Dependent Role="ToRole_Assoc_BusinessPartner_SalesOrders">
            <PropertyRef Name="CustomerID"/>
        </Dependent>
    </ReferentialConstraint>
</Association>
<EntityContainer Name="GWSAMPLE_BASIC_Entities" m:IsDefaultEntityContainer="true">
    <EntitySet Name="BusinessPartnerSet" EntityType="GWSAMPLE_BASIC.BusinessPartner" sap:content-version="1"/>
    <EntitySet Name="SalesOrderSet" EntityType="GWSAMPLE_BASIC.SalesOrder" sap:updatable="false" sap:content-version="1"/>
    <AssociationSet Name="Assoc_BusinessPartner_SalesOrders_AssocS" Association="GWSAMPLE_BASIC.Assoc_BusinessPartner_SalesOrders" sap:creatable="false" sap:updatable="false" sap:deletable="false" sap:content-version="1">
        <End EntitySet="BusinessPartnerSet" Role="FromRole_Assoc_BusinessPartner_SalesOrders"/>
        <End EntitySet="SalesOrderSet" Role="ToRole_Assoc_BusinessPartner_SalesOrders"/>
    </AssociationSet>
</EntityContainer>
```

fiori-elements-framework ovp stack-card object-stream manifest.json edmx OData quick-view


**TITLE**: Stacked Bar Micro Chart (UI.Chart + UI.DataPoint Annotations)

**INTRODUCTION**: Define a Stacked Bar Micro Chart for Fiori Elements by annotating your service metadata (XML) or CDS (ABAP/CAP). Use UI.Chart to configure the chart (title, description, chart type, measures, measure attributes) and UI.DataPoint to provide the measure value and criticality mapping. Measures and measure attributes must reference the same underlying property used by the DataPoint.

**TAGS**: fiori-elements-framework, stacked-bar, micro-chart, UI.Chart, UI.DataPoint, CDS, CAP, ABAP, XML

**STEP**: 1 — Add UI.Chart annotation (Stacked Bar)
**DESCRIPTION**: Create a UI.Chart annotation with ChartType set to BarStacked (BarStacked / BarStacked equivalent). Define Title and Description, list the Measure(s) (property path(s)) and configure MeasureAttributes to set Measure, Role (Axis1), and tie to the DataPoint via AnnotationPath or DataPoint reference. Use the Qualifier to reference this chart configuration from the UI.

**LANGUAGE**: XML
**CODE**:
```xml
<Annotation Term="UI.Chart" Qualifier="SalesPriceStackedBarChart">
    <Record Type="UI.ChartDefinitionType">
        <PropertyValue Property="Title" String="Sales Price"/>
        <PropertyValue Property="Description" String="Stacked BarChart"/>
        <PropertyValue Property="ChartType" EnumMember="UI.ChartType/BarStacked"/>
        <PropertyValue Property="Measures">
            <Collection>
                <PropertyPath>Width</PropertyPath>
            </Collection>
        </PropertyValue>
        <PropertyValue Property="MeasureAttributes">
            <Collection>
                <Record Type="UI.ChartMeasureAttributeType">
                    <PropertyValue Property="Measure" PropertyPath="Width"/>
                    <PropertyValue Property="Role" EnumMember="UI.ChartMeasureRoleType/Axis1"/>
                    <PropertyValue Property="DataPoint" AnnotationPath="@UI.DataPoint#Width"/>
                </Record>
            </Collection>
        </PropertyValue>
    </Record>
</Annotation>
```

**LANGUAGE**: ABAP
**CODE**:
```
@UI.Chart: [
  {
    title: 'Sales Price',
    description: 'Stacked BarChart',
    chartType: #BAR_STACKED,
    measures: [
      'WIDTH'
    ],
    measureAttributes: [
      {
        measure: 'Width',
        role: #AXIS_1,
        asDataPoint: true
      }
    ],
    qualifier: 'SalesPriceStackedBarChart'
  }
]
annotate view STTA_C_MP_PRODUCT with {

}
```

**LANGUAGE**: CDS
**CODE**:
```
UI.Chart #SalesPriceStackedBarChart : {
    $Type : 'UI.ChartDefinitionType',
    Title : 'Sales Price',
    Description : 'Stacked BarChart',
    ChartType : #BarStacked,
    Measures : [
        Width
    ],
    MeasureAttributes : [
        {
            $Type : 'UI.ChartMeasureAttributeType',
            Measure : Width,
            Role : #Axis1,
            DataPoint : '@UI.DataPoint#Width'
        }
    ]
}
```

**STEP**: 2 — Add UI.DataPoint annotation for the measure
**DESCRIPTION**: Define a UI.DataPoint for the measure used by the chart. Ensure the DataPoint Value points to the same property as the Chart Measures and MeasureAttributes. Optionally map Criticality to enable color/criticality behavior in the micro chart. Use a Qualifier that matches DataPoint reference in the Chart (e.g., #Width).

**LANGUAGE**: XML
**CODE**:
```xml
<Annotation Term="UI.DataPoint" Qualifier="Width">
    <Record>
        <PropertyValue Property="Value" Path="Width"/>
        <PropertyValue Property="Criticality" Path="criticalityValue"/>
    </Record>
</Annotation>
```

**LANGUAGE**: ABAP
**CODE**:
```
@UI.dataPoint: {
  criticality: 'criticalityValue'
}
Width;
```

**LANGUAGE**: CDS
**CODE**:
```
UI.DataPoint #Width : {
    Value : Width,
    Criticality : criticalityValue
}
```

**STEP**: 3 — Constraints and required mappings
**DESCRIPTION**: Enforce entity and property constraints required by the Stacked Bar Micro Chart and ensure all references align.

**LANGUAGE**: Text
**CODE**:
```
- Chart dimensions and measures cannot be of the same entity; they must come from a 1:n navigation entity.
- The following properties must all point to the same property in the entityType:
  - Measures property of the UI.Chart annotation.
  - Measure property inside MeasureAttributes of the UI.Chart annotation.
  - Value property of the UI.DataPoint annotation.
- Use the Chart qualifier (e.g., SalesPriceStackedBarChart) and DataPoint qualifier (e.g., #Width) consistently so MeasureAttributes.DataPoint / DataPoint references resolve.
- Refer to SAP Samples for behavior and rendering details: https://ui5.sap.com/1.82.5/#/entity/sap.suite.ui.microchart.StackedBarMicroChart
```

fiori-elements-framework stacked-bar micro-chart UI.Chart UI.DataPoint CDS CAP ABAP XML


**TITLE**: Stacked Column Chart Card (Fiori Elements / OVP)

**INTRODUCTION**: This document explains how to implement a stacked column chart card. Use-case: show multiple measures or series stacked per category (x-axis). It includes required data-role mappings, recommended practices, and minimal JSON configuration examples for code-generation agents.

**TAGS**: fiori-elements-framework, ovp, stacked-column, chart-card, category-role, series-role, semantic-coloring, axis

**STEP**: 1 - Purpose and visual reference

**DESCRIPTION**: Use a stacked column chart when you need to display multiple values stacked on top of each other for each category on the x-axis. All measures (and/or series dimensions) are stacked. Keep stacking consistent: either stack by dimensions (series) or by measures — do not mix both.

**LANGUAGE**: TEXT

**CODE**:
```text
Example image (reference):
../01_Whats-New/images/WhatsNew_138_OVP_StackedColumn_751363a.png
```

**STEP**: 2 - Data mapping requirements

**DESCRIPTION**: Configure the card data model so that:
- At least one dimension is assigned role "category" — all category-role dimensions are rendered on the x-axis (axis category).
- Dimensions assigned role "series" (optional) are used to create stacks across the category axis (use this when stacking by dimension).
- Measures are stacked when stacking by measures (use this when stacking by measure).
- Do not mix stacking strategies: either use series dimensions OR multiple measures for stacking, not both in the same chart card.
- The chart supports semantic coloring via a color palette.

**LANGUAGE**: JSON

**CODE**:
```json
{
  "data": {
    "path": "/YourEntitySet"
  },
  "settings": {
    "chartType": "stacked_column",
    "dimensions": [
      { "property": "CategoryProperty", "role": "category" },
      { "property": "SeriesProperty",   "role": "series" }  /* optional: use for stacking by dimension */
    ],
    "measures": [
      { "property": "Measure1", "label": "Measure 1" },
      { "property": "Measure2", "label": "Measure 2" }     /* use for stacking by measures */
    ]
  }
}
```

**STEP**: 3 - Recommended stacking strategy (explicit)

**DESCRIPTION**: Choose one of the two explicit stacking patterns and implement accordingly in the card configuration.

- Stacking by dimensions (recommended when semantic categories/labels define stacks):
  - Use one or more category-role dimensions for the x-axis.
  - Use a series-role dimension to create stacks within each category.
  - Measures provide the numeric values (typically a single measure or multiple measures aggregated per series).

**LANGUAGE**: JSON

**CODE**:
```json
{
  "settings": {
    "chartType": "stacked_column",
    "dimensions": [
      { "property": "Year",   "role": "category" },
      { "property": "Region", "role": "series" }   /* series creates stacks */
    ],
    "measures": [
      { "property": "Revenue" }                    /* numeric measure */
    ]
  }
}
```

**STEP**: 4 - Alternative: stacking by measures

**DESCRIPTION**: If stacking by measures, avoid using a series dimension. Provide multiple measures that will stack for each category value.

**LANGUAGE**: JSON

**CODE**:
```json
{
  "settings": {
    "chartType": "stacked_column",
    "dimensions": [
      { "property": "Month", "role": "category" }   /* x-axis */
    ],
    "measures": [
      { "property": "OnlineSales" },
      { "property": "InStoreSales" },
      { "property": "PartnerSales" }               /* each measure becomes a stack segment */
    ]
  }
}
```

**STEP**: 5 - Semantic coloring and palette support

**DESCRIPTION**: Enable semantic coloring by supplying a color palette or mapping semantic values to palette entries. Chart rendering will apply the palette to series or measure stacks for consistent semantic coloring.

**LANGUAGE**: JSON

**CODE**:
```json
{
  "settings": {
    "chartType": "stacked_column",
    "colorPalette": [
      "#0A6ED1",
      "#2A9F76",
      "#F6C85F",
      "#E4572E"
    ],
    "semanticColoring": true
  }
}
```

**STEP**: 6 - Implementation notes and validations

**DESCRIPTION**: Validate the following before generating the chart card:
- Ensure at least one dimension is marked role: "category".
- If using series stacking, ensure the series dimension contains meaningful semantic values.
- If stacking by measures, ensure measures are numeric and semantically comparable.
- Do not mix series-based and measure-based stacking in the same card.
- Confirm color palette entries match the expected number of series/measures or provide a palette large enough to cover all stacks.

**LANGUAGE**: TEXT

**CODE**:
```text
Validation checklist:
- category dimension exists -> Yes/No
- stacking strategy chosen -> "by-dimensions" or "by-measures"
- series dimension present only if stacking by-dimensions
- multiple numeric measures present only if stacking by-measures
- colorPalette provided (optional) for semantic coloring
```

fiori-elements-framework ovp stacked-column chart-card category-role series-role semantic-coloring axis


**TITLE**: Status Colors and Icons (UI Criticality) for SAP Fiori Elements

**INTRODUCTION**: Define and render status colors, icons, and importance for fields in LineItem, Identification and FieldGroup using a separate criticality property. This guide shows how to reference a criticality property from UI annotations (XML, ABAP CDS, CAP CDS), the allowed criticality values, default icon behavior, and OData V4 extension for "Information".

**TAGS**: fiori-elements-framework, annotations, UI.LineItem, criticality, CDS, ABAP, CAP, XML, OData V4, icons, ObjectStatus

**STEP**: 1 - Add a criticality property to your data model

**DESCRIPTION**: Create a property (typically on a related entity) that holds the criticality numeric value. This property must contain one of the values defined by com.sap.vocabularies.UI.v1.CriticalityType. The UI annotation for a field should reference that property via the Criticality Path.

**LANGUAGE**: (data model / conceptual)

**CODE**:
```text
// Conceptual: Define a property (e.g., StockCriticality) on the related entity
// The property stores numeric values derived from com.sap.vocabularies.UI.v1.CriticalityType
// Possible values:
// 0 - Neutral
// 1 - Negative (red)
// 2 - Critical (orange)
// 3 - Positive (green)
// (OData V4 additional) 5 - Information (blue)
```

**STEP**: 2 - Reference the criticality property in XML annotations (OData V2 / V4)

**DESCRIPTION**: In UI.LineItem (or Identification / FieldGroup) add a DataField record where the Criticality PropertyValue Path points to the criticality property. Also set the Value Path for the display text and optionally set UI.Importance.

**LANGUAGE**: XML

**CODE**:
```xml
<Annotation Term="UI.LineItem">
   <Collection>
      <Record Type="UI.DataField">
         <PropertyValue Property="Criticality" Path="to_ProductStock/StockCriticality"/>
         <PropertyValue Property="Value" Path="to_ProductStock/StockEmergencyLevel"/>
         <Annotation Term="UI.Importance" EnumMember="UI.ImportanceType/High"/>
      </Record>
   </Collection>
</Annotation>
```

**STEP**: 3 - Reference the criticality property in ABAP CDS annotations

**DESCRIPTION**: In ABAP CDS UI.lineItem annotations, set criticality to point to the related property (use underscore notation to reference associations). Also set value and importance as needed.

**LANGUAGE**: ABAP CDS

**CODE**:
```
@UI.lineItem: [
  {
    criticality: '_ProductStock.StockCriticality',
    value: '_ProductStock.StockEmergencyLevel',
    importance: #HIGH
  }
]
```

**STEP**: 4 - Reference the criticality property in CAP CDS (service definition)

**DESCRIPTION**: For CAP-based services, set UI.LineItem entry with Criticality and Value pointing to the related target paths. Preserve the UI.Importance annotation if required. (Example shows CAP CDS syntax.)

**LANGUAGE**: CAP CDS

**CODE**:
```
UI.LineItem : [
    {
        $Type : 'UI.DataField',
        Criticality : to_ProductStock.StockCriticality,
        Value : to_ProductStock.StockEmergencyLevel,
        ![@UI.Importance] : #High
    }
]]
```

**STEP**: 5 - Useable criticality values, default icon behavior and representation

**DESCRIPTION**: Use these numeric values in the criticality property. The mapping is derived from com.sap.vocabularies.UI.v1.CriticalityType. SAP Fiori elements uses these values to apply colors and (by default) icons.

- Values and meanings:
  - 0 — Neutral
  - 1 — Negative (red)
  - 2 — Critical (orange)
  - 3 — Positive (green)
  - 5 — Information (blue) — supported additionally in SAP Fiori elements for OData V4

- Default icon behavior:
  - By default Fiori elements assumes DataField is represented with CriticalityRepresentationType/WithIcon and maps criticality to ObjectStatus icons (e.g., com.sap.vocabularies.UI.v1.CriticalityType/Negative => 'sap-icon://status-negative').
  - If the field is marked with CriticalityRepresentationType/WithoutIcon, ObjectStatus is rendered without the icon.

- Texts:
  - The display texts (Value) are not static — place your text value in the referenced value path (e.g., StockEmergencyLevel) so you can customize messages per criticality.

**LANGUAGE**: text

**CODE**:
```text
// Example image demonstrating status colors and icons
// images/LROP_Status_Colors_and_Icons_75aa307.png
```

**STEP**: 6 - Implementation checklist

**DESCRIPTION**: Quick checklist before deploying:
- Ensure the criticality property exists and contains valid numeric values.
- Reference the criticality property via Path in XML or the equivalent in CDS annotations.
- Verify UI.Importance if you want to influence prominence.
- Decide whether to show icons (WithIcon) or hide icons (WithoutIcon).
- For OData V4, include support for value 5 (Information) if applicable.

**LANGUAGE**: text

**CODE**:
```text
// Checklist:
// - Criticality property defined and populated (0,1,2,3[,5 for OData V4])
// - Annotations reference Criticality path correctly
// - Value path supplies the display text (customizable)
// - CriticalityRepresentationType set to WithIcon or WithoutIcon as required
// - Verify rendered ObjectStatus and icon mapping in UI
```

fiori-elements-framework
annotations
UI.LineItem
criticality
CDS
ABAP
CAP
XML
OData V4
icons
ObjectStatus


**TITLE**: Store and Restore Application State (iAppState) — Actionable Guide for Fiori Elements

**INTRODUCTION**: This guide explains what the SAP Fiori elements iAppState mechanism stores and restores, differences between OData V2 and V4 behaviors, security considerations, scenarios where iAppState is not applied, and how changes from other flex layers are merged. Use this as a concise checklist for implementing, debugging, or instrumenting state persistence and restore in Fiori elements apps.

**TAGS**: fiori-elements, iAppState, state-persistence, OData-V2, OData-V4, variant-management, personalization, launchpad, flexibility

**STEP**: 1 — What iAppState Stores and Restores

**DESCRIPTION**: List the concrete application artifacts captured by iAppState so code and config can be verified against expectations. Use this list when validating saved state or when extending custom UI elements to participate in state persistence.

**LANGUAGE**: JSON

**CODE**:
```json
{
  "stores_restores": [
    "Filter field values in the List Report filter bar (includes 'Go' button state when available)",
    "Chosen variant (see OData V2/V4 differences below)",
    "Object Page details: tab selection, chart/table personalization",
    "Data from custom UI elements (requires custom state handling implementation)"
  ],
  "notes": [
    "Selections in a chart/table and table scroll position are NOT stored/restored",
    "Visibility changes of filter fields in filter bar are NOT stored/restored for OData V2",
    "Order of smart filter fields is NOT stored/restored"
  ],
  "odata_variant_behavior": {
    "ODataV2": "Chosen variant restored only if stored in a 'clean' state. If variant is 'dirty', fallback to 'Standard' with 'dirty' indicator.",
    "ODataV4": "Chosen variant is always restored when available; fallback to 'Standard' only if chosen variant is unavailable at restore time."
  }
}
```

**STEP**: 2 — Security and Sensitive Fields

**DESCRIPTION**: Ensure sensitive data annotated with PersonalData.v1.IsPotentiallySensitive is excluded from iAppState. Validate filter-context exceptions and implement alternative persistence only when compliant.

**LANGUAGE**: JSON

**CODE**:
```json
{
  "sensitive_field_handling": {
    "annotation": "PersonalData.v1.IsPotentiallySensitive",
    "behavior": "Fields annotated as potentially sensitive are NOT stored/restored by iAppState",
    "exception": "If the sensitive field is used in filter context, it may be considered for storage",
    "recommendation": "Do NOT implement custom persistence for such fields unless security review permits"
  },
  "launchpad_note": "Browser refresh does NOT restore iAppState unless SAP Fiori launchpad backend is configured to persist it."
}
```

**STEP**: 3 — OData V4 Additional Restriction

**DESCRIPTION**: Be aware of the one explicit limitation for OData V4 chart drilldown filters so that UI tests or sync code can handle missing state on restore.

**LANGUAGE**: JSON

**CODE**:
```json
{
  "odataV4_restriction": {
    "item": "Drilldown filters applied to charts via 'View By' options",
    "behavior": "These drilldown filters are NOT stored/restored"
  }
}
```

**STEP**: 4 — Handling Changes from Other Flex Layers (Merging Rules)

**DESCRIPTION**: When end-user personalization arrives in an iAppState, flex-layer changes (key-user or other layers) may be merged with it. Use these rules to implement or test merge logic in custom extensions or when debugging inconsistent UIs.

**LANGUAGE**: JSON

**CODE**:
```json
{
  "merge_rules": {
    "general": "Changes from other flex layers are merged with user personalization coming from iAppState.",
    "merging_applies_only_if": "The variant referenced in the iAppState is available at restore time.",
    "merge_priority": {
      "single_valued_field": "End-user iAppState value has priority over other-layer value (other-layer ignored for same field)."
    },
    "not_considered_scenarios": [
      "Navigation from dynamic tiles created by user using 'Save as Tile'",
      "Navigation from integration cards (expectation: return to same app state as when card was created)"
    ],
    "in_those_scenarios": {
      "behavior": "Changes from other layers are NOT considered; user-end changes are NOT retained/restored.",
      "details_not_retained": [
        "Filter fields or table columns that were removed",
        "Changes in position of filter fields or table columns"
      ]
    },
    "fallback_behavior_if_variant_unavailable": "App loads using 'Standard' variant; the full shared page state is applied on top without merging other-layer changes."
  }
}
```

**STEP**: 5 — Practical Checklist for Implementers

**DESCRIPTION**: Use this checklist when enabling or troubleshooting state persistence, or when extending the app to include custom state.

**LANGUAGE**: JSON

**CODE**:
```json
{
  "implementation_checklist": [
    "Confirm which artifacts must persist in your app (filters, variant, object page details, custom UI state).",
    "If adding custom UI elements, implement custom state handling to participate in iAppState (see related docs).",
    "Verify that fields annotated with PersonalData.v1.IsPotentiallySensitive are not being persisted.",
    "For OData V2 apps: verify variant 'clean' state behavior and handle the 'dirty' fallback to Standard variant.",
    "For OData V4 apps: account for missing 'View By' drilldown filter persistence.",
    "Ensure SAP Fiori launchpad is configured in the backend to persist iAppState if you expect restore after browser refresh.",
    "Test restores in scenarios with flex-layer changes; validate merge behavior when variant is available vs unavailable.",
    "When supporting dynamic tiles or integration cards, explicitly document that changes from other layers are not merged on return."
  ]
}
```

**STEP**: 6 — Related Files and Further Reading (Preserve links/file paths)

**DESCRIPTION**: Follow these related topics for implementation-level details, enablement steps, and extended scenarios. Use paths as-is to locate source docs in the repository.

**LANGUAGE**: JSON

**CODE**:
```json
{
  "related_topics": [
    "The Share Functionality: the-share-functionality-022bf0d.md",
    "Enabling Discovery/Persistence Mode: enabling-discovery-persistence-mode-7c62084.md",
    "Custom State Handling for Extended Apps: custom-state-handling-for-extended-apps-89fa878.md",
    "Security Configuration: security-configuration-ba0484b.md",
    "Configuring Default Filter Values: configuring-default-filter-values-f27ad7b.md",
    "SAPUI5 Flexibility: Adapting UIs Made Easy: ../04_Essentials/sapui5-flexibility-adapting-uis-made-easy-a8e55aa.md",
    "This topic source: store-restore-the-application-state-46bf248.md"
  ]
}
```

fiori-elements iAppState state-persistence OData-V2 OData-V4 variant-management personalization launchpad flexibility


**TITLE**: Support for Extended OData Annotations (SAP Fiori elements for OData V4)

**INTRODUCTION**: This document describes the supported extended OData annotations and IF-expression/odata.concat usage in SAP Fiori elements for OData V4. Use these annotations to control visibility, field control, operation availability, and capability-based restrictions with conditional expressions. Includes exact XML examples you can copy into annotation files.

**TAGS**: fiori-elements-framework, odata-v4, annotations, if-expressions, odata.concat, FieldControl, UpdateRestrictions, InsertRestriction, DeleteRestriction, OperationAvailable, UI.Hidden, Capabilities

**STEP**: Applicability and supported annotations

**DESCRIPTION**: This feature is applicable only to SAP Fiori elements for OData V4. The following annotations support OData IF-expressions and related conditional constructs:
- com.sap.vocabularies.Common.v1.FieldControl (FieldControl)
- com.sap.vocabularies.UI.v1.Hidden (UI.Hidden)
- com.sap.vocabularies.Common.v1.OperationAvailable (Core.OperationAvailable)
- SAP__capabilities.UpdateRestrictions
- SAP__capabilities.InsertRestriction
- SAP__capabilities.DeleteRestriction

**LANGUAGE**: text

**CODE**:
```
Applicable only to SAP Fiori elements for OData V4.

Supported annotations:
- FieldControl (com.sap.vocabularies.Common.v1.FieldControl)
- UI.Hidden (com.sap.vocabularies.UI.v1.Hidden)
- Core.OperationAvailable (com.sap.vocabularies.Common.v1.OperationAvailable)
- SAP__capabilities.UpdateRestrictions
- SAP__capabilities.InsertRestriction
- SAP__capabilities.DeleteRestriction
```

**STEP**: Use IF-expressions with FieldControl

**DESCRIPTION**: Example XML annotation showing an IF expression for FieldControl. The IF expression evaluates Eq(Path FieldControlDynamicIfValue, Int 5) and returns EnumMember Common.FieldControlType/ReadOnly or Common.FieldControlType/Optional. Copy this block into your annotations file (e.g., Annotation XML for the entity or property).

**LANGUAGE**: xml

**CODE**:
```xml
<Annotations Target="sap.fe.core.FieldEdit.RootEntity/FieldControlDynamicIf">
    <Annotation Term="com.sap.vocabularies.Common.v1.FieldControl">
        <If>
            <Eq>
                <Path>FieldControlDynamicIfValue</Path>
                <Int>5</Int>
            </Eq>
            <EnumMember>Common.FieldControlType/ReadOnly</EnumMember>
            <EnumMember>Common.FieldControlType/Optional</EnumMember>
        </If>
    </Annotation>
</Annotations>
```

**STEP**: Use conditional expressions for Update/Insert restrictions (Capabilities)

**DESCRIPTION**: Example XML annotation demonstrating conditional InsertRestrictions and UpdateRestrictions inside Capabilities.NavigationRestrictions. The snippet shows:
- RestrictedProperties collection with a NavigationProperty path
- InsertRestrictions using a Path expression (owner/isVerified)
- UpdateRestrictions with an If expression that evaluates a logical Or of Eq(Null, Path owner/isVerified) and Eq(String, Path owner/isVerified) to select Bool false/true results

Use this pattern to make insert/update permissions dynamic based on entity data.

**LANGUAGE**: xml

**CODE**:
```xml
<Annotation Term="Capabilities.NavigationRestrictions">
    <Record Type="Capabilities.NavigationRestrictionsType">
        <PropertyValue Property="RestrictedProperties">
            <Collection>
                <Record Type="Capabilities.NavigationPropertyRestriction">
                    <PropertyValue Property="NavigationProperty" NavigationPropertyPath="_Item" />
                    <PropertyValue Property="InsertRestrictions">
                        <Record Type="Capabilities.InsertRestrictionsType">
                            <PropertyValue Property="Insertable" Path="owner/isVerified" />
                        </Record>
                    </PropertyValue>
                    <PropertyValue Property="UpdateRestrictions">
                        <Record Type="Capabilities.UpdateRestrictionsType">
                            <PropertyValue Property="Updatable">
                                <If>
                                    <Or>
                                        <Eq>
                                            <Null />
                                            <Path>owner/isVerified</Path>
                                        </Eq>
                                        <Eq>
                                            <String />
                                            <Path>owner/isVerified</Path>
                                        </Eq>
                                    </Or>
                                    <Bool>false</Bool>
                                    <Bool>true</Bool>
                                </If>
                            </PropertyValue>
                        </Record>
                    </PropertyValue>
                </Record>
            </Collection>
        </PropertyValue>
    </Record>
</Annotation>
```

**STEP**: Use odata.concat for object page header title

**DESCRIPTION**: odata.concat is supported for the Title property of the object page header. Use Apply Function="odata.concat" to concatenate database field values and static strings for the header title. Example below concatenates CompanyName and LegalForm (with an empty string separator) for the BusinessPartner header.

**LANGUAGE**: xml

**CODE**:
```xml
<Annotations Target="SAP__self.BusinessPartner">
    <Annotation Term="com.sap.vocabularies.UI.v1.HeaderInfo">
        <Record Type="com.sap.vocabularies.UI.v1.HeaderInfoType">
            <PropertyValue Property="TypeName" String="Business Partner" />
            <PropertyValue Property="TypeNamePlural" String="Business Partners" />
            <PropertyValue Property="Title">
                <Record Type="com.sap.vocabularies.UI.v1.DataField">
                    <PropertyValue Property="Label" String="Name" />
                    <PropertyValue Property="Value">
                        <Apply Function="odata.concat">
                            <Path>CompanyName</Path>
                            <String />
                            <Path>LegalForm</Path>
                        </Apply>
                    </PropertyValue>
                </Record>
            </PropertyValue>
        </Record>
    </Annotation>
</Annotations>
```

fiori-elements-framework odata-v4 annotations if-expressions odata.concat FieldControl UpdateRestrictions InsertRestriction DeleteRestriction OperationAvailable UI.Hidden Capabilities


**TITLE**: Support for Terminologies in SAP Fiori elements (OData V4)

**INTRODUCTION**: Configure and activate terminologies for SAP Fiori elements applications (OData V4) by enhancing the ResourceModel in manifest.json and registering the model or resource bundles with the template via enhanceI18n. This enables switching UI texts per scenario/industry using terminology-specific resource bundles.

**TAGS**: fiori-elements-framework, sapui5, terminologies, i18n, manifest.json, resourceModel, enhanceI18n, OData V4

**STEP**: 1 — Add terminologies to the ResourceModel in manifest.json

**DESCRIPTION**: In the manifest.json "models" section, enhance the i18n ResourceModel with a "terminologies" entry. Provide the terminology bundle URL, relation to manifest, and supported locales. This registers a terminology set (for example "travel") with the app's resource model.

**LANGUAGE**: JSON

**CODE**:
```json
"models": {
    "i18n": {
        "type": "sap.ui.model.resource.ResourceModel",
        "settings": {
            "bundleUrl": "i18n/i18n.properties",
            "supportedLocales": ["en", "de"],
            "fallbackLocale": "en",
            "terminologies": {
                "travel": {
                    "bundleUrl": "i18n/terminologies/travel/i18n.terminologies.travel.properties",
                    "bundleUrlRelativeTo": "manifest",
                    "supportedLocales": ["en", "de"]
                }
            }
        }
    },
    ...
    ...
    ...
}
```

**STEP**: 2 — Make the resource model (and any additional resource files) available to Fiori elements via enhanceI18n

**DESCRIPTION**: Adding a terminology to a ResourceModel does not automatically enable it for SAP Fiori elements templates. In the template target definition (e.g., ListReport/LineItemsList), add the resource model key and/or resource files to the "enhanceI18n" array under the template "options.settings". The template will search enhancements in array order; the last entry has priority when resolving keys.

**LANGUAGE**: JSON

**CODE**:
```json
"targets": {
    "LineItemsList": {
        "type": "Component",
        "id": "LineItemsList",
        "name": "sap.fe.templates.ListReport",
        "options": {
            "settings": {
                "contextPath": "/LineItems",
                "enhanceI18n": ["i18n/ManageItemsListReport.properties", "i18n"],
                "variantManagement": "Page",
                "initialLoad": true,
                "navigation": {
                    "LineItems": {
                        "detail": {
                            "route": "LineItemsObjectPage"
                        }
                    }
                }
        }
    }
}
```

**STEP**: 3 — Precedence, usage rules, and edge cases

**DESCRIPTION**: Implementation behavior and rules to follow:
- enhanceI18n accepts any combination of resource files (paths) and resource model keys. Example: ["i18n/ManageItemsListReport.properties", "i18n"].
- The template resolves keys by searching the enhanceI18n array from first to last; the LAST enhancement wins. In the example above, the template first checks the "i18n" model, then "i18n/ManageItemsListReport.properties", then the default texts.
- If a model included in enhanceI18n has no terminology configured, adding a terminology elsewhere does not affect UI texts for that model—terminology is effective only for models that include a "terminologies" entry.
- This configuration and terminology mechanism applies only to SAP Fiori elements for OData V4.

**LANGUAGE**: JSON

**CODE**:
```json
// Example enhanceI18n order: last wins when resolving keys
"enhanceI18n": ["i18n/ManageItemsListReport.properties", "i18n"]
```

**STEP**: 4 — Reference for deeper terminology concepts

**DESCRIPTION**: For conceptual details and advanced usage patterns (multiple terminologies, switching scenarios), consult the Terminologies documentation referenced by your project (e.g., ../04_Essentials/terminologies-eba8d25.md). This step is informational and does not require manifest edits.

**LANGUAGE**: JSON

**CODE**:
```json
// See: ../04_Essentials/terminologies-eba8d25.md for full terminology concepts and examples
```


**TITLE**: Table Cards — OVP Table Card Configuration and UI Annotations

**INTRODUCTION**: Action-oriented reference for implementing OVP table cards in SAP Fiori Elements. Includes manifest settings and annotation examples (XML, ABAP CDS, CAP CDS) for title/subtitle, units, KPI, PresentationVariant, SelectionVariant, DataPoint, LineItem, smart links, contact, text arrangement, and text alignment. Use these examples directly in manifest.json, OData metadata, and annotation files.

**TAGS**: fiori-elements, ovp, table-card, annotations, UI.LineItem, DataPoint, PresentationVariant, SelectionVariant, manifest, smart-links, contact, text-arrangement

STEP: Manifest — Title sample
DESCRIPTION: Configure a table card in the application manifest to set model, template, entitySet and display a title on the card.
LANGUAGE: JSON
CODE:
```json
"sap.ovp": {
    "globalFilterModel": "salesOrder",
    "globalFilterEntityType": "GlobalFilters", // Deprecated since SAPUI5 1.54.
    "globalFilterEntitySet": "GlobalFilters",  // Available from SAPUI5 1.54.
    ...
    "cards": {
        "card014": {
            "model": "salesOrder",
            "template": "sap.ovp.cards.table",
            "settings": {
                "title": "Purchase Forecast",
                "entitySet": "SalesShare",
                ...
            }
        }
    }
}
```

STEP: Manifest — Subtitle sample
DESCRIPTION: Add a subtitle to the table card via manifest settings under the card's settings.
LANGUAGE: JSON
CODE:
```json
"sap.ovp": {
    "globalFilterModel": "salesOrder",
    "globalFilterEntityType": "GlobalFilters", // Deprecated since SAPUI5 1.54.
    "globalFilterEntitySet": "GlobalFilters",  // Available from SAPUI5 1.54.
    ...
    "cards": {
        "card014": {
            "model": "salesOrder",
            "template": "sap.ovp.cards.table",
            "settings": {
                "title": "Sales Forecast",
                "subTitle": "per Supplier",
                "entitySet": "SalesShare",
                ...
            }
        }
    }
}
```

STEP: Unit of Measure — Data sample
DESCRIPTION: Provide data containing a unit property and numeric value to be bound with sap:unit or annotation.
LANGUAGE: JSON
CODE:
```json
{
    "CurrencyCode": "KG",
    "GrossAmount": 850
}
```

STEP: Unit of Measure — Option 1: sap:unit in metadata
DESCRIPTION: Define sap:unit in OData EDMX metadata so UI displays unit next to numeric values automatically.
LANGUAGE: XML
CODE:
```xml
<Property
    Name="CurrencyCode"
    Type="Edm.String"
    MaxLength="5"
    sap:label="Currency"
    sap:updatable="false"
    sap:semantics="currency-code"
/>
<Property
    Name="GrossAmount"
    Type="Edm.Decimal"
    Precision="16"
    Scale="3"
    sap:unit="CurrencyCode"
    sap:label="Gross Amt."
    sap:creatable="false"
    sap:updatable="false"
/>
```

STEP: Unit of Measure — Option 2: ISOCurrency annotation
DESCRIPTION: Annotate the property using Org.OData.Measures.V1.ISOCurrency to bind unit by annotation instead of EDMX sap:unit.
LANGUAGE: XML
CODE:
```xml
<Annotations Target="GWSAMPLE_BASIC.SalesOrder/GrossAmount">
    <Annotation Term="Org.OData.Measures.V1.ISOCurrency" Path="CurrencyCode"/>
</Annotations>
```

STEP: KPI — Manifest setting
DESCRIPTION: Set kpiAnnotationPath in sap.ovp manifest to reference a KPI annotation for the card.
LANGUAGE: JSON
CODE:
```json
"sap.ovp": {
    // section for ovp-specific manifest settings
    ...
    "kpiAnnotationPath": "com.sap.vocabularies.UI.v1.KPI#AllActualCosts", // Represents the KPI annotation path
    ...
}
```

STEP: KPI — XML Annotation sample
DESCRIPTION: Use UI.KPI XML annotation to define KPI with DataPoint, Detail, SelectionVariantQualifier and ID.
LANGUAGE: XML
CODE:
```xml
<Annotation Term="UI.KPI" Qualifier="Eval_by_Country-Generic">
    <Record>
        <PropertyValue Property="DataPoint" Path="@UI.DataPoint#Eval_by_Country-Generic"/>
        <PropertyValue Property="Detail">
            <Record Type="UI.KPIDetailType">
                <PropertyValue Property="DefaultPresentationVariant" Path="@UI.PresentationVariant#Eval_by_Currency1"/>
                <PropertyValue Property="AlternativePresentationVariants">
                    <Collection>
                        <Path>@UI.PresentationVariant#Eval_by_Currency_Column</Path>
                    </Collection>
                </PropertyValue>
                <PropertyValue String="Action" Property="SemanticObject"/>
                <PropertyValue String="toappnavsample" Property="Action"/>
            </Record>
        </PropertyValue>
        <PropertyValue String="String for KPI Annotation" Property="ID"/>
        <PropertyValue Property="SelectionVariantQualifier" Path="@UI.SelectionVariant#Eval_by_Currency_1"/>
    </Record>
</Annotation>

<Annotation Term="UI.DataPoint" Qualifier="Eval_by_Country_Generic">
    <Record>
        <PropertyValue Property="Value" Path="Currency"/>
        <PropertyValue String="test" Property="Title"/>
    </Record>
</Annotation>
```

STEP: KPI — ABAP CDS sample
DESCRIPTION: Equivalent KPI definition in ABAP CDS: declare UI.KPI with detail block, selectionVariantQualifier and dataPoint.
LANGUAGE: ABAP CDS
CODE:
```
@UI.KPI: [
    {
        detail: {
            defaultPresentationVariantQualifier: 'Eval_by_Currency1',
            alternativePresentationVariantQualifiers: [
                'Eval_by_Currency_Column'
            ],
            semanticObject: 'Action',
            semanticObjectAction: 'toappnavsample'
        },
        selectionVariantQualifier: 'Eval_by_Currency_1',
        id: 'String for KPI Annotation',
        qualifier: 'Eval_by_Country-Generic',
        dataPoint: {
            title: 'test'
        }
    }
]
```

STEP: KPI — CAP CDS sample
DESCRIPTION: CAP CDS syntax for UI.KPI with DataPoint reference and Detail presentation variants.
LANGUAGE: CAP CDS
CODE:
```
UI.KPI #AllActualCosts: {
    $Type: 'UI.KPIType',
    Detail: {
        $Type: 'UI.KPIDetailType',
        DefaultPresentationVariant: ![@UI.PresentationVariant#Eval_by_Currency1],
        AlternativePresentationVariants: [
            ![@UI.PresentationVariant#Eval_by_Currency_Column]
        ],
        SemanticObject: 'Action',
        Action: 'toappnavsample'
    },
    SelectionVariant: ![@UI.SelectionVariant#Eval_by_Currency_1],
    DataPoint: ![@UI.DataPoint#Eval_by_Country-Generic],
    ID: 'String for KPI Annotation'
}
```

STEP: PresentationVariant — XML
DESCRIPTION: Define PresentationVariant XML to control MaxItems, GroupBy, SortOrder and Visualizations for a KPI or view variant.
LANGUAGE: XML
CODE:
```xml
<Annotation Term="UI.PresentationVariant" Qualifier="Eval_by_Currency1">
    <Record>
        <PropertyValue Property="MaxItems" Int="5"/>
        <PropertyValue Property="GroupBy">
            <Collection>
                <PropertyPath>Country</PropertyPath>
                <PropertyPath>Currency</PropertyPath>
            </Collection>
        </PropertyValue>
        <PropertyValue Property="SortOrder">
            <Collection>
                <Record>
                    <PropertyValue Property="Property" PropertyPath="TotalSales"/>
                    <PropertyValue Property="Descending" Bool="true"/>
                </Record>
            </Collection>
        </PropertyValue>
        <PropertyValue Property="Visualizations">
            <Collection>
                <AnnotationPath>@UI.Chart#Eval_by_Currency_Donut</AnnotationPath>
            </Collection>
        </PropertyValue>
    </Record>
</Annotation>
```

STEP: PresentationVariant — ABAP CDS
DESCRIPTION: PresentationVariant in ABAP CDS with groupBy, sortOrder and visualizations settings.
LANGUAGE: ABAP CDS
CODE:
```
@UI.PresentationVariant: [
    {
        maxItems: 5,
        groupBy: [
            'COUNTRY',
            'CURRENCY'
        ],
        sortOrder: [
            {
                by: 'TOTALSALES'
            }
        ],
        visualizations: [
            {
                type: '#AS_CHART',
                qualifier: 'Eval_by_Currency_Donut'
            }
        ],
        qualifier: 'Eval_by_Currency1'
    }
]

// Annotation for VIEWNAME
annotate view VIEWNAME with {}
```

STEP: PresentationVariant — CAP CDS
DESCRIPTION: CAP CDS PresentationVariant syntax for grouping, sorting, and visualization declaration.
LANGUAGE: CAP CDS
CODE:
```
UI.PresentationVariant #Eval_by_Currency1: {
    MaxItems: 5,
    GroupBy: [
        "Country",
        "Currency"
    ],
    SortOrder: [
        {
            Property: "TotalSales",
            Descending: true
        }
    ],
    Visualizations: [
        "@UI.Chart#Eval_by_Currency_Donut"
    ]
}
```

STEP: SelectionVariant — XML
DESCRIPTION: Define SelectionVariant XML for pre-filtering via SelectOptions and Parameters used by PresentationVariant or KPI.
LANGUAGE: XML
CODE:
```xml
<Annotation Term="UI.SelectionVariant" Qualifier="Eval_by_Currency_1">
    <Record>
        <PropertyValue Property="SelectOptions">
            <Collection>
                <Record>
                    <PropertyValue Property="PropertyName" PropertyPath="Country"/>
                    <PropertyValue Property="Ranges">
                        <Collection>
                            <Record>
                                <PropertyValue Property="Sign" EnumMember="UI.SelectionRangeSignType/I"/>
                                <PropertyValue Property="Option" EnumMember="UI.SelectionRangeOptionType/EQ"/>
                                <PropertyValue Property="Low" String="IN"/>
                            </Record>
                        </Collection>
                    </PropertyValue>
                </Record>
            </Collection>
        </PropertyValue>
        <PropertyValue Property="Parameters">
            <Collection>
                <Record Type="UI.Parameter">
                    <PropertyValue Property="PropertyName" PropertyPath="Currency_Target"/>
                    <PropertyValue Property="PropertyValue" String="EUR"/>
                </Record>
                <Record Type="UI.Parameter">
                    <PropertyValue Property="PropertyName" PropertyPath="UoM_Target"/>
                    <PropertyValue Property="PropertyValue" String="KGM"/>
                </Record>
            </Collection>
        </PropertyValue>
    </Record>
</Annotation>
```

STEP: SelectionVariant — CAP CDS
DESCRIPTION: CAP CDS SelectionVariant example mapping SelectOptions and Parameters for pre-filters.
LANGUAGE: CAP CDS
CODE:
```
UI.SelectionVariant #Eval_by_Currency_1: {
    SelectOptions: [
        {
            PropertyName: "Country",
            Ranges: [
                {
                    Sign: "#I",
                    Option: "#EQ",
                    Low: "IN"
                }
            ]
        }
    ],
    Parameters: [
        {
            $Type: "UI.Parameter",
            PropertyName: "Currency_Target",
            PropertyValue: "EUR"
        },
        {
            $Type: "UI.Parameter",
            PropertyName: "UoM_Target",
            PropertyValue: "KGM"
        }
    ]
}
```

STEP: DataPoint — XML
DESCRIPTION: Define UI.DataPoint in XML to configure title, value, format, criticality, target and trend for KPI/DataPoint visualizations.
LANGUAGE: XML
CODE:
```xml
<Annotation Term="UI.DataPoint" Qualifier="Eval_by_Country_Generic">
    <Record Type="UI.DataPointType">
        <PropertyValue Property="Title" String="Sales India - Generic Card" />
        <PropertyValue Property="Value" Path="Sales" />
        <PropertyValue Property="ValueFormat">
            <Record>
                <PropertyValue Property="ScaleFactor" Decimal="2" />
                <PropertyValue Property="NumberOfFractionalDigits" Int="1" />
            </Record>
        </PropertyValue>
        <PropertyValue Property="CriticalityCalculation">
            <Record>
                <PropertyValue Property="ImprovementDirection" EnumMember="UI.ImprovementDirectionType/Minimize" />
                <PropertyValue Property="DeviationRangeHighValue" String="7300" />
                <PropertyValue Property="ToleranceRangeHighValue" String="7200" />
            </Record>
        </PropertyValue>
        <PropertyValue Property="TargetValue" String="2.000" />
        <PropertyValue Property="TrendCalculation">
            <Record>
                <PropertyValue Property="ReferenceValue" String="5201680" />
                <PropertyValue Property="DownDifference" Decimal="10000000.0" />
            </Record>
        </PropertyValue>
    </Record>
</Annotation>
```

STEP: DataPoint — ABAP CDS
DESCRIPTION: ABAP CDS DataPoint declaration showing valueFormat, criticalityCalculation and trendCalculation mapping.
LANGUAGE: ABAP CDS
CODE:
```
@UI.dataPoint: {
    title: "Sales India - Generic Card",
    valueFormat: {
        scaleFactor: 2,
        numberOfFractionalDigits: 1
    },
    criticalityCalculation: {
        improvementDirection: "#MINIMIZE",
        deviationRangeHighValue: 7300,
        toleranceRangeHighValue: 7200
    },
    targetValue: 2.000,
    trendCalculation: {
        referenceValue: "refValElement",
        downDifference: 10000000.0
    }
} Sales;
```

STEP: DataPoint — CAP CDS
DESCRIPTION: CAP CDS DataPoint example mapping UI.DataPointType properties to fields and calculations.
LANGUAGE: CAP CDS
CODE:
```
UI.DataPoint #Eval_by_Country-Generic: {
    $Type: "UI.DataPointType",
    Title: "Sales India - Generic Card",
    Value: "Sales",
    ValueFormat: {
        ScaleFactor: 2,
        NumberOfFractionalDigits: 1
    },
    CriticalityCalculation: {
        ImprovementDirection: "#Minimizing",
        DeviationRangeHighValue: "7300",
        ToleranceRangeHighValue: "7200"
    },
    TargetValue: "2.000",
    TrendCalculation: {
        ReferenceValue: "5201680",
        DownDifference: 10000000.0
    }
}
```

STEP: View Switch / Tabs — Manifest sample
DESCRIPTION: Use valueSelectionInfo and tabs[] in card settings to configure a dropdown view selector on the card. Each tab maps annotation paths and optional dataPoint/presentation/selection variants. Paste this JSON into sap.ovp.cards.<cardId>.settings.
LANGUAGE: JSON
CODE:
```json
"sap.ovp": {
    "globalFilterModel": "salesOrder",
    "globalFilterEntityType": "GlobalFilters", //Deprecated since SAPUI5 1.54.
    "globalFilterEntitySet": "GlobalFilters", //Available from SAPUI5 1.54.
    "showDateInRelativeFormat": false,
    "disableTableCardFlexibility": false,
    "considerAnalyticalParameters": true,
    "useDateRangeType": false,
    "cards": {
        "card014": {
            "model": "salesOrder",
            "template": "sap.ovp.cards.table",
            "settings": {
                "title": "Sales Forecast",
                "subTitle": "per Supplier",
                "valueSelectionInfo": "Value Selection Info",
                "entitySet": "SalesShare",
                "tabs": [
                    {
                        "dynamicSubtitleAnnotationPath": "com.sap.vocabularies.UI.v1.HeaderInfo#dynamicSubtitle",
                        "annotationPath": "com.sap.vocabularies.UI.v1.LineItem#View1",
                        "selectionAnnotationPath": "com.sap.vocabularies.UI.v1.SelectionVariant#line1",
                        "presentationAnnotationPath": "com.sap.vocabularies.UI.v1.PresentationVariant#line",
                        "identificationAnnotationPath": "com.sap.vocabularies.UI.v1.Identification",
                        "dataPointAnnotationPath": "com.sap.vocabularies.UI.v1.DataPoint#line",
                        "value": "{{dropdown_value2}}"
                    },
                    {
                        "dynamicSubtitleAnnotationPath": "com.sap.vocabularies.UI.v1.HeaderInfo#dynamicSubtitle",
                        "annotationPath": "com.sap.vocabularies.UI.v1.LineItem#View4",
                        "identificationAnnotationPath": "com.sap.vocabularies.UI.v1.Identification#item2",
                        "dataPointAnnotationPath": "com.sap.vocabularies.UI.v1.DataPoint#line",
                        "value": "{{dropdown_value4}}"
                    }
                ]
            }
        }
    }
}
```

STEP: Table Area — LineItem annotation (XML)
DESCRIPTION: Define com.sap.vocabularies.UI.v1.LineItem to control columns: Label property is the header, Value property or Target for DataPoint provides column values.
LANGUAGE: XML
CODE:
```xml
<Annotation Term="com.sap.vocabularies.UI.v1.LineItem" Qualifier="View4">
    <Collection>
        <Record Type="com.sap.vocabularies.UI.v1.DataField">
            <PropertyValue Property="Label" String="Order ID"/>
            <PropertyValue Property="Value" Path="SalesOrderID"/>
        </Record>
        <Record Type="com.sap.vocabularies.UI.v1.DataField">
            <PropertyValue Property="Label" String="Customer"/>
            <PropertyValue Property="Value" Path="ToBusinessPartner/EmailAddress"/>
        </Record>
        <Record Type="com.sap.vocabularies.UI.v1.DataField">
            <PropertyValue Property="Label" String="Customer"/>
            <PropertyValue Property="Value" Path="CustomerName"/>
        </Record>
        <Record Type="com.sap.vocabularies.UI.v1.DataFieldForAnnotation">
            <PropertyValue Property="Label" String="TaxAmount"/>
            <PropertyValue Property="Target" AnnotationPath="@com.sap.vocabularies.UI.v1.DataPoint#TaxAmount"/>
        </Record>
    </Collection>
</Annotation>
```

STEP: Table Area — LineItem ABAP CDS
DESCRIPTION: ABAP CDS define per-field @UI.lineItem qualifier usage to map fields to LineItem columns.
LANGUAGE: ABAP CDS
CODE:
```
@UI.lineItem: [
    {
        label: "Order ID",
        position: 10,
        qualifier: "View4"
    }
] SALESORDERID;

@UI.lineItem: [
    {
        label: "Customer",
        value: "_BUSINESSPARTNER.EMAILADDRESS",
        position: 20,
        qualifier: "View4"
    }
] _BUSINESSPARTNER;

@UI.lineItem: [
    {
        label: "Customer",
        position: 30,
        qualifier: "View4"
    }
] CUSTOMERNAME;

@UI.lineItem: [
    {
        label: "TaxAmount",
        valueQualifier: "TaxAmount",
        type: "#AS_DATAPOINT",
        position: 40,
        qualifier: "View4"
    }
] PROPERTY_NAME;
```

STEP: Table Area — LineItem CAP CDS
DESCRIPTION: Define UI.LineItem in CAP CDS with DataField and DataFieldForAnnotation entries; used by the table card for columns.
LANGUAGE: CAP CDS
CODE:
```
UI.LineItem #View4: [
    {
        $Type: "UI.DataField",
        Label: "Order ID",
        Value: "SalesOrderID"
    },
    {
        $Type: "UI.DataField",
        Label: "Customer",
        Value: "ToBusinessPartner.EmailAddress"
    },
    {
        $Type: "UI.DataField",
        Label: "Customer",
        Value: "CustomerName"
    },
    {
        $Type: "UI.DataFieldForAnnotation",
        Label: "TaxAmount",
        Target: "@UI.DataPoint#TaxAmount"
    }
]
```

STEP: DataPoint TaxAmount — XML
DESCRIPTION: DataPoint annotation for TaxAmount used as DataFieldForAnnotation target to populate and style the third column.
LANGUAGE: XML
CODE:
```xml
<Annotation Term="com.sap.vocabularies.UI.v1.DataPoint" Qualifier="TaxAmount">
    <Record Type="com.sap.vocabularies.UI.v1.DataPointType">
        <PropertyValue Property="Title" String="TaxAmount"/>
        <PropertyValue Property="Value" Path="TaxAmount"/>
    </Record>
</Annotation>
```

STEP: DataPoint TaxAmount — ABAP CDS
DESCRIPTION: ABAP CDS DataPoint declaration for TaxAmount qualifier.
LANGUAGE: ABAP CDS
CODE:
```
@UI.dataPoint: {
    title: "TaxAmount"
} TaxAmount;
```

STEP: DataPoint TaxAmount — CAP CDS
DESCRIPTION: CAP CDS DataPoint mapping for TaxAmount to be used by DataFieldForAnnotation.
LANGUAGE: CAP CDS
CODE:
```
UI.DataPoint #TaxAmount: {
    $Type: "UI.DataPointType",
    Title: "TaxAmount",
    Value: "TaxAmount"
}
```

STEP: Manifest — annotationPath sample (use qualifier)
DESCRIPTION: Example manifest card configuration showing annotationPath with qualifier and other card settings; use when you want a qualified LineItem.
LANGUAGE: JSON
CODE:
```json
"sap.ovp": {
    ...
    "disableTableCardFlexibility": false,
    ...
    "card02": {
        "model": "salesOrder",
        "template": "sap.ovp.cards.table",
        "settings": {
            "title": "Sales Orders With Analytical Header",
            "subTitle": "Sales Orders With Analytical Header",
            "listFlavor": "bar",
            "listType": "extended",
            "entitySet": "SalesOrderSet",
            "dataPointAnnotationPath": "com.sap.vocabularies.UI.v1.DataPoint#line_without_trend",
            "selectionAnnotationPath": "com.sap.vocabularies.UI.v1.SelectionVariant#line1",
            "annotationPath": "com.sap.vocabularies.UI.v1.LineItem#View1",
            "presentationAnnotationPath": "com.sap.vocabularies.UI.v1.PresentationVariant#line"
        }
    },
    ...
}
```

STEP: Note — OData V4 template
DESCRIPTION: For OData V4 Fiori elements, use template "sap.ovp.cards.v4.table" in the manifest; all other settings remain identical to OData V2 docs.
LANGUAGE: JSON
CODE:
```json
// Use "sap.ovp.cards.v4.table" as template for OData V4
```

STEP: TableCard Flexibility behavior (actionable rules)
DESCRIPTION: Runtime behavior for disableTableCardFlexibility:
- If disableTableCardFlexibility = true: DataField records are sorted by Importance and entry order; first two DataField become first two columns; third column is DataPoint target (DataFieldForAnnotation) if present, otherwise next DataField.
- If disableTableCardFlexibility = false: columns sorted according to Importance and entry order.
- If a DataField points to a property that also exists inside a DataPoint target, the DataField is skipped to avoid duplicate display.

LANGUAGE: TEXT
CODE:
```text
Behavior rules described above apply at runtime; no code required.
```

STEP: Example — Product Weight Measure (XML)
DESCRIPTION: Full XML example that shows a DataPoint WeightMeasure and a LineItem collection. Use this to render three-column table: Product Name, Supplier, Weight Measure (DataPoint target).
LANGUAGE: XML
CODE:
```xml
<Annotation Term="com.sap.vocabularies.UI.v1.DataPoint" Qualifier="WeightMeasure">
    <Record Type="com.sap.vocabularies.UI.v1.DataPointType">
        <PropertyValue Property="Title" String="Weight"/>
        <PropertyValue Property="Description" Path="Name"/>
        <PropertyValue Property="Value" Path="WeightMeasure"/>
        <PropertyValue Property="CriticalityCalculation">
            <Record Type="com.sap.vocabularies.UI.v1.CriticalityCalculationType">
                <PropertyValue Property="ImprovementDirection" EnumMember="com.sap.vocabularies.UI.v1.CriticalityCalculationType/Maximize"/>
                <PropertyValue Property="ToleranceRangeLowValue" Int="2"/>
                <PropertyValue Property="DeviationRangeLowValue" Int="4"/>
            </Record>
        </PropertyValue>
    </Record>
</Annotation>

<Annotation Term="com.sap.vocabularies.UI.v1.LineItem">
    <Collection>
        <Record Type="com.sap.vocabularies.UI.v1.DataField">
            <PropertyValue Property="Label" String="Product ID"/>
            <PropertyValue Property="Value" Path="ProductID"/>
        </Record>
        <Record Type="com.sap.vocabularies.UI.v1.DataField">
            <PropertyValue Property="Label" String="Category"/>
            <PropertyValue Property="Value" Path="Category"/>
        </Record>
        <Record Type="com.sap.vocabularies.UI.v1.DataField">
            <PropertyValue Property="Label" String="Product Name"/>
            <PropertyValue Property="Value" Path="Name"/>
            <Annotation Term="com.sap.vocabularies.UI.v1.Importance" EnumMember="com.sap.vocabularies.UI.v1.ImportanceType/High"/>
        </Record>
        <Record Type="com.sap.vocabularies.UI.v1.DataField">
            <PropertyValue Property="Label" String="Supplier"/>
            <PropertyValue Property="Value" Path="SupplierName"/>
            <Annotation Term="com.sap.vocabularies.UI.v1.Importance" EnumMember="com.sap.vocabularies.UI.v1.ImportanceType/High"/>
        </Record>
        <Record Type="com.sap.vocabularies.UI.v1.DataField">
            <PropertyValue Property="Label" String="Unit Price"/>
            <PropertyValue Property="Value" Path="Price"/>
            <Annotation Term="com.sap.vocabularies.UI.v1.Importance" EnumMember="com.sap.vocabularies.UI.v1.ImportanceType/High"/>
        </Record>
        <Record Type="com.sap.vocabularies.UI.v1.DataFieldForAnnotation">
            <PropertyValue Property="Label" String="Weight Measure"/>
            <PropertyValue Property="Target" AnnotationPath="@com.sap.vocabularies.UI.v1.DataPoint#WeightMeasure"/>
        </Record>
    </Collection>
</Annotation>
```

STEP: Example — Product Weight Measure (ABAP CDS)
DESCRIPTION: ABAP CDS variant of the weight measure and line item mapping. Use annotate/view declarations as shown.
LANGUAGE: ABAP CDS
CODE:
```
@UI.dataPoint: {
    title: "Weight",
    description: "Name",
    valueFormat: {
        scaleFactor: 2,
        numberOfFractionalDigits: 1
    },
    criticalityCalculation: {
        improvementDirection: "#MAXIMIZE",
        deviationRangeHighValue: 4.3,
        toleranceRangeHighValue: 2.5
    }
} WeightMeasure;

@UI.lineItem: [
    {
        label: "Product ID",
        position: 10
    }
] PRODUCTID;

@UI.lineItem: [
    {
        label: "Category",
        position: 20
    }
] CATEGORY;

@UI.lineItem: [
    {
        importance: "#HIGH",
        label: "Product Name",
        position: 30
    }
] NAME;

@UI.lineItem: [
    {
        importance: "#HIGH",
        label: "Supplier",
        position: 40
    }
] SUPPLIERNAME;

@UI.lineItem: [
    {
        importance: "#HIGH",
        label: "Unit Price",
        position: 50
    }
] PRICE;

@UI.lineItem: [
    {
        label: "Weight Measure",
        valueQualifier: "WeightMeasure",
        type: "#AS_DATAPOINT",
        position: 60
    }
] PROPERTY_NAME;
```

STEP: Example — Product Weight Measure (CAP CDS)
DESCRIPTION: CAP CDS example mapping DataPoint and LineItem entries for the product weight scenario.
LANGUAGE: CAP CDS
CODE:
```
UI.DataPoint #WeightMeasure: {
    $Type: "UI.DataPointType",
    Title: "Weight",
    Description: "Name",
    Value: "WeightMeasure",
    CriticalityCalculation: {
        $Type: "UI.CriticalityCalculationType",
        ImprovementDirection: "#Maximize",
        ToleranceRangeLowValue: 2.5,
        DeviationRangeLowValue: 4.3
    }
},

UI.LineItem: [
    {
        $Type: "UI.DataField",
        Label: "Product ID",
        Value: "ProductID"
    },
    {
        $Type: "UI.DataField",
        Label: "Category",
        Value: "Category"
    },
    {
        $Type: "UI.DataField",
        Label: "Product Name",
        Value: "Name",
        "![@UI.Importance]": "#High"
    },
    {
        $Type: "UI.DataField",
        Label: "Supplier",
        Value: "SupplierName",
        "![@UI.Importance]": "#High"
    },
    {
        $Type: "UI.DataField",
        Label: "Unit Price",
        Value: "Price",
        "![@UI.Importance]": "#High"
    },
    {
        $Type: "UI.DataFieldForAnnotation",
        Label: "Weight Measure",
        Target: "@UI.DataPoint#WeightMeasure"
    }
]
```

STEP: Smart Links — Semantic Object (XML)
DESCRIPTION: Annotate an entity/set property with SemanticObject so smart links are enabled for table values.
LANGUAGE: XML
CODE:
```xml
<Annotations Target="GWSAMPLE_BASIC.SalesOrder/SalesOrderID">
    <Annotation Term="com.sap.vocabularies.Common.v1.SemanticObject" String="OVP"/>
</Annotations>
```

STEP: Smart Links — Semantic Object (ABAP CDS)
DESCRIPTION: ABAP CDS annotate view field with @Consumption.semanticObject to enable smart links.
LANGUAGE: ABAP CDS
CODE:
```
annotate view SALESORDER with {
    @Consumption.semanticObject: 'OVP'
    salesorderid;
}
```

STEP: Smart Links — Semantic Object (CAP CDS)
DESCRIPTION: CAP CDS annotate entity property with @Common.SemanticObject to enable navigation.
LANGUAGE: CAP CDS
CODE:
```
annotate GWSAMPLE_BASIC.SalesOrder with {
    @Common.SemanticObject: 'OVP'
    SalesOrderID;
}
```

STEP: Contact in LineItem — XML
DESCRIPTION: Use DataFieldForAnnotation pointing to Communication.Contact to render contact details in table card.
LANGUAGE: XML
CODE:
```xml
<Annotation Term="com.sap.vocabularies.UI.v1.LineItem" Qualifier="NewSalesOrders">
    <Collection>
        <Record Type="com.sap.vocabularies.UI.v1.DataField">
            <PropertyValue Property="Label" String="Order ID (Company)"/>
            <PropertyValue Property="Value" Path="SalesOrderID"/>
        </Record>
        <Record Type="com.sap.vocabularies.UI.v1.DataFieldForAnnotation">
            <PropertyValue Property="Label" String="Created by (Role)" />
            <PropertyValue Property="Target" AnnotationPath="ToBusinessPartner/@com.sap.vocabularies.Communication.v1.Contact" />
        </Record>
    </Collection>
</Annotation>
```

STEP: Contact in LineItem — ABAP CDS
DESCRIPTION: ABAP CDS line item entries; use type #AS_CONTACT to render contact UI for a property.
LANGUAGE: ABAP CDS
CODE:
```
@UI.lineItem: [
    {
        label: "Order ID (Company)",
        position: 10,
        qualifier: "NewSalesOrders"
    }
] SALESORDERID;

@UI.lineItem: [
    {
        label: "Created by (Role)",
        value: "_BUSINESSPARTNER",
        type: "#AS_CONTACT",
        position: 20,
        qualifier: "NewSalesOrders"
    }
] PROPERT_NAME;
```

STEP: Contact in LineItem — CAP CDS
DESCRIPTION: CAP CDS mapping where UI.DataFieldForAnnotation Target references Communication.Contact for ToBusinessPartner.
LANGUAGE: CAP CDS
CODE:
```
UI.LineItem #NewSalesOrders: [
    {
        $Type: "UI.DataField",
        Label: "Order ID (Company)",
        Value: "SalesOrderID"
    },
    {
        $Type: "UI.DataFieldForAnnotation",
        Label: "Created by (Role)",
        Target: "ToBusinessPartner/@Communication.Contact"
    }
]
```

STEP: Communication.Contact — XML
DESCRIPTION: Define the Communication.Contact annotation (tel/email) to control contact display (phone, fax, email) used by DataFieldForAnnotation.
LANGUAGE: XML
CODE:
```xml
<Annotation Term="com.sap.vocabularies.Communication.v1.Contact">
    <Record>
        <PropertyValue Property="tel">
            <Collection>
                <Record>
                    <PropertyValue Property="type" EnumMember="com.sap.vocabularies.Communication.v1.PhoneType/fax"/>
                    <PropertyValue Property="uri" Path="FaxNumber"/>
                </Record>
                <Record>
                    <PropertyValue Property="type" EnumMember="com.sap.vocabularies.Communication.v1.PhoneType/work com.sap.vocabularies.Communication.v1.PhoneType/preferred"/>
                    <PropertyValue Property="uri" Path="PhoneNumber"/>
                </Record>
            </Collection>
        </PropertyValue>
        <PropertyValue Property="email">
            <Collection>
                <Record>
                    <PropertyValue Property="type" EnumMember="com.sap.vocabularies.Communication.v1.ContactInformationType/preferred com.sap.vocabularies.Communication.v1.ContactInformationType/work"/>
                    <PropertyValue Property="address" Path="EmailAddress"/>
                </Record>
            </Collection>
        </PropertyValue>
    </Record>
</Annotation>
```

STEP: Contact fields — ABAP CDS view definition
DESCRIPTION: Example ABAP CDS view fields with semantics annotations for email and telephone used by Communication.Contact.
LANGUAGE: ABAP CDS
CODE:
```
define view VIEWNAME {
    @Semantics.name.fullName: true
    CompanyName,

    @Semantics.eMail.address: true
    @Semantics.eMail.type: [#WORK]
    EmailAddress,

    @Semantics.telephone.type: [#FAX]
    FaxNumber,

    @Semantics.telephone.type: [#WORK]
    PhoneNumber
}
```

STEP: Communication.Contact — CAP CDS
DESCRIPTION: CAP CDS representation of Communication.Contact for tel and email mappings used by UI annotations.
LANGUAGE: CAP CDS
CODE:
```
Communication.Contact: {
    tel: [
        {
            type: "#fax",
            uri: "FaxNumber"
        },
        {
            type: ["#work", "#pref"],
            uri: "PhoneNumber"
        }
    ],
    email: [
        {
            type: ["#pref", "#work"],
            address: "EmailAddress"
        }
    ]
}
```

STEP: Text Arrangement — XML
DESCRIPTION: Use Common.Text and UI.TextArrangement annotations to control text format (TextLast/TextFirst/TextOnly) for label/value composition.
LANGUAGE: XML
CODE:
```xml
<Annotations xmlns="http://docs.oasis-open.org/odata/ns/edm" Target="GWSAMPLE_BASIC.SalesOrder/CustomerID">
    <Annotation Term="com.sap.vocabularies.Common.v1.Text" Path="Supplier_Name">
        <Annotation Term="com.sap.vocabularies.UI.v1.TextArrangement" EnumMember="com.sap.vocabularies.UI.v1.TextArrangementType/TextLast"/>
    </Annotation>
</Annotations>
```

STEP: Text Arrangement — ABAP CDS
DESCRIPTION: ABAP CDS syntax to apply UI.TextArrangement on a field (TextLast/TextFirst/TextOnly).
LANGUAGE: ABAP CDS
CODE:
```
annotate view SALESORDER with {
    @UI.TextArrangement: #TEXT_LAST
    customerid;
}
```

STEP: Text Arrangement — CAP CDS
DESCRIPTION: CAP CDS annotate Common.Text and UI.TextArrangement to set text arrangement for a property.
LANGUAGE: CAP CDS
CODE:
```
annotate GWSAMPLE_BASIC.SalesOrder with {
    @Common.Text: Supplier_Name
    @UI.TextArrangement: #TextLast
    CustomerID;
}
```

STEP: Text Alignment — Table alignment rules
DESCRIPTION: Use these alignment rules while designing annotations; they are applied automatically by the table card:
- DataField or Contact annotation: Left aligned.
- DataPoint (with or without Criticality/CriticalityCalculation) OR any property of type Edm.DateTime/Edm.DateTimeOffset: Right aligned.
- DataPoint with Criticality and property of type Edm.String: Center aligned.
LANGUAGE: TEXT
CODE:
```text
Apply alignment rules when creating DataField/DataPoint annotations to ensure correct table alignment at runtime.
```

fiori-elements ovp table-card annotations UI.LineItem DataPoint PresentationVariant SelectionVariant manifest smart-links contact text-arrangement


**TITLE**: Table Groupings in SAP Fiori Elements (OData V2 & V4)

**INTRODUCTION**: This document explains how SAP Fiori elements handles table row grouping (automatic behavior, supported table types, restrictions) and how to control grouping and defaults for OData V2 and OData V4. It includes actionable configuration snippets (manifest.json), annotation examples (XML, CAP CDS), and implementation notes for responsive and analytical tables.

**TAGS**: fiori-elements, table-grouping, analytical-table, responsive-table, ODataV2, ODataV4, PresentationVariant, manifest.json, annotations

STEP: Supported table types and quick overview
DESCRIPTION: Identify which UI5 table types support automatic row grouping and when grouping is handled by the server vs. client.
LANGUAGE: text
CODE:
```text
- Supported table types for grouping:
  - sap.m.Table (ResponsiveTable) -> grouping supported
  - sap.ui.Table.AnalyticalTable -> grouping supported
  - Not supported: GridTable, TreeTable

- Grouping behavior:
  - Grouping is handled automatically by SAP Fiori elements.
  - For AnalyticalTable grouping takes place on the server.
  - Header formatters do NOT affect server-side grouping (groups remain separate even if formatted identically).
```

STEP: Analytical table restrictions (must-know)
DESCRIPTION: Actionable restrictions to apply when using analytical tables with grouping. Validate model/annotations against these constraints.
LANGUAGE: text
CODE:
```text
Restrictions for AnalyticalTable groupings:
- Grouping can only be activated for dimension columns.
- Grouping is server-side; header formatter does not change grouping keys.
- TextArrangement annotation is NOT supported for grouping headers. Text + property displays as: "m – Meter".
  See API reference: sap.ui.comp.smarttable.SmartTable.annotations.TextArrangement
- Displaying values with units-of-measure within grouping headers is NOT supported for analytical tables.
```

STEP: How SAP Fiori elements sets grouping header text formatters
DESCRIPTION: Use these hooks when implementing or customizing grouping header formatting for responsive and analytical tables.
LANGUAGE: text
CODE:
```text
- ResponsiveTable:
  - A grouping function is set on the sorter: fnGroup of sap.ui.model.Sorter
  - Use sorter with fnGroup to customize group header text for responsive tables.

- AnalyticalTable:
  - The property groupHeaderFormatter of sap.ui.table.AnalyticalColumn is set.
  - Customize groupHeaderFormatter to control group header text for analytical columns.
```

STEP: Grouping header types and formatting rules (OData -> formatted header examples)
DESCRIPTION: Use this mapping to predict or implement formatted grouping header text for common OData types. Keep in mind units/currencies formatting availability.
LANGUAGE: HTML
CODE:
```html
<table>
<tr>
<th valign="top">OData Type</th>
<th valign="top">SAP Display Format</th>
<th valign="top">OData Example</th>
<th valign="top">Unformatted</th>
<th valign="top">Formatted</th>
<th valign="top">Comments</th>
</tr>
<tr>
<td valign="top">Edm.DateTimeOffsetDate</td>
<td valign="top">Date</td>
<td valign="top">/Date(1485471600000 +0000)/</td>
<td valign="top">Fri Jan 27 2017 00:00:00 GMT+0100 (Central European Standard Time)</td>
<td valign="top">Jan 26, 2017</td>
<td valign="top">UTC</td>
</tr>
<tr>
<td valign="top">Edm.DateTimeOffset</td>
<td valign="top"> </td>
<td valign="top">/Date(1485471600000 +0000)/</td>
<td valign="top">Fri Jan 27 2017 00:00:00 GMT+0100 (Central European Standard Time)</td>
<td valign="top">Jan 27, 2017, 12:00:00 AM</td>
<td valign="top"> </td>
</tr>
<tr>
<td valign="top">Edm.DateTime</td>
<td valign="top">Date</td>
<td valign="top">/Date(1485471600000 +0000)/</td>
<td valign="top">Fri Jan 27 2017 00:00:00 GMT+0100 (Central European Standard Time)</td>
<td valign="top">Jan 26, 2017</td>
<td valign="top">UTC</td>
</tr>
<tr>
<td valign="top">Edm.DateTime</td>
<td valign="top"> </td>
<td valign="top">/Date(1485471600000 +0000)/</td>
<td valign="top">Fri Jan 27 2017 00:00:00 GMT+0100 (Central European Standard Time)</td>
<td valign="top">Jan 27, 2017, 12:00:00 AM</td>
<td valign="top"> </td>
</tr>
<tr>
<td valign="top">Edm.Time</td>
<td valign="top">Time</td>
<td valign="top">PT11H13M01S</td>
<td valign="top">[object Object] is: {ms: 43980000, __edmType: "Edm.Time"}</td>
<td valign="top">11:13:01 AM</td>
<td valign="top"> </td>
</tr>
<tr>
<td valign="top">Edm.String</td>
<td valign="top">Date</td>
<td valign="top">20180313</td>
<td valign="top">20180313</td>
<td valign="top">Mar 13, 2018</td>
<td valign="top"> </td>
</tr>
<tr>
<td valign="top">Edm.Boolean</td>
<td valign="top"> </td>
<td valign="top">true</td>
<td valign="top">true</td>
<td valign="top">Yes</td>
<td valign="top"> </td>
</tr>
<tr>
<td valign="top">Edm.Decimal</td>
<td valign="top"> </td>
<td valign="top">10</td>
<td valign="top">10</td>
<td valign="top">10.000 m*</td>
<td valign="top">Unit of measure</td>
</tr>
<tr>
<td valign="top">Edm.Decimal</td>
<td valign="top"> </td>
<td valign="top">2498.00</td>
<td valign="top">2498.00</td>
<td valign="top">2,498.00 EUR*</td>
<td valign="top">Currency</td>
</tr>
<tr>
<td valign="top">Edm.String</td>
<td valign="top"> </td>
<td valign="top">m</td>
<td valign="top">m</td>
<td valign="top">Meter (m)*</td>
<td valign="top">Unit of measure and TextArrangement</td>
</tr>
<tr>
<td valign="top">Edm.String</td>
<td valign="top"> </td>
<td valign="top">EUR</td>
<td valign="top">EUR</td>
<td valign="top">Euro (EUR)*</td>
<td valign="top">Currency and TextArrangement</td>
</tr>
</table>

* Units of measure or currencies in the grouping header are supported only in responsive tables.
```

STEP: Disable grouping in Responsive Table (OData V4) via manifest.json
DESCRIPTION: Disable grouping (and other personalization options) using table personalization in manifest.json under the LineItem annotation. Insert the snippet under the relevant LineItem entry in your manifest.
LANGUAGE: JSON
CODE:
```json
"_Item/@com.sap.vocabularies.UI.v1.LineItem": {
     "tableSettings": {
          "type": "ResponsiveTable",
          "condensedTableLayout": true,
          "personalization": {
               "column": true,
               "sort": false,
               "group": false
          },
          ...
     }
}
```

STEP: Define default groups and totals using PresentationVariant (OData V4)
DESCRIPTION: Define default group levels and totals at application launch by annotating entity sets with UI.PresentationVariant (PV) or SelectionPresentationVariant (SPV). Always include Visualizations in the PV/SPV so Fiori elements will consider it. Use the XML or CAP CDS code samples below.
LANGUAGE: XML
CODE:
```xml
<Annotations Target="sap.fe.managepartners.ManagePartnersService.EntityContainer/BusinessPartners">
  <Annotation Term="UI.PresentationVariant">
    <Record Type="UI.PresentationVariantType">
      <PropertyValue Property="GroupBy">
        <Collection>
          <PropertyPath>Country</PropertyPath>
        </Collection>
      </PropertyValue>
      <PropertyValue Property="Total">
        <Collection>
          <PropertyPath>SalesAmount</PropertyPath>
        </Collection>
      </PropertyValue>
      <PropertyValue Property="Visualizations">
        <Collection>
          <AnnotationPath>@UI.Chart</AnnotationPath>
          <AnnotationPath>@UI.LineItem</AnnotationPath>
        </Collection>
      </PropertyValue>
    </Record>
  </Annotation>
</Annotations>
```

STEP: Define default groups and totals using CAP CDS annotation (OData V4)
DESCRIPTION: CAP CDS alternative for PresentationVariant. Ensure Visualizations is present.
LANGUAGE: CDS
CODE:
```cds
UI.PresentationVariant : {
    GroupBy : [
        Country
    ],
    Total : [
        SalesAmount
    ],
    Visualizations : [
        '@UI.Chart',
        '@UI.LineItem',
    ]
}
```

STEP: Behavioral notes and restrictions for PresentationVariant / totals
DESCRIPTION: Operational rules to validate when providing PresentationVariant for analytical lists and responsive tables.
LANGUAGE: text
CODE:
```text
- You MUST provide PresentationVariant.Visualizations. Without Visualizations the PV/SPV is ignored.
  - Chart visualization renders only in the Analytical List Page (ALP) template.
  - On the List Report Page, only the LineItem visualization is rendered.

- Default totals behavior:
  - If no PresentationVariant is defined for an analytical table, totals are provided by default for all aggregatable columns.
  - If a PresentationVariant is defined and includes Total entries, totals are provided only for the listed aggregatable properties.
  - If Total is defined but empty -> no totals.
  - If Total attribute is missing -> totals provided by default for all aggregatable properties.

- Restrictions:
  - If a group contains multiple units or currencies, a direct total cannot be computed.
    - The table displays a "Show Details" link which opens a popup with totals/subtotals per unit or currency.
  - Responsive table supports only one level of grouping. If multiple levels are specified in PresentationVariant, only the first level is applied.
```

STEP: Screenshots and UI references
DESCRIPTION: Reference image file paths used in the original documentation for visual verification.
LANGUAGE: text
CODE:
```text
Screenshots referenced:
- images/Table_Grouping_b36df77.png
- images/ALP_Groupings_and_Totals_ae1b171.png
- images/ALP_Changing_Groupings_and_Totals_d94d57a.png
```

fiori-elements table-grouping analytical-table responsive-table ODataV2 ODataV4 PresentationVariant manifest.json annotations