Las Actions son el corazón de la lógica de negocio en RAP. Pero, ¿qué tipo de Action elegir en cada caso? Este artículo compara todas las opciones de procesamiento y muestra con ejemplos de reserva de vuelos cómo se implementa cada tipo.
Visión General de los Tipos de Action
RAP ofrece diferentes tipos de Action para distintos casos de uso:
| Tipo de Action | Vinculación | Propósito | Ejemplo |
|---|---|---|---|
| Instance Action | Vinculada a entidad | Operación sobre instancia seleccionada | Cancelar reserva |
| Static Action | Sin vinculación a instancia | Operaciones masivas, nueva creación | Liberar todas las reservas pendientes |
| Factory Action | Vinculada a entidad | Crear nueva instancia desde existente | Copiar reserva |
| Action con Parámetro | Instance o Static | Entradas de usuario antes de ejecución | Cancelación con motivo |
| Action con Resultado | Instance o Static | Devolución de datos | Recalcular precio |
Instance Action: Operación sobre una Entidad
Las Instance Actions trabajan sobre una o más instancias seleccionadas. El tipo de Action más común.
Behavior Definition
managed implementation in class zbp_i_flightbooking unique;strict ( 2 );
define behavior for ZI_FlightBooking alias FlightBookingpersistent table zflight_booklock masterauthorization master ( instance ){ create; update; delete;
// Instance Action sin parámetro action confirmBooking result [1] $self;
// Instance Action con devolución de estado action cancelBooking result [1] $self;
// Instance Action sin resultado action markAsNoShow;}Implementación
CLASS lhc_flightbooking DEFINITION INHERITING FROM cl_abap_behavior_handler. PRIVATE SECTION. METHODS confirmBooking FOR MODIFY IMPORTING keys FOR ACTION FlightBooking~confirmBooking RESULT result.
METHODS cancelBooking FOR MODIFY IMPORTING keys FOR ACTION FlightBooking~cancelBooking RESULT result.
METHODS markAsNoShow FOR MODIFY IMPORTING keys FOR ACTION FlightBooking~markAsNoShow.ENDCLASS.
CLASS lhc_flightbooking IMPLEMENTATION. METHOD confirmBooking. " Confirmar reservas MODIFY ENTITIES OF zi_flightbooking IN LOCAL MODE ENTITY FlightBooking UPDATE FIELDS ( booking_status ) WITH VALUE #( FOR key IN keys ( %tky = key-%tky booking_status = 'C' " Confirmed ) ).
" Leer datos actualizados READ ENTITIES OF zi_flightbooking IN LOCAL MODE ENTITY FlightBooking ALL FIELDS WITH CORRESPONDING #( keys ) RESULT DATA(bookings).
" Devolver resultado result = VALUE #( FOR booking IN bookings ( %tky = booking-%tky %param = booking ) ).
" Mensaje de éxito APPEND VALUE #( %msg = new_message_with_text( severity = if_abap_behv_message=>severity-success text = |{ lines( bookings ) } reserva(s) confirmada(s)| ) ) TO reported-flightbooking. ENDMETHOD.
METHOD cancelBooking. " Primero verificar si la cancelación está permitida READ ENTITIES OF zi_flightbooking IN LOCAL MODE ENTITY FlightBooking FIELDS ( booking_status flight_date ) WITH CORRESPONDING #( keys ) RESULT DATA(bookings).
LOOP AT bookings INTO DATA(booking). " Solo se pueden cancelar reservas abiertas o confirmadas IF booking-booking_status <> 'O' AND booking-booking_status <> 'C'. APPEND VALUE #( %tky = booking-%tky %msg = new_message_with_text( severity = if_abap_behv_message=>severity-error text = |Reserva en estado { booking-booking_status } no puede cancelarse| ) ) TO reported-flightbooking. APPEND VALUE #( %tky = booking-%tky ) TO failed-flightbooking. CONTINUE. ENDIF.
" Ejecutar cancelación MODIFY ENTITIES OF zi_flightbooking IN LOCAL MODE ENTITY FlightBooking UPDATE FIELDS ( booking_status cancellation_date ) WITH VALUE #( ( %tky = booking-%tky booking_status = 'X' " Cancelled cancellation_date = cl_abap_context_info=>get_system_date( ) ) ). ENDLOOP.
" Leer y devolver resultado READ ENTITIES OF zi_flightbooking IN LOCAL MODE ENTITY FlightBooking ALL FIELDS WITH CORRESPONDING #( keys ) RESULT DATA(updated_bookings).
result = VALUE #( FOR bk IN updated_bookings ( %tky = bk-%tky %param = bk ) ). ENDMETHOD.
METHOD markAsNoShow. " Action simple sin devolución de resultado MODIFY ENTITIES OF zi_flightbooking IN LOCAL MODE ENTITY FlightBooking UPDATE FIELDS ( booking_status no_show_date ) WITH VALUE #( FOR key IN keys ( %tky = key-%tky booking_status = 'N' " No-Show no_show_date = cl_abap_context_info=>get_system_date( ) ) ).
" Solo mensaje, sin result APPEND VALUE #( %msg = new_message_with_text( severity = if_abap_behv_message=>severity-success text = 'Marcado como No-Show' ) ) TO reported-flightbooking. ENDMETHOD.ENDCLASS.Cardinalidad del Result
| Sintaxis | Significado | Uso |
|---|---|---|
result [1] $self | Exactamente una instancia de la misma entidad | Estándar para cambios de estado |
result [0..1] $self | Opcionalmente una instancia | Si el resultado no está garantizado |
result [0..*] $self | Cualquier cantidad de instancias | Operaciones masivas |
result [1] EntityName | Una entidad diferente | Navegación a entidad relacionada |
| (sin result) | Sin devolución | Operaciones fire-and-forget |
Static Action: Operaciones Masivas y Nueva Creación
Las Static Actions no están vinculadas a una instancia. Se usan típicamente para operaciones globales.
Behavior Definition
define behavior for ZI_FlightBooking alias FlightBooking{ // Static Action para operación masiva static action releaseAllPending;
// Static Action con resultado static action createQuickBooking result [1] $self;
// Static Action con Feature Control static action ( features: global ) sendDailyReport;
// Para Global Feature Control static features;}Implementación
CLASS lhc_flightbooking IMPLEMENTATION. METHOD releaseAllPending. " Encontrar todas las reservas con estado 'Pending' SELECT * FROM zflight_book WHERE booking_status = 'P' INTO TABLE @DATA(pending_bookings).
IF pending_bookings IS INITIAL. APPEND VALUE #( %msg = new_message_with_text( severity = if_abap_behv_message=>severity-information text = 'No se encontraron reservas pendientes' ) ) TO reported-flightbooking. RETURN. ENDIF.
" Establecer todas a 'Confirmed' MODIFY ENTITIES OF zi_flightbooking IN LOCAL MODE ENTITY FlightBooking UPDATE FIELDS ( booking_status ) WITH VALUE #( FOR booking IN pending_bookings ( booking_id = booking-booking_id booking_status = 'C' " Confirmed ) ).
APPEND VALUE #( %msg = new_message_with_text( severity = if_abap_behv_message=>severity-success text = |{ lines( pending_bookings ) } reservas liberadas| ) ) TO reported-flightbooking. ENDMETHOD.
METHOD createQuickBooking. " Crear reserva rápida con valores predeterminados DATA(today) = cl_abap_context_info=>get_system_date( ). DATA(user) = cl_abap_context_info=>get_user_technical_name( ).
MODIFY ENTITIES OF zi_flightbooking IN LOCAL MODE ENTITY FlightBooking CREATE FIELDS ( flight_date customer_id flight_id booking_status flight_price currency_code created_by created_at ) WITH VALUE #( ( %cid = 'QUICK_BOOKING' flight_date = today + 14 " En 2 semanas customer_id = get_default_customer( user ) flight_id = get_next_available_flight( today + 14 ) booking_status = 'P' " Pending flight_price = 299 currency_code = 'EUR' created_by = user created_at = cl_abap_context_info=>get_system_time( ) ) ) MAPPED DATA(mapped).
" Leer reserva creada READ ENTITIES OF zi_flightbooking IN LOCAL MODE ENTITY FlightBooking ALL FIELDS WITH VALUE #( ( %tky = mapped-flightbooking[ 1 ]-%tky ) ) RESULT DATA(created_bookings).
" Devolver resultado con %cid_ref result = VALUE #( ( %cid_ref = 'QUICK_BOOKING' %param = created_bookings[ 1 ] ) ).
APPEND VALUE #( %msg = new_message_with_text( severity = if_abap_behv_message=>severity-success text = 'Reserva rápida creada' ) ) TO reported-flightbooking. ENDMETHOD.
METHOD get_global_features. " Verificar si el usuario tiene autorización para el reporte DATA(has_report_auth) = check_report_authorization( ).
result = VALUE #( %action-sendDailyReport = COND #( WHEN has_report_auth = abap_true THEN if_abap_behv=>fc-o-enabled ELSE if_abap_behv=>fc-o-disabled ) ). ENDMETHOD.ENDCLASS.Factory Action: Nueva Instancia desde Existente
Las Factory Actions crean una nueva instancia basada en una existente. Ideal para escenarios de copia y plantillas.
Behavior Definition
define behavior for ZI_FlightBooking alias FlightBooking{ // Factory Action crea copia factory action copyBooking [1];
// Factory Action con parámetros factory action rebookToDate parameter ZA_RebookParams [1];}Implementación
CLASS lhc_flightbooking IMPLEMENTATION. METHOD copyBooking. " Leer reservas originales READ ENTITIES OF zi_flightbooking IN LOCAL MODE ENTITY FlightBooking ALL FIELDS WITH CORRESPONDING #( keys ) RESULT DATA(bookings).
DATA: lt_mapped TYPE RESPONSE FOR MAPPED EARLY zi_flightbooking.
LOOP AT bookings INTO DATA(booking). DATA(lv_cid) = |COPY_{ sy-tabix }|.
" Crear copia con nuevo estado MODIFY ENTITIES OF zi_flightbooking IN LOCAL MODE ENTITY FlightBooking CREATE FIELDS ( flight_date customer_id flight_id flight_price currency_code booking_status created_by created_at ) WITH VALUE #( ( %cid = lv_cid flight_date = booking-flight_date customer_id = booking-customer_id flight_id = booking-flight_id flight_price = booking-flight_price currency_code = booking-currency_code booking_status = 'P' " Nueva reserva como Pending created_by = cl_abap_context_info=>get_user_technical_name( ) created_at = cl_abap_context_info=>get_system_time( ) ) ) MAPPED DATA(mapped_single).
" Agregar mapped APPEND VALUE #( %cid_ref = keys[ sy-tabix ]-%cid_ref %key = mapped_single-flightbooking[ 1 ]-%key ) TO mapped-flightbooking. ENDLOOP.
APPEND VALUE #( %msg = new_message_with_text( severity = if_abap_behv_message=>severity-success text = |{ lines( bookings ) } reserva(s) copiada(s)| ) ) TO reported-flightbooking. ENDMETHOD.
METHOD rebookToDate. " Leer reservas originales READ ENTITIES OF zi_flightbooking IN LOCAL MODE ENTITY FlightBooking ALL FIELDS WITH CORRESPONDING #( keys ) RESULT DATA(bookings).
LOOP AT keys ASSIGNING FIELD-SYMBOL(<key>). READ TABLE bookings INTO DATA(booking) WITH KEY booking_id = <key>-booking_id.
" Nueva fecha del parámetro DATA(new_date) = <key>-%param-NewFlightDate.
" Validación IF new_date < cl_abap_context_info=>get_system_date( ). APPEND VALUE #( %tky = <key>-%tky %msg = new_message_with_text( severity = if_abap_behv_message=>severity-error text = 'La nueva fecha debe estar en el futuro' ) ) TO reported-flightbooking. APPEND VALUE #( %tky = <key>-%tky ) TO failed-flightbooking. CONTINUE. ENDIF.
" Crear nueva reserva con nueva fecha DATA(lv_cid) = |REBOOK_{ sy-tabix }|.
MODIFY ENTITIES OF zi_flightbooking IN LOCAL MODE ENTITY FlightBooking CREATE FIELDS ( flight_date customer_id flight_id flight_price currency_code booking_status original_booking_id ) WITH VALUE #( ( %cid = lv_cid flight_date = new_date customer_id = booking-customer_id flight_id = booking-flight_id flight_price = booking-flight_price currency_code = booking-currency_code booking_status = 'P' " Pending original_booking_id = booking-booking_id " Referencia a original ) ) MAPPED DATA(mapped_single).
" Establecer reserva original en 'Rebooked' MODIFY ENTITIES OF zi_flightbooking IN LOCAL MODE ENTITY FlightBooking UPDATE FIELDS ( booking_status ) WITH VALUE #( ( %tky = <key>-%tky booking_status = 'R' " Rebooked ) ).
APPEND VALUE #( %cid_ref = <key>-%cid_ref %key = mapped_single-flightbooking[ 1 ]-%key ) TO mapped-flightbooking. ENDLOOP. ENDMETHOD.ENDCLASS.Action con Parámetro de Resultado
Las Actions pueden devolver resultados estructurados que van más allá de $self.
Abstract Entity para Resultado
@EndUserText.label: 'Resultado de Cálculo de Precio'define abstract entity ZA_PriceCalculation{ BookingId : abap.numc(10); NetPrice : abap.curr(15,2); TaxAmount : abap.curr(15,2); TotalPrice : abap.curr(15,2); Currency : abap.cuky; DiscountPct : abap.dec(5,2); DiscountText : abap.string(100);}Behavior Definition
define behavior for ZI_FlightBooking alias FlightBooking{ // Action con tipo de resultado propio action recalculatePrice result [1] ZA_PriceCalculation;
// Action que devuelve otra entidad action createInvoice result [1] ZI_Invoice;}Implementación
METHOD recalculatePrice. " Leer datos de reserva READ ENTITIES OF zi_flightbooking IN LOCAL MODE ENTITY FlightBooking FIELDS ( booking_id flight_price currency_code customer_id ) WITH CORRESPONDING #( keys ) RESULT DATA(bookings).
LOOP AT bookings INTO DATA(booking). " Determinar descuento del cliente DATA(discount_pct) = get_customer_discount( booking-customer_id ). DATA(net_price) = booking-flight_price * ( 1 - discount_pct / 100 ). DATA(tax_amount) = net_price * '0.19'. DATA(total_price) = net_price + tax_amount.
" Actualizar precio en reserva MODIFY ENTITIES OF zi_flightbooking IN LOCAL MODE ENTITY FlightBooking UPDATE FIELDS ( flight_price ) WITH VALUE #( ( %tky = booking-%tky flight_price = total_price ) ).
" Llenar estructura de resultado APPEND VALUE #( %tky = booking-%tky %param = VALUE za_pricecalculation( BookingId = booking-booking_id NetPrice = net_price TaxAmount = tax_amount TotalPrice = total_price Currency = booking-currency_code DiscountPct = discount_pct DiscountText = COND #( WHEN discount_pct > 0 THEN |Descuento cliente habitual: { discount_pct }%| ELSE 'Sin descuento' ) ) ) TO result. ENDLOOP.ENDMETHOD.Manejo de Errores en Actions
Las Actions robustas deben manejar y reportar errores correctamente.
Patrón: Validación Antes de Ejecución
METHOD processBooking. DATA: lt_failed TYPE TABLE FOR FAILED EARLY zi_flightbooking, lt_reported TYPE TABLE FOR REPORTED EARLY zi_flightbooking.
" Leer reservas READ ENTITIES OF zi_flightbooking IN LOCAL MODE ENTITY FlightBooking ALL FIELDS WITH CORRESPONDING #( keys ) RESULT DATA(bookings).
LOOP AT bookings INTO DATA(booking). " === FASE DE VALIDACIÓN ===
" Error 1: Verificar estado IF booking-booking_status = 'X'. APPEND VALUE #( %tky = booking-%tky %msg = new_message_with_text( severity = if_abap_behv_message=>severity-error text = 'Las reservas canceladas no pueden procesarse' ) ) TO lt_reported. APPEND VALUE #( %tky = booking-%tky ) TO lt_failed. CONTINUE. ENDIF.
" Error 2: Verificar fecha IF booking-flight_date < cl_abap_context_info=>get_system_date( ). APPEND VALUE #( %tky = booking-%tky %msg = new_message_with_text( severity = if_abap_behv_message=>severity-error text = 'La fecha de vuelo está en el pasado' ) %element-flight_date = if_abap_behv=>mk-on ) TO lt_reported. APPEND VALUE #( %tky = booking-%tky ) TO lt_failed. CONTINUE. ENDIF.
" Advertencia: Precio alto IF booking-flight_price > 2000. APPEND VALUE #( %tky = booking-%tky %msg = new_message_with_text( severity = if_abap_behv_message=>severity-warning text = |Precio superior a 2.000 { booking-currency_code }| ) %element-flight_price = if_abap_behv=>mk-on ) TO lt_reported. " ¡NO se añade entrada failed en Warning! ENDIF.
" === FASE DE EJECUCIÓN === TRY. " Ejecutar lógica de negocio MODIFY ENTITIES OF zi_flightbooking IN LOCAL MODE ENTITY FlightBooking UPDATE FIELDS ( booking_status processed_at ) WITH VALUE #( ( %tky = booking-%tky booking_status = 'D' " Done processed_at = cl_abap_context_info=>get_system_time( ) ) ).
CATCH cx_root INTO DATA(lx_error). " Error inesperado APPEND VALUE #( %tky = booking-%tky %msg = new_message_with_text( severity = if_abap_behv_message=>severity-error text = |Error del sistema: { lx_error->get_text( ) }| ) ) TO lt_reported. APPEND VALUE #( %tky = booking-%tky ) TO lt_failed. ENDTRY. ENDLOOP.
" Pasar errores y mensajes failed-flightbooking = lt_failed. reported-flightbooking = lt_reported.
" Resultado para reservas exitosas READ ENTITIES OF zi_flightbooking IN LOCAL MODE ENTITY FlightBooking ALL FIELDS WITH CORRESPONDING #( keys ) RESULT DATA(updated_bookings).
result = VALUE #( FOR bk IN updated_bookings WHERE ( booking_status = 'D' ) ( %tky = bk-%tky %param = bk ) ).ENDMETHOD.Matriz de Decisión: ¿Qué Action Cuándo?
| Requisito | Tipo de Action | Ejemplo |
|---|---|---|
| Cambio de estado de una reserva | Instance Action | confirmBooking, cancelBooking |
| Liberar todas las reservas abiertas | Static Action | releaseAllPending |
| Copiar reserva | Factory Action | copyBooking |
| Cancelación con motivo | Instance Action + Parámetro | cancelWithReason |
| Nueva reserva sin plantilla | Static Action + Result | createQuickBooking |
| Cambio de reserva a nueva fecha | Factory Action + Parámetro | rebookToDate |
| Recalcular precio y mostrar | Instance Action + Result Entity | recalculatePrice |
| Crear factura desde reserva | Instance Action + otra Entity | createInvoice |
¿Cuándo Instance vs. Static?
┌─────────────────────────────────────────────────────────────────┐│ ¿La Action necesita ││ contexto de instancia? ││ │ ││ ┌───────────┴───────────┐ ││ │ │ ││ ▼ ▼ ││ [ SÍ ] [ NO ] ││ │ │ ││ ┌──────────┴──────────┐ │ ││ │ │ ▼ ││ ▼ ▼ STATIC ACTION ││ ¿Crea nueva ¿Modifica ││ instancia? existente? ││ │ │ ││ ▼ ▼ ││ FACTORY INSTANCE ││ ACTION ACTION │└─────────────────────────────────────────────────────────────────┘¿Cuándo con o sin Parámetro?
| Escenario | Con Parámetro | Sin Parámetro |
|---|---|---|
| Entrada de usuario requerida | Diálogo popup | |
| Confirmación sin detalles | Ejecución directa | |
| Información adicional opcional | Parámetro con defaults | |
| Action con opciones de selección | Parámetro con Value Help |
¿Cuándo usar Result?
| Escenario | Tipo de Result |
|---|---|
| UI debe actualizarse | result [1] $self |
| Fire-and-Forget | Sin Result |
| Mostrar resultado de cálculo | result [1] ZA_ResultEntity |
| Operación masiva con resultados individuales | result [0..*] $self |
| Entidad relacionada creada | result [1] OtherEntity |
Mejores Prácticas
1. Convención de Nombres Consistente
" Verbos para Actionsaction confirmBooking ...action cancelBooking ...action recalculatePrice ...
" Evitar sustantivosaction confirmation ... " No está claro qué pasaaction cancellation ...2. Siempre Indicar Result para Actualización de UI
" La UI se actualiza después de la Actionaction confirmBooking result [1] $self;
" La UI permanece en estado antiguoaction confirmBooking; " Sin result3. Detectar Errores Temprano
METHOD myAction. " Validación PRIMERO, antes de cualquier cambio READ ENTITIES ... LOOP AT ... IF NOT valid( ). " Reportar error y CONTINUE CONTINUE. ENDIF. ENDLOOP.
" Solo después de validación: realizar cambios MODIFY ENTITIES ...ENDMETHOD.4. Usar IN LOCAL MODE
" Omite verificación de autorización dentro de la ActionREAD ENTITIES OF zi_flightbooking IN LOCAL MODE ...MODIFY ENTITIES OF zi_flightbooking IN LOCAL MODE ...5. Combinar con Feature Control
" Behavior Definitionaction ( features: instance ) cancelBooking result [1] $self;determination setFeatures on modify { field booking_status; }
" Implementación: cancelBooking solo activo para reservas abiertasResumen
| Tipo de Action | Cuándo Usar | Keys Presentes | Crea Instancia |
|---|---|---|---|
| Instance | Operación sobre selección | Sí | No |
| Static | Operación global | No | Opcional |
| Factory | Copiar, plantillas | Sí | Sí |
La elección correcta del tipo de Action marca la diferencia entre una interfaz de usuario intuitiva y una confusa. Usa Instance Actions para operaciones individuales, Static Actions para acciones globales y Factory Actions para crear nuevas instancias desde existentes.
Artículos relacionados: RAP Actions y Functions para fundamentos, Popup Actions para Actions con diálogo, RAP Mensajes para manejo de errores y Feature Control para activación dinámica.