Quantcast
Channel: SAP CRM: Webclient UI - Framework
Viewing all 188 articles
Browse latest View live

Make a field Dynamically Mandatory - Custom Solution

$
0
0

Overview

Disclaimer: This blog post was originally created internally and i apologize for any sarcasm or criticism that i unintentionally leave in the blog. It is my hope that this basic guide will assist anyone searching with creating dynamic mandatory fields by providing a clear and detailed description how to do it.


If you have not read the section about creating dynamic mandatory fields first then go do that now, otherwise if you have just read that or read it previously...

 

Welcome Back! In this section I will describe a custom solution to complete the dynamic mandatory field development done previously so that some existing SAP errors no longer plague you. To solve our woes we will implement a custom class, I will provide a file for this, however, be aware that some standard enhancements were made to allow some functionality to work. I will attempt to describe the custom class here but be aware that some modifications may need to be made to make it function perfectly. I have attempted to remove references that use standard code enhancements but there is the potential that some still exist.

 

Please note that this tutorial assumes the developer has a general understanding of UI components, context nodes, and their various getter methods. Also the developer has read the previous section and knows how to make a field dynamically mandatory.


Introduction

As described the current SAP implementation(at least for the version we have) is flawed. Mandatory fields are checked in the DO_FINISH_INPUT and through the first configuration of the page... When you set the field as mandatory in the P Getter as previously shown this code will be called in the DO_PREPARE_OUTPUT method of your UI Component View Controller. This is going to be fine to load a page and set the field as mandatory first time round. Unfortunately, when another field changes, which forces the conditions of your mandatory field in the P getter the order of checking fails to identify that the mandatory states have changed. The reason is as follows(in a simplified roundabout description):

 

DO_PREPARE_OUTPUT(Calls P Getters setting up conditions) -> |User Input Changes|(Hopefully triggering your conditions) -> DO_FINISH_INPUT(Gets the current mandatory fields and applies the messages)

 

!-- Page Refresh -!

 

DO_PREPARE_OUTPUT (Calls P Getters setting up conditions) -> |Page ready for user input again|...

 

The flaw here is that on first load the page checked the conditions and the fields are set as mandatory/not-mandatory, then the user makes some changes. Next the do_finish_input method is called which adds the messages but it uses the mandatory fields that it knows of since the page was loaded! There is no check to see if the conditions have changed, which may have modified the state of the mandatory fields. Now from here you can debug through and make necessary changes to get it to work for you. You can probably guess that your going to need to check the conditions again. Well this is going to be annoying to do every single time you want to configure a new view with some dynamic mandatory fields on it. To solve this issue i created a custom class.

 

NOTE: The following steps ONLY work for a totally custom view... IF you are enhancing a standard component you could copy the ZCL_BSP_VIEW_CONTROLLER class to a custom version and change IT'S super-class to be the same as the enhanced view controller.

 

Custom Controller Class

The custom controller class provides a bunch of functionality to reduce the need to re-create that functionality for each view for example the following features exist:

  • Enhancement to determine if mandatory check is required.Can make use of the MV_GLOBAL_EVENT attribute.
  • Enhancement to check 'P Getters' for registered context nodes prior to getting the empty mandatory fields which fixes the issue discussed below'
  • Enhancement to remove messages for specific events e.g. EDIT
  • Enhancement to create the view_group_context if it is initial.
  • Enhancement to solve an issue where global messages don't block save in overview pages

 

Click here for the custom class as a .nugg file.

 

Step 1: Add the ZCL_BSP_VIEW_CONTROLLER class as a super class

Go to your class definition and navigate up the hierarchy until you locate the standard CL_BSP_WD_VIEW_CONTROLLER class sitting as the super class to your Z* class and 'Change Inheritance' of the class so that ZCL_BSP_VIEW_CONTROLLER is now the super class.

bonus01a.jpg

Step01b.jpg

 

Step01c.jpgStep01d.jpg

 

Step 2: Register the Context Node(s) that have the Dynamic Mandatory Fields

This step is required as otherwise the conditions will not be rechecked. You could imagine that if we didn't have dynamic mandatory fields and just always rechecked every single attribute for every single context node on finish then efficiency would suffer. However, SAP standard does do exactly that in many other instances so you could choose not to care and follow their example. In this case, if using this class you need to register the node.

 

Right click the DO_FINISH_INPUT method of you controller class and 'Redefine' it (my screenshot shows this has already occurred).

Step02a.jpg

 

Add the code to as shown to register the applicable context node(in my case its some PERSON node)

Step02c.jpg

 

Bonus 1: Don't Check on Certain Events

Now that we have our custom class in place some bonus functionality is available. As shown if we have an event where we don't need to see irritating messages in the header we can remove the messages. In this case the fields are mandatory(shown with a red *) but we are not spammed with a message. But sometimes we might not even want to check for messages. For example the standard implementation kindly checks if the fields are mandatory for us when the user clicks the cancel button... Most circumstances dictate that there really is no need to check on a cancel event so we can override the IS_MANDATORY_CHECK_REQUIRED method and provide our own custom results. By default the custom class checks if the view is in display or edit mode for example before even checking for mandatory fields. We can include or remove that functionality once redefined or add our own criteria. Just remember to return a true or false result no matter what you choose to do...

 

The below example shows overriding the above mentioned method, including the check for display mode etc, and choosing not to check when the event is 'CANCEL'.

bonus01a.jpg

bonus01b.jpg

bonus01c.jpg

 

Bonus 2: Add a Custom Error Message(* Removed as requires standard enhancement)

I won't describe this as it used a standard enhancement to the CL_BSP_MESSAGES class to allow modifying a message by absolute ID(known as 'dummy' in the standard code).


Make a field Dynamically Mandatory

$
0
0

Overview

Please note that this blog was originally created internally and i apologize for any sarcasm or criticism that i unintentionally leave in the blog. It is my hope that this basic guide will assist anyone searching with creating dynamic mandatory fields by providing a clear and detailed description how to do it.

 

When a field is required to be mandatory, the easiest method is to set the field as statically "Mandatory" via the page configuration. In order to do this you would go to the page configuration view and set the "Mandatory" checkbox. This means that the field is disabled on the current configuration of this view. Often, however, we have some requirement to set a field as mandatory, based off some entries or values of the current view context. This is completed as follows:

 

Please note that this tutorial assumes the developer has a general understanding of UI components, context nodes, and their various getter methods

 

Step 1: Redefine / Generate the P Getter method

The P getter is a 'Property' getter method that receives an input argument dependent on a set functionality check. Sometimes this method is already defined and you simply have to right click and 'Redefine' the method. Other times, as shown below, you need to right click and 'Generate P-GETTER'.

The result should be as follows:

step01_a.jpg

Step 2: Modify the P Getter method to handle the check for Mandatory

When the awesome P getter method is repeatedly called, a parameter is passed to show what check is being executed so we create a switch / case statement to handle the input variable.

 

Double click into the above highlighted method and enter the following:

step02_a.jpg

As shown you do your custom logic in the area mentioned in comments, returning abap_true(X) or abap_false( ) depending on your custom logic.

In my example i need to check an attribute in a structure of the current view controller class so this will be easy as the attribute is stored as an abap_bool already.

step02_b.jpg

Step 3: Set the input type to ensure no 'complications' occur

One important thing to note about the P Getter is, as previously, mentioned... it is repeatedly called and the return value is different depending on what the input was. Throughout the processing of preparing a page, setting details and so on the P getter is called with various inputs. Due to this..., it is important to set the input type here as we have redefined the property getter and the field may no longer know what type of input it is. The following code is required:

step03_a.jpg

I should point out that this is the same way we change the input type to other types. There are a range of options you are welcome to explore. Some examples are:

cl_bsp_dlc_view_descriptor=>field_type_picklist - (a drop down list box)

cl_bsp_dlc_view_descriptor=>field_type_textarea - (a text area field)

