← Volver a tutoriales

RAP desde cero · Lección 5 de 6

Un semáforo en Fiori con RAP: pinta de colores la valoración de los libros

Colorea en rojo, amarillo o verde la valoración de cada libro con un campo calculado en la CDS y una anotación, y añade estrellas en el detalle. Sin JavaScript.

Also available in English →

La lista de libros de la lección 3 muestra la valoración como un número: 4, 5, 3. Funciona, pero hay que leerla. Un semáforo la convierte en algo que se entiende de un vistazo:

Valoración Color Significado
0 gris Sin valorar
1–2 rojo Mala
3 amarillo Regular
4–5 verde Buena

Lo mejor: en RAP el semáforo no se programa. No hay JavaScript ni UI5, y tampoco hace falta una clase ABAP. Son tres cambios pequeños, uno por capa:

ZR_LibBook   (1) calcula el color: un campo nuevo con CASE
ZC_LibBook   (2) lo deja pasar hacia el servicio
MDE          (3) le dice a Fiori qué campo pinta con ese color

Al final, como extra, pondremos la valoración en estrellas en la cabecera del detalle.

Antes de empezar: necesitas la biblioteca de las lecciones 2, 3 y 4. La lección 4 hace falta para cambiar la valoración desde la app al probar.

Código guía: el código sigue la sintaxis de ABAP Cloud, pero no se compiló en un sistema SAP para este tutorial. Si algo no activa en tu sistema, el mensaje de ADT indica la línea exacta.

Cómo entiende Fiori los colores

Fiori Elements no sabe de libros ni de valoraciones. Solo entiende un número de criticidad (criticality):

Valor Color Nombre en Fiori
0 gris Neutral
1 rojo Negative
2 amarillo Critical
3 verde Positive

Así que el trabajo consiste en dos cosas: calcular ese número para cada libro y decirle a Fiori a qué campo se lo aplica.

1. Calcular la criticidad en la Root View Entity

Abre ZR_LibBook y añade un campo calculado justo después de Rating. No existe en la tabla: la base de datos lo calcula al leer, con un CASE.

Extracto de ZR_LibBook (lección 2). Va entre rating as Rating, y @Semantics.amount.currencyCode: 'CurrencyCode'; el resto de la vista no cambia:

      rating                as Rating,
      case
        when rating = 0 then 0     -- sin valorar: gris
        when rating <= 2 then 1    -- 1 o 2: rojo
        when rating = 3 then 2     -- 3: amarillo
        else 3                     -- 4 o 5: verde
      end                   as RatingCriticality,

Dos detalles:

  • El orden de los when importa. Se evalúan de arriba abajo y gana el primero que se cumple. Por eso rating = 0 va primero: si no, el 0 caería en rating <= 2 y saldría rojo.
  • Dentro del CASE se usa rating, el nombre de la tabla, no Rating, el alias de la vista.

Activa ZR_LibBook (Ctrl+F3) y compruébalo con F8 (Data Preview): aparece la columna RatingCriticality con un 3 o un 2 en cada libro.

2. Dejarlo pasar en la proyección

Un campo que no está en la proyección no viaja por OData. Si no lo añades, la anotación del paso 3 se activa sin errores, pero el semáforo no se pinta. Es el error más típico.

ZC_LibBook completo (el de la lección 3, con la línea nueva RatingCriticality):

@AccessControl.authorizationCheck: #NOT_REQUIRED
@Metadata.allowExtensions: true
@EndUserText.label: 'Biblioteca: libros (app)'
@Search.searchable: true
define root view entity ZC_LibBook
  provider contract transactional_query
  as projection on ZR_LibBook
{
  key BookUuid,
      @Search.defaultSearchElement: true
      BookId,
      @Search.defaultSearchElement: true
      @Search.fuzzinessThreshold: 0.8
      Title,
      AuthorId,
      _Author.Name as AuthorName,
      Pages,
      Isbn,
      Rating,
      RatingCriticality,
      Price,
      CurrencyCode,
      LocalLastChangedAt
}

Activa ZC_LibBook.

3. Pintar el campo en la Metadata Extension

Ahora le decimos a Fiori: «la columna Rating se pinta con el color que diga RatingCriticality». Se hace con criticality dentro de lineItem (la lista) y de identification (el detalle).

Extracto de la Metadata Extension de ZC_LibBook (lección 3). Sustituye el bloque de Rating por este y añade debajo el de RatingCriticality:

  @UI: { lineItem:       [ { position: 60,
                             criticality: 'RatingCriticality',
                             criticalityRepresentation: #WITH_ICON } ],
         identification: [ { position: 60,
                             criticality: 'RatingCriticality' } ] }
  Rating;

  @UI.hidden: true
  RatingCriticality;
  • criticality: 'RatingCriticality' es el nombre del campo que trae el color, entre comillas.
  • criticalityRepresentation: #WITH_ICON añade un icono (✓, ⚠, ✕) junto al número. Así el semáforo se entiende también sin distinguir colores. Si prefieres solo color, usa #WITHOUT_ICON.
  • @UI.hidden: true oculta RatingCriticality: es un 3 o un 1 que solo sirve para pintar, y al usuario no le dice nada.

Activa la Metadata Extension.

4. Pruébalo

  1. Abre el Service Binding ZUI_LIB_BOOK_O4, selecciona Book y pulsa Preview.
  2. Pulsa Go. La columna Rating sale en color: Ríos de montaña (5), Aves del sur (4) y Cuentos de invierno (4) en verde, y El último tren (3) en amarillo.
  3. ¿Y el rojo? Entra en El último tren, pulsa Edit, cambia la valoración a 1 y guarda. Vuelve a la lista: ahora está en rojo.
  4. Prueba con 0: sale en gris, sin valorar.

Si la vista previa ya estaba abierta, recárgala: Fiori guarda en caché los metadatos del servicio.

Extra: estrellas en la cabecera del detalle

El número en color está bien para la lista. En el detalle de un libro queda mejor con estrellas, como en una tienda online. Fiori lo trae de serie con un Data Point de tipo #RATING.

Hacen falta dos cosas en la misma Metadata Extension:

  1. Un Data Point sobre Rating, que dice cómo se dibuja (estrellas, sobre 5).
  2. Un facet de cabecera (purpose: #HEADER) que lo coloque arriba del detalle.

Un facet es una sección de la página de detalle. El de la lección 3 (id: 'Book') es el cuerpo; este nuevo va en la cabecera. El targetQualifier del facet y el qualifier del Data Point deben coincidir: es lo que los une.

Esta es la Metadata Extension completa, con los cambios de este tutorial (el paso 3 y las estrellas):

@Metadata.layer: #CUSTOMER
@UI.headerInfo: {
  typeName: 'Libro',
  typeNamePlural: 'Libros',
  title: { type: #STANDARD, value: 'Title' },
  description: { value: 'AuthorName' }
}
annotate entity ZC_LibBook with
{
  @UI.facet: [ {
    id: 'HeaderRating',
    purpose: #HEADER,
    type: #DATAPOINT_REFERENCE,
    targetQualifier: 'Rating',
    position: 10
  }, {
    id: 'Book',
    purpose: #STANDARD,
    type: #IDENTIFICATION_REFERENCE,
    label: 'Libro',
    position: 10
  } ]
  @UI.hidden: true
  BookUuid;

  @UI: { lineItem: [ { position: 10 } ], identification: [ { position: 10 } ], selectionField: [ { position: 10 } ] }
  BookId;

  @UI: { lineItem: [ { position: 20 } ], identification: [ { position: 20 } ] }
  Title;

  @UI: { lineItem: [ { position: 30 } ], identification: [ { position: 30 } ], selectionField: [ { position: 20 } ] }
  AuthorId;

  @UI: { lineItem: [ { position: 40 } ], identification: [ { position: 40 } ] }
  AuthorName;

  @UI: { lineItem: [ { position: 50 } ], identification: [ { position: 50 } ] }
  Pages;

  @UI: { lineItem:       [ { position: 60,
                             criticality: 'RatingCriticality',
                             criticalityRepresentation: #WITH_ICON } ],
         identification: [ { position: 60,
                             criticality: 'RatingCriticality' } ],
         dataPoint:      { qualifier: 'Rating',
                           title: 'Valoración',
                           visualization: #RATING,
                           targetValue: 5 } }
  Rating;

  @UI.hidden: true
  RatingCriticality;

  @UI: { lineItem: [ { position: 70 } ], identification: [ { position: 70 } ] }
  Price;

  @UI.hidden: true
  LocalLastChangedAt;
}

Activa y recarga la vista previa. Entra en un libro: arriba, junto al título, aparecen sus estrellas. Ríos de montaña tiene las cinco llenas.

Si algo no aparece

Síntoma Causa habitual
La columna sale sin color RatingCriticality no está en la proyección ZC_LibBook (paso 2)
Todo sale gris El CASE devuelve siempre 0: revisa que compare rating y el orden de los when
El 0 sale rojo when rating = 0 no es el primero del CASE
Aparece una columna con números 1, 2, 3 Falta @UI.hidden: true en RatingCriticality
No salen las estrellas El targetQualifier del facet no coincide con el qualifier del Data Point ('Rating' en los dos)
Nada cambia La vista previa sigue con los metadatos viejos: recárgala

Resumen

  • Fiori pinta colores a partir de un número de criticidad: 0 gris, 1 rojo, 2 amarillo y 3 verde.
  • Ese número se calcula en la CDS con un CASE, sin ABAP ni JavaScript, y se proyecta para que llegue al servicio.
  • En la Metadata Extension, criticality une el campo visible con su color, y @UI.hidden esconde el campo auxiliar.
  • Un Data Point #RATING en un facet de cabecera convierte la valoración en estrellas.

El mismo patrón sirve para cualquier estado: pedidos abiertos o cerrados, stock bajo, fechas vencidas. Cambia el CASE y el resto se queda igual.