Quantcast
Channel: SCN : Blog List - SAP CRM: Webclient UI - Framework
Viewing all 195 articles
Browse latest View live

Delete Custom Fields created via AET in sap CRM Web UI

$
0
0

Base on business requirement we add custom fields in SAP CRM Web UI via AET by using that tool we can enhance standard table and store data in customized fields.

But when we need to remove unnecessary fields from standard table at that time we only remove that custom fields from screen only of CRM Web UI but that custom field still remained in standard table which occupy unnecessary space in standard table.

By using AET we can add new field in SAP CRM Web UI and if you want to remove unwanted field to be removed from database table that will not remove by AET only deletion flag is added for that unwanted field it won’t remove that custom field physically.

To remove unused custom fields from database table SAP CRM has provided on standard program to delete custom fields from standard table AXT_EXT_GENERATE.


Steps to remove custom fields added via AET in SAP web UI:

 

Step 1: Go to your business role and Remove screen fields which you no longer needed from CRM web UI transactions.

 

Step 2: Click on configuration button and click on view area

crm_web_ui_1.png

Step 3: Click on show enhancement button and click edit list and delete custom fields which you want to delete.

crm_web_ui_2.png

Step 4: once (deletion) flag is assigned at right hand side of custom field

crm_web_ui_3.png

Step 5: Note down your enhancement ID for that custom fields in which AET has assigned name.

 

Step 6: In SAP GUI go to SE38 transaction and run AXT_EXT_GENERATE report and add your enhancement id and execute.

crm_web_ui_4.png

 

Special Thanks to Ravirajsinh Jadeja for the guidance


Step by Step SAP CRM ACE Configurations for 'new' Super Object -> Object

$
0
0

Overview:

 

Many times we have requirement to restrict access through ACE (Access Control Engine) but the related object seems not to be available in Super object type. For example I have requirement to activate ACE for Product Category but the super object is not available in SAP CRM 7.3

 

Details for Super Object:

 

So I had to make a new ACL, GRP and UCT tables and Extension class. I have copied ACL, GRP and UCT tables from PRODUCT super object entry and make three new DDIC tables (no extra fields are required as these tables have similar structure through all Super object). I have coped extension class from ACCOUNTCRM super object entry. Please find below code snippet from method IF_CRM_ACE_OTYPE_OF_GUIDS~GET_OTYPE_OF_GUIDS extension class:

 

DATA:
     lwa_guid_with_otype TYPE crms_ace_objs_with_type.

   FIELD-SYMBOLS:
     <ls_obj_guid> TYPE crms_ace_object_guid.

   CONSTANTS:
     lc_crm_super_type TYPE crmt_prt_otype
                            VALUE 'PRODUCTCATEGORYCRM'.

*=> copy imported as long as there is no otype determination support
*   for the stype

   LOOP AT it_object_guids ASSIGNING <ls_obj_guid>.
     lwa_guid_with_otype-object_type = lc_crm_super_type.
     lwa_guid_with_otype-is_bor_otype = space.
     lwa_guid_with_otype-object_guid = <fs_obj_guid>-object_guid.
*=> add object guid with CRM object type to result list
     APPEND ls_guid_with_otype TO et_otype_of_guids.
   ENDLOOP.

 

I had selected PRODUCTCATEGORYCRM as Super Object and configured relevantly.

 

Details for Object:

 

I had chose same PRODUCTCATEGORYCRM as Object to configure with Super Object. Identification Type is GUID and a new Info class id, Info class ID is representation with class copied from CL_CRM_ACE_PR_INFO_DEFAULT. In IF_CRM_ACE_DETAILS~GET_DETAILS method code must be written to select GUID from ID and ID from GUID (similar coding from GET_OBJECTS_BY_FILTER of AFO class).

 

Other Configuration for AFO, OBF and AFU class are same for other ACE implementation and can be found from other class.

 

Challenge and calling ACE:

 

When SAP Standard has the Super Object type not available then ACE is not called automatically through SAP Standard code (generally in FILTER method).

 

Solution would be either Enhance ONSEARCH event handler or GENIL class enhancement for Serach, I have chosen GENIL class enhancement as it would be called from all search functionality! what ever after getting the search result below code should be called with GUID entries:

 

Call ACE Runtime methodes
       TRY.
           CALL METHOD cl_crm_ace_runtime=>check_multiple_objects_guid
             EXPORTING
               im_object_type  = 'PRODUCTCATEGORYCRM'
             CHANGING
               ch_object_guids = li_ace_guids.
         CATCH cx_crm_ace_unsupported_action .
       ENDTRY.

*     Check the filtered results
       LOOP AT li_hier_select INTO lwa_hierarchy_selection.

         READ TABLE li_ace_guids TRANSPORTING NO FIELDS WITH KEY object_guid = lwa_hierarchy_selection-hierarchy_guid.
         IF sy-subrc NE 0.
           DELETE li_hier_select WHERE hierarchy_guid = lwa_hierarchy_selection-hierarchy_guid.
         ENDIF.
       ENDLOOP.

       SORT li_hier_select BY hierarchy_id.


Hope it would be helpful to all who are struggling, if you have questions or comment please add it!


Web UI fields (Model Node/Model Attributes) validation using JavaScript

$
0
0

Purpose :

 

It is helpful to know the UI fields validation errors prior to pressing the "Enter" key  or "Save" button .In a situation where there is an error, JavaScript functions are handy in identifying the issues/validations at client side without server round trip.

 

I have explained how JavaScript functions can be attached to view fields and how JavaScript functions can raise alerts in case of errors when user navigates from one field to another field.

 

 

  • Created a view with IBHeader (Root object) fields .

                                                                                                IBHeader.PNG

    - IBase

        - IBase Description

        - External ID

Initial UI.PNG

  • Created default configuration with above three fields.

UI Configuration.PNG

 

  • Wrote Java Script functions for field contents validation in .htm page

                                                                                                            htm img.PNG

  • JavaScript Functions:

     

    These functions are specific to my configuration fields (I wrote these functions with simple functionality to explain how JavaScript functions work on configuration fields). Based on your requirement , if needed , implement more generic functions with parameters.

 

"UIValidations" function gets the "IBase Description" field contents with "getElementById" document method and checks whether content's length is less than or equal to 10 characters , if the validation fails,then JavaScript function raises an alert.

Field Contents Length Validation.PNG

 

"UIValidateNumber" function gets the "External ID" field contents with "getElementById" document method and checks whether contents are numbers or not , if the validation fails,then JavaScript function raises an alert.

Field Contents numeric Validation.PNG

  • Finding the UI field's generated ID:

 

UI field's ID will get generated as "component_id" "_" "Context_ndoe" "_" "Structure" "." "fieldname",so I built the UI element ID with controller component ID , context node and structure field. Example field ID will be like : C1_W1_V2_ibase_struct.descr.


Finding the UI fields in the configuration.PNG


I have explained client side validations using JavaScript functions with the below approaches .Alerts will be raised in case of "onblur" event (which fires when user leaves an input field).

 

 

 

Approach - 1:

 

In this approach , I first attached the JavaScipt functions to the fields in a function and called this function explicitly.

OnBlur Event.PNG

 

Calling the Field Events.PNG

 


Approach - 2 :

 

In this approach , I created a custom class ,attached the interface IF_CHTMLB_FORM_ITERATOR,

implemented method of the interface RENDER_CELL_START and assigned JavaScript functions to the event

"onclientblur" of the input field.

Iterator Method.PNG

Script Attachment.PNG

 

    In ".htm" code , I created the iterator object and assigned to the config.

Iterator addition in htm.PNG

 

 

Execution Process(Validations) :

 

   Screens to show how JavaScript function displays output in case of validation failure.

 

 

    • Case - 1 : When IBase Description is less than 10 characters

UI field contents length validation Popup.PNG

 

    •         Case - 2 : When External ID contains non-numeric values

 

UI Number validation Popup.PNG

 

    •    Screen fields with correct data(no errors in the input)

No Popup with right Values.PNG

 

  • Component hierarchy

Component.PNG

Display first name and last name of BP instead of BP number in the error messages

$
0
0

Hello All,

 

Some opportunities will contain invalid Business Partners( like archived, marked for deletion, not released). If such business partners are added then system will throw error message saying " The BP is marked for deletion / archived / not released with the BP number".

 

Now in this blog i am going to show how to display first name and last name of the BP instead of the BP number in the error message.

 

This will involve 3 steps.

 

1. Delete the standard error messages.

2. Structure the custom message.

3. Display the custom error message.

 

You can use all the below code in do_prepare_output method of the opportunity view.

 

1.Delete the standard error messages.

 

DATA: lr_msg_cont    TYPE REF TO  if_genil_message_container,
          lr_msg_service TYPE REF TO cl_bsp_wd_message_service.

     DATA: lt_msg                TYPE crmt_genil_message_tab,
               lv_partner            TYPE bu_partner,
               ls_bp_detail         TYPE bapibus1006_central_person,
               lv_chk_msg         TYPE boolean,
               ls_msg               TYPE crmt_genil_message,
               lt_msg_partner    TYPE crmt_genil_message_tab,
               ls_msg_partner   TYPE crmt_genil_message,
               lv_guid               TYPE crmt_genil_object_guid,
 
*****Initially delete the standard error messages raised for the invalid BPs
      lr_msg_service = cl_bsp_wd_message_service=>get_instance( ).
      lr_msg_cont er_entity->get_message_container( ).


*These are the standard error messages thrown by system when we add invalid BPs to sales team
     ls_msg-id = 'R11'.
     ls_msg-number = '185'.
     APPEND ls_msg TO lt_msg.

     ls_msg-id = 'COM_PARTNER'.
     ls_msg-number = '156'.
     APPEND ls_msg TO lt_msg.

     ls_msg-id = 'COM_PARTNER'.
     ls_msg-number = '158'.
     APPEND ls_msg TO lt_msg.


     IF lr_msg_cont IS BOUND.
       LOOP AT  lt_msg INTO ls_msg.
         lr_msg_cont->delete_messages( iv_msg_id     = ls_msg-id
                                                         iv_msg_number = ls_msg-number ).
       ENDLOOP.
     ENDIF."lr_msg_cont

     lv_guid = er_entity->get_property_as_string( 'GUID' ) .



2. Structure the custom message.


*function module to read the invalid BPs from the opportunity and structuring the custom error message

     CALL FUNCTION 'ZCHECK_PARTNERS'
       EXPORTING
         iv_guid    =      lv_guid
       IMPORTING
         et_message = lt_msg_partner.


3. Display the custom error message.


     IF lt_msg_partner IS NOT INITIAL.
       LOOP AT lt_msg_partner INTO ls_msg_partner.
         IF lr_msg_service IS BOUND.
           lr_msg_service->add_message( iv_msg_type         = ls_msg_partner-type
                                                          iv_msg_id            = ls_msg_partner-id
                                                          iv_msg_number    = ls_msg_partner-number
                                                          iv_msg_v1            = ls_msg_partner-var1
                                                          iv_msg_v2            = ls_msg_partner-var2
                                                          iv_msg_v3            = ls_msg_partner-var3
                                                          iv_msg_v4            = ls_msg_partner-var4
                                            ).
         ENDIF."lr_msg_service
       ENDLOOP.
     ENDIF.




function module source code.

ZCHECK_PARTNERS



FUNCTION zcheck_partners.
*"----------------------------------------------------------------------
*"*"Local Interface:
*"  IMPORTING
*"     REFERENCE(IV_GUID) TYPE  CRMT_OBJECT_GUID
*"  EXPORTING
*"     REFERENCE(ET_MESSAGE) TYPE  CRMT_GENIL_MESSAGE_TAB
*"----------------------------------------------------------------------

*****Data Declarations
   DATA: lt_header_guid      TYPE crmt_object_guid_tab,
             lt_partner              TYPE crmt_partner_external_wrkt,
             ls_but000              TYPE but000,
             lt_msg                  TYPE crmt_genil_message_tab,
             ls_msg                 TYPE crmt_genil_message,
             ls_partner_fct        TYPE CRMC_PARTNER_FT,
             ls_partner             TYPE crmt_partner_external_wrk,
             lt_partner_fct        TYPE STANDARD TABLE OF crmc_partner_ft,
             lt_but000              TYPE STANDARD TABLE OF but000.


   CHECK iv_guid IS NOT INITIAL.

   APPEND iv_guid TO lt_header_guid.

   CALL FUNCTION 'CRM_ORDER_READ'
     EXPORTING
       it_header_guid       = lt_header_guid
       iv_no_auth_check     = 'X'
     IMPORTING
       et_partner           = lt_partner
.

   CLEAR: lt_but000,lt_msg,ls_msg,lt_partner_fct,ls_partner_fct.

   SELECT * FROM but000 INTO TABLE lt_but000 FOR ALL ENTRIES IN lt_partner WHERE type = 1
                                                                           AND  partner_guid = lt_partner-bp_partner_guid.
   SELECT * FROM CRMC_PARTNER_FT INTO TABLE lt_partner_fct where spras = 'E'.

   IF lt_but000 IS NOT INITIAL.
     LOOP AT lt_partner INTO ls_partner.
       READ TABLE lt_but000 INTO ls_but000 WITH KEY partner_guid = ls_partner-bp_partner_guid.
       IF sy-subrc IS INITIAL.
         CONCATENATE ls_but000-name_first ls_but000-name_last INTO ls_msg-var2 SEPARATED BY SPACE.
*****Now Read the Partner function description
         READ TABLE lt_partner_fct INTO ls_partner_fct WITH KEY partner_fct = ls_partner-partner_fct.
         IF sy-subrc IS INITIAL.
           CONCATENATE '(' ls_partner_fct-description ')' into ls_msg-var3.
         ENDIF."lt_partner_fct

         IF ls_but000-xdele EQ 'X'."If BP marked for deletion.
           ls_msg-type = 'E'.
           ls_msg-id ='XXXXXX'.
           ls_msg-number = '000'.
           ls_msg-var1 = 'Business Partner'.
           ls_msg-var4 = 'has status "Flagged for Archiving"'.

           append ls_msg to lt_msg.
         ENDIF."ls_but000-XDELE

         IF ls_but000-xblck EQ 'X'."If the BP is blocked
           ls_msg-type = 'E'.
           ls_msg-id ='XXXX'.
           ls_msg-number = '000'.
           ls_msg-var1 = 'Business Partner'.
           ls_msg-var4 = 'has status "Locked"'.

           append ls_msg to lt_msg.
         ENDIF."ls_but000-XBLCK

         IF ls_but000-not_released EQ 'X'."If the BP marked as not released
           ls_msg-type = 'E'.
           ls_msg-id ='XXXX'.
           ls_msg-number = '000'.
           ls_msg-var1 = 'Business Partner'.
           ls_msg-var4 = 'has status "Not Released"'.

           append ls_msg to lt_msg.
         ENDIF."ls_but000-NOT_RELEASED
       ENDIF."sy-subrc
       clear: ls_msg.
     ENDLOOP."lt_partner
   ENDIF."lt_but000

et_message = lt_msg.

ENDFUNCTION.



The final result will be like this.


Standard error messages.


 

Custom error messages.



Br,

Navn

Raising Data Loss Popup for Custom Component

$
0
0

Summary:

How to give data loss popup when navigating from custom component to other components or documents using Quick links or Navigation bar links when used in WEBUI

 

This document will be helpful when we are using custom component in WEBUI as standalone component

 

Step1:In custom component mainwindow IMPL class we have add one interfaceIF_BSP_WD_EVENT_HANDLER under interfacedata1.PNG

 

Step2:We have to create one method for data loss poupup and register it for data loss in methods

data5.PNG

 

After this keep cursor on the method and click Detail View (highlighted) and give below details in the screenshot

data6.PNG

 

Here we have to code for triggering the data loss popup. Put logic whether data entered or modified in the component and raise popup


IF gv_update EQ abap_true.

    data_loss_handler->set_save_handler( me ).
    data_loss_handler->set_revert_handler( me ).
    data_loss_handler->set_cancel_handler( me ).

    data_loss_handler->trigger_data_loss_handling( ).
  ENDIF.

 

Step3:Activate Data loss popup Event Handler

We have to activate data loss popup event in method DO_VIEW_INIT_ON_ACTIVATION

data4.PNG

Here we have to put code to activate data loss popup event

CALL METHOD SUPER->DO_VIEW_INIT_ON_ACTIVATION.

* Enable Data Loss Popup

  SET HANDLER on_before_wa_content_change ACTIVATION abap_true.

 

Step4:Deactivating data loss popup event handler

Here in method DO_CLEANUP_CONTEXT

data7.PNG

Here put code to deactivate event handler

CALL METHOD super->do_cleanup_context
    .

  SET HANDLER on_before_wa_content_change ACTIVATION abap_false.

 

Step5:Add attributes

Under Attributes add two attributes DATA_LOSS_TRIGGER_VIEW and DATA_LOSS_TRIGGER_EVENT

data3.PNG

 

Step6:In WIndow IMPL class we will have method IF_BSP_WD_EVENT_HANDLER~HANDLE_EVENT under methods

data2.PNG

Here we have to code for data loss popup buttons. Here you will have the user option whether save or cancel

 

When user clicked yes you have to put logic to update your custom table with the details entered in custom component view

 

CASE iv_event_name.
    WHEN if_bsp_wd_data_loss_handler=>save_event.
      rv_success = abap_true.

      lr_core ?= cl_crm_bol_core=>get_instance( ).
      lr_msg_srv ?= lr_core->get_global_message_cont( ).
      lr_coco ?= me->comp_controller.
      lr_col ?= lr_coco->typed_context->data->collection_wrapper.


      lr_entity ?= lr_col->get_first( ).

      WHILE lr_entity IS BOUND.

        CALL METHOD lr_entity->get_properties
          IMPORTING
            es_attributes = lwa_data.

          APPEND lwa_data TO li_data.
          CLEAR lwa_emp_org.
      
        lr_entity ?= lr_col->get_next( ).

      ENDWHILE.


      MODIFY Ztable FROM TABLE li_data.
      IF sy-subrc = 0.
        COMMIT WORK.
      ENDIF.
      CLEAR:gv_update.
      lr_msg_srv->add_message( iv_msg_id = 'ZCRM_MESS' iv_msg_type = 'S' iv_msg_number = '031' iv_show_only_once = 'X').
      CLEAR me->data_loss_trigger_view.
      CLEAR me->data_loss_trigger_event.
    WHEN if_bsp_wd_data_loss_handler=>revert_event.
      rv_success = abap_true.
      CLEAR me->data_loss_trigger_view.
      CLEAR me->data_loss_trigger_event.
    WHEN if_bsp_wd_data_loss_handler=>cancel_event.
      rv_success = abap_false.
**      RETURN.
      CLEAR me->data_loss_trigger_view.
      CLEAR me->data_loss_trigger_event.
    WHEN OTHERS.

  ENDCASE.


This Popup will be called when user navigates out of component without saving the data.

 

Regards,

Deepika.

Do you know that?Interaction Center does not support Google Chrome and Safari browser.

$
0
0

Hi All,

 

As you know, we can verify the corresponding supportive IE versions to our CRM system by referring to note below.

1746385 - Main WEBCUIF Browser Support Note

 

But for Interaction Center(logon IC WebUI by IC role like IC_Agent, etc), we should be aware of follow note too.

As IC WebUI does not support Google Chrome and Safari. We can find the relevant
information in Note 1876371 - Browser compatibility of SAP CRM 7.0 EhP 3 (Functional restrictions section).

 

==>
Functional restrictions for Safari and Google Chrome:

The functions of the CRM Interaction Center are not released for these two browsers.
==>

 

Also, eventhough the title of Note 1876371 is related to CRM 7.0 EhP3, but this Functional restrictions also
apply to other crm versions.

 

Running IC WebUI on Google Chrome and Safari browsers may encounter potential functional
issues, and also the session issues. For example, even after we closed the Google Chrome and Safari,
the http session in SM04 and the lock entries in SM12 will not be released. ( Non-IC role like business role

salespro doesn't have such issue, after we closed the Google Chrome and Safari brower, depending

on the server workload, if we wait 10-20 seconds,the http session and lock entries will be released automaticaly

in sm04 and sm12.)

 

So if You have some issues when running IC WebUI on Google Chrome or Safari browsers, please use supportive
IE versions mentioned in Note 1876371 instead.Interaction Center does not support Google Chrome and Safari browser.


Have a nice day!

 

Best Regards,
Bruce

WEBCUIF EhP3 SP10 - Release Notes

$
0
0

These Release Notes focus on new features and enhancements delivered as part of the Web Client UI Framework EhP3 Support Package 10.

 

The WEBCUIF development team members are doing their best to provide those new developments on older releases. So if you are interested in a specific feature, verify its availability by checking the corresponding SAP Note.

 

New Features and Enhancement

 

Keyboard Shortcuts for Advanced Search Pages

 

On advanced search pages, the new keyboard shortcuts <Shift>+Down and <Shift>+Up will allow users to navigate through either the Criteria, Operator and Criteria Value directly, as well as cycle from the first to last entry and vice versa.  For instance, if the cursor is currently in a Criteria Value field, <Shift>+Down will move the cursor to the next Criteria value until the last Criteria Value is reached, at which point pressing <Shift>+Down again will set the cursor to the first Criteria Value.

 

asp_keyboard.png

 

See SAP Note: 2165904

 

 

Rich Text Editor Default Font Name and Font Size Personalization

 

Text editor personalization was added in SPERS_MAINT which adds 2 new fields (default font name, default font size) in table WCF_TEXT_EDITOR_PERS which, when changed, changes default font and size globally for all text editors. If the font name and size are defined in the tag declaration of a view, it will still take precedence.

 

See SAP Note: 2161387

 

 

If you missed them, check out the WEBCUIF EhP3 SP09 - Release Notes

Asynchronous Rendering of Table Views

$
0
0

1 Requirement

In WebUI scenarios specific requests and queries often take a long time until the data is available. In particular, RFC calls to external systems like the ERP can slow down performance. Due to the WebUI framework where visualization and rendering is done after server side processes are finished the user requires dedicated parallel processing. Table Views in WebUI include usually a large amount of different data and therefore different request origins. The ambition is to separate slow requests from the other request in order to fasten the entire visualization.


1.1 Preview

Take a look at the asynchronous rendering in action.



2 Proposal

Using a combination of server implementation and client side scripting Table Views can be rendered asynchronously where required. At first rendering the data is not received but a loading information is displayed instead.1.png

After an AJAX-Callback is started, the data is received and the response is sent back to the client in order to display the Table View entries at the moment they’re getting available.

2.png

3 Implementation Steps

Both server side and client side implementation needs to be done in order to achieve this functionality.

 

3.1 Server Side

The implementation class that handles the callback needs to be the same instance as the one the table view is rendered. Therefore, a modification in the method IF_HTTP_EXTENSION~HANDLE_REQUEST of class CL_CRM_WEB_UTILITY needs to be done. Similar to SAP Note 1968050 where the instance is not created again.

 

3.1.1 Modification in Web Utility Class

The modification is not critical from my perspective. It might be usefull to integrate a customizing there if more than one class needs to be included for different Table Views.

 

* -> create handler class
 TRY.
 IF LV_HANDLER_CLASS_NAME = 'CL_CRM_BSP__RECENTOBJECT0_IMPL'
 OR LV_HANDLER_CLASS_NAME = 'ZL_ZWEBUI_B_ZACCOUNTOPPOR_IMPL'.
 lv_handler_class ?= lv_target_controller.
 ELSE.
 CREATE OBJECT lv_handler_class
 TYPE
 (LV_HANDLER_CLASS_NAME).
 ENDIF.
 * -> call back application handler
 lv_handler_class->handle_request(
 ir_server     = server
 ir_controller = lv_target_controller ).
 CATCH cx_root.
 ENDTRY.

 

3.1.2 HTML

The rendering of the Table View itself must be done manually without using BSP tags to save the created BEE in the respective implementation class. Otherwise, the logic would be called after every roundtrip.

 

<%
 DATA: lr_config_table TYPE REF TO cl_chtmlb_config_cellerator.
 IF controller->gr_config_table IS INITIAL.
 CALL METHOD cl_chtmlb_config_cellerator=>factory
 EXPORTING
 id             = 'Table'
 table          = controller->typed_context->btqropp->table
 _table         = '//BTQROPP/Table'
 xml            = controller->configuration_descr->get_config_data( )
 width          = '100%'
 selectionmode  = cl_thtmlb_cellerator=>gc_selection_mode_none
 personalizable = 'FALSE'
 RECEIVING
 element        = lr_config_table.
 controller->gr_config_table ?= lr_config_table.
 %><script>
 thtmlbAJAXCall.callBackend("<%= controller->create_ajax_url( ) %>",thtmlbCCelleratorManager.asynchronousRenderingCallback);</script><%
 lr_config_table->emptytabletext = cl_wd_utilities=>get_otr_text_by_alias( 'CRM_BSP_UI_FRAME_RECOBJ/LOADING' ).
 ENDIF.
 lr_config_table ?= controller->gr_config_table.
 lr_config_table->if_bsp_bee~render( _m_page_context ).
 %>

3.1.3 Clear on new focus

Depending on the usage it may be required to handle the logic whenever the focus is changed. For instance, in an assignment block that is included in the BP_HEAD. If the business partner is changed the search must be done again. I guess, there can be done some additional investigation to handle the partner change itself and in those cases just take the data out of the BOL. So the performance can be improved even more.

 

3.1.3.1 Method: IF_BSP_MODEL~INIT

Get the instance of the controller implementation class.

 

CALL METHOD super->if_bsp_model~init
 EXPORTING
 id    = id
 owner = owner.
 gv_owner ?= owner.

 

3.1.3.2 Method: ON_NEW_FOCUS

Clear the BSP bee.

 

CLEAR gv_owner->gr_config_table.

3.1.4 AJAX-URL

The URL which calls the backend via JavaScript can be created in the implementation class directly.

 

CALL METHOD cl_crm_web_utility=>create_service_url
 EXPORTING
 iv_handler_class_name = 'ZL_ZWEBUI_B_ZACCOUNTOPPOR_IMPL'
 iv_controller_id      = me->component_id
 RECEIVING
 ev_url                = ev_url.

3.1.5 Callback

The implementation class needs the Interface IF_CRM_WEB_CALLBACK in order to receive the previously callback.

 

3.1.5.1 Method: IF_CRM_WEB_CALLBACK~HANDLE_REQUEST

The method handles the callback, retrieves the data and creates the HTML code for the response.


*|-- References  DATA: lr_result          TYPE REF TO if_bol_bo_col,
 lr_query_service   TYPE REF TO cl_crm_bol_dquery_service.
*|-- Variables
 DATA: lv_partner         TYPE string,
 lv_html            TYPE string.
 *|-- BP number
 lv_partner = me->typed_context->builheader->collection_wrapper->get_current( )->get_property_as_string( iv_attr_name = 'BP_NUMBER' ).
 CHECK lv_partner IS NOT INITIAL.
 TRY.
 *|-- Query Service for Opportunities
 lr_query_service = cl_crm_bol_dquery_service=>get_instance( 'BTQOpp' ).
 *|-- Query-Parameter
 CALL METHOD lr_query_service->add_selection_param
 EXPORTING
 iv_attr_name = 'PROSPECT'
 iv_sign      = 'I'
 iv_option    = 'EQ'
 iv_low       = lv_partner.
 *|-- Result
 lr_result = lr_query_service->get_query_result( ).
 CATCH cx_crm_genil_general_error.
 RETURN.
 ENDTRY.
 *|-- Sorting
 IF lr_result IS BOUND.
 lr_result->sort(
 EXPORTING
 iv_attr_name  = 'EXP_REVENUE'
 iv_sort_order = if_bol_bo_col=>sort_descending ).
 ENDIF.
 *|-- Set Result to Context & build table
 me->typed_context->btqropp->collection_wrapper->set_collection( lr_result ).
 me->typed_context->btqropp->build_table( ).
 *|-- Clear text
 CLEAR me->gr_config_table->emptytabletext.
 *|-- Create HTML
 CALL METHOD create_table_view_html
 EXPORTING
 ir_server         = ir_server
 ir_controller     = ir_controller
 iv_binding_string = '//BTQROPP/TABLE'
 iv_table_id       = me->get_id( 'Table' )
 IMPORTING
 ev_html           = lv_html.
 *|-- Set Response
 ir_server->response->set_cdata( lv_html ).
 ir_server->response->set_header_field( name  = 'content-type'
 value = 'text/xml' ).
 *|-- Invalidate ´content
 CALL METHOD cl_ajax_utility=>invalidate_area_content
 EXPORTING
 ir_controller = ir_controller.

3.1.5.2 Method: CREATE_TABLE_VIEW_HTML

 

*|-- Constants
 DATA: lc_separator TYPE string VALUE '__'.
 *|-- Variables
 DATA: lv_attribute_path     TYPE string,
 lv_model_name         TYPE string,
 lv_lines              TYPE i,
 lv_string_lines       TYPE string,
 lv_count              TYPE i VALUE 0,
 lv_row_id             TYPE string,
 lv_html               TYPE string,
 lv_template_row_tr_id TYPE string,
 lv_new_row_tr_id      TYPE string,
 lv_rows               TYPE string,
 lv_row_ids            TYPE string,
 lv_fixed_left_rows    TYPE string,
 lv_fixed_right_rows   TYPE string,
 lv_marked_rows        TYPE string.
 *|-- Strucures
 DATA: ls_area_content TYPE crms_tajax_area_content.
 *|-- References
 DATA: lo_page             TYPE REF TO cl_bsp_ctrl_adapter,
 lo_view_manager     TYPE REF TO cl_bsp_wd_view_manager,
 lo_view_controller  TYPE REF TO cl_bsp_wd_view_controller,
 lo_model            TYPE REF TO if_bsp_model_binding,
 lo_context_node     TYPE REF TO cl_bsp_wd_context_node,
 lo_context_node_tv  TYPE REF TO cl_bsp_wd_context_node_tv.
 *|-- Field Symbols
 FIELD-SYMBOLS: <fs_page>  TYPE bsprtip.
 *|-- Create page instance
 READ TABLE cl_bsp_context=>c_page_instances
 WITH KEY page_name = cl_bsp_wd_appl_controller=>appl_controller_name
 ASSIGNING <fs_page>.
 *|-- Rendering
 IF sy-subrc IS INITIAL AND <fs_page>-instance IS BOUND.
 lo_page            ?= <fs_page>-instance.
 lo_view_manager    ?= lo_page->m_adaptee.
 lo_view_controller ?= ir_controller.
 lo_view_manager->render( iv_root_view = lo_view_controller ).
 ENDIF.
 *|-- Get model
 CALL METHOD cl_bsp_model=>if_bsp_model_util~split_binding_expression
 EXPORTING
 binding_expression = iv_binding_string
 IMPORTING
 attribute_path     = lv_attribute_path
 model_name         = lv_model_name.
 TRY.
 lo_model ?= ir_controller->get_model( lv_model_name ).
 lo_context_node ?= lo_model.
 lo_context_node_tv ?= lo_model.
 lv_lines = lo_context_node->collection_wrapper->size( ).
 CATCH: cx_root.
 EXIT.
 ENDTRY.
 WHILE lv_count < lv_lines.
 "Create AJAX content
 lv_count = lv_count + 1.
 lv_string_lines = lv_count.
 CONDENSE lv_string_lines NO-GAPS.
 CONCATENATE iv_table_id '__' lv_string_lines '__1' INTO lv_row_id.
 CALL METHOD lo_view_controller->retrieve_ajax_area_content
 EXPORTING
 iv_area_id         = lv_row_id
 iv_page_id         = ir_controller->component_id
 IMPORTING
 es_content_info    = ls_area_content
 er_used_controller = lo_view_controller.
 "Covert HTML
 IF ls_area_content-area_content IS NOT INITIAL.
 lv_html = cl_thtmlb_util=>escape_xss_javascript( ls_area_content-area_content ).
 ENDIF.
 CLEAR ls_area_content.
 "Build table
 lo_context_node_tv->build_table( ).
 "Create Response
 IF lv_rows IS INITIAL.
 CONCATENATE `'` lv_html `'` INTO lv_rows.
 CONCATENATE `'` '' `'` INTO lv_fixed_left_rows.
 CONCATENATE `'` '' `'` INTO lv_fixed_right_rows.
 CONCATENATE `'` lv_row_id `'` INTO lv_row_ids.
 CONCATENATE `'` '' `'` INTO lv_marked_rows.
 ELSE.
 CONCATENATE lv_rows `,'` lv_html `'` INTO lv_rows.
 CONCATENATE lv_fixed_left_rows `,'` '' `'` INTO lv_fixed_left_rows.
 CONCATENATE lv_fixed_right_rows `,'` '' `'` INTO lv_fixed_right_rows.
 CONCATENATE lv_row_ids `,'` lv_row_id `'` INTO lv_row_ids.
 CONCATENATE lv_marked_rows `,'` '' `'` INTO lv_marked_rows.
 ENDIF.
 ENDWHILE.
 CONCATENATE `{ "rows": [ ` lv_rows ` ],  "fixedLeftRows": [ ` lv_fixed_left_rows ` ], "fixedRightRows": [ ` lv_fixed_right_rows
 ` ], "markedRows": [ ` lv_marked_rows ` ],  "tableId": [ '` iv_table_id `' ], "rowIds": [ ` lv_row_ids ` ]}` INTO ev_html.

3.2 Client Side

The response that is created on the server side now must be handled on the client side for direct rendering without the need of a round trip.

Therefore the JavaScript scripts_.oo_tableview.js of BSP application THTMLB_SCRIPTS must be modified.

 

3.2.1 Modification in JavaScript

Basically the logic of the new Javascript function is the same as the function createFastRowsCallback where the system creates new empty rows in a Table View.

 

3.2.2 Function: asynchronousRenderingCallback

This function has following changes compared to the fast row creation logic:

 

  • Change the loading text of the no result line to take cases without any results into consideration
  • Hide the no result line in cases where we get at least one result

 

3.2.2.1 Change text

 

var noResultRow = document.getElementById(values.tableId[0]+"_noresult");
 var regexExp = new RegExp ("<%= cl_wd_utilities=>get_otr_text_by_alias( 'CRM_BSP_UI_FRAME_RECOBJ/LOADING' ) %>","g");
 var noResultText = "<%= cl_wd_utilities=>get_otr_text_by_alias( 'BSP_DYN_CONFIG_TAG_LIB/NO_RESULT_FOUND' ) %>";
 noResultRow.firstChild.innerHTML = noResultRow.firstChild.innerHTML.replace(regexExp,noResultText);

 

3.2.2.2 Hide line

 

for (var i = 0, length = values.rows.length; i < length; i++) {<%-- Hide no result line --%>
 noResultRow.className += ' th-displayNone' ;<%-- check if the row already exists in the case where the table has inserted empty rows --%>
 rowFound = true;
 row = document.getElementById(values.rowIds[i]);
 if (values.fixedLeftRows[i] != "")
 rowFixedLeft = document.getElementById(values.rowIds[i]+"_left");
 if (values.fixedRightRows[i] != "")
 rowFixedRight = document.getElementById(values.rowIds[i]+"_right");

 

4 Summary

This logic provides a good opportunity in scenarios where dedicated requests take a long time and therefore the entire visualization is slow. However, the modification in the JavaScript is highly critical. One mistake leads to heavy errors in the WebUI as this file is used in almost every view. As a result, I can't recommend this for productive systems. I hope, that this can help the SAP to create an improment note to support this functionality.

 

Cheers,

Sebastian


Edit webUI log in screen Layout html

$
0
0

1.go to transaction SICF
    execute then got default host -> sap->bc->bsp->sap->crm_ui_start

 

 


2. click on configuration button of tab error pages

 

 

click on adjust links and images

 

 

 

here you can specify different images to be shown . but changing these settings will not make any effect in standard layout of login page.

 

 

how to change the complete layout of login page

click on custom implementation radio button.

 

 

here we need to specify a class which should be subclass of CL_ICF_SYSTEM_LOGIN

You can use the following classes as a reference to implementation

  • CL_ICF_BASIC_LOGIN
  • CL_ICF_IDES_LOGIN
  • CL_ICF_NW04_LOGIN


here i have copied CL_ICF_BASIC_LOGIN to ZCL_ICF_BASIC_LOGIN

goto metod RENDER_PAGE
there we can see compleate html. make necessary changes here

 

 

upload any image in the MIME repository at above path

 

 

save and test the output

 

New-Login page for Fiori.jpg

UPLOAD A FILE IN SAP WEB UI

$
0
0

UPLOAD A FILE IN SAP WEB UI

1.Add component usage ‘GS_FILE_UPLOAD’.

 

 

 

 

 

2.create a TABLE view with  button upload.

 

 

               

 

 

 

3.call component usage as popup on clicking that button.

 

 

 

 

 

 

 

 

create event handler onpopup_closed.

 

METHOD eh_onpopup_closed.
“structure corresponds to view attributes
TYPES :BEGIN OF ls_struct,
emp_id TYPE char10,
name TYPE char30,
END OF ls_struct.
FIELD-SYMBOLS <fs_wa_data> TYPE ls_struct.
DATA : lr_value_node   TYPE REF TO cl_bsp_wd_value_node,
lr_bo_col       TYPE REF TO if_bol_bo_col,
lr_struct       TYPE REF TO ls_struct,
lr_output_node  TYPE REF TO cl_bsp_wd_context_node,
lr_property     TYPE REF TO if_bol_bo_property_access,
lv_file_content TYPE string,
lt_file_content TYPE stringtab,
lv_dummy        TYPE string.

"CLEAR EXISTING VALUES
me->typed_context->filecontent->collection_wrapper->clear( ).
"GET UPLOADED VALUES
lr_property  = gr_popup->get_context_node( iv_cnode_name = 'FILE' )->get_collection_wrapper( )->get_current( ).
lr_property->get_property_as_value(
EXPORTING
iv_attr_name = 'FILE_CONTENT_STRING'    " Component Name
IMPORTING
ev_result    = lv_file_content
).
IF lv_file_content IS NOT INITIAL.
CREATE DATA lr_struct.
ASSIGN lr_struct->* TO <fs_wa_data>.
"SPLIT EACH LINE TO TABLE
SPLIT lv_file_content AT cl_abap_char_utilities=>cr_lf INTO TABLE lt_file_content.
CLEAR lv_file_content.
IF lr_bo_col IS NOT BOUND.
CREATE OBJECT lr_bo_col TYPE cl_crm_bol_bo_col.
ENDIF.
LOOP AT lt_file_content INTO lv_file_content .

“ignore the title
IF sy-tabix <> 1.
"SPLIT VALUES FROM STRING
SPLIT lv_file_content AT ',' INTO <fs_wa_data>-emp_id <fs_wa_data>-name lv_dummy.
"CREATE VALUE NODE OBJECT
CREATE OBJECT lr_value_node
EXPORTING
iv_data_ref = lr_struct.
"ADD TO COLLECTION
lr_bo_col->add(
EXPORTING
iv_entity    = lr_value_node     " Access Interface for BO Attributes
*      iv_set_focus = ABAP_FALSE    " Indicator: Set Focus on New Element
).
ENDIF.
ENDLOOP.
me->typed_context->filecontent->collection_wrapper->add_collection( iv_collection = lr_bo_col  ).
ENDIF.
ENDMETHOD.

 

 

Output

 

 

 

 

 

 

 

Upload the file

 

 

 

How to find the relevant AET database table for your AET fields

$
0
0

Someone asked me that how to find the relevant AET tables for his created AET fields. When we created the AET fields from the object part with which we are familiar, then we can easily find it. For example, if we create an AET field from object part ORDERADM_H, then we can easily guess that the relevant database table will be CRMD_ORDERADM_H.

 

But if we created the AET fields from an unfamiliar component/view, object part, then what is the easy way to find the relevant database AET table? Actually you can follow the following 3 steps. In example below, we created an AET field under component PRDHS and its enhancement place is INCL_EEW_PROD_MAT.

 

1. Open AET by configuration and note down the enhancement place(ex.INCL_EEW_PROD_MAT) of your AET field.

1.JPG

 

2. Run t-code:se11, then enter enhancement place INCL_EEW_PROD_MAT in field Data type and display it. Then click button “Display Object List”.

2.JPG

 

3.Then you can find relevant AET table under folder “Database Tables”. As we enhanced the field on header, So it is easy to find the table is CRM_EXT_MATH.

 

3.JPG

How to find out who calls a function module in update task in CRM

$
0
0

Purpose


In CRM, when saving a transaction(T_code CRMD_ORDER or CRM webui), there are function modules executed in update task. Sometimes, we get errors from these function modules. The typical sample is: SAPSQL_ARRAY_INSERT_DUPREC which happens in function modules like CRM_SERVICE_OS_UPD_SUB_DU.

 

Most of time, it happens because the same function module is executed twice with the same records to insert. If we know from where the function module is called, we can understand the whole logic more clearly and find out the reason why it runs in this way.

 

Normally, updates use database table VBMOD and VBDATA to record the update tasks. So we can use T-code SM13 to get information for the update function modules. But for CRMD_ORDER and CRM webui, we cannot find the update information in SM13. It is because both T-code CRMD_ORDER and CRM webui use ABAP Memory technology instead of VBMOD and VBDATA.

 

We can consider setting a breakpoint in the update function module. But when the breakpoint stops, it is already inside this function module. We still don't know who call it.


Of couse, we can also set breakpoint in the command 'CALL FUNCTION' or 'CALL FUNCTION IN UPDATE TASK'. It will stop at every 'CALL FUNCTION' statement. If we are lucky enough, we can find out quickly the line where the expected function module is called. But for me, I cannot say so.


Then, how can we locate quickly the place where the update function module is called? In this article, I will explain with a sample how I do.


How is the update information stored and retrieved

 

If we display program SAPMSSY0 in T-code SE38, we can find export to memory id statement. It writes %_vb_calls into ABAP memory with ID %%vbkey while %_vb_calls contains the update function modules information.
1 export statement.PNG


Let's display program SAPMSSY4. We will see import from memory statement. Now the update information in the ABAP memory is imported to %_vb_calls.

2 import statement.PNG

Sample

I want to find out where the update function module CRM_SERVICE_OS_UPD_OST_DU is called.

 

steps in T-code CRMD_ORDER

1. Set breakpoint in line 575 of program SAPMSSY0 and line 31 of program SAPMSSY4.

2. Create a transaction, input values. Before clicking 'save' button, input /h and click Enter first.

3 create a transaction to save.PNG
3. Click 'save' button, it will go into debug mode. Check from menu 'Settings'->'Change Debugger Profile/Settings', make sure system debug is switch on since SAPMSSY0 and SAPMSSY4 are system programs.

4 into debug mode.PNG

5 debug setting.PNG

4. Click F8, the breakpoint will stop at the line 575 of program SAPMSSY0. Double click the variant vb_func_name, the value now is, for example, CRM_ACTIVITY_H_UPDATE_DU.

6 stop at export.PNG

5. From the callstack, if we double click on the previous program, we can see how FM CRM_ACTIVITY_H_UPDATE_DU is called in FM CRM_ORDER_TABLE_SAVE.

6-2 stop at export.PNG

6. If we click F8, we can get all callstacks and notice that the variant VB_FUNC_NAME is the update function module name which is being called.

7 update tasks calling.PNG

7. Of course, I just want to find out where FM CRM_SERVICE_OS_UPD_OST_DU is called. If I click F8 everytime, I have to stop many times. In order to make it fast, in step 5, I will set a condition for the breakpoint. Go to 'Break/Watchpoints' tab, click 'new' to create a condition.

8-1 set condition.PNG

8. The condition is VB_FUNC_NAME = 'CRM_SERVICE_OS_UPD_OST_DU'.

8-2 set condition.PNG

9. Go back to 'standard' tab, click F8. This time, it will stop only when the update function module 'CRM_SERVICE_OS_UPD_OST_DU' is called. In this way, I can find out where the expected function module is called.

8-3 back to bk.PNG

The entries of %_vb_calls change every time when we stop here. At the moment, its content is:

8-4 vb tab exported.PNG

10. If we continue to click F8, finally, we will come to the line 31 of SAPMSSY4.

9-1 vb table.PNG

Content of %_vb_calls will be:

9-2 vb table.PNG

After this, system will loop %_vb_calls, execute the update function modules one by one.

 

steps in CRM webui

The steps in CRM webui are similiar to the ones in T-code CRMD_ORDER. For example, if I create an interaction record, all the steps will be:

1. Set breakpoint at line 575 of program SAPMSSY0 and line 31 of program SAPMSSY4. Please notice the breakpoints are 'external breakpoint'.

2. Set breakpoint at method CL_ICCMP_BT_BUTTONBAR_IMPL->EH_ONSAVE.

3. Create an interaction record and click 'save' button.

P-1 web save.PNG

4. Breakpoint will stop at line 575 of program SAPMSSY0. Also make sure system debug is switched on. Set condition VB_FUNC_NAME = 'CRM_SERVICE_OS_UPD_OST_DU', then click F8 to continue.

5. Breakpoint will stop when FM CRM_SERVICE_OS_UPD_OST_DU is called.

New WEBCUIF Standard Theme: Blue Crystal

$
0
0

The Web Client UI Framework (WEBCUIF) is now offering the new standard SAP Blue Crystal theme. SAP Blue Crystal is the new visual design theme, introduced by SAP Fiori, which succeeds the older Corbu design. It is based on the same interaction design and UI controls as Corbu, but uses different colors. This new visual design offers a modern and fresh look.

 

SAP Blue Crystal can also be used to integrate existing user interfaces into SAP Fiori scenarios. It thus aims to reduce visual disruption between the different technologies. it harmonizes the coloring and design of different controls, but does not resemble Fiori's user interaction, navigation and the like.

 

Characteristics of the "SAP Blue Crystal" design for Unified Rendering:

  • very light design
  • less use of grey colors
  • harmonized coloring with "SAP Blue Crystal" for SAPUI5
  • based on the metrics of "SAP Corbu"
  • uses CSS3 technology

 

01_home.png09_leads_search.png12_leads_search_bar.png13_leads_ovp.png

 

For more information, see SAP Note 2227135 "New visual design Blue Crystal for the Web Client User Interface" and 2239424 "Blue Crystal Theme in Interaction Center".

Common issue when open excel/URL / Cache issue

$
0
0

Hello everyone,

 

Recently we got chance to work on excel download/upload/open functionality from CRM UI.

In result table view of custom application we have some field of type hyperlink, on click of these hyperlink fields we have to display different data of customers

in excel form. The issue we were facing that the open of excel was working only first time means when we were opening excel  on click of hyperlink field it was opening perfectly only for first time but second time none of hyperlink field was working.

Event if we were opening same excel twice , it was not working.

 

I searched this issue on SCN and find number of incomplete threads on the same , so just sharing a small solution that is working fine to remove this issue.

We are using callback class approach to open excel and using window.open() method in .HTM page to oprn excel URL.

 

After preparing all data in callback class when we were opening the URL from HTM page with Window.open() , system was considering the every URL as same one. So to remove this one we have to pass unique URL every time on click of any hyperlink field.

 

so in HTM page we change our final URL as::

 

 

<script type  = "text/Javascript"    language  = "Javascript" >

 

<%   IF lv_our_URL is not initial.  %>

 

 

Window.open("<% lv_our_url  %> , <%   sy-uzeit %> ");

 

 

<%

 

Clear lv_our_url.

 

endif .  %>

 

 

</script>

 

 

Above code made URL unique each time and open excel without any issue.

 

Hope it will Help.

 

Regards,

Harish kumar.

WEBCUIF EhP4 SP01 - Release Notes

$
0
0

These Release Notes focus on new features and enhancements delivered as part of the Web Client UI Framework EhP4 Support Package 01.

 

The WEBCUIF development team members are doing their best to provide those new developments on older releases. So if you are interested in a specific feature, verify its availability by checking the corresponding SAP Note.

 

New Features and Enhancements

 

New visual design Blue Crystal for the Web Client User Interface

 

SAP Blue Crystal is the new visual design theme, introduced by SAP Fiori, which succeeds the older Corbu design. It is based on the same interaction design and UI controls as Corbu, but uses different colors. This new visual design offers a modern and fresh look.

 

SAP Blue Crystal can also be used to integrate existing user interfaces into SAP Fiori scenarios. It thus aims to reduce visual disruption between the different technologies. it harmonizes the coloring and design of different controls, but does not resemble Fiori's user interaction, navigation and the like.

 

See blog post New WEBCUIF Standard Theme: Blue Crystal.

 

See SAP Note: 2227135

 

 

Direct URL for Saved Search

 

A new button "Open Saved Search with a persistent URL" has been added to the Central Search Launcher. When the user clicks on this button, the selected Saved Search will be launched in a new window (or tab depending on the user's browser settings) with a stable URL.

 

direct_url_ss.png

 

See SAP Note: 2211185

 

 

Recent Items filtered on object type

 

This feature allows users to quickly filter out their recent activity without having to go through the whole list. Also, the limits on how many recent items that are stored has increased, allowing each object type to have its own limit.

 

For example, before this feature, if the total Recent Items limit was 5 items, the 6th item is deleted. Now, there will be 5 of each type that is stored in the backend. This way, when the filter is applied, the last 5 of that object type are displayed.

 

recent_items.png

 

See SAP Note: 2181937

 

 

Custom help documents

 

In order to further help and guide the user, it is possible to provide Custom Help content via integration with the Workforce Performance Builder.

 

wpb_integration.png

 

See SAP Note: 2218828

 

 

If you missed them, check out the WEBCUIF EhP3 SP10 - Release Notes


BPath. Lesson 11. Enhancements on sub-queries

$
0
0
Table of Contents ...... Table of Code Examples
<< Lesson 10. Aggregations

 

Hello everybody,

 

first of all I have to apologize pretty much, we simply missed out that there was one lesson pending. So here comes lesson 11 after a quite long waiting period.


As suggested before the chapter mainly deals with the sub function. But enough talking, let's concentrate on the details:

 

Copy data from sub queries using * = sub(...)

 

Upto now it was possible to add data returned by a subquery, either if it was a single field or as reference to a structure or a table. In case it was required to add two fields (e.g. Average and Standard Deviation), this would require two distinct sub queries harming performance and readability.

Now it is possible to using the star operator "as target". In this case the data returned by the sub query is examined. If it is a table or an unstructured field, an error is risen. In case it is a structure all fields of the structure are copied to the result.

 

~*/SearchResFlightRel{@CARRID;@CONNID;@FLDATE;*=SUB(~*/FlightBookRel[@CLASS="Y"]$(*::!Count=Count();!Average=AVG(@LOCCURAM,2);!Median=Median(@LOCCURAM)))}$
Code Example 50,*=SUB(), copy data from sub query

 

Well ok, the example got a bit complicated. But it is worth taking a look at. On the outer side we have list of flights from which we want to return the keys and some data from the sub query. The inner side / sub query works on the bookings using the "aggregate to one value" feature to ensure that the result is a structure and no table. The sub query filters to Class = Y (Economy Class) and determines the three values Count, Average and Median, speaking for themselves. Interestingly Median is mostly the same, guess that's caused by the fact, that it is generated data. Please note also that some of the flights have no bookings, hence the fields remain empty / null.

 

The result of the query is a list of keys plus number, average and median amount (in local currency) of the economy class bookings of the respective flight.

A small remark, in case the complexity above is still not enough for you. I tried to work with a second grouping on the outer level. Actually this should work, except that you do not have the feature you probably want: Access to the data generated within the sub. Every access to a target within the group code is interpreted as access to the group item and not to the actual item.

 

Addings rows from a sub query using $ = sub() [ the OR feature ]

 

Sometimes data might be reached on different pathes and it is wishful to return the data from several pathes instead of a distinctive path. Although it was possible with sub queries to return the data either as linked structure or (using dereferencing) in columns, it was not possible to simply "or" the data assembled by the various sub-queries, meaning to add a new row for every dataset found.

This is now possible using the $= feature which realizes kind of OR. For every element returned by the sub query a new row is added and a move-corresponding is executed. This means that no new columns were added by this statement (in contrast to *= ).

 

See below a non-trivial example of the usage.

 

~*CRMS_BOL_UIF_TRAVEL_CONN_ATT/SearchResFlightRel{!SOURCE:="MAIN"}/FlightConnectionRel{$=sub(~*CRMS_BOL_UIF_TRAVEL_CONN_ATT/.{!SOURCE="SUBQUERY"}/*);!1=@CONNID}/ConnectionCarrierRel/CarrierConnectionRel[@CONNID<>!1]/*$
Code Example 51,$=SUB(), adding single rows from sub query


Data is collected for the Connection object on two distinct pathes. The first is directly related to the connection and is fetched by the sub-query. The other is executing the relation to the carrier and checks which other connections are available, which are also added to the return data. In fact we are returning data as "my connection" OR "other connections". In this example case here, the task could be resolved with standard tools also, but there exist typical examples in real life (fetching emails from contacts, which may be placed under contact, relation ship or address details) requiring this feature.
Please note that in above example only a single element is returned by the subquery (no dollar appears in sub query). If we turn the logic around, we have to return and add a full table, so the code would look like:

 

~*CRMS_BOL_UIF_TRAVEL_CONN_ATT/SearchResFlightRel{!SOURCE:="MAIN"}/FlightConnectionRel{!1=@CONNID;$=sub(~*CRMS_BOL_UIF_TRAVEL_CONN_ATT/ConnectionCarrierRel/CarrierConnectionRel{!SOURCE="SUBQUERY"}[@CONNID<>!1]/*$)}/*$
Code Example 52,$=SUB(...$), adding rows from sub query

 

Note that the subquery accesses the global variable !1, which is set by the embedding query.

Sub queries can also be used (either returning structures or tables) in this manner, in case the embedding queries returns only the first element (as structure). In this case the inner sub query should also return only the first element, since anyway all others are ignored, but syntactically it would be also supported to return a table.

 

Merging structures

 

This enhancement allows to merge structures as in the following self-explanatory example:

 

~*CRMS_BOL_UIF_TRAVEL_BOOK_ATT+~CRMS_BOL_UIF_TRAVEL_FLIGHT_ATT/SearchResFlightRel{$:=sub(*)}/FlightBookRel/*$
<Code Example 53,~STRUCT1+~STRUCT2/./..., merging structures


 

Textsearch()

 

~*/SearchResFlightRel/FlightBookRel[TEXTSEARCH("*ller*")]/*$
Code Example 54,!x:=Textsearch("*"), text search on complete structure

 

Text search provides the feasibility to search the given pattern on all string fields of the structure which have at least a certain size. The size might be specified as second, optional parameter. If not specified only strings with size 9 or bigger are encountered.

 

 

 

 

Well I guess with this last feature we are through with our series.

 

I thank all readers for their interest and the patience as the whole series spawned over a pretty long period.

 

Best Regards, Juergen

Sort Ascending/ Descending on a field in a table view

$
0
0

Purpose

 

Sometimes on a table view, you want to sort the list by a field, you select “Sort Ascending” or “Sort Descending” on the field, but it does not provide the accurate result you expect.

 

One example: you log on with SALESPRO business role, open an account, go to the “ERP Sales Order” assignment block, click on field “Sales Order ID”, select “Sort Ascending”, the result looks like:

Screenshot1.png

This is not the result you expect. I will explain here why the result looks like this.

 

Get the model information

 

1. Press F2 button on the Sales Order ID field and get the technical data:

    component/view: BP_ERPBT/ERPTransactionsOV

    context node: ERPQRORDER

    attribute: VBELN

2. Go to component workbench (TCode BSP_WD_CMPWB), open component/view BP_ERPBT/ERPTransactionsOV, find the context node ERPQRORDER, as shown in the screenshot the base entity of the context node is ERPQROrder. This is the object model used.

component workbentch.png

 

Get the data type information

 

Run TCode GENIL_MODEL_BROWSER, check the radio button Component and enter ERP, then click Display button, expand Query Result Objects, and find the model ERPQROrder, expand the attribute structure, and locate the VBELN attribute

model.png

 

Double click on the VBELN attribute, see the Date Type is CHAR.

data element.png


So even the value of the Sales Order ID field are numbers, the date type used for Sales Order ID field is CHAR therefor it will be sorted as TEXT. This is why you see the result as shown in the first screenshot.

 

You can also set a breakpoint in method SORT_INTERNAL of class CL_CRM_BOL_BO_COL, and check how the sorting works. In this method it will get the date type of the attribute you select to sort, and then execute different coding for different data type, like Date, Time, CHAR, etc.

coding.png

Combining SAP CRM and SAP Screen Personas

$
0
0

 

This is going to be a rather short blog. However, as I didn't read anything related to the topic so far I think is worthwhile sharing my experience.

 

Introduction

Since the first time I saw a demo of SAP Screen Personas on SCN I really liked the idea of being able to change the look and feel of existing ERP transactions. Therefore, I immediately installed the add on on one of our internal development system and tried it out. However, as earlier versions of SAP Screen Personas required the installation of Silverlight at the client computer I never started to roll it out for our customers.

In version 3 SAP Screen Personas was redesigned to no longer require Silverlight at the client computer. Therefore, I started to look at possible usage scenarios for SAP Screen Personas again. One scenario that immediately came to my mind was the simplification of ERP transaction integrated into SAP CRM using the transaction launcher technology.

 

Note that in this blog I won't give any introduction to the SAP Screen Personas functionality. A comprehensive collection of demo's and learning content for SAP Screen Personas is available here: SAP Screen Personas – Getting Started

 

SAP CRM Transaction Launcher

In short, the SAP CRM transaction launcher is a technology to integrate ERP transactions into SAP CRM. This is require if, for example, if no suitable SAP CRM functionality is available but a process needs to be executed from with SAP CRM. The integration of the ERP transaction into the SAP CRM Web UI is achieved using SAP GUI for HTML. If you are interested in further details regarding the transaction launcher technology as well as other usage scenarios I reccomand reading the two excellent document Almost Everything About Transaction Launcher - Part I and Almost Everything About Transaction Launcher - Part II by Hasan Zubairi.

One of the processes where we use the the integration of ERP transactions into SAP CRM is changing the contract account in the future via transaction CAA2. The layout of the transaction when displayed in the transaction launcher is shown in the screen shot below. As usually for ERP transaction it contains quite a number of fields that are not required in all processes variants.

2015-11-16 10_03_21-Vertragskonto ändern (IS-U) - [Interaction Center ] - Internet Explorer bereitge.png

Using SAP Screen Personas we could simplify the transactions to the required set of fields. An example of such a simplified transaction is shown in the following screen shot. From the screen shot it is immediate obvious, that it is possible to combine SAP Screen Personas and SAP CRM.

2015-11-16 13_36_07-Unbenannt - paint.net v4.0.5.png

Configuring Transaction Launcher with SAP Screen Personas

So the question now is what is required to integrate SAP CRM transaction launcher and SAP Screen Personas. After executing the necessary post installation steps for screen personas (cf. Pre- and post-installation Checklist) the configuration is quite straight forward. Using transaction CRMS_IC_CROSS_SYS it is only necessary to change the URL for ERP_ISU from http://<server>:<port>/sap/bc/gui/sap/its/webgui/!?~transaction=IC_LTXE&~okcode=ICEXECUTE&sap-client=100 to http://<server>:<port>/sap/bc/personas/!?~transaction=IC_LTXE&~okcode=ICEXECUTE&sap-client=100 (cf. the following screenshot).

2015-11-16 10_14_12-Sicht _Logische Systeme und URLs für Transaktionsstarter definieren_ a.png

After this, all ERP transaction integrated into SAP CRM via the transaction launcher technology are rendered using Screen Personas. Furthermore, it is even possible to adjust the transaction using Screen Personas directly from within the SAP CRM session.

 

Christian

those things about framework enhancement

$
0
0

Purpose:

In this article, I will show how the framework enhancement is managed, where to find related information, the navigations between SE18 enhancement spot tool and enhancement implementation tool, and some other related information.


Introduction

We have known about new Framework enhancement technology.

 

In CRM system, the mostly used technology is Kernel-BADI enhancement. For example, BADI component_loading is integrated into enhancement spot COMPONENT_HANDLING. BADI CRM_BP_UIU_BT is part of enhancement spot CRM_UIU_BP_ENHANCEMENT.

 

Even though I don’t use it, but I also found Source Code enhancement spot es_crm_btx_eew_wzd in function group CRM_BTX_EEW_WZD.

 

Of course, implicit enhancement interfaces are also provided in classes, function modules, subroutines, etc.

 

We can find lots of documents regarding framework enhancement - about the advantages, about the four technologies which are used for different purposes, about how to create implementations,  etc. For example:

The new Enhancement Framework and the new kernel-based BAdI

Enhancement Framework in ABAP - Blog 1

Enhancement Framework in ABAP - Blog 2

...

 

Prerequisite:

  • Understand the framework enhancement technology
  • Basic knowledge on how to create implementations for an enhancement spots


Objects:

In order to make it clear, the objects I will create are:

  • A package ZPACK_CORRI.
  • My own program Z_REP_CORRI, and include file Z_REP_INCL under package ZPACK_CORRI.
  • Enhancement spot ZENH_CORRI_SPOT1 with enhancement point Z_POINT1_1 in program Z_REP_CORRI,
    Enhancement spot ZENH_CORRI_SPOT1 with enhancement point Z_POINT1_2 in include file Z_REP_INCL,
    Enhancement spot ZENH_CORRI_SPOT2 with enhancement point Z_POINT2_1 in program Z_REP_CORRI.
  • Another package ZPACK_CORRI_TMP.
  • Enhancement Z_POINT11_SPOT1 for enhancement point Z_POINT1_1 for enhancement spot ZENH_CORRI_SPOT1.
  • Enhancement Z_POINT12_SPOT1 for enhancement point Z_POINT1_2 for enhancement spot ZENH_CORRI_SPOT1.

 

Steps:

  1. In Z_REP_CORRI, put cursor in the expected line, then go to menu 'Edit'->'Enhancement Operations'->'Create Option'. In the pop up dialog, input enhancement point Z_POINT1_1, enhancement spot ZENH_CORRI_SPOT1, package ZPACK_CORRI.
    1 add a point and spot.PNG
  2. In the same way, create enhancement point Z_POINT2_1 for enhancement spot ZENH_CORRI_SPOT2.
    2 add a point and spot 2.PNG
  3. After that, enhancement spot ZENH_CORRI_SPOT2 is also created.
    3 after report points added.PNG
  4. Create enhancement point Z_POINT1_2 for enhancement spot ZENH_CORRI_SPOT1 in file Z_REP_INCL. This time, since enhancement spot ZENH_CORRI_SPOT1 has already been created, we just need to select the entry.
    4 add 2nd point for spot 1.PNG
  5. After added the enhancement point in file Z_REP_INCL.
    5 after add point in inclu.PNG
  6. Double click enhancement spot ZENH_CORRI_SPOT1 on the left side, it will navigate to the enhancement spot tool.
    6 spot 1.PNG
    Actually, this enhancement spot tool is SE18 itself.
    7 se18 for spot 1.PNG
    click 'Display' button, it goes into the same screen.
    8 se18 inside.PNG
  7. Let's go to 'Enhancem. Implementations' tab. There is nothing because there is no any enhancement yet.
    9 enhancement impl..PNG
  8. Now, create an enhancement for enhancement spot ZENH_CORRI_SPOT1 in point Z_POINT1_1. The enhancement's name is Z_POINT11_SPOT1. I put this enhancement under the 2nd package ZPACK_CORRI_TMP(Of course, you can put it under any package even ZPACK_CORRI itself also. But as I'm simulating the process, I pretend that package ZPACK_CORRI is standard developer package while ZPACK_CORRI_TMP is customer package).
    9-1 create an enhancement for point 1-1.PNG
  9. Let's check the implementation tool under package ZPACK_CORRI_TMP. From here, we can also go to enhancement spot tool.
    9-2 implement tool.PNG
  10. Of course, if we goto 'Enhancem. Implementations' tab again, an entry is added. If we double click the cell of 'Z_POINT11_SPOT1', it will navigate to the same implementation tool as in above point 9.
    9-1.5.PNG
  11. From implementation tool, if click 'Editor' button, it will navigate to the ABAP editor. If click 'Source' button, the enhancement source codes will be displayed in the same screen.
    9-3 check source.PNG


 

 

Additional information:

I made above samples from my own Z programs. Actually, the normal way to use enhancement spots are:

  1. SAP developers create enhancement spots, provide enhancement points in SAP delivered standard programs.
  2. Then enhancements will be created by SAP developers for utility purposes. In this situation, the enhancements will be provided to customers as a part of SAP standard. Or the enhancements can be created by customer per their business requirements. At this time, the enhancements’ names of course will start with Z or Y.

 

For example:

enhancements by different purpose.PNG

From this source codes, double click ES_SAPMV45A, it navigates to enhancement spot tool. Go to 'Enhancem. Implementations' tab, the customer enhancement ZMY_IMP_CORRI can be found. Of course, we can find ECO_HBS_SAPMV45A, /SAPMP/SALES_ORDER_V_SAPMV45A, etc also.

9-4.PNG

 

If you are interested, please check the same information in DB table

9-5 db table.PNG

 

Related DB tables:

ENHSPOTHEADER, ENHOBJ, ENHLOADINVAL, ENHHEADER, ENHSPOTNAME_TYPE, ENHSPOTOBJ, ENHOBJCONTRACT, ENHINCINX, ENHLOG, ENHTAB, ENHDEPENDENT

How transaction launcher determines the remote system

$
0
0

Purpose

Sometime you faced the problem that the remote system is not determined correctly while calling a transaction launcher. This article will show how transaction launcher determines the remote system.

 

Introduction

Basically there is a static way to determine the remote system but also with release CRM 7.0 and higher, it comes with a feature to determine the remote system dynamically as business need it. for e.g. documents of different ERP systems should be displayed.


Determine the logical system from transaction CRMS_IC_CROSS_SYS

While configuring the transaction launcher, a Logical System is specified.

configuretransactionlauncher.PNG

System reads the mapped logical system in transaction CRMS_IC_CROSS_SYS.

transaction CRMS_IC_CROSS_SYS.PNG

This is a static way of determining the remote system.


Determine the logical system from Global Data Context (GDC)

Sometime business needs to use multiple remote systems. You can check the “MultiSys” checkbox in transaction CRMS_IC_CROSS_SYS.

multiplesys.png


Then the transaction launcher will read the attribute LOGICAL_SYSTEM from the GDC which can mainly happen in the interaction center.

You can check method CL_CRM_IC_ACTION_UTIL=>GET_LOGSYS_FROM_MAPPING from technical point of view.


Determine the logical system using enhancement spot WCF_LTX

System also has the enhancement spot WCF_LTX which contains the BAdI WCF_LTX_BADI with its method ADJUST_LOGSYS. This method will be called during the initialization phase of the transaction launcher. You can set a breakpoint in method INIT of the transaction launcher

handler class to check the BADI.

Viewing all 195 articles
Browse latest View live


<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>