CRM and CX Blogs by SAP
Stay up-to-date on the latest developments and product news about intelligent customer experience and CRM technologies through blog posts from SAP experts.
cancel
Showing results for 
Search instead for 
Did you mean: 
eileenriediger
Explorer
The generated Custom Business Object (CBO) User Interface only allows deletion of single entries. This blog post explains how you can delete all CBO entries at once or how to delete multiple entries based on deletion rules.

User Interface Overview


You need to create an own CBO that will serve as "Deletion CBO" for all of your CBOs. An end user will select in which CBO they want to delete entries. And in a second step they can either delete all data or define several deletion rules and execute those.




Deletion CBO Setup


Execute the following steps to build the "Deletion CBO":

  1. Create a Custom Code List YY1_SIGN with the code values I for Include and E for Exclude. Create a second Custom Code List YY1_OPERATOR with the following entries:


































    Code Description
    EQ Equal
    GE Greater Than or Equal
    GT Greater Than
    LE Lower Than or Equal
    LT Lower Than
    NE Not Equal


  2. Create a new CBO YY1_MASS_DELETE. The name of the CBO is important if you want to copy the code of this blog post. The root node consists of the following fields:


































    Label Identifier Type Key Read Only
    CBO Name CBOName Text (Length 30) X
    Deletion Last Executed On LastExecutedOn Date X
    All Data Deleted DeletedAll Checkbox X


  3. Create a subnode DeletionRule with the following fields:































    Label Identifier Type
    Field Name FieldName Text (Length 30)
    Sign Sign Code List YY1_SIGN
    Option Operator Code List YY1_OPERATOR
    Value Value Text (Length 100)


  4. Mark the CBO for UI Generation, publish your CBO and maintain the Catalog Extension. As next step, in order to allow mass deletion and deletion based on deletion rules, you will now maintain two actions in the tab 'Logic'. The action will automatically appear as buttons on your generated UI.

  5. Create the action "DeleteAllData" with Label "Delete All CBO Data". Also create the action "DeleteRuleBased" with Label "Execute Deletion Rules". Publish your CBO. After publishing, you are able to define the logic for your actions.

  6. Open the logic for the action "DeleteAllData". In the section 'Select entries' you have to add each CBO which you want to enable for deletion. In case of this blog post the CBOs YY1_USER and YY1_BUILDING are enabled. Publish your action logic after implementation.
    * Action DeleteAllData for Node ID MASS_DELETE
    *
    * Importing Parameter : association (Navigation to Parent/Child/
    * Associated Node Instances)
    * write (API for creating and updating
    * Custom Business Object Node Instances)
    * Changing Parameter : MASS_DELETE (Current Node Data)
    * Exporting Parameter : message (Message with Severity S(uccess),
    * W(arning), E(rror))

    DATA: lv_timezone TYPE timezone.

    CONSTANTS: lc_package_size TYPE i VALUE 5000.

    *----------------------------------------------------------------------*
    * Select entries
    *----------------------------------------------------------------------*
    CASE mass_delete-cboname.
    WHEN 'YY1_USER'.
    SELECT sap_uuid FROM yy1_user INTO TABLE @DATA(lt_keys).
    WHEN 'YY1_BUILDING'.
    SELECT sap_uuid FROM yy1_building INTO TABLE @lt_keys.
    WHEN OTHERS.
    message = VALUE #(
    severity = co_severity-error
    text = |CBO { mass_delete-cboname } | &
    |not enabled for deletion| ).
    RETURN.
    ENDCASE.
    DATA(lv_lines) = LINES( lt_keys ).
    DATA(lv_all_lines) = lv_lines.

    *----------------------------------------------------------------------*
    * Delete entries in 5000 chunks -> Prevent System Overloading
    *----------------------------------------------------------------------*
    DATA(lv_packaging) = abap_false.
    IF lv_lines > lc_package_size.
    lv_packaging = abap_true.
    ENDIF.
    DATA(lv_end_delete) = abap_false.
    WHILE lv_end_delete = abap_false.
    IF lv_lines <= lc_package_size.
    lv_end_delete = abap_true.
    ENDIF.

    DATA(lt_current_keys) = lt_keys.
    IF lv_lines > lc_package_size.
    DATA(lv_delete_index) = lc_package_size + 1.
    DELETE lt_current_keys FROM lv_delete_index.
    DELETE lt_keys FROM 1 TO lc_package_size.
    lv_lines = lines( lt_keys ).
    ENDIF.

    TRY.
    write->delete_root(
    EXPORTING
    business_object_id = CONV #( mass_delete-cboname )
    keys = lt_current_keys
    ).
    CATCH cx_root.
    message = VALUE #( severity = co_severity-error
    text = 'Deletion of Entries failed' ).
    RETURN.
    ENDTRY.

    ENDWHILE.

    *----------------------------------------------------------------------*
    * Update Last Executed at Column and Delete All indicator
    *----------------------------------------------------------------------*
    GET TIME STAMP FIELD DATA(lv_current_time).
    CONVERT TIME STAMP lv_current_time TIME ZONE lv_timezone
    INTO DATE DATA(lv_current_date).

    mass_delete-lastexecutedon = lv_current_date.
    mass_delete-deletedall = abap_true.

    *----------------------------------------------------------------------*
    * Success Message
    *----------------------------------------------------------------------*
    message = VALUE #( severity = co_severity-success
    text = 'All data deleted successfully' ).


  7. Open the logic for the action "DeleteRuleBased". You have to implement the following sections:

    • Data declarations per field name: Define a range table for each field, you want to enable for rule based deletion.

    • Build Range Tables: Add each CBO with its field names which you want to enable for deletion. In case of this blog post the CBO YY1_USER is enabled. Deletion rules for CBO YY1_BUILDING would fail as they are not implemented.

    • Select Entries: Add the select statement for each enabled CBO with the corresponding range tables.


    Publish your action logic after implementation.
    * Action DeleteRuleBased for Node ID MASS_DELETE
    *
    * Importing Parameter : association (Navigation to Parent/Child/
    * Associated Node Instances)
    * write (API for creating and updating
    * Custom Business Object Node Instances)
    * Changing Parameter : MASS_DELETE (Current Node Data)
    * Exporting Parameter : message (Message with Severity S(uccess),
    * W(arning), E(rror))

    DATA: lv_timezone TYPE timezone.

    *-----------------------------------------------------------------------*
    * Data declarations per field name
    *-----------------------------------------------------------------------*
    DATA: lt_range_city TYPE RANGE OF yy1_s_yy1_user_d-city,
    lt_range_country TYPE RANGE OF yy1_s_yy1_user_d-country.

    CONSTANTS: lc_package_size TYPE i VALUE 5000.

    *-----------------------------------------------------------------------*
    * Allowed Values Check -> Prevent Dump
    *-----------------------------------------------------------------------*
    DATA(lt_allowed_values_sign) = VALUE string_table( ( `I` ) ( `E` ) ).
    DATA(lt_allowed_values_option) = VALUE string_table( ( `EQ` ) ( `NE` )
    ( `CP` ) ( `LE` )
    ( `GE` ) ( `NP` )
    ( `GT` ) ( `LT` )
    ).

    *-----------------------------------------------------------------------*
    * Check Deletion Rules
    *-----------------------------------------------------------------------*
    DATA(lt_rules) = association->to_deletionrule( ).
    IF lines( lt_rules ) = 0.
    message = VALUE #( severity = co_severity-error
    text = 'No deletion rules defined' ).
    RETURN.
    ENDIF.

    LOOP AT lt_rules INTO DATA(ls_rule).
    IF NOT line_exists( lt_allowed_values_sign[
    table_line = ls_rule-deletionrule-sign ] ).
    message = VALUE #( severity = co_severity-error
    text = |Sign { ls_rule-deletionrule-sign } | &
    |is not allowed| ).
    RETURN.
    ENDIF.
    IF NOT line_exists( lt_allowed_values_option[
    table_line = ls_rule-deletionrule-operator ] ).
    message = VALUE #( severity = co_severity-error
    text = |Option | &
    |{ ls_rule-deletionrule-operator } | &
    |is not allowed| ).
    RETURN.
    ENDIF.

    *-----------------------------------------------------------------------*
    * Build Range Tables
    *-----------------------------------------------------------------------*
    DATA(lv_no_fieldname) = abap_false.
    CASE mass_delete-cboname.
    WHEN 'YY1_USER'.

    CASE ls_rule-deletionrule-fieldname.
    WHEN 'City'.
    APPEND VALUE #( sign = ls_rule-deletionrule-sign
    option = ls_rule-deletionrule-operator
    low = ls_rule-deletionrule-value )
    TO lt_range_city.
    WHEN 'Country'.
    APPEND VALUE #( sign = ls_rule-deletionrule-sign
    option = ls_rule-deletionrule-operator
    low = ls_rule-deletionrule-value )
    TO lt_range_country.
    WHEN OTHERS.
    lv_no_fieldname = abap_true.
    ENDCASE.

    WHEN OTHERS.
    message = VALUE #( severity = co_severity-error
    text = |Deletion for CBO | &
    |{ mass_delete-cboname } | &
    |is not implemented| ).
    RETURN.
    ENDCASE.

    IF lv_no_fieldname = abap_true.
    message = VALUE #( severity = co_severity-error
    text = |Fieldname | &
    |{ ls_rule-deletionrule-fieldname } | &
    |does not exist in CBO | &
    |{ mass_delete-cboname } | ).
    RETURN.
    ENDIF.

    ENDLOOP.

    *-----------------------------------------------------------------------*
    * Select entries
    *-----------------------------------------------------------------------*
    CASE mass_delete-cboname.
    WHEN 'YY1_USER'.
    SELECT sap_uuid FROM yy1_user INTO TABLE @DATA(lt_keys)
    WHERE city IN @lt_range_city
    AND country IN @lt_range_country.
    SELECT count( sap_uuid ) FROM yy1_user INTO @DATA(lv_db_lines).
    WHEN OTHERS.
    message = VALUE #( severity = co_severity-error
    text = |Deletion for CBO | &
    |{ mass_delete-cboname } | &
    |is not implemented| ).
    RETURN.
    ENDCASE.

    DATA(lv_lines) = LINES( lt_keys ).
    DATA(lv_all_lines) = lv_lines.
    IF lv_lines = 0.
    message = VALUE #( severity = co_severity-success
    text = 'No entries match the deletion rules' ).
    RETURN.
    ENDIF.

    *-----------------------------------------------------------------------*
    * Delete entries in 5000 chunks -> Prevent System Overloading
    *-----------------------------------------------------------------------*
    IF lv_db_lines = lv_all_lines.
    CLEAR lt_keys.
    write->get_context_node( )->execute_action(
    EXPORTING
    action_id = 'DeleteAllData'
    IMPORTING
    data = mass_delete
    " messages = " Action messages are returned anyhow to the UI
    ).
    mass_delete-deletedall = abap_false.
    RETURN.
    ENDIF.

    DATA(lv_packaging) = abap_false.
    IF lv_lines > lc_package_size.
    lv_packaging = abap_true.
    ENDIF.
    DATA(lv_end_delete) = abap_false.
    WHILE lv_end_delete = abap_false.
    IF lv_lines <= lc_package_size.
    lv_end_delete = abap_true.
    ENDIF.

    DATA(lt_current_keys) = lt_keys.
    IF lv_lines > lc_package_size.
    DATA(lv_delete_index) = lc_package_size + 1.
    DELETE lt_current_keys FROM lv_delete_index.
    DELETE lt_keys FROM 1 TO lc_package_size.
    lv_lines = lines( lt_keys ).
    ENDIF.

    TRY.
    write->delete_root(
    EXPORTING
    business_object_id = CONV #( mass_delete-cboname )
    keys = lt_current_keys
    ).
    CATCH cx_root.
    message = VALUE #( severity = co_severity-error
    text = 'Deletion of Entries failed' ).
    RETURN.
    ENDTRY.

    ENDWHILE.

    *-----------------------------------------------------------------------*
    * Update Last Executed at Column
    *-----------------------------------------------------------------------*
    GET TIME STAMP FIELD DATA(lv_current_time).
    CONVERT TIME STAMP lv_current_time TIME ZONE lv_timezone
    INTO DATE DATA(lv_current_date).

    mass_delete-lastexecutedon = lv_current_date.

    *-----------------------------------------------------------------------*
    * Success Message
    *-----------------------------------------------------------------------*
    message = VALUE #(
    severity = co_severity-success
    text = COND #( WHEN lv_all_lines = 1 THEN
    |1 entry deleted successfully|
    ELSE
    |{ lv_all_lines } entries deleted successfully| )
    ).

     


Deletion through OData Service


For both actions a function import was created in the generated OData Service - YY1_MASS_DELETEDeletealldata and YY1_MASS_DELETEDeleterulebased. You can call these function imports to delete your CBO data from the outside of the Marketing system, e.g. through SAP Cloud Platform Integration (Example for scheduled Function Import call). You will need the SAP_UUID of your root node entry. To get this, use the following call with your CBO Name:
GET https://my<...>-api.s4hana.ondemand.com/sap/opu/odata/sap/YY1_MASS_DELETE_CDS/YY1_MASS_DELETE?$selec... eq 'YY1_USER'

 

Afterwards you can e.g. delete all data using this call with the returned SAP_UUID:
POST https://my<...>-api.s4hana.ondemand.com/sap/opu/odata/sap/YY1_MASS_DELETE_CDS/YY1_MASS_DELETEDeletealldata?SAP_UUID=guid'00163e69-ebdd-1ee9-9785-c254cae1b958'
8 Comments