SAP-samples / SAP-samples/cap-sflight

Converted Bookings in AnalyticsService to a parameterized entity but travel_analytics app not able to use it

Open
#1,502 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
CAP CDS
Stars
254
Forks
189
Avg merge
1d 22h
Merged PRs (30d)
1

Description

Created a Parameterized entity in AnalyticsService to test with OData V4 ALP app - travel_analytics.
Since Parameterized entity is only supported in HANA DB. Using HANA Cloud to deploy and test.

  • CAP service definition for parametrized entity

// SAMPLE Parameterized entity to use with Fiori Elements OData V4 ALP
  @readonly
  @Capabilities.FilterRestrictions    : {NonFilterableProperties: [P_Price]}
    @Capabilities.NavigationRestrictions: {RestrictedProperties: [{
        NavigationProperty: Parameters,
        FilterRestrictions: {Filterable: false}
    }]}
  entity BookingsWithParam(P_Price : String(10)) as
    select from my.Booking {
      @UI.Hidden           : false
      BookingUUID                                          as ID,
      to_Travel.TravelID,
      BookingID,

      @title               : 'Travel/Booking ID'
      to_Travel.TravelID || '/' || BookingID               as CombinedID        : String,


      ConnectionID,
      FlightDate,

      // pretend all bookings have the same currency so the FlightPrice can be aggregated
      @title               : '{i18n>CurrencyCode}'
      'USD'                                                as CurrencyCode_code : String(3),
      //CurrencyCode.code as CurrencyCode_code,
      @Measures.ISOCurrency: CurrencyCode_code
      FlightPrice,

      @title       : '{i18n>BookingStatus}'
      @Common.Text : statusName  @Common.TextArrangement: #TextOnly
      BookingStatus.code                                   as status,
      BookingStatus.name                                   as statusName,

      @Common.Text         : airlineName
      to_Carrier.AirlineID                                 as airline,
      to_Carrier.Name                                      as airlineName,
      BookingDate,
      to_Travel,
      to_Carrier,
      // Java has a problem with this association
      to_Flight,
      // Workaround:
      to_Flight.PlaneType,
      to_Flight.to_Connection.Distance,
      to_Flight.to_Connection.DistanceUnit,
      @Common.Label: '{i18n>DepartureAirport}'
      @Common.Text : DepCity
      to_Flight.to_Connection.DepartureAirport.AirportID   as DepAirport,
      to_Flight.to_Connection.DepartureAirport.City        as DepCity,
      @Common.Label: '{i18n>ArrivalAirport}'
      @Common.Text : DestCity
      to_Flight.to_Connection.DestinationAirport.AirportID as DestAirport,
      to_Flight.to_Connection.DestinationAirport.City      as DestCity,
    }
    where
      FlightPrice >= :P_Price;

  • Response working using curl

GET https://port4004-workspaces-ws-xxxxx.xxxx.applicationstudio.cloud.sap/analytics/BookingsWithParamParameters(P_Price=10000)/Set

{
"@odata.context": "../$metadata#BookingsWithParam(10000)/Set",
"value": [
{
"BookingDate": "2025-11-27",
"BookingID": 1,
"CombinedID": "635/1",
"ConnectionID": "0002",
"CurrencyCode_code": "USD",
"DepAirport": "SIN",
"DepCity": "Singapore",
"DestAirport": "SFO",
"DestCity": "San Francisco, California",
"Distance": 13523,
"DistanceUnit": "KM",
"FlightDate": "2025-12-11",
"FlightPrice": "10007.000",
"ID": "277E7221A8E4645C17002DF03754AB66",
"PlaneType": "747-400",
"TravelID": 635,
"airline": "SW",
"airlineName": "Sunset Wings",
"status": "N",
"statusName": "New",
"to_Carrier_AirlineID": "SW",
"to_Travel_TravelUUID": "CC677221A8E4645C17002DF03754AB66"
},
{
"BookingDate": "2025-11-27",
"BookingID": 2,
"CombinedID": "635/2",
"ConnectionID": "0002",
"CurrencyCode_code": "USD",
"DepAirport": "SIN",
"DepCity": "Singapore",
"DestAirport": "SFO",
"DestCity": "San Francisco, California",
"Distance": 13523,
"DistanceUnit": "KM",
"FlightDate": "2025-12-11",
"FlightPrice": "10007.000",
"ID": "287E7221A8E4645C17002DF03754AB66",
"PlaneType": "747-400",
"TravelID": 635,
"airline": "SW",
"airlineName": "Sunset Wings",
"status": "N",
"statusName": "New",
"to_Carrier_AirlineID": "SW",
"to_Travel_TravelUUID": "CC677221A8E4645C17002DF03754AB66"
},
{
"BookingDate": "2025-12-01",
"BookingID": 1,
"CombinedID": "636/1",
"ConnectionID": "0002",
"CurrencyCode_code": "USD",
"DepAirport": "SIN",
"DepCity": "Singapore",
"DestAirport": "SFO",
"DestCity": "San Francisco, California",
"Distance": 13523,
"DistanceUnit": "KM",
"FlightDate": "2025-12-11",
"FlightPrice": "10007.000",
"ID": "297E7221A8E4645C17002DF03754AB66",
"PlaneType": "747-400",
"TravelID": 636,
"airline": "SW",
"airlineName": "Sunset Wings",
"status": "B",
"statusName": "Accepted",
"to_Carrier_AirlineID": "SW",
"to_Travel_TravelUUID": "CD677221A8E4645C17002DF03754AB66"
}
}

  • Annotations for Fiori Elements - ALP
using AnalyticsService as service from '../../srv/analytics-service';

annotate service.BookingsWithParam with @(
  Aggregation.CustomAggregate #FlightPrice : 'Edm.Decimal',
  Aggregation.CustomAggregate #CurrencyCode_code : 'Edm.String',
  Common.SemanticKey : [ID],
) {
  ID                @ID : 'ID';
  FlightPrice       @Aggregation.default: #SUM;
  CurrencyCode_code @Aggregation.default: #MAX;
};

annotate service.BookingsWithParam with @Aggregation.ApplySupported : {
  Transformations : [
    'aggregate',
    'topcount',
    'bottomcount',
    'identity',
    'concat',
    'groupby',
    'filter',
    'search'
  ],
  GroupableProperties  : [
    TravelID,
    BookingID,
    CombinedID,
    ConnectionID,
    FlightDate,
    CurrencyCode_code,
    status,
    airline,
  ],
  AggregatableProperties : [
    {Property : status      },
    {Property : FlightPrice },
    {Property : ID          },
  ],
};

annotate service.BookingsWithParam with @(
  Analytics.AggregatedProperty #countBookings :
  {
    Name                 : 'countBookings',
    AggregationMethod    : 'countdistinct',
    AggregatableProperty : ID,
    @Common.Label        : '{i18n>BookingsWithParam}'
  },
  Analytics.AggregatedProperty #minPrice :
  {
    Name                 : 'minPrice',
    AggregationMethod    : 'min',
    AggregatableProperty : FlightPrice,
    @Common.Label        : '{i18n>MinPrice}'
  },
  Analytics.AggregatedProperty #maxPrice :
  {
    Name                 : 'maxPrice',
    AggregationMethod    : 'max',
    AggregatableProperty : FlightPrice,
    @Common.Label        : '{i18n>MaxPrice}'
  },
  Analytics.AggregatedProperty #avgPrice :
  {
    Name                 : 'avgPrice',
    AggregationMethod    : 'average',
    AggregatableProperty : FlightPrice,
    @Common.Label        : '{i18n>AvgPrice}'
  },
  // measure "sum of prices" is available by default (but name/label doesn't indicate summing -> ?)
  // Analytics.AggregatedProperty #sumPrice :
  //  {
  //   Name                 : 'sumPrice',
  //   AggregationMethod    : 'sum',
  //   AggregatableProperty : FlightPrice,
  //   @Common.Label        : '{i18n>TotalPrice}'
  // }
);


annotate service.BookingsWithParam with @UI.LineItem : [
  {
    Value          : TravelID,
    @UI.Importance : #High,
    @HTML5.CssDefaults: {width:'8em'},
  }, {
    Value          : BookingID,
    Label          : '{i18n>Booking}',
    @UI.Importance : #High,
    @HTML5.CssDefaults: {width:'8em'},
  }, {
    Value          : airline,
    @UI.Importance : #High,
    @HTML5.CssDefaults: {width:'14em'},
  }, {
    Value          : ConnectionID,
    @UI.Importance : #High,
    @HTML5.CssDefaults: {width:'8em'},
  }, {
    Value          : FlightDate,
    @UI.Importance : #High,
  }, {
    Value          : FlightPrice,
    @UI.Importance : #High,
    @HTML5.CssDefaults: {width:'12em'},
  }, {
    Value          : status,
    @UI.Importance : #High,
    @HTML5.CssDefaults: {width:'8em'},
  }
];


annotate service.BookingsWithParam with @UI.Chart : {
  Title               : '{i18n>BookingsWithParam}',
  ChartType           : #Column,
  DynamicMeasures : [
    '@Analytics.AggregatedProperty#minPrice',
    '@Analytics.AggregatedProperty#maxPrice',
    '@Analytics.AggregatedProperty#avgPrice'
  ],
  Dimensions          : [airline],
  MeasureAttributes   : [{
    DynamicMeasure : '@Analytics.AggregatedProperty#minPrice',
    Role    : #Axis1
  }],
  DimensionAttributes : [{
    Dimension : airline,
    Role      : #Category
  }],
};
annotate service.BookingsWithParam with @UI.PresentationVariant : {
  GroupBy : [  // default grouping in table
    airline,
    status
  ],
  Total : [    // default aggregation in table
    FlightPrice
  ],
  Visualizations : [
    '@UI.Chart',
    '@UI.LineItem',
  ]
};


//
// Visual Filters
//
annotate service.BookingsWithParam with @(
  UI.PresentationVariant #pvAirline : {
    Visualizations : ['@UI.Chart#chartAirline']
  },
  UI.Chart #chartAirline : {
    ChartType           : #Bar,
    DynamicMeasures : [
      '@Analytics.AggregatedProperty#countBookings',
    ],
    Dimensions          : [airline],
    MeasureAttributes   : [{
      DynamicMeasure : '@Analytics.AggregatedProperty#countBookings',
      Role      : #Axis1,
    }],
    DimensionAttributes : [{
      Dimension : airline,
      Role      : #Category
    }],
  }
) {
  airline @(
    Common.ValueList #vlAirline : {
      CollectionPath               : 'BookingsWithParam',
      PresentationVariantQualifier : 'pvAirline',
      Parameters                   : [{
        $Type             : 'Common.ValueListParameterInOut',
        LocalDataProperty : airline,
        ValueListProperty : 'airline'
      }]
    },
    Common.ValueList : {
      CollectionPath : 'Airline',
      Parameters : [{
        $Type             : 'Common.ValueListParameterInOut',
        LocalDataProperty : airline,
        ValueListProperty : 'AirlineID',
      }, {
          $Type : 'Common.ValueListParameterDisplayOnly',
          ValueListProperty : 'Name',
      }]
    }
  )
};


annotate service.BookingsWithParam with @(
  UI.PresentationVariant #pvStatus : {
    Visualizations : ['@UI.Chart#chartStatus']
  },
  UI.Chart #chartStatus : {
    ChartType           : #Bar,
    DynamicMeasures : [
      '@Analytics.AggregatedProperty#countBookings',
    ],
    Dimensions          : [status],
    MeasureAttributes   : [{
      DynamicMeasure : '@Analytics.AggregatedProperty#countBookings',
      Role      : #Axis1,
    }],
    DimensionAttributes : [{
      Dimension : status,
      Role      : #Category
    }]
  }
) {
  status @(
    Common.ValueList #vlStatus : {
      CollectionPath               : 'BookingsWithParam',
      PresentationVariantQualifier : 'pvStatus',
      Parameters                   : [{
        $Type             : 'Common.ValueListParameterInOut',
        LocalDataProperty : status,
        ValueListProperty : 'status'
      }]
    },
    Common.ValueList : {
      CollectionPath : 'BookingStatus',
      Parameters : [{
        $Type : 'Common.ValueListParameterInOut',
        LocalDataProperty : status,
        ValueListProperty : 'code',
      }]
    },
    //Common.ValueListWithFixedValues : true
  )
};


annotate service.BookingsWithParam with @(
  UI.PresentationVariant #pvFlightDate : {
    SortOrder      : [{
      Property   : FlightDate,
      Descending : true
    }],
    Visualizations : ['@UI.Chart#chartFlightDate']
  },
  UI.Chart #chartFlightDate            : {
    Title               : 'BookingsWithParam over FlightDate',
    ChartType           : #Line,
    DynamicMeasures : [
      '@Analytics.AggregatedProperty#countBookings',
    ],
    Dimensions          : [FlightDate],
    MeasureAttributes   : [{
      DynamicMeasure : '@Analytics.AggregatedProperty#countBookings',
      Role      : #Axis1,
    }],
    DimensionAttributes : [{
      Dimension : FlightDate,
      Role      : #Category
    }]
  }
) {
  FlightDate @Common.ValueList #vlFlightDate : {
    CollectionPath               : 'BookingsWithParam',
    PresentationVariantQualifier : 'pvFlightDate',
    Parameters                   : [{
      $Type             : 'Common.ValueListParameterInOut',
      LocalDataProperty : FlightDate,
      ValueListProperty : 'FlightDate'
    }]
  };
};



//
// KPI
//
annotate service.BookingsWithParam with @(
  UI.KPI #myKPI1 : {
    DataPoint : {
      Value            : FlightPrice,
      Title            : 'TOT',
      Description      : '{i18n>Total Price}',
      CriticalityCalculation : {
        ImprovementDirection: #Maximize,
        AcceptanceRangeLowValue: 26000000,
        ToleranceRangeLowValue:  24000000,
        DeviationRangeLowValue:  22000000
      }
    },
    Detail : {
      DefaultPresentationVariant : {
        Visualizations : [
          '@UI.Chart#kpi1'
        ],
      },
    },
    SelectionVariant : {
      SelectOptions : [{
        PropertyName : FlightPrice,
        Ranges       : [{
          Sign   : #E,
          Option : #EQ,
          Low    : 0,
        }, ],
      }],
    }
  },
  UI.Chart #kpi1 : {
    ChartType         : #Line,
    Measures          : [FlightPrice],
    Dimensions        : [FlightDate],
    MeasureAttributes : [{
      Measure : FlightPrice,
      Role    : #Axis1
    }],
    DimensionAttributes : [{
      Dimension : FlightDate,
      Role      : #Category
    }]
  },
);



//
// Detail page
//
annotate service.BookingsWithParam with @UI : {
  Identification : [
    { Value : CombinedID },
  ],
  HeaderInfo : {
    TypeName       : '{i18n>BookingsWithParam}',
    TypeNamePlural : '{i18n>BookingsWithParam}',
    Title          : { Value : CombinedID },
    Description    : { Value : CombinedID }
  },
  Facets : [{
    $Type  : 'UI.CollectionFacet',
    Label  : '{i18n>BookingDetails}',
    ID     : 'Booking',
    Facets : [{
      $Type  : 'UI.ReferenceFacet',
      ID     : 'TravelData',
      Target : '@UI.FieldGroup#TravelInformation',
      Label  : '{i18n>Travel}'
    }, {
      $Type  : 'UI.ReferenceFacet',
      ID     : 'BookingData',
      Target : '@UI.FieldGroup#BookingInformation',
      Label  : '{i18n>Booking}'
    }, {
      $Type  : 'UI.ReferenceFacet',
      ID     : 'FlightData',
      Target : '@UI.FieldGroup#FlightInformation',
      Label  : '{i18n>Flight}'
    }]
  }],
  FieldGroup #TravelInformation : { Data : [
    { Value : to_Travel.TravelID,
      Label : '{i18n>TravelID}'            },
    { Value : to_Travel.Description        },
    { Value : to_Travel.to_Agency.Name,    },
    { Value : to_Travel.CustomerName,      },
    { Value : to_Travel.TravelStatus.code,
      Label : '{i18n>Status}'              },    // why does the label not come from below?
  ]},
  FieldGroup #BookingInformation : { Data : [
    { Value : BookingID,
      Label : '{i18n>BookingID}'        },
    { Value : BookingDate               },
    { Value : FlightDate,               },
    { Value : FlightPrice               },
    { Value : status,
      Label : '{i18n>Status}'           },
  ]},
  FieldGroup #FlightInformation : { Data : [
    { Value : airline,                  },
    { Value : to_Carrier.AirlinePicURL, },
    { Value : ConnectionID              },
    // Java doesn't work with these association paths
    // { Value : to_Flight.PlaneType       },
    // { Value : to_Flight.to_Connection.DepartureAirport.AirportID,
    //   Label: '{i18n>DepartureAirport}'          },
    // { Value : to_Flight.to_Connection.DestinationAirport.AirportID,
    //   Label: '{i18n>ArrivalAirport}'            },
    // { Value : to_Flight.to_Connection.Distance, },

    // Workaround:
    { Value : PlaneType       },
    { Value : DepAirport,     },
    { Value : DestAirport     },
    { Value : Distance,       },
  ]},
};

// determines the order of visual filters
annotate service.BookingsWithParam with @UI.SelectionFields : [
  FlightDate,
  status,
  airline,
];

Error while processing building block FilterBar

TypeError: Cannot read properties of undefined (reading 'map')
    at Object._formatPropertyInfo (https://ui5.sap.com/1.130.2/resources/sap/fe/templates/library-preload.js:1644:12314)
    at Object.formatPropertyInfo (https://ui5.sap.com/1.130.2/resources/sap/fe/templates/library-preload.js:1644:12248)
    at a.e [as getTemplate] (https://ui5.sap.com/1.130.2/resources/sap/fe/templates/library-preload.js:1679:13243)
    at https://ui5.sap.com/1.130.2/resources/sap/fe/core/library-preload.js:171:10025
    at i.renderAsXML (https://ui5.sap.com/1.130.2/resources/sap/fe/core/library-preload.js:61:541)
    at D (https://ui5.sap.com/1.130.2/resources/sap/fe/core/library-preload.js:171:10002)

How the building block was called

<macroInternal:FilterBar xmlns:macroInternal="sap.fe.macros.internal" _applyIdToContent="true" metaPath="{entityType>}" variantBackreference="fe::PageVariantManagement" selectionFields="{filterBarContext>selectionFields}" internalFilterChanged=".handlers.onFiltersChanged" internalSearch=".handlers.onSearch" afterClear=".onAfterClear" liveMode="false" showAdaptFiltersButton="true" p13nMode="Item,Value" suspendSelection="false"/>

Trace info

{
    "initialProperties": {
        "showMessages": false,
        "variantBackreference": "fe::PageVariantManagement",
        "enableFallback": false,
        "showAdaptFiltersButton": true,
        "p13nMode": "Item,Value",
        "useSemanticDateRange": true,
        "liveMode": false,
        "suspendSelection": false,
        "isDraftCollaborative": false,
        "initialLayout": "compact",
        "showClearButton": false,
        "_applyIdToContent": true,
        "disableDraftEditStateFilter": false,
        "useOldVH": false,
        "internalFilterChanged": ".handlers.onFiltersChanged",
        "internalSearch": ".handlers.onSearch",
        "afterClear": ".onAfterClear"
    },
    "resolvedProperties": {
        "contextPath": {
            "path": "/BookingsWithParam/Set/",
            "value": {
                "$kind": "EntityType",
                "$Key": [
                    "ID"
                ],
                "ID": {
                    "$kind": "Property",
                    "$Type": "Edm.String",
                    "$Nullable": false
                },
                "TravelID": {
                    "$kind": "Property",
                    "$Type": "Edm.Int32",
                    "$DefaultValue": "0"
                },
                "BookingID": {
                    "$kind": "Property",
                    "$Type": "Edm.Int32"
                },
                "CombinedID": {
                    "$kind": "Property",
                    "$Type": "Edm.String"
                },
                "ConnectionID": {
                    "$kind": "Property",
                    "$Type": "Edm.String",
                    "$MaxLength": 4
                },
                "FlightDate": {
                    "$kind": "Property",
                    "$Type": "Edm.Date"
                },
                "CurrencyCode_code": {
                    "$kind": "Property",
                    "$Type": "Edm.String",
                    "$MaxLength": 3
                },
                "FlightPrice": {
                    "$kind": "Property",
                    "$Type": "Edm.Decimal",
                    "$Precision": 16,
                    "$Scale": 3
                },
                "status": {
                    "$kind": "Property",
                    "$Type": "Edm.String",
                    "$MaxLength": 1
                },
                "statusName": {
                    "$kind": "Property",
                    "$Type": "Edm.String",
                    "$MaxLength": 255
                },
                "airline": {
                    "$kind": "Property",
                    "$Type": "Edm.String",
                    "$MaxLength": 3
                },
                "airlineName": {
                    "$kind": "Property",
                    "$Type": "Edm.String",
                    "$MaxLength": 40
                },
                "BookingDate": {
                    "$kind": "Property",
                    "$Type": "Edm.Date"
                },
                "to_Travel": {
                    "$kind": "NavigationProperty",
                    "$Type": "AnalyticsService.Travels",
                    "$ReferentialConstraint": {
                        "to_Travel_TravelUUID": "TravelUUID"
                    }
                },
                "to_Travel_TravelUUID": {
                    "$kind": "Property",
                    "$Type": "Edm.String"
                },
                "to_Carrier": {
                    "$kind": "NavigationProperty",
                    "$Type": "AnalyticsService.Airline",
                    "$ReferentialConstraint": {
                        "to_Carrier_AirlineID": "AirlineID"
                    }
                },
                "to_Carrier_AirlineID": {
                    "$kind": "Property",
                    "$Type": "Edm.String",
                    "$MaxLength": 3
                },
                "to_Flight": {
                    "$kind": "NavigationProperty",
                    "$Type": "AnalyticsService.Flight",
                    "$ReferentialConstraint": {
                        "airline": "AirlineID",
                        "FlightDate": "FlightDate",
                        "ConnectionID": "ConnectionID"
                    }
                },
                "PlaneType": {
                    "$kind": "Property",
                    "$Type": "Edm.String",
                    "$MaxLength": 10
                },
                "Distance": {
                    "$kind": "Property",
                    "$Type": "Edm.Int32"
                },
                "DistanceUnit": {
                    "$kind": "Property",
                    "$Type": "Edm.String",
                    "$MaxLength": 3
                },
                "DepAirport": {
                    "$kind": "Property",
                    "$Type": "Edm.String",
                    "$MaxLength": 3
                },
                "DepCity": {
                    "$kind": "Property",
                    "$Type": "Edm.String",
                    "$MaxLength": 40
                },
                "DestAirport": {
                    "$kind": "Property",
                    "$Type": "Edm.String",
                    "$MaxLength": 3
                },
                "DestCity": {
                    "$kind": "Property",
                    "$Type": "Edm.String",
                    "$MaxLength": 40
                },
                "Parameters": {
                    "$kind": "NavigationProperty",
                    "$Type": "AnalyticsService.BookingsWithParamParameters",
                    "$Partner": "Set"
                }
            }
        },
        "isPublic": false
    },
    "missingContexts": {}
}

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the AnalyticsService BookingsWithParam definition and the travel_analytics Fiori elements annotations, then reproduce the parameterized request against the HANA Cloud deployment using the provided curl endpoint. Done means travel_analytics can use the parameterized entity and its ALP annotations work with the returned data.

Written by the indexing model from the issue text.

Assessment

Domain
api, data-visualization, frontend
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.