cl_bsp_dlc_view_descriptor=>field_type_checkbox - (you get the idea...)

 

At this point the functionality should 'Sort of' work or ... 'Function as Designed' according to the following official  link:

 

http://help.sap.com/saphelp_crm700_ehp01/helpdata/en/e3/a7340445e14d94ad7ccd8ae2be93db/content.htm

 

Unfortunately the reality is that this is flawed and further steps are required to fully make your view attributes dynamically mandatory. To see this just leave this as is and try changing the settings as required to trigger your mandatory rules. You should find that initially the page finds the mandatory fields without any problem. But when changing other fields that may make your field become mandatory, the field will not realise it is now mandatory until 2 page refreshes. This is, however, the first step

 

The follow up which includes a brief summary of the issues mentioned can be found here

AXT Rapid Applications Currency/Quantity fields

$
0
0

SAP_BASIS SAPKB73105

SAP_ABA    SAPKA73105

WEBCUIF    SAPK-73105INWEBCUIF

BBPCRM     SAPKU70204

 

Introduction:

 

I created 2 custom tables (header/item model) and I wanted to maintain those tables in the Web UI. So I decided to use Rapid Applications in order to generate the Web UI components. For more information about Rapid Applications:

 

http://help.sap.com/saphelp_crm700_ehp02/helpdata/en/23/fb4e7b70e54ca092fca55f261a74d9/frameset.htm

http://scn.sap.com/docs/DOC-5404

http://scn.sap.com/docs/DOC-5405

 

The main problem that I had is regarding to the header table, which has the ref field for the currency and the items had the currency amount, this scenario is not supported by rapid applications:

 

http://help.sap.com/saphelp_crm700_ehp02/helpdata/en/6e/29cec294bc45abbd45b48370e7a183/content.htm?frameset=/en/23/fb4e7b70e54ca092fca55f261a74d9/frameset.htm

 

  • The reference fields for currency and quantity must be in the same table.

 

The generation of the Rapid Application will skip those fields and generate the component, I'm saying this because it's easy to: next-next-next-next and wow! what's happening?! why the currency amount fields are not in the view!?

 

Unfortunally for me was too late to re-do the model so I needed to come with a workaround.

 

Caution!!!

 

All the steps which I describe will be removed in case that you re-generate the RA via the Rapid Application Development Tool

 

STEPS:

 

BOL/GENIL/API

 

The RA framework generates those structures for each table:

 

ZTABLENAME_ATTR

ZTABLENAME_DYN_QUER

ZTABLENAME_H_LOG_KEY

ZTABLENAME_H_WORK

 

For this scenario the important structures are the ones finished with ATTR and WORK, which you need to add the currency amount field (For technicall reasons don't forget to specify the ref table for amounts/quantity in both structures although this is not relevant for the RA).

 

Once added the fields the GENIL/BOL layer is almoust done, you also need to modify the API generated to update the DB, for each RA application will generate a function group ZAFUGR* with a function for each table usually  ZAFUNC*. This Function modules are generated from the template AXT_TABLE_UPDATE_CT_TMPL, you can check it at SE37.

If you observe the source you will see there's no need to worry about the insert but the update is generated for each field during the RA generation, so the new one won't be there, this requires to add it manually. No problem so far, is a Z function module

 

Web UI

 

If you let the RA framework propose the component structure you probably will have the following views:

 

ZCOMPONENT/Embed_TABLENAME_HEADER_SRC_Form

ZCOMPONENT/Embed_TABLENAME_HEADER_SRC_Table

ZCOMPONENT/Embed_TABLENAME_HEADER_SRC_VS

ZCOMPONENT/TABLENAME_HEADER_DETAILS

ZCOMPONENTTABLENAME_HEADER_OVP

ZCOMPONENT/TABLENAME_HEADER_SRC_SRC_QUERY

ZCOMPONENT/TABLENAME_HEADER_SRC_SRC_RESULT

ZCOMPONENT/TABLENAME_HEADER_SRC_SRC_VS

ZCOMPONENT/TABLENAME_ITEMS_DETAILS

ZCOMPONENT/TABLENAME_ITEMS_MAIN

ZCOMPONENT/TABLENAME_ITEMS_OVP

 

We will enhance the ITEMS_DETAILS and the ITEMS_MAIN views:

 

View: * ITEMS_DETAILS

 

We need to add the currency amount atribute as a model attribute in the item context node, the attribute will be avaliable as we already added it at the structure *ATTR in the bol/genil/append step.

The only really important thing left is do de input/output conversion in the SETTER/GETTER method, To acomplish this is quite easy:

 

Capture.JPG

 

Capture.JPG

 

For a friendly interface you can also add the currency reference field in the context node as an value attribute.

 

Capture.JPG

coding in the getter to retrieve the root attribute (as we did in the GET_COND_PRT method) and disabling permanently the field in the GET_I_REF_CURRENCY method, we need to add the new attribute in the configuration but for me there's no point on disabling it there.

 

 

View: * ITEMS_MAIN

 

In this case the items are represented as a tableview and this gave me some troubles in the moment to add currency reference as value attribute.

 

Capture.JPG

Creating it via right click on the contex node(as we do usually) give some syntax error so instead of that we need ro redefine the INIT mehtod and put the following code

 

Capture.JPG

 

And create the getters/setter method manually in the context class, yes you hear it well, manually, remeber getter/setter methods must be public, otherviwse te atrribute  won't appear in  the context node

 

The steps for coding the getter/setter are the same which wie did in the view *ITEMS_DETAILS

 

And that's it, the only need left is add the fields in the configuration.

 

Conclusions:

 

Well as you see we did an extra steps in order to avoid having the currency/quantity reference field at item level, another aproach can be having those fields in both header/item and trasspasing the value via the BADI  AXT_RT_TABLES_API - ON_CHANGE

 

There's documentation in the BADI definition or in the class CL_AXT_CUSTOMER_TABLES_UTIL

 

you can also go to the following blog:

 

http://scn.sap.com/community/crm/webclient-ui-framework/blog/2013/07/11/table-enhancements-for-aet-views

 

 

Hope it helps!

 

Luis

Active check for web UI transactions.

$
0
0

Hi,

 

In our last projects when clients upgrade their CRM versions from lower to higher we faced some common issues.One common issue is to know how to check whether a transaction is creating using GUI or using WEB UI.

This is needed because in CRM lower versions clients used number of custom GUI enhancements in their business Add Ins and user exists and in other places to show GUI pop up, screens etc.

So at GUI level they want the same working environment and but when user logon from WEB UI these same BADI and exits having custom code for GUI popup,dialog box,screen calls which always create problem.

To avoid to run this unwanted code we used a standard Class which is CL_GUI_CONTROL.The class CL_GUI_CONTROL has number of methods and parameters to control GUI operations.

Parameter WWW_ACTIVE, GUI_IS_RUNNINGof  class CL_GUI_CONTROL played a very important role for all this.

 


 

This parameter is in Active state when transaction is calling from GUI .

 

Some used cases:-

We have Exit for GUI EXIT_SAPLSUSF_001  which calls when user logon to GUI . In this we have to call a screen for particular user id when that user logon to GUI and not for UI ,but when the same user logon from web UI and call some GUI transaction with Transaction launcher then the code for call screen was creating problem with UI.So for this we have used same parameter as :-

 

 

Similarly we have used this parameter in BADI Order_save to allow GUI popup only when creating transaction from GUI only .

   Hope this will help someone.

 

Regards,

Harish Kumar

Table Personalization: New enhancement features

$
0
0

Hi All,

 

This is about the feature which is most awaited by many of the End Users and Consultants too.

 

And that feature is - The search result page should retain the sort order for the user throughout the session as well for any new session similar to the saved search functionality.

 

I have interacted with end users who felt, the search page should remember the sort order, instead of making users to sort the search results every time manually when they perform a search on the attribute they need as well in every new session.

 

That would definitely save them a few clicks and increase their productivity & usability.

 

This had been posted in the UI Wish list as well in the wiki https://wiki.sdn.sap.com/wiki/display/CRM/CRM+WebClient+UI+Wish+List

 

When these users complained about this, me and one of my colleague felt won't it be good to have a configuration feature which would enable us as consultants to configure on which column field and in which order( ascending or descending ) the search results should be sorted.

So finally I think that wish is fulfilled now.

 

I have come across this note which speaks about the new Table Personalization enhancements features which are introduced in the latest Service Packs.

https://service.sap.com/sap/support/notes/1855398

 

To have access to these new features you must install the relevant service pack as below:

WEBUI 701 SP11
WEBUI 731 SP08
WEBUI 747 SP01

 

I am awaiting a system with the new SP level to check on how this exciting feature works.

 

Nevertheless this is a great feature which enables users to personalize the sorting, filtering and fixed columns for tables across the Web Client UI.

At the same time it is giving the Consultants/Power users the functionality to configure the sorting and fixed columns for all the users.

 

Hope this blog will help the consultants who have complaining-users about this missing feature!

 

Regards

Vinod

Custom PDF Fachsheet

$
0
0
Requirement : Generating custom PDF Factsheet.
Standard Smart form: CRM_ACC_ACCOUNT_OVERVIEW_PRN
Standard Class: CL_UIU_PRN_ACCOUNT
Method that gets called: COLLECT_DATA
Copy the standard form to Z*SMARTFORM
Copy the standard class: ZCL_*PRN_ACCOUNT (Including all methods)
Settings in SM30: CRMV_PRN_CONTROL
Role:                        SAP_CRM_UIU_SLS_PROFESSIONAL     or (Z*role)
External Object:    BuilHeader
Form Name:           Z*SMARTFORM
Class Method:        ZCL_*PRN_ACCOUNT
View:                       001
Settings in SM34: CRMVC_BUIL_PRT
Same as Above.
Can cross check the tables
CRMC_PRN_CONTROL and CRMC_PRN_CONTR2.
Will display some fields like name, employee responsible territory some marketing attributes, custom fields, in the factsheet:
Create the pages and windows as per your requirement and variables to print on the factsheet.
On UI, when you select the PDF Factsheet option, the method collect method of the class ZCL_*PRN_ACCOUNT     gets triggered.
1.PNG
When you select PDF fachsheet ,
2.PNG
So the BP value gets stored in the print variable, you can access the same in the smart form.
3.PNG
Now the coding for displaying the account fax ,telephone ,name can be done in the INITILIZATION TAB.
First create the page and Text variables to hold the name and the data.
Declare the variable data to be print on the factsheet in the output parameters and in the global declaration.
If you  consider the BP ID ,fax ,telephone
5.PNG
6.PNG
To get the name fax city write the coding in initialization tab
7.PNG
Output:
4.PNG
If you want to display the factsheet on the user logon language then, first maintain the required translations and then make changes in the collect method (ZCL_*PRN_ACCOUNT ).
Declare and change the control parameters and pass the FM lv_fm_name
9.PNG
Output :
10.PNG
Checks to be done:
If Z* business role is used, it should mapped to PFCG role, you can check in the table crmc_ui_profile, else the more option will be in disabled mode.
8.PNG
Hope it helps!!

Enable/Disable Conditions fields in Web UI

$
0
0
ComponentSupport Package
SAP_BASISSAPKB73105
SAP_ABASAPKB73105
WEBCUIFSAPK-73105INWEBCUIF
BBPCRMSAPKU70204

 

Hi,

 

In my previous blog Add/manage complex help searches on Conditions views in Web UI I explained how you can use complex search helps in the Web UI conditions maintenance, now is the turn to enable/disabel fields. As you already realized, the condition doesn't relay on the Web UI configurations, depends customizing and coding. So if a customer ask to disable fields on some critera what should we do?

 

Scenario 1 view CRMCMP_CND/CondRecEditConfView

 

There's no major problem here,  as you alread know, Just put the logic on each GET_I* method, as easy as this.

 

Scenario 2 view CRMCMP_CND/CondRecEditListView

 

Here is where the party starts, the properties of the table view can not relay on the GETTERS/SETTERS because each condition fields can have different( mandatory enabled/disabled fields, etc.) as they relay to customizing and how you have defined the condition tables.

 

Capture1.JPG

Capture2.JPG

 

I know the language doesn't help, but for what I whant to show, doesn't need to be in english

 

As you see in the first screenshot, the conditions is "Dto. Producto Establ/ID Pr.." this conditions refers to a condition table which has a specific key and specific fields, In the second screenshot I add a row which points to a different condition, "Dto Val. Cant. Distr/Produ...", as you are realizing some columns are grayed out and some other not, this is due the condition table related to the second condition has his specific fields and his specific key, which doesn't have to be the same as the previous condition and viceversa, this is the main reason the GET_I* will not be used, GET_I is columm dependent, not column/row dependent, now you will say: "ok, ok, I get it, now give me the solution" unfortunately the standard is "not prepared" for that I said "prepared" because in some way it is, but won't cover our scenario without an "extra efffort".

 

You have the BADI /SAPCND/MNT_USAGE which you can control this behaviour with the method SET_EDIT_STATES_ITEM,good news until you read the BADI interface documentation(/SAPCND/IF_EX_MNT_USAGE)

 

This feature is available for the following methods: HIDE_ATTRIBUTES_ITEM,  PUT_BEFORE_IMAGE_TO_DBA, SCALE_DEFAULT_CHECK, SCALE_F4_HELP, SCALE_ADD_DIMENSION, SCALE_SET_SCALE_BASE_TYPE, SCALE_SET_SCALE_UNIT. For all other methods, overriding is not possible. The following holds true for the methods that can be overridden:

 

It's a bit weird because the BADI is not meant for multiple usage, but you can implement your version as long as you use the methods which SAP specifies in the documentation...in resume, this won't work for us because we need the method SET_EDIT_STATES_ITEM.

 

The class CL_IM_FGD_USAGE_CND_CRM is the one who manages the SET_EDIT_STATES_ITEM method, so if you need to enable/disable fields on some criteria you will need to create a enhancement spot at the end of the method to edit the changing parameter CT_ITEM_LINE_FCAT.

 

The good news is this changes will apply as well to the view CRMCMP_CND/CondRecEditConfView!

 

As is an implicit enhancement spot, you should do it with care and of course with your own resposability!!

 

I hope you find this usefull.

 

Cheers!

 

Luis

Account hierarchy from ECC to CRM

$
0
0
This blog shall guide you how to retrive the BP from the account  hierarchy using some standard FM's when data is passed from ECC.
Requirement : To check if the BP transferred from the ECC, is in the 8th level (Account hierarchy), if yes then capture the BP's on the 6th and 7th level of the hierarchy.
Pre-requisites:
Both ECC, CRM having the Account hierarchy present and connection between ECC and CRM should have been set-up.
Format of the Hierarchy Node: BP/salesorg/division/channel
                                                   e.g.  8986932/13002010
So when a customer is created or changed in ECC (based on some factors like industry key, group), along with all the details of the customer, we need to capture the hierarchy and get the BP of the above levels.
Standard FM (CRM): CRM_BUPA_MTCS_TO_MAIN
Create an implicit Z* enhancement:  Z _BUPA_MTCS_TO_MAIN.
1.png
Let take some BP: 555136 at CRM in BPH Tcode, it's on the level 8th and the above level BP No's are 625587 and 762605
2.PNG
These need to be mapped with the BUT000 custom fields L6, L7 Account.
These values need to populate automatically when the data from ECC is created or changed.
So code in the standard FM CRM_BUPA_MTCS_TO_MAIN
You will get the BP no from the ECC:
3.PNG
4.PNG
Now get the path of the BP, if it is in the 8th level or not.
Table: BUT_HIER_NODE
Check in the Hierarchy Node as from ECC it will be in above mentioned format and BP without leading zeroes.
6.PNG
And now give the above hierarchy node guid in
FM:  BUHI_GET_PATH_BY_NODE and get the path.
7.PNG
8.PNG
Then take the hierarchy node guid of the level 1 and 2 respectively and use below FM to get the BP's.
9.PNG
10.PNG
Use update statement to update the BUT000.
12.PNG
Hope this helps!!

Steps to test Asynchronous Web services - SPROXY

$
0
0

Why separately and not in SPROXY?

 

This is because, when we test Asynchronous service like CustomerCRMChangeRequest_In, the response will not be posted immediately. But it would be posted asynchronously separately and the response will be using the service CustomerCRMConfirmation_out. Usually errors will not be shown in Asynchronous
services testing but there will be an exception raised like following:

WS.jpg

 

 

How we can see the errors raised out of Asynchronous services?

 

  • Download the XML from SPROXY by clicking on the button as shown below:

WS1.jpg

  • Now execute the report SE_COUNTERPART_TEST_TOOL and fill up the data as shown in the screen shot and execute.

     WS2.jpg

         WS3.jpg

  • After this is performed, open the transaction SXMB_MONI and click on "Monitor for processed XML messages".
  • Select the status group as "Errors".
  • Click on the red flag as shown in the screenshot below:

          WS4.jpg

  • Now you will be shown with the actual error which has happened and this will not be displayed in the SPROXY directly for Asynchronous services. This is an error thrown in the Text collection data set of Accounts.

        WS5.jpg

  • These errors will be shown in the response message of the synchronous services. For Asynchronous services, we need to rely on a OUT service to actually log the error.
  • If there are no errors in the service, confirmation will be shown as below:

        WS6.jpg

            WS7.jpg

 

I hope this short blog helps to identify and check the errors thrown in the Asynchronous services and help to analyse the errors to resolve it.

 

Regards,

Venkat

         

         

Inside AET: why "create field" button is visible in some UI while invisible in others?

$
0
0

recently I was asked by one customer why they can create extension field via AET in intellectual property overview page:

can.png

                                                                  Figure1

however they cannot see the "create field" button when trying to enhance "edit scope" page:

cannot.png

                                                            Figure2

 

in order to explain this discrepancy, it is necessary to understand how does AET work. The SAP development will make registrations on those Business object which are considered as extensible and you can view the registration via tcode AXTREG:

 

clipboard.png

                                                            Figure3

 

Below is an example for PRODUCT:

sample.png

                                                            Figure4

 

So it is not technically possible to extend one UI which is created based on a non-extensible BO.

 

Let's analyze why the second ui could not be extended. Just set breakpoint on the method below, which can be used as an entry point for your trouble shooting on such kind of issue:

 

e1.png

                                                            Figure5

 

The framework will first check whether there exists an extensible BO which is dedicatedly registered with an UI component and its child view -

nothing found. Then try to check design layer assignment.

 

design.png

                                                            Figure6

 

The reason to try with design layer assignment is that the context node of ui view could be assigned to design layer object while the latter always belongs to one ui object. The ui object type is mapped to Genil component, BOL object, BOR object, and one extensible BO if any. See below example for UI object type PRODUCT ( view via tcode BSP_DLC_SDESIGN_DL)

 

ui object.png

                                                            Figure7

 

as displayed in the above picture, there is no design layer object assigned for edit scope view, so finally "create field" button is not rendered at all, according to the logic below:

button.png

                                                            Figure8

 

Now go back to the first example. The first check fails as well, however 18 design layer assignments are found:

 

 

design have.png

                                                            Figure9

 

it shows there are so many context nodes of the view which are assigned to design objects

18.png

                                                            Figure10

 

we can also find such assignment relationships in ui component workbench:

workbench.png

                                                            Figure11

 

w2.png

                                                            Figure12

 

get the respective UI object type by design object:

get ui object.png

                                                            Figure13

 

Now the extensible BO maintained in ui object type is evaluated. Now there would be one entry appended to result table, so finally "create field"  button is enabled.

check.png

                                                            Figure14

 

Summary: if "create field" button is invisible or disabled ( in lower release ), it is not the issue of AET itself but simply because that UI is not regarded as extensible by AET at all.

Attachment to Business Partner or Product in CRM

$
0
0

This Blog is a step by step tutorial for attaching documents to a Business Partner and Product in CRM using ABAP from Application Server.

 

Business Partner is a Person, Organizations and Group to which we have a Business Relationship. A Business Partner can be for example An Account, Prospect, Vendor or Competitor. Account can be subdivided into Person (a private person), Organization (Part of a legal person or legal person), and Group (Partner Group).

 

SAP CRM provides creation of Product in Product Master. Product Master can be defined with different Product Types. Product types are as follows Material, Service, Financing, and Warranty.

 

The Objective is to automate the process of attaching additional document to a Business Partner or Product document tab.

 

Business partner:

1.jpg

 

CRM Web UI of Business Partner

2.jpg

 

Product:

3.jpg

CRM Web UI of Product

4.jpg

 

Procedure for Attachment Uploading in CRM:

The step by step process involved in uploading attachment to Business Partner or Product from Application Layer automatically (with the help of a program) is as follows.

 

  1. File that needs to be attachment to Business Partner or Product is available on Application server (AL11).
  2. The file can be place on Application server with the help of a Basis team, or a utility program can be developed to place files on Application server.

    E.g.: Files on Application Server

5.JPG

3.    Once the files to be uploaded are available on Application server, we need to fetch the file details as follows.

4.    Read the File from application server into internal table one at a time in binary format. As file in Binary format support multiple formats of attachments.

5.    Reading File from Application server as follows

            a.  OPEN DATASET lv_file FOR INPUT MESSAGE lv_msg IN LEGACY BINARY MODE. 

                    lv_file is the absolute file path on Application Server

        lv_msg if any error occurs in opening file, the corresponding error message is assigned for the reference.

b.  Move the data read into internal table of type binary format i.e. SDOKCNTBIN along with the size of the file, e.g.: i_text[].

6.    Attaching File

a.    In order to attach documents from Application Server to an existing Business partner or Product one of the mostly used

       class is CL_CRM_DOCUMENTS (KW Explorer in CRM).

b.    This class have various build in methods for document attachment, method CREATE_WITH_TABLE (Create a Document (Content in Table)) is used in this procedure.

 

C.  The basic parameters used in this method CREATE_WITH_TABLE are shown below

6.jpg

Of all the parameters listed, we are concerned about few parameters like BUSINESS_OBJECT, PROPERTIES, FILE_ACCESS_INFO, FILE_CONTENT_BINARY, and RAW_MODE.

 

à EXPORTING.

 

i.        BUSINESS_OBJECT: Local Persistent Object Reference - BOR-Compatible, following attribute are to be considered.

1.    INSTID: Instance Identification in BOR Compatibility, Persistent Object Reference. Pass the Business partner GUID or Product GUID for which Account or the Product the attachment need to be maintained. Business Partner GUID can be found in table BUT000 and Product GUID in COMM_PRODUCT.

 

2.    TYPEID: Type of Objects in Persistent Object References. Object reference are present in table TOJTB.

7.jpg

TYPEID = TOJTB-NAME, w.r.t Business Partner and Product.

3.    CATID: Category of Objects in Persistent Object References, as Business partner and Product are Business Objects.

CATID = ‘BO’ (BO = BO Instances of BOR Object Types).

 

ii.        PROPERTIRES: SDOK: Object attribute, name and feature. It has following attributes.

 

1.    NAME: It represents Attribute of a document or a relationship.

2.    VALUE: Attribute Value.

The above two parameters have a combination of 3 values to be passed w.r.t NAME and VALUE i.e.

8.jpg

  • Unique Name with in a folder

NAME = ‘KW_RELATIVE_URL’.

VALUE = File Name for the attachment.                E.g.: EXCEL.xlsx

 

  • Short Description

NAME = ‘DESCRIPTION’.

VALUE = File description text.                            E.g.: Excel file

 

  • Language

Name = ‘LANGUAGE’.

    VALUE = Language in which the attachment is loaded.    E.g.: ‘EN’.

iii.        FILE_ACCESS_INFO : File Access Information properties has following attributes

9.jpg

  • File Size: Size of the file which have to be attached, point 5.b.
  • Binary flag: As the file is read in Binary format.
  • First line: Stating the line number in the internal table to be read.
  • File Name: Absolute file path of the attachment from application server.
  • Mime type: Internal representation of File format/extension which the file need to be read. MIME types are available in table SDOKMIME (MIME content type for file name enhancement).
  • Property: Extension of the file.

                        e.g.: The properties of the attachment are saved as

                        10.jpg

iv.        FILE_CONTENT_BINARY: File contents of internal table saved as per    point 5.

v.        RAW_MODE: Indicating that file is Raw Data. (pass value  ‘X’)

 

 

à  IMPORTING

i.        The Importing parameter are as follows: LOIO, PHIO, and ERROR.

  • LOIO: A unique Logical Document number is generated for attachment.

                        E.g.:

                              11.jpg

  • PHIO: A unique Physical Document number is generated for attachment.

                        E.g.:

                              12.jpg

  • ERROR: Any error while attaching Document are assigned.

 

This above process is common for Business Partner and Product, but product have Predefined folders were attachments are saved.

13.JPG

As we intend to place the attachment in DOCUMENTS->PICTURES->THUMBNAILS, so the class CL_CRM_DOCUMENTS has a method GET_INFO_FOR_FOLDER (Get Folders for BOR Objects/Attributes).

The various parameters used in this method are BUSINESS_OBJECT, PROPERTIES_RESULT, and FOLDERS.

à  EXPORTING

i.        BUSINESS_OBJECT: Local Persistent Object Reference - BOR-Compatible, it has following attributes

1.    INSTID: Instance Identification in BOR Compatibility, Persistent Object Reference. Pass the Product GUID for the product to which the attachment need to be uploaded, Product GUID can be found from table COMM_PRODUCT for the corresponding Product.

2.    TYPEID: Type of Objects in Persistent Object References. Object reference are present in table TOJTB.   

TYPEID = TOJTB-NAME, Product.

14.JPG

3.    CATID: Category of Objects in Persistent Object References, Product as Business Objects. 

CATID = ‘BO’ (BO = BO Instances of BOR Object Types).

 

à  IMPORTING

i.          PROPERTIES_RESULT: The predefined folder details are fetched. Now read the folder in which we want to attach the files.

                    E.g.: As we are trying to place files to THUMBNAILS folder, read the NAME and VALUE attributes.

Read PROPERTIES_RESULT where NAME = 'KW_RELATIVE_URL' and          VALUE = 'THUMBNAILS' and get OBJTYPE, CLASS, and OBJID fill this values into internal table LS_FOLDER type SKWF_IO.

ii.      FOLDERS: Table with folders.

Once the Folder details are fetched, pass above details to Class CL_CRM_DOCUMENTS, the method CREATE_WITH_TABLE with necessary parameters.

 

Pseudo Code:

Sample pseudo code and usage of class CL_CRM_DOCUMENTS and methods used for create attachment in Document tab of Business partner or Product.

Pseudo Code  (file1)

 

With the above code we can attachment multiple attachments that are maintained either form Application server or Presentation server, this program main objective mass loading of attachment to Business Partner or Product automatically.

Example of attachments attached.

Excel 1 Test.xslx (file2)    Test PPT1.pptx (file3)

  1. After execution of the sample code, go to Transaction BP / COMMPR01 else CRM_UI.
  2. Check Business Partner Attachment in GUI T-CODE: BP or in WEB UI under ACCOUNT MANAGEMENT -> ACCOUNT passing Account ID (BP).
  3. Pass Account ID (BP) Number for which attachment are loaded.

    15.JPG

4.    Check the details of Account by clicking on the Name of the Account.

    16.JPG

5.    Check the Details of the Attachment by clicking on Name of the attachment.

17.JPG

E.g: Test PPT 1.pptx

18.JPG

Similarly other attachments can be viewed by double click on the link of the attachment.

 

6.    In order to check the attachment for Product GUI T-CODE: COMMPR01 or in Web UI as follows SALES OPERATIONS->PRODUCTS.

7.    Give the product ID for which attachment are loaded.

19.JPG

8.    Double click on Product ID to check details.

20.JPG

Click on Name of the attachment to open attachments.               

Eg: Excel 1 Text.xslx

21.JPG

Conclusion: This Document explains the procedure to attach multiple attachments from Application server to Business Partner or Products (Generally Mass Uploading of Attachments)

Creating Survey URL in CRM_SURVEY_SUITE

$
0
0

Hi,

 

After creating the survey in the TC 'CRM_SURVEY_SUITE' under any Node we need its URL which we will provide to Customers to get their feedback e.g. by Embedding in Mail Forms.

So before going to create Survey URL we need to do some changes in the Repository XML files. Below are the steps which we need to follow:

 

Step1:

Go to TC 'CRM_SURVEY_SUITE' and open the survey repository .

Step2:

        Open the tree structure Survey Repository->Parameter XMLs->BSP.

       Now Select the standard parameter file CRM_SVY_BSP_SYSTEMPARAM.XML with double-click and choose Export and save to to local PC with a new name e.g.  ZCRM_SVY_BSP_SYSTEMPARAM.XML

 

Step3.

Open the file in the Notepad and make the below given changes:-    

 

<?xml version="1.0" encoding="UTF-8"?>

<SurveySystemParam Action="http://Host Name:Port//sap/bc/bsp/sap/crm_svy_server/survey.htm?sap-client=300" Method="post"

IncludeStylesheetInOutput="true"

AccessURL="http://Host Name:Port/sap/bc/bsp/sap/crm_svy_server/survey.htm" Enctype="application/x-www-form-urlencoded"/>                          <SurveySystemParam  Action="" Method="post"  IncludeStylesheetInOutput="true" Enctype="application/x-www-form-urlencoded"    />

 

Save the file.

 

Step4:

Now we need to Import the File back to Survey repository.

Open the survey repository and open the node as mentioned in step 2 and choose Import from Toolbar. Give the short and long description and choose file from the PC and import.

 

Step5:-

Now we can create the survey url using this file in Get File and Send File Options .

Press generate URL and then test the URL.

 

Note :- To check the Host name and Port number you can go to TC 'SMICM' and from the Menu choose GOTO->SERVICES. Here you will find the Host server URL and Port number .

 

 

Thanks & Regards,

Kumar Gaurav.

Step by step to enable your Genil Component with AET

Web UI : Dynamic queries - Adding operators

$
0
0

In search screens in SAP CRM, you sometimes run in to the fact that for some reason, you are not able to select a search option you might want to be able to select. 

Screen Shot1.png

For instance in the example, let's say we would like to select all activity types starting with 'ZB*'. This is not possible in the standard, but there is a way around this. Let's talk about 'Query Objects in the Generic Interaction Layer (GenIL).


Query objects are used to find business objects within the BOL. Many of SAP’s business objects have queries implemented to support specific search conditions. These query objects can easily be found using the GenIL Model Browser.


Besides standard query objects, supporting only 'values equal to' searches, some of the query objects are implemented as 'dynamic query objects'
Using these dynamic query objects it is possible to support multiple operators within the search. As said, it is possible. Not all dynamic query objects support all kinds of operators. This blog explains how to change the operators for dynamic query objects, to support custom specific search scenarios.

                                

1. Dynamic Query Object : Within this blog we will use component “BT”, dynamic query object “BTQAct”.

Using the BOL browser(GENIL_BOL_BROWSER - Browser for Business Object Layer) , we want to search for specific objects, where field “PROCESS_TYPE” is in between a range of values, but the dynamic query object doesn't allow us to do so.BOL.png
Using the Generic Interaction Layer Model Browser it’s easy to locate the dynamic query objects for a specific business object.
Screen Shot2.png

2. Check default query operators

Since the dynamic query object doesn't allow us to search with operator “BT” for field “PROCESS_TYPE”, we need to check what is causing this behavior. By double clicking the Dynamic Query Object, we get an overview of all allowed operators. As we can see, operator “BT” is supported for this query object.Screen Shot3.png

3. Check exceptions per attribute

The dynamic query object specifies which operators are allowed within the search. But this doesn't mean that all fields allow these operators as well. It is possible to set exceptions. By double clicking the field within the dynamic query object, we can see all allowed operators for that specific field.

Screen Shot4.png
As we can see, operator “BT” is not allowed for field “PROCESS_TYPE”.

4. Define operators for dynamic queries

To change the operators for dynamic query object we need to open the customizing using path:
Customer Relationship Management -> CRM Cross-Application Components -> Generic Interaction Layer/Object Layer -> Component-Specific Settings -> Define Operators for Dynamic Queries
Spro.png
Spro2.png
Search for the corresponding component and dynamic query object. The customizing allows us to either change the default settings or the exceptions per attribute. In our specific case we need to change the exceptions per attribute and activate the “BT” operator.

5. Check new operator  and test for dynamic query

Since we have added the “BT” operator for our field, the BOL browser should now enable us to search using this operator.Test Query.pngLast result.png

Note: - In case the dynamic query object itself doesn't supply the required values, meaning the newly added operator doesn’t work correctly, you’ll have to find / enhance the corresponding search implementation.

Enhance mass change process for Sales Orders in Web UI - Enhance Item Query

$
0
0
ComponentSupport Package
SAP_BASISSAPKB73105
SAP_ABASAPKA73105
WEBCUIFSAPK-73105INWEBCUIF
BBPCRMSAPKU70204

 

Introduction:

I my last blog about MASSEnhance mass change process for Sales Orders in Web UI - Modificable fields I explained how you can enhance the process of modify data adding new or standard fields in Web UI. In this blog I will explain the basics to add standard fields in the query object, to be more specific I will explain how to add the order line description as a searchable field in the sales order item query.

 

How to enhance the item query object?

 

We are dealing with the search of positions so the dynamic query object is BTQSlsItem, in order to add the new field avaliable you need to enhance the structure CRMST_QUERY_SLSITM_BTIL as you will see and probably wonder, we have a custom include for AET: INCL_EEW_BUS2000131_SEARCH, I guess this custom include only is modified if we add new fields to the BT model via AET, but doesn't apply if we only want to make some standard field avaliable to be used as search criteria, so on our scenario I created a new append structure in the include and I added the field ZZPRODUCT_DESCRIPTION_UC.

 

How to map input fields to the data dictionary?

 

The first thing you need to know is MASS uses the customizing table CRMC_REPDY to map the search parameters to the target in the database, the example which I'm explaining is "quite easy" because we are dealing with the standard table CRMD_ORDERADM_I. If you add your field via SM30.

ZZPRODUCT_DESCRIPTION_UC, wait?! I thought you say you will use standard field!! well I will explain that later (aproach2)

 

mass1.JPG

As you see the field is repeated I will use this to descrive both approaches.

 

Approach 1: Using an already delivered standard field.

 

If you take a look at the table CRMC_REPDY you will see, there are more fields to be used than actually what you can use in the Web Client, so why we can not use an already defined field adding this field in the append structure? That will be the best approach....but there's something which will make you change your mind

 

The function module CRM_SALESORDER_MASS_SELECT is the one which will do the mapping of your Dynamic query parameters to the internal queryparts (quparts) if you check the FORM BUILD_THE_QUERY (CRM_SALESORDER_MASS_SELECT) you will see a big loop at the internal table LT_RANGE with a case. So if the field is defined in the Dynamic Query structure and in the table CRMC_REPDY, even if is a standard delivered field (CRMC_REPDY), won't work as long is not included in the case. I rasied a message to make one standard field (delivered in table CRMC_REPDY) avaliable in the case and SAP support won't change anything, you can see it as a product error or as custom enhancement, but the resume is if you want to go for that whay you will need to modify the code to add your one case. You can also add a enhancement point at the end of the form, but in this scenario,  I think the best option is do a standard modification.

 

 

Approach 2: Using a custom field which points to the standard field.

 

This aproach is taking advantage on the WHEN OTHERS case, the OTHERS is meant for the AET fields and to take your field in consideration needs the customer name convenion Z* or Y*. Now you are starting to understand why I created the field on the CRMC_REPDY starting with ZZ rignt?

Ok, there's one little step more, this field needs to be populated in the table AXT_RUN_FIELDDEF, this table is meant for the AET extensions so you can't modify it directly, the only way is create a maintenance view and generate a view maitenance program in order to add the new entry via SM30.

So the result will be something like this:

 

mass1.JPG

I informed the LOCATION, just to avoid naming confilcts with the fields generated by AET.

 

Once is everything done, you will be able to search order item description

 

If for any reason the field is not avaliable in the view configuration (BT115MU_SLSO/SearchItems) that's because you will need to copy/add your new field via desing layer.

 

Approach 3: Using a custom field created via AET(CUSTOMER_H or CUSTOMER_I)

 

In this scenario I will cover the case of using fields enhanced via AET at CRMD_CUSTOMER_H or CRMD_CUSTOMER_I level (for AET fields which points directly at CRMD_ORDERADM_H or CRMD_ORDERADM_I, you can follow the Approach 1.

 

Ok! Let's say I created a new feld on the table CRMD_CUSTOMER_H via AET, the field name generated is ZZAFLD00001W. The first thing I need to do is add this field at the table CRMC_REPDY.

 

Capture.JPG

 

Let's pay attention on the Dynamic Access Name field, as you observe informed ZZDYN_CUSTOMER_H this should be a existing method of the standard class CL_CRM_REPORT_ACC_DYNAMIC which is called dynamically at the method BUILD_DYN_SQL (for example), at my current version I don't have a DYN_CUSTOMER_H so I created one myself enhancing the standard class CL_CRM_REPORT_ACC_DYNAMIC adding the new method (ZZDYN_CUSTOMER_H) the interface of the new method should be the same a other DYN* methods:

 

Capture.JPG

 

Capture.JPG

 

This scenario es simple, so the code is not a big deal, other DYN* methods are more complicated, for example, in order to influence the join.

 

METHOD ZZDYN_CUSTOMER_H .
  IF i_add_sql_part NE 'X' AND it_add_where_for IS NOT INITIAL.
    CALL FUNCTION 'CRM_REPORT_DYN_ITAB_BREAK_DOWN'
      EXPORTING
        i_name_on_db = 'CRMD_CUSTOMER_H~ZZAFLD00001W'
        it_quparts   = it_add_where_for
      CHANGING
        ct_where     = gt_where.
  ENDIF.
ENDMETHOD.

 

The only thing missign now is enhance the mass query object, structures CRMST_QUERY_SLSORD_BTIL (for header search) and CRMST_QUERY_SLSITM_BTIL (for item search) I put here both, despite this blog is focused on the mass item query, because in this approach both header and Item works equaly.

 

Conclusion:

 

Between Approach 1 and Approach 2, Which is better? I prefeir the second one, at least I don't need to modify the standard source and I think informing the location on AXT_RUN_FIELDDEF secures the solution, one thing to considere is during upgrades you should check the WHEN OTHERS code doesn't change so this development will stop working, and of course, this is how I filled the GAP between the standard and my customer requeriment, this is not a standard solution and should be perfromed with care and of course this also applies for Approach 3.

 

This blog is specific for the Item query, the header query works different for approach 1 and 2!

 

Cheers!

 

Luis


Inbound plug of window receives data : Where to process in the view

$
0
0

Hello Fellows,

 

I was going through this issue in the production system of a client. I will not use exact names and scenario and would stick to using general/technical terms.

 

Scenario:-

In production system on click of a hyper link , navigation was happening to anther Web UI component.

 

I noticed that the transaction data from the source component was getting filled into a collection and it was getting passed to the inbound plug of the target component and the target component was getting launched.The code in the inbound plug of the target window was setting the received collection to the context node of the target component.

 

There was no issue in navigation.

 

The issue reported was that the target component was getting launched with the details of the previously confirmed transaction in source component.

If user had transaction A in source component, first time when the link was clicked ,the target component was not having any details about transaction A.

User goes back and click on transaction B in source component , this time the target component was getting launched with details of transaction A.

User goes back and click on transaction C in source component , this time the target component was getting launched with details of transaction B.

 

The root cause of the problem was the place in the target component/view at which the processing was being done from the context node.

Colleagues had redefined the method DO_VIEW_INIT_ON_ACTIVATION in the target component/view to process the data from the context node.

 

The SAP standard call stack showed that the method DO_VIEW_INIT_ON_ACTIVATION is called first and the IP_Inbound plug is called after wards.

The context was getting read in the view and processing was done and after that the inbound plug was setting the context with the correct received data.

 

Line 108 explains this in the SAP Standard method CL_CRM_UI_CORE_APPL_CONTROLLER->EXECUTE_NAVIGATION

code.JPG

 

We moved the processing from DO_VIEW_INIT_ON_ACTIVATION to  DO_PREPARE_OUTPUT

which solved the problem.

 

I think the another way to solve the problem could have been to redefine the WD_USAGE_INITIALIZE in source component and bind the target context node from the source.

 

Hope this helps.

 

Parveen Kumar

Removing Unwanted Messages from WebUI Display

$
0
0

There are many times when we override an existing functionality for e.g override standard EH_ONSAVE/EH_ONEDIT etc. but the standard messages are still triggered. These messages don't make any business relevance any more and have to be removed. If the messages are added to the global message containter or genil level message container then they can be removed easily but the message was added directly using cl_bsp_wc_message_service=>add_message( ) ,and removing the specific message was not happening in my case. I tried many approaches suggested in the SCN , but they did not work hence I had to do the below mentioned.

 

The following blog , I have written would help you to remove a specific message. This approach looks fine but then if there are side-effects of this please feel to share using the comments in the blog. Actually there could be based on the scenario and I was not able to determine in my case.

 

For an example I am trying to remove message of class CRM_BOL , message no 003, message type I .

   data: lr_message_service type ref to cl_bsp_wd_message_service,        ls_genil_message type crmt_genil_message,        lt_genil_message type crmt_genil_message_tab,         lr_msg             type ref to bsp_wd_message_tab.  field-symbols: <lt_message> type bsp_wd_message_tab,                 <ls_message> type bsp_wd_message.      lr_message_service = cl_bsp_wd_message_service=>get_instance( ).      lr_message_service->get_messages(        exporting          iv_msg_type             = if_genil_message_container=>mt_all    " Messages, Message Type
*    iv_max_lines            =     " Max. Number of Returned Messages          iv_delete_read_messages = abap_true        receiving          rv_result               =   lr_msg  " Table of Messages      ).      assign lr_msg->* to <lt_message>.      check <lt_message> is assigned.      loop at <lt_message> assigning <ls_message> where type = 'I' and id = 'CRM_BOL' and number = '003'.        delete <lt_message> index sy-tabix.      endloop.      unassign <ls_message>.      check <lt_message> is assigned.      loop at <lt_message> assigning <ls_message>.        ls_genil_message-id = <ls_message>-id.        ls_genil_message-number = <ls_message>-number.        ls_genil_message-type = <ls_message>-type.        ls_genil_message-var1 = <ls_message>-var1.        ls_genil_message-var2 = <ls_message>-var2.        ls_genil_message-var3 = <ls_message>-var3.        ls_genil_message-var4 = <ls_message>-var4.        ls_genil_message-message = <ls_message>-message.        ls_genil_message-dyn_msg_num = <ls_message>-msg_handle.        append ls_genil_message to lt_genil_message.      endloop.      check lt_genil_message is not initial.
*     Add the remaining messages back to message class      lr_message_service->add_messages(        exporting          it_messages  =  lt_genil_message   " Table of Messages
*      iv_msg_level = '1'    " Message Level      ).

Sample Codes used in BOL Programming

$
0
0

The BOL API consists of various interfaces and classes that you can use to access business

data:

  • CL_CRM_BOL_CORE

You can use this class to access directly with Business object implementations.

Also said as Heart of Root objects , only single instance can exists per session.

  • CL_CRM_BOL_QUERY_SERVICE  

You use this class for a simple search to select a business objects.

Also called as Query service provider.

  • CL_CRM_BOL_DQUERY_SERVICE

You use this class for a dynamic search to select a business objects.

  • CL_CRM_BOL_ENTITY

You use this class for implementing business objects.

Also called as Entity Service Provider , represents unique object instance.

  • CL_CRM_BOL_ENTITY_MANAGER

Holds the refrences of all the BOL entities in a table attribute (ENTITY_TAB).

  • IF_BOL_TRANSACTION_CONTEXT

You use this interface to control transaction behavior.

  • IF_BOL_BO_COL

You use this interface to provide collections to hold business objects.

  • IF_BOL_BO_PROPERTY_ACCESS

You can use this interface to access the property of an attribute of entity class.

 

Sample Code :

 

Loading a BOL object using  CL_CRM_BOL_CORE

 

 

data : lr_core type ref to cl_crm_bol_core.

try.

  lr_core = cl_crm_bol_core=>get_instance( ).

  lr_core->start_up('BOL object name').   

Catch cx_crm_genil_general_error.

Endtry.

 

 

Build Create Parameters of Root Object.

 

 

  DATA: ls_params               TYPE crmt_name_value_pair.
  DATA: lt_params               TYPE crmt_name_value_pair_tab.  

  CLEAR lt_params[].
* Build create parameters for Root Object

* Status Profile
  ls_params-name  = 'STSMA'.
  ls_params-value   =  'ABC'.
  APPEND ls_params TO lt_params..

* Objective
  ls_params-name  = 'OBJECTIVE'.
  ls_params-value = ls_data-objective.
  APPEND ls_params TO lt_params.

 

 

 

Create Root Instance or Entity Factory.

 

 

  DATA : lr_factory             TYPE REF TO cl_crm_bol_entity_factory.
  DATA : lr_entity              TYPE  REF TO cl_crm_bol_entity.


* Create Root Instance in a Collection.   
TRY.
        CALL METHOD lr_core->root_create
          EXPORTING
            iv_object_name  = lc_entity
            iv_create_param = lt_params
            iv_number       = 1
          RECEIVING
            rv_result       = lr_col.

 

* Obtain Factory of Root Object in Entity.

     lr_factory = lr_core->get_entity_factory( iv_entity_name = lc_entity ).

        lr_entity = lr_factory->create( lt_params ).

      CATCH cx_crm_unsupported_object.

 

 

 

Retrieving the data (Query object or dynamic query objects)


data: lr_qs         type ref to cl_crm_bol_dquery_service.
        ls_param    type        crmt_name_value_pair.
        lt_param    type        crmt_name_value_pair_tab.
        lr_result     type ref to if_bol_entity_col.
        lr_iter        type ref to if_bol_entity_col_iterator.
        Lr_entity    type ref to cl_crm_bol_entity.

 

“Get and prepare dynamic query service

lr_qs ?= cl_crm_bol_dquery_service=>get_instance('SearchObjectName').
ls_param-Name = 'MAX_HITS'.
ls_param-Value = '5'.
append ls_param to lt_param.
lr_qs->set_query_parameters( lt_param ).
lr_qs->add_selection_param( iv_attr_name = 'Attr_id'
                 iv_sign = 'I'
                           iv_low  = 'VALUE'
                           iv_high = ' ').
lr_result = lr_qs->get_dquery_result.

 

 

 

Retrieving data from BOL entities.

 

lr_result = lr_qs->get_query_result.

Lr_iter = lr_result->get_iterator( ).

Lr_entity = lr_iter->get_first( ).

While lr_entity is bound.

    Lv_name = lr_entity->get_property_as_string( ‘name’ ).

    Lv_id = lr_entity->get_property_as_string( ‘id’ ).

    Write :

Lr_entity = lr_iter->get_next( ).

End while.

 

 

Saving Objects

 

  data lr_tx      TYPE REF TO if_bol_transaction_context.
  data lr_entity TYPE REF TO cl_crm_bol_entity.
  data lr_core    TYPE REF TO cl_crm_bol_core.

  lr_entity ?= me->typed_context->object_name->collection_wrapper->get_current( ).
  lr_tx = lr_entity->get_transaction( ).
  if lr_tx is not BOUND.
    lr_core = cl_crm_bol_core=>get_instance( ).
    lr_tx = lr_core->begin_transaction( ).
  endif.

  if lr_tx is bound.
    if lr_tx->check_save_possible( ) = abap_true.
      check lr_tx->save( ) = abap_true.
      lr_tc->commit( ).
    endif.
  endif.
   me->view_group_context->reset( ).

 

Cancel Changes or Reset Objects

 

method EH_ONCANCEL.

DATA lr_entity   TYPE REF TO cl_crm_bol_entity.

data lr_tx        TYPE REF TO if_bol_transaction_context.

lr_entity ?= me->typed_context->node->collection_wrapper->get_current( ).

lr_tx = lr_entity->get_transaction( ).

lr_tx->revert( iv_suppress_buffer_sync = abap_true ).

me->view_group_context->reset( ).

endmethod.

 

Edit Objects

 

  data: lr_entity type REF TO cl_crm_bol_entity.
  lr_entity ?= me->typed_context->node->collection_wrapper->get_current( ).

  check lr_entity is BOUND.
   CHECK lr_entity->is_change_allowed( ) = abap_true.
    lr_entity->lock( ).

    if lr_entity->is_locked( ) = abap_false.
      me->view_group_context->reset( ).
    else.
      me->view_group_context->set_all_editable( ).
    endif.
endmethod.

 

 

 

Some Methods of Iterators to fetch the entity using IF_BOL_BO_COL_ITERATOR

 

lr_item ?= lr_iterator->get_current( ).
lr_item ?= lr_iterator->get_first( ).
lr_item ?= lr_iterator->get_last( ).
lv_tab_size = lr_iterator->size( ).  " Get no of entities

 

 

 

 

 

Some methods of Property access using IF_BOL_BO_PROPERTY_ACCESS

 

CALL METHOD lr_item->get_property_as_value

                        ( EXPORTING iv_attr_name = lc_amount 

                          IMPORTING ev_result = lv_amount ).

 

 

More to update.....

 

Regards,

Sumeet Gehlot

SAP CRM Practice

Converting HTML to XHTML using CL_HTMLTIDY

$
0
0

For some projects or applications one may need XHTML-data instead of HTML. In some cases you may need XHTML to parse data to Adobe Forms for example.

 

One idea to convert the data is based on the Tidy library, which was originally developed by Dave Reggett (HTML Tidy Project Page)

It's also possible to use this library within the ABAP stack by instrument the class CL_HTMLTIDY.

 

Here I describe roughly the way to do that:

 

1. First you have to convert the HTML to UTF8-XSTRING e.g. with help of the class cl_abap_conv_out_ce or  cl_gstext_tools

Example:

  lv_text_as_xstring = cl_gstext_tools=>convert_string_to_xstring( iv_string  =  lv_html ).

 

2. Create a global obkject  from CL_HTMLTIDY-object: cl_htmltidy=>create( ).

 

3. Set the options for the Tidy-object by using the method set-option from the class. The parameter input encoding has to be 'utf8'

You can also have a look at this german blog: Rüdiger Plantiko: Testbare Oberflächen

 

4. Use the instance (object) of the CL_HTMLTIDY-class to trigger the method to convert. Have a look at the available methods in SE24.

    I will enhance this blog by a step by step manual as soon as possible. Pass the UFT8-XSTRING as Import data.

 

Regards,

Daniel

how to persist the UI exception so you can view them later

$
0
0

When I am working together with local partner to resolve one issue caused by incorrect enhancement set configuration for new custom Product set type, I have realized that if the UI exception is raised and caught by framework, there would be no entry in ST22, which causes the difficulties for later trouble shooting.  

 

When I am debugging the code how the framework handles with the exception, I found there is the possibility to let the framework call the error handler defined by ourselves being registered in table bsperrhandler.

clipboard1.png

So I think it is worthy to create a simple error handler class to persist the exception information into a new transparent table for later checking.

 

1. create a class ZCL_ERROR_HANDLER with a static public method STORE_ERROR_INFO, signature as below:

clipboard2.png

Source code as below. Just extract error message text and the exact position which line of source code has raised the exception:

METHOD store_error_info.  DATA: lv_header_text TYPE string,        l_einternal TYPE REF TO cx_bsp_einternal,        l_exception      TYPE REF TO cx_root,        l_program_name   TYPE syrepid,        l_include_name   TYPE syrepid,        l_source_line    TYPE i,        lv_log_text      TYPE string,        ls_log           TYPE zbsplog.  l_exception = exception.  CHECK server IS NOT INITIAL AND exception IS NOT INITIAL.  lv_header_text = exception->get_text( ).  TRY.      l_einternal ?= exception.    CATCH cx_root.  ENDTRY.  IF l_einternal IS BOUND.    CALL METHOD l_einternal->get_source_position      IMPORTING        program_name = l_program_name        include_name = l_include_name        source_line  = l_source_line.  ELSE.    WHILE l_exception->previous IS BOUND.      l_exception = l_exception->previous.    ENDWHILE.    CALL METHOD l_exception->get_source_position      IMPORTING        program_name = l_program_name        include_name = l_include_name        source_line  = l_source_line.  ENDIF.  CALL FUNCTION 'GUID_CREATE'    IMPORTING      ev_guid_16 = ls_log-uuid.  ls_log-error_date = sy-datlo.  ls_log-error_time = sy-timlo.  ls_log-error_string = |<head><h1>{ lv_header_text }</h1><h2>Error Date:{ sy-datlo }</h2><h2>Error Time:{ sy-timlo }</h2>| &&  |<h3>Error program:{ l_program_name }</h3><h3>Error include:{ l_include_name }</h3><h3>Source code line number:{ l_source_line }</h3>|  && |</head>|.  INSERT zbsplog FROM ls_log.  COMMIT WORK AND WAIT.
ENDMETHOD.

 

2. Create a new transparent table to store the exception detail:

 

clipboard3.png

3. Register the new error handler into table bsperrhandler:

clipboard4.png

4. Write a simple report to list the exception information. Of course more elegant UI like ALV could be used:

 

data: lt_table type STANDARD TABLE OF zbsplog,      lv_error TYPE zbsplog-error_string.
FIELD-SYMBOLS:<item> TYPE zbsplog.
START-OF-SELECTION.   SELECT * INTO TABLE lt_table FROM zbsplog.   LOOP AT lt_table ASSIGNING <item>.      WRITE:/ 'guid: ', <item>-uuid,'date: ', <item>-error_date, <item>-error_time.      lv_error = <item>-error_string.      HIDE lv_error.   ENDLOOP.   AT LINE-SELECTION.      cl_demo_output=>display_html( lv_error ).

execute the report and double click one line item, the detail information would be displayed via the handy class cl_demo_output.

With the include name and source code line number available, you could implement further handling like automatically navigation to the source code in ABAP editor by calling function module RS_TOOL_ACCESS with include name and source code number passed in.

clipboard5.png

Viewing all 188 articles
Browse latest View live


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