riccardo.escher

9 Posts

While studying the SAP Solution Manager 7.1 Master Guide (version 1.0 20110516) I stepped into this funny typo on page 24:
Hardcopy

As an enthusiastic reader of Sigmund Freuds wonderfull (but very dangerous to read) book "The Psychopathology of Everyday Life" I suspect that the poor documentation woRker loves asian cooking and that he/she was hungry as a hunter while typing :-)

h1. Preamble ABAP developers which cannot create or release transport requests behave somehow like truck drivers with heavily tattooed arms who are getting impatient when the loading of their lorry halts. This happens for example in the ChaRM when the maintenance cycle is locked. But implementing a really nice idea of Woody Wu from the SAP Solution Manager Development Support will help to get out of a tight spot. This is also a good example for a PPF action scheduled via BAdI (for Solution Manager 7.0 EHP1) and we show how to extract the original message variables from a message. The history of this blog series: {code:html}Pep Up Your ChaRM - Part 1: HowTo Create a Smart e-Mail Action{code} {code:html}Pep Up Your ChaRM - Part 2: a CRMD_ORDER Slimming Cure{code} {code:html}Pep Up Your ChaRM - Part 3: Turn Cinderella PDF-Mails into Pretty&Usefull Ones{code}Pep Up Your ChaRM - Part 4: How To Avoid a Nag Screen (Pep Up Your ChaRM - Part 4: How To Avoid a Nag Screen) h1. The Missing Link As many ChaRM customers do, we use only the urgent correction (SDHF) as described in SAP note 952803 (https://service.sap.com/sap/support/notes/952803) to transport changes from the development to the downstream systems. During the process of the *SDHF* change document one crucial step is the creation of the hotfix task list and of the links to it and to the maintenance cycle document (*SDMN*) which can be found after pressing the +document flow+ button: DocFlow But if the *SDMN* transaction type belonging to the maintenance cycle (1014 in our example) is locked - guess it or not, this happens ofter than needed -, the link to it will fail, and the step of the creation of the hot fix tasklist will not be executed, resulting in a change document with a +red led+ showing the error message *CHM1_ACTION_LOG 030* with a text which is meaningful only to the change manager: Change document with red led You can now execute the PPF action "+Recheck Correction+" starting a thorny path of save and recheck actions (we hope that in the meantime the lock of the maintenance cycle was released) which is really difficult to explain to normal ChaRM users, or you read this blog and implement an action which does the job using internally the service report (following the nice idea of Woody Wu from the SAP ChaRM development support). h1. And How to Supply It In order to offer a rescue action we have to do two main steps: create the PPF action, schedule this action. h2. The PPF Action We need a PPF action of type Method Call. This is done implementing the filter-dependend BAdI *EXEC_METHODCALL_PPF*. The name of the PPF action method is simply a filter value for this BAdI. h3. BAdI Implementation To implement the BAdI you can use the IMG with this path: +SPRO -> Customer Relationship Management -> Basic Functions -> Actions -> Actions in Transaction -> Business Add-Ins -> BAdI: Processing Methods+. You will get a dialog where you can add your own implementation and your filter value. If you have already created an own implementation you have to deactivate it before you can add a new filter value: Add Method ZOG_CREATE_BO_LINKS After having added the new filter value you can (re-)activate your implementation. On the Interface tab you have to insert your implementing class. In the method *IF_EX_EXEC_METHODCALL_PPF~EXECUTE* we will insert our rescue coding: BAdI Implementation Interface Tab The rescue coding is rather simple: METHOD if_ex_exec_methodcall_ppf~execute. DATA: lv_guid TYPE crmt_object_guid, ls_msgidno TYPE bal_s_idno, lt_msgidno TYPE bal_r_idno. CASE flt_val. WHEN 'ZOG_CREATE_BO_LINKS'. * action ok is our default value rp_status = '1'. * get guid for referenced object CALL METHOD cl_hf_helper=>action_helper->get_ref_object EXPORTING io_appl_object = io_appl_object IMPORTING ev_guid_ref = lv_guid. CHECK lv_guid IS NOT INITIAL. * delete possible old error messages ls_msgidno-option = 'EQ'. ls_msgidno-sign = 'I'. ls_msgidno-low-msgid = 'CHM1_ACTION_LOG'. ls_msgidno-low-msgno = '030'. APPEND ls_msgidno TO lt_msgidno. ls_msgidno-low-msgid = 'SOCM_ACTION_LOG'. ls_msgidno-low-msgno = '029'. APPEND ls_msgidno TO lt_msgidno. ls_msgidno-low-msgno = '014'. APPEND ls_msgidno TO lt_msgidno. CALL FUNCTION 'CRM_MESSAGES_DELETE' EXPORTING it_r_msgidno = lt_msgidno iv_ref_object = lv_guid. * write message into action-log (text in change document) CALL METHOD cl_hf_helper=>insert_notice EXPORTING im_text = 'Action create missing BO links with service report'(002) im_guid = lv_guid. CALL METHOD cl_hf_helper=>handle_notice EXPORTING im_change_document_id = lv_guid. * the service report will try to lock the order, so unlock it before CALL FUNCTION 'CRM_ORDER_DEQUEUE' EXPORTING iv_guid = lv_guid. * avoid additional scheduling of this action; is evaluated in eval_schedcond EXPORT guid = lv_guid TO MEMORY ID 'ZOG_CREATE_BO_LINKS'. * let the service report do it's job of update without status change SUBMIT crm_socm_service_report WITH sguidhd EQ lv_guid WITH formal EQ abap_true WITH next EQ abap_false WITH called EQ abap_true WITH noupd EQ abap_false AND RETURN. * restore the previous lock CALL FUNCTION 'CRM_ORDER_ENQUEUE' EXPORTING iv_guid = lv_guid EXCEPTIONS foreign_lock = 1 system_failure = 2 distributed_lock = 3 no_change_allowed = 4 transferring = 5 contract_locked = 6 OTHERS = 7. IF sy-subrc <> 0 AND sy-msgid IS NOT INITIAL. MESSAGE ID sy-msgid TYPE 'I' NUMBER sy-msgno WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4. ENDIF. ENDCASE. ENDMETHOD. h3. The Action Definition To define the action we use transaction *CRMC_ACTION_DEF* (see Part 1 (Pep Up Your ChaRM - Part 1: HowTo Create a Smart e-Mail Action) of this series), but this time we select the rule type +Conditions Using Business AddIn (BAdI)+: PPF Action Definition 1 The +Sort Order For Display+ = 1 is a psychological trick to draw the attention of the user to it. But please pay attention that the +Action Merging+ allows only one execution (see later). Also this time we will select the +Method Call processing type+ and insert the filter value defined in the last step as +Method+: PPF Action definition 2 h2. Smart Scheduling In order not to irritate the ChaRM user we want to offer this special PPF action only when the Business Object links are missing. To accomplish this we have to create a scheduling via BAdI. h3. BAdI Implementation This time we have to implement the BAdI *EVAL_SCHEDCOND_PPF*. I didn't find an IMG entry for this activity so we directly start with transaction *SE18*, insert the BAdI name and select +Menue -> Filter value -> Create+ (or +Change+ if you have already an own implementation). It is the same handling as described above: BAdI Implementation BAdI Implementation Interface Tab This time the coding is more complex. First we have to find the message which should trigger the scheduling of our action. Then we have to extract the object id of the locked cycle and then we have to test if the cycle is still locked, because we can execute our rescue action only one time (see later). So we would not splash our dart uselessly. The coding: METHOD if_ex_eval_schedcond_ppf~evaluate_schedule_condition. INCLUDE crm_mode_con. DATA: lv_proc_guid TYPE crmt_object_guid, lr_order TYPE REF TO cl_doc_crm_order, lv_guid TYPE crmt_object_guid, lv_log_handle TYPE balloghndl, lt_msg_handle TYPE bal_t_msgh, ls_msg_handle TYPE LINE OF bal_t_msgh, ls_msg TYPE bal_s_msg, lv_msg_string TYPE string, ls_bapimsg TYPE bapiret2, lv_object_id TYPE crmt_object_id_db, lt_guid TYPE crmt_object_guid_tab. CASE flt_val. WHEN 'ZSV2I_OG_CM_MISSING_BO_LINKS'. BREAK-POINT ID zog_charm_eval. ep_rc = 1. "we are pessimistic, default is not to show the action TRY. lr_order ?= io_context-> appl. CATCH cx_sy_move_cast_error . EXIT. ENDTRY. * now let's read the current messages of the order IF lr_order IS BOUND. lv_proc_guid = lr_order->get_crm_obj_guid( ). IF lv_proc_guid IS INITIAL. EXIT. ELSE. * avoid recursion during service report run IMPORT guid = lv_guid FROM MEMORY ID 'ZOG_CREATE_BO_LINKS'. IF sy-subrc = 0 AND lv_guid = lv_proc_guid. EXIT. ENDIF. ENDIF. * get the message handle CALL FUNCTION 'CRM_MESSAGES_REGISTER' EXPORTING iv_docnumber = lv_proc_guid iv_read_only = abap_true CHANGING cv_log_handle = lv_log_handle. * get all messages CALL FUNCTION 'CRM_MESSAGES_SEARCH' EXPORTING iv_log_handle = lv_log_handle IMPORTING et_msg_handle = lt_msg_handle EXCEPTIONS appl_log_error = 1 error_occurred = 2 OTHERS = 3. IF sy-subrc <> 0. MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4. EXIT. ENDIF. LOOP AT lt_msg_handle INTO ls_msg_handle. CALL FUNCTION 'CRM_MESSAGES_GET_MSG_INFO' EXPORTING is_msg_handle = ls_msg_handle IMPORTING es_msg = ls_msg EXCEPTIONS not_found = 1 wrong_context_structure = 2 data_error = 3 OTHERS = 4. IF sy-subrc <> 0. MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4. EXIT. ENDIF. * Now look for messages indicating that BO links are missing. * This message is created in CL_CHM1_URGNT_CORR_INSTANCE * ->IF_SOCM_INSTANCE~CREATE_REMOTE * after the call to FM /TMWFLOW/HFIX_TASKLIST_CREATE. But the real lock message * was originally CRM_ORDER 13 "Transaction &1 is being processed by user &2". IF ( ls_msg-msgid = 'CHM1_ACTION_LOG' AND ls_msg-msgno = '030' ). * build the complete message string MESSAGE ID ls_msg-msgid TYPE ls_msg-msgty NUMBER ls_msg-msgno WITH ls_msg-msgv1 ls_msg-msgv2 ls_msg-msgv3 ls_msg-msgv4 INTO lv_msg_string. ls_bapimsg-message = lv_msg_string. * now check if it was the original CRM_ORDER 13 and extract the variables ls_bapimsg-id = 'CRM_ORDER'. ls_bapimsg-number = '013'. CALL FUNCTION 'Z_SV2I_MESSAGE_FILLET' EXPORTING pv_ignore_spaces = abap_true "necessary because one space is destroyed in german CHANGING ps_message = ls_bapimsg EXCEPTIONS wrong_parameters = 1 message_not_matched = 2. IF sy-subrc > 0. RETURN. "<<==== ENDIF. * in message_v1 we should now have the order id of the locked maintenance cycle. * now try to find it's guid CALL FUNCTION 'CONVERSION_EXIT_ALPHA_INPUT' EXPORTING input = ls_bapimsg-message_v1 IMPORTING output = lv_object_id. "with leading zeroes SELECT SINGLE guid INTO lv_proc_guid FROM crmd_orderadm_h WHERE object_id = lv_object_id. IF sy-subrc = 0. * we found the cycle transaction, so try to lock it INSERT lv_proc_guid INTO TABLE lt_guid. CALL FUNCTION 'CRM_ORDER_READ' EXPORTING it_header_guid = lt_guid iv_mode = gc_mode-change EXCEPTIONS document_locked = 3 OTHERS = 9. IF sy-subrc = 3. * "Cycle transaction &1 still locked by user &2. Contact ChaRM management" MESSAGE i070(zsv2i_n001) WITH sy-msgv1 sy-msgv2. ELSEIF sy-subrc > 0. MESSAGE ID sy-msgid TYPE 'I' NUMBER sy-msgno WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4. ELSE. * Finally all ok. Schedule the action ep_rc = 0. * be nice and release the lock CALL FUNCTION 'CRM_ORDER_DEQUEUE' EXPORTING iv_guid = lv_proc_guid. ENDIF. ENDIF. "object_id found in crmd_orderadm_h EXIT. "this hit is enough, leave the loop ENDIF. "it is our trigger message ENDLOOP. "loop over all current messgaes ENDIF. "if lr_order is bound ENDCASE. ENDMETHOD. And this is the function module used to fillet the message into it's constituent parts: FUNCTION z_sv2i_message_fillet. *"---- ----------------------------------------------------------------- *"*"Local Interface: *" IMPORTING *" REFERENCE(PV_NATXT) TYPE NATXT OPTIONAL *" REFERENCE(PV_IGNORE_SPACES) TYPE ABAP_BOOL OPTIONAL *" CHANGING *" REFERENCE(PS_MESSAGE) TYPE BAPIRET2 *" EXCEPTIONS *" WRONG_PARAMETERS *" MESSAGE_NOT_MATCHED *"---- ----------------------------------------------------------------- * We have an expanded message build out of constants from t100 * and dynamic variables. Here we try to reconstruct the variables * because structure balmi has no place for the expanded message * in bapiret2-message but stores only msgnr + variables * Replace regex is not so comfortable in the case of &1&2 variables CONSTANTS: lc_field(9) TYPE c VALUE 'MESSAGE_V'. FIELD-SYMBOLS: . DATA: lv_natxt TYPE natxt, "T100 message text lv_nawork TYPE natxt, lv_found TYPE abap_bool, lv_message TYPE bapi_msg, lt_result TYPE match_result_tab, "results of regex lv_varoff TYPE i, "offset of number of variable lv_varnam(17) TYPE c, "variable name for dynamic move lv_varidx TYPE n, "if only & is supplied, we use the index lv_cnt TYPE i, "number of hits lv_textln TYPE i, "length of t100-string lv_msgln TYPE i, "length of expanded message lv_ixa TYPE i, "actual tabix ls_resulta TYPE match_result, "actual hit lv_ixn TYPE i, "next tabix ls_resultn TYPE match_result, "next hit lv_tkoff TYPE i, "offset of t100 token lv_tklen TYPE i, "length of t100 token lv_varoffa TYPE i, "offset of begin of actual variable lv_varlen TYPE i, "length of variable lv_varoffn TYPE i, "offset bo begin of next varialbe lv_tka TYPE string. "actual token lv_message = ps_message-message. IF pv_ignore_spaces = abap_true. CONDENSE lv_message NO-GAPS. ENDIF. IF pv_natxt IS INITIAL. * if pv_natxt is empty then msgid and msgno must be provided IF ps_message-id IS INITIAL OR ps_message-number IS INITIAL. RAISE wrong_parameters. ENDIF. * performance: first try with current languange (should always give a hit) SELECT SINGLE text INTO lv_natxt FROM t100 WHERE sprsl = sy-langu AND arbgb = ps_message-id AND msgnr = ps_message-number. IF sy-subrc = 0. IF pv_ignore_spaces = abap_true. CONDENSE lv_natxt NO-GAPS. ENDIF. lv_nawork = lv_natxt. REPLACE ALL OCCURRENCES OF REGEX '&[s|1-4]' IN lv_nawork WITH '*'. IF lv_message CP lv_nawork. * found! lv_found = abap_true. ELSE. lv_found = abap_false. ENDIF. ELSE. lv_found = abap_false. ENDIF. * second try: if not found with current language, try other ones IF lv_found = abap_false. SELECT text INTO lv_natxt FROM t100 WHERE sprsl <> sy-langu AND arbgb = ps_message-id AND msgnr = ps_message-number. IF pv_ignore_spaces = abap_true. CONDENSE lv_natxt NO-GAPS. ENDIF. lv_nawork = lv_natxt. REPLACE ALL OCCURRENCES OF REGEX '&[s|1-4]' IN lv_nawork WITH '*'. IF lv_message CP lv_nawork. * found! lv_found = abap_true. EXIT. ENDIF. ENDSELECT. IF sy-subrc > 0 OR lv_found <> abap_true. RAISE message_not_matched. ENDIF. ENDIF. ELSE. * all the checks were done by the caller, so simply go on lv_natxt = pv_natxt. IF pv_ignore_spaces = abap_true. CONDENSE lv_natxt NO-GAPS. ENDIF. ENDIF. * first we analyse the t100 text if and where it contains variables FIND ALL OCCURRENCES OF REGEX '&[s|1-4]' IN lv_natxt MATCH COUNT lv_cnt RESULTS lt_result. IF sy-subrc > 0. EXIT. "no variable found, do nothing ENDIF. CHECK lv_cnt > 0. "to be really sure * prepare the limits lv_textln = STRLEN( lv_natxt ). lv_msgln = STRLEN( lv_message ). * DO lv_cnt TIMES. MOVE sy-index TO lv_ixa. READ TABLE lt_result INDEX lv_ixa INTO ls_resulta. * determine the name of the actual variable (can be &1 or & ) lv_varoff = ls_resulta-offset + 1. ASSIGN lv_natxt+lv_varoff(1) TO INTO lv_varnam. "this will be the destination of the move ELSE. MOVE lv_ixa TO lv_varidx. CONCATENATE lc_field lv_varidx INTO lv_varnam. ENDIF. * we need the offset and the length of the message token after the first hit lv_tkoff = ls_resulta-offset + ls_resulta-length. IF lv_ixa < lv_cnt. * read next hit lv_ixn = lv_ixa + 1. READ TABLE lt_result INDEX lv_ixn INTO ls_resultn. lv_tklen = ls_resultn-offset - lv_tkoff. ELSE. lv_tklen = lv_textln - lv_tkoff. "last line, take the rest of the string ENDIF. * if first line, then the begin of the variable is the offset of the hit, * else we have to calculate using the value of the preceeding variable and it's length IF lv_ixa = 1. lv_varoffa = ls_resulta-offset. ELSE. lv_varoffa = lv_varoffn. ENDIF. * build the next t100 text token, if existing IF lv_tklen > 0. ASSIGN lv_natxt+lv_tkoff(lv_tklen) TO . * find it's place in the message to be analyzed FIND FIRST OCCURRENCE OF SUBSTRING 0. * ???? CONTINUE. ENDIF. lv_varlen = lv_tkoff - lv_varoffa. * token is not existing, the next variable is directly adiacent to the actual ELSE. * one variable can be 50 bytes long, so try to put as much into it as possible (quick&dirty) lv_varlen = lv_msgln - lv_varoffa. IF lv_varlen > 50. lv_varlen = 50. ENDIF. lv_tkoff = lv_varoffa + lv_varlen. "shift pseudo token ENDIF. "if lv_tklen > 0. * prepare for the next turn. lv_varoffn = lv_tkoff + lv_tklen. * finally save the reconstructed variable IF lv_varlen > 0. ASSIGN lv_message+lv_varoffa(lv_varlen) TO . ENDIF. * we expect only 4 message variables IF lv_ixa = 4. EXIT. ENDIF. ENDDO. ENDFUNCTION. h3. Scheduling Definition We start transaction *CRMC_ACTION_CONF*, open our action profile in change mode and press the +Create+ button: CRMC_ACTION_CONF add scheduling

There is an impressive dialog in scene 4 of Bertold Brecht's Drama "Life of Galileo" where the court scholars refuse to use Galileo's telescope as it is useless to observe things that cannot exist because they would contradict Aristoteles and the Absolute Truth of the Church ("... if your tube shows something that cannot exist it must be a rather unreliable tube.").
I experienced such a Jesuitical sophistry last week with a customer message.

Java Gui and Happines

At our companies plants we have many machine tools controlled by Linux systems. As we work highly cost optimized we use these systems and also the SAP Java Gui for the required SAP QM transactions. To better support the colleagues I use the Java Gui too for most of my SAP work, finding bugs and helping to improve it.

So since I have been using the Java Gui on Linux with the Solution Manager for the past seven years I seldom had problems.
OK, the SolMan graphics don't work, but you get a polite message about this. Sometimes the html display of the DSWP transaction is messed up, but after some service packs it works again.
Sometimes while coding I am sad that the new ABAP editor is not ported as Java Bean (why not?) and I am angry about the missing graphical screenpainter. Sometimes I shake my head because the SOLMAN_WORKCENTER's login dialog is broken (which would be very easy to fix ...), but it works great when opened directly in firefox. Almost all other transactions such as SOLAR01, SOLAR02, STWB_2, and so on, work well.

Dumps are Not Nice

During some tests last week with SOLAR02 "Test Cases" tab I tried to upload a file as a Test Document and suddenly I faced a dump. I opened the post mortem debugger, looked at the coding and understood the problem.

In method CL_SA_DOC_CONT -> IF_SA_DOC_CONT~UPLOAD_DOCUMENT there is at line 186 ff. (ST SP 25) following code which tries to separate the path from the filename:

Here we have a misunderstanding of the SPLIT commands.
It does not behave like a search expression that would be false (or RC > 0) if the search item is not found. Instead if the separator is not found it will copy the whole character string into the destination table.
So the destination table will always have at minimum one row and the expression "if not l_pathix > 0" will always be false, so that the "split at '/'" will never be executed, with the sad consequence that in the following code:

l_length_path will finally be 0 and the "write" statement will overwrite l_path_data with spaces, so that the following method will throw the uncaught exception DIRECTORY_SET_CURRENT_FAILED ==> dump.

A simple and transparent case, wouldn't you say? So did I and opened a customer message with a nice screen shot of the post mortem debugger with all important variables visible and a clear explanation.

A Dump That Cannot Exist!

The first level support was impressed and passed it directly to the development support (wow!). And here it comes:

Dear Customer,

your analysis is completely correct.

As you have slashes and not the Windows backslashes in your file paths,
we suppose that you use SAP GUI for Java.
However, transaction solar02 and Solution Manager in general is not
released for the Java GUI, as you can see in transaction
se93.
The problem now is that a correction would be fairly simple for the
upload method, but as we do not know what else is necessary to enable
this GUI, we will only provide a correction in the context of a general
Java GUI enablement.

Best regards

After having recovered a bit from the shock I answered that I spent a lot of time to present the bug on a silver tablet and that a correction refusal would not be very polite, that the coding relies heavily on peculiarities of MS Windows which might change in the future, that I never asked to activate the little nice check box for the Java Gui in SE93 and finally that a bug is a bug is a bug and should always be fixed.

The dismal answer ("Solution provided" with a link to SAP note 10):

Dear Mr. Escher,

first of all I would like to thank you very much for your elaborated
analysis. Basically you are right, that this piece of code is not 100%
clean.
But: Considering the assumptions where this code is supposed to be
executed (e.g. running within SAP GUI for Windows only) it has been
working correctly, as far as we know, and the potential bug is not
actually a bug in this environment.
Anyway, in general I fully agree that code should be as clean as
possible, and we discussed it again. We came to the conclusion that in
this particular case we would not change the code in the proposed way.
Let me briefly try to explain why:
We simply do not know how far our transactions actually work in a non
Windows environment. So we do not think that it is useful to change one
detail without being able to assure that everything else works fine in
the non-supported environment, where we definitely have known
restrictions.
This would not be serious from our side, in my opinion, and not really
helpful.
I understand if you do not accept our answer, but cannot provide a more
satisfying answer for you.
With kind regards,
Development SAP Solution Manager

Conclusions

Here we have another example that SAP is a very rich company.

Instead of replacing the few lines of code with lines as they can be found in the same method (line 53: if l_test_directory cs '\'. l_separator = '\'. else. l_separator = '/'. endif.), which would have been done by one person in some minutes, they preferred to verbosely dispute about not doing it!
How many people were involved in the discussion about these 5 lines of code?

Imagine you have a car and one day you discover that the cigarette lighter causes a short circuit if you use it. You bring it to the garage to have it fixed, but the automobile mechanic refuses to do his job and fix it, pointing to a "no smoking allowed" sign inside the car. Then he makes a speech that it would not be serious from his side and not really helpful to repair a cigarette lighter in a car that has a smoking ban.

What would Scott Adams's humoristic genius make out of this grotesque?

OK, then let's begin with the Copernican revolution and ask for Java Gui support for the Solution Manager! May be then we will have this little bug fixed :-)

Riccardo Escher

Play It Again, Sam

Posted by Riccardo Escher Apr 4, 2011

In a world of lacking resources either you are rich or you have to be smart. SAP seems to be rich and loves to do everything twice.

Usually you fight against the lack of resources by being smart and avoid doing nthings twice. But since it's early R/2 days SAP loves to do double work.

And the pity is that it is not an evolution where a new component replaces and old one. No, both elements remain in competition with each other with a more or less large intersection - and the customer always has to worry about which one to use.

Do you remember the wars between the SAPDYNP and the SAPPG38 guys? Every party tried to do the same things the other one did, but differently. So, instead of simply attaching dynpros to reports for selections, we now have to struggle with two types of screens, dynpros and selection-screens (and an impending  carpal tunnel syndrome when coding the latter).

A smart developer facing the customers heterogeneity would adopt a cross compiler framework, so he/she codes only once and then he/she throws the code through the cross compiler for the different customer environments. This would have been smart! But SAP is rich and for the SAP Gui development it prefers to use Microsoft products which notoriously bind you to the Microsoft Windows platform (Honi soit qui mal y pense) and then SAP rejoices in rewriting all gui coding a second time in java (unfortunately not all modules).

Do you wonder why you have to bother with both an ABAP and a Java instance? I have often seen my BW colleagues scratching their head trying to figure out on which platform they should implement their requirements.

But the Gui is from yesterday. Now we have html-stuff because it is reputed to be more modern. So all new transactions are realized as WebDynpros for Java, oh, pardon, as WebDynpros for ABAP.

Ok, let's just talk generically about WebDynpros. They all have the same MVC paradigm and look&feel and so on. But what's that? There is a second UI with another programming model and another look&feel, the CRM UI, sprouting in front of to the WebDynpro one. So what?

Play It Again, Sam, and again, and again...

A pioneer strands

After years of sermonizing to our system admins to have a look at the features of the Solution Manager one of them finally gets interested into Solution Manager System Monitoring.

Happy to find the first potential admin ally I give him some documentation links, show him the system monitoring work center and also the old SOLUTION_MANAGER transaction and the suitable solution he should use.

Two days later he sits in front of me frustrated that in the Setup System Monitoring screen of that solution the menu entry Edit -> Create Step for Check is grayed out.

Disactivated Menu Entry

He then shows me another (obsolete) solution where this menu entry is active(!).

I am puzzled. Why is this so? I search for some sort of settings in the transaction itself, in the solution, in the SMSY_SETUP, in the Expert Settings of SMSY_SETUP: Nothing.

I start the wonderful new  xsearch but I don't find any peace of text touching on this situation.

No chance to convince my brave admin to use the "User Defined Alerts" which are offered for any application server. He is determined to add checks to the tree (for example an SM51 check at the beginning) and wants to know why in one solution this is allowed an in the other solution not.

Once upon a time

Little digression:

Once I worked together with a super consultant, who was not one of the ordinary slide flippers. Besides many other things I admired his deep knowledge of the whole status maintenance (SD, CRM), of all the tons of strange buttons, transactions, and so on, and asked him where he found all that documentation. He looked into my eyes like Gary Cooper in High-noon and said: "The hard way. I debugged the whole coding three times!".

I might be a crummy search machine user, but I am a quit good ABAP developer, so I remember that lesson, don't loose time in searching for non existing documentation and begin to dig.

Here comes the cavalry!

No help from SAP Help - the cavalry it's me.

First I notice that there are always three menu items which are active or not, together with the button "Action List": It must be a coded feature. Let's have a look at the menu.

I open the dialog "Menu -> System ->  Status":
image

Now I do a double click on the GUI status DYN200 and I determine the code of the menu entry: CHECK_ACTION:

 

GUI Status

I press the button of the "Where-used list" and  select "In the program":

Where-used list

And so I find in the function group DSVAS_SERV the local method lcl_session_dispatcher->exclude_status where the menu items are switched off:

Source code 1

The name of the method sounds convincing. I put an external break-point (see below) and run the transaction: Yes, it is the right place. In our case "no_actionlist" contains 'X'. But why?

I  put the cursor on "no_actionlist" and press the lovely "Where-used List" button again and find that in the tapeworm method "new" the value is taken from a memory id:

Source code 2

Damned! The lovely "Where-used List" button will forsake me. What now? Debug the whole program until I find the place where this memory id is filled? It would take days of F5-hitting.

Big Berta will do the job

No chance, I have to take Big Bertha out! I  start transaction SE30

SE30 Variant
Now I create the variant statement_trace. Usually SE30 is taken to find the performance hot spots which need code optimization, so it aggregates the coding. But as I am looking for a single statement, I have to switch off the aggregation. Here my choices for the statements (the more statement you trace, the bigger the trace file):

SE30 Variant Statements

And the switched off aggregation:

SE30 Variant DurationType

I indulge in 100 MB file size - do you think they will be enough to trace SOLUTION_MANAGER? :-)

I start SE30 with the transaction SOLUTION_MANAGER and navigate to the Setup System Monitor (all is really slow now!) and then I leave the setup.

I receive a warning, that the file size was reached! I hope that our memory id is already in the trace file and quit the warning; now I can evaluate the resulting performance data file. The system has to process the giant trace file.

I select Menu -> Utilities -> Dump (perf. file) -> Standard. I have now time enough to view in SM50 the rapidly increasing memory consumption. But our solution manager system is hardened for SOLAR_EVAL Reports and so I don't fear out of memory dumps.

SE30 List hit

2,5 GB memory plus 2 GB of private memory - not bad! By the way, the shrunk list would be faster consuming less memory, but would not contain the string we are searching for.

Having the list I search now for the string "DSA_ACTIONLIST" which is the first part of the memory id as we have seen in the coding before. And I find it!

Now I press the button "Source code" and here we are!

Source code 3

So Big Berta hit the code (I could also have used a statement breakpoint like I will describe later, but I wanted to show this last solution).

I suppose that our solution manager system administrator would be glad if I now delete the trace file.

By the way, the second part of the memory id is the session number which can also be found in the Setup System Monitoring Menu -> Goto -> Technical information. SM is the session type and 090 the actual client. You can also open the Setup using transaction DSA with the session number.

An inveterate foe

I use the "Where-used List" button and discover that RDSVAS_GEN_INCLUDE is included by an overwhelming amount of programs; I try to put an external breakpoint and receive a similar crowd of programs to select one of. Which one should I choose?

I deleted already the trace file, so temerariously I press the "Select all" button, but I receive the message "You cannot set more than 30 breakpoints".

OK, you are an inveterate foe, but I will get you!

I start the transaction SOLUTION_MANAGER which opens the last screen with the System Monitoring Administration  of our solution. I enter the famous hex "/h" into the OK-Code and click on the "Setup System Monitoring" link on the left.

I am in the debugger now, my second home, my documentation library. First I open the Tab "Break./Watchpoints" to delete the useless breakpoints, so that I can set new breakpoints during debugging. And I let the journey begin.

I cannot determine the main program where the form  switch_of_actionlist is called, but fortunately the statement which makes a search so difficult is also a seldom used one. So I select the tab for Breakpoints:

Debugger Select Breakpoints

and create an ABAP command breakpoint:

ABAP command export to memory breakpoint

Now I can relax and press F8! After some time the debugger pops up: This is the place where our memory id is set: during the processing of function module DSVAS_PROC_SESSION_OPEN:

Debugger breakpoint

I select the Tab "Desktop 2" to climb up the ABAP stack and find that the decision to deactivate the action list is performed in the method EXECUTE by dynamically choosing the form routine action_027(RDSVASASOLMON_CUST_________027):

Debugging method execute

By navigating to the source code (Menu -> Goto -> Goto source code; also as a button in the stack window) I determine the local class name lcl_action_sequence.

Some more comfort

Little digression:

I realize that it is clumsy to always start my debugging with SOLUTION_MANAGER. So I prepare a smarter starting point. First I look in the ABAP stack for a function module which has only few and persistent import parameters (tab Desktop 1 -> Local). I choose DSVAS_SERV_SESSION_OPEN:

Function DSVAS_SERV_SESSION_OPEN

I point the cursor at one of the local variables and press the Tool-Service Button:

Debugger Save Variables as Test Data

I save the actual data as test data for the SE37 transaction. So when I want to do a second debug session I can start directly via SE37 the function module DSVAS_SERV_SESSION_OPEN -> Test/Execute -> Button "Test Data Directory", which is really faster than starting via SOLUTION_MANAGER!

Just as a hint, there are some more interesting debugging tools hidden behind the "New tool" button of one of the "Variables" tabs:

Debugger more tools

If you like your new tools, you might also save your new layout by pressing on the button "Layout".

Understanding the problem

I make a paragon with the (obsolete) solution which does activate the action list menu entries. Not surprisingly the export to memory breakpoint does not fire (which means that the memory id will never be "<> space").

So I have to insert a normal breakpoint to stop at the crucial step:

Debugger create method breakpoint

The program stops as expected and I determine that  lf_form_name is still = 'ACTION_027' but this time the main program is 'RDSVASASOLMON_CUST_________018'.

So I must find the place where PROGRAM is set. It's not a local and not a global variable. I suspect that it is a class attribute (the debugger doesn't reveal it). So I insert "ME" as a variable and double click upon it, the debugger opens the tab "Objects" with the reference "ME" and yes, program is an attribute of the local class lcl_action_sequence.

Some tests with a watchpoint "PROGRAM" or "ME->PROGRAM" were not successful, the rules of this tool are too tight, so I  open the local class definition in the editor, mark the attribute "PROGRAM" and press the lovely "Where-Used List" button. I get a list of hits; I find two places where the attribute might get his value: lcl_action_sequece->new (Include LDSVAS_PROCCD0) where "PROGRAM" is chosen by a call to the function module DSVAS_CDMNT_CONTAINER_NAME and lcl_action_sequence->load, where the value is read from the database.

I set two external  breakpoints at these places so that I can debug normally this call. One example:

Editor set external breakpoint

and I restart in SE37 the function module DSVAS_SERV_SESSION_OPEN.

It's the second place, the name of the program is taken (Method ->restore) from the database dsvasresultsgen(as).

So I have found that the program name (and thus the disactivation of the menu entries) is an integral part of the system monitoring session of my solution.

Indeed, when I take a closer look at the technical information of both sessions I notice that the session which allows to edit the action list has the "Check Group SOLMON_CUST Version 18" while the session which annoys us has the "Check Group SOLMON_CUST Version 27".

A brief look at the attributes of both programs shows that _018 seems to belong to "ST-SER Release 2005_1" while _027 seems to belong to "ST-SER Release 2008_2". This is really funny because both solutions where created in 2006.

Our first impession was true: The disactivation of the menu entries seems to be a feature. We take a brief look at the transaction DSADEV Service Development Workbench. Yes, we can open the CheckGroup Version 27 (actual is 28) and have a look. We find also a Tab "Compile Report", so our suspicion that the above mentioned reports were machine generated comes true.

When we open in the "CheckGroup Version 027" the tree "Actions" we find the action "027 Initialize SALR". Double clicking upon this action we jump into the already mentioned form routine  action_027(RDSVASASOLMON_CUST_________027) which calls switch_of_actionlist.

Result

We have found the reason for the difference in behavior of both solutions - it seems to be a feature. But we didn't find the motivation of this difference: Why should the action list be switched off?

This question cannot be answered with the debugger.

May be one of you has an answer ...

Preamble

The history of this blog series:
Pep Up Your ChaRM - Part 1: HowTo Create a Smart e-Mail Action
Pep Up Your ChaRM - Part 2: a CRMD_ORDER Slimming Cure
Pep Up Your ChaRM - Part 3: Turn Cinderella PDF-Mails into Pretty&Usefull Ones

This time we will present a small and lightweight blog. The next weekend we will refresh via system copy our Q systems, so we have to push the colleagues to finish and close the ChaRMs they left lying around. Obviously praying to the fishes is more effective than our appeals, so probably we will have to do the closing ourselves.

Many ChaRMs can be closed via the service report, but not all.  So we will get repeatedly this brain dead nag screen:
The nag screen

Sometimes this screen appears more than one time when doing a status change.

Do you love it too?

A pestilent dialog!

By the way, this nag screen is also really dangerous! Two years ago our hotline became incandescent because nobody could create a hotfix.

Finally they found my hideout; I analysed the situation: A user was owning four locks, one of them locking the maintenance plan itself. The user was not responding to my calls so I closed his session. I tried then to reproduce the locks but I didn't succeed in creating such a long during lock of the maintenance plan itself. So I asked the user by mail what the hell he was doing to be able to lock the ChaRM for hours and when he came back from his meeting he sent me in his candour this screen shot:The all locking nag screen

You probably have already noticed that the nag screen appears when it wants; in this case the nag screen decided to attack the user only after he started the status change to "In development".
First the user confirmed the creation of the transport requests. As he was short of time, he hurried to a meeting without waiting for this status change to be finished. So when the nag screen appeared he was not there to quit it.
Murphey rules! The change document he was asked to accept was the SDMN of the maintenance plan itself! (This happened during the status dependand action SET_BO_LINK_TO_CHANGE_DOC).

I opened a customer message hoping to get a note which eliminates this pestilent screen, but pitifully I received only a workaround: Go into the IMG SAP Solution Manager -> Scenario-Specific Settings -> Change Request Management -> Extended Configuration -> Change Transaction -> Change Transaction Types -> Make Settings for Change Transaction Types (Id SOCM_MAIN_001) and delete the existing entry (marked in red):IMG current user

Did you wonder why the nag screen appears sometimes twice? Now you know it: You have also to accept changes to predecessor documents.

I cannot immagine which deeper sense it might have to have every ChaRM user to accept (or not) the maintenance plan. So I can only suggest to all to use this workaround!

In my understanding the only feature of this dialog is to decide if you want to appear as the Current User (partner function SDCD0004) of the ChaRM. There is a Condition CHECK_PROCESSOR, that generates a warning message 020(SOCM_ACTION_LOG). And there is the transaction S_DMC_47000022 "Changes to be Processed by Me" which uses this partner function for selection.

We have the policy that users should always answer YES to the question. So why bother them? The ony one who would answer NO to the nag screen question is an amministrator who needs to help a user and doesn't want to touch the actual assignment.

Best would have been if the pop up dialog offered the additional choice: "Answer always yes" plus a check-box "Never ask me again", but this simple ergonomic feature is not provided by the standard. So we have to code our own solution.

Disinfection

To make both the administrator and the user happy we will create a new user parameter which gives the user the chance to choose what he wants: automatic yes, automatic no or please ask.

The screen itself is called inside the call back function module SOCM_CRM_PA_ACTUAL_PARTNER. You can see it with transaction CRMV_EVENT (Selections: BUS2000116 - 1 Immediately - STATUS- BEFORE_CHANGE). We will have to enhance this function module. We prefer this over the replacement with a customer function module because so we participate to further development if any.

First we create with SE80 in one of our customer packages the user parameter (SPA/GPA Parameter) ID ZSV2I_CHARM_AUTO_ACC "Charm: autom. accept CD (X=Yes, -=No, else ask)".

To enhance SOCM_CRM_PA_ACTUAL_PARTNER we need to insert an enhancement-section around the call of the loved pop-up (before you start coding, please have a look if SAP note 1334845 "SE38: Dump when creating an enhancement section" needs to be implemented).

First open in SE37 the function module in change mode, then select the call of the popup:Select the pop up call

Then go to Menu -> Edit -> Enhancement Operations -> Create Enhancement. You will get a new dialog "Create Enhancement Option", the radio button "Enhancement Section" is already selected.
Please do not press ENTER, but first insert the ID of the Enhancement Section (we choose "POP_TO_CONFIRM_TURNOUT"), then press the button "append new row" to create a new enhancement spot and insert all needed values for this spot before pressing ENTER:
Creation of enhancement object

Save and generate. Now we are ready to change the behaviour of the coding by replacing the coding embraced by the enhancement section with our own one.

First we leave the change mode of the function module. Then we call Menu -> Function Module -> Enhance Source Code (or press the button with the helix), then we put the cursor in the line with the ENHANCEMENT-SECTION selecting it and call context menu -> Enhancement Implementation -> Create Implementation.

We get a small dialog asking us for a name and a short text. We insert ZSV2I_EICM42 "ChaRM Enhance SOCM_CRM_PA_ACTUAL_PARTNER" and select the same package when saving (if we have before created a switch in this package we can also connect the enhancement implementation to this switch, so that the implementation itself can be switched on and off).

The system creates the ENHANCEMENT as a new edit section under the section and copies the old coding of the section into it. We edit now our coding and then save & activate the enhancement.

SOCM_CRM_PA_ACTUA_PARTNERS will finally appear like this:


IF lv_partner_guid <> lv_partner_guid1.
IF lv_partner_guid IS NOT INITIAL.
*{ REPLACE C2IK901968 1
* CALL FUNCTION 'POPUP_TO_CONFIRM'
* EXPORTING
* titlebar = text-001
* text_question = text-002
* text_button_1 = text-003
* text_button_2 = text-004
* display_cancel_button = 'X'
* IMPORTING
* answer = lv_answer
* EXCEPTIONS
* text_not_found = 1
* OTHERS = 2.
ENHANCEMENT-SECTION POPUP_TO_CONFIRM_TURNOUT SPOTS ZSV2I_ESCM14 .
CALL FUNCTION 'POPUP_TO_CONFIRM'
EXPORTING
titlebar = text-001
text_question = text-002
text_button_1 = text-003
text_button_2 = text-004
display_cancel_button = 'X'
IMPORTING
answer = lv_answer
EXCEPTIONS
text_not_found = 1
OTHERS = 2.
END-ENHANCEMENT-SECTION.
*$*$-Start: POPUP_TO_CONFIRM_TURNOUT------------------------------------------------------------$*$*
ENHANCEMENT 1 ZSV2I_EICM43. "active version
* 2009/10/23 Escher Call pop up "Accept document" only
* when the user likes it
DATA:
zlv_param TYPE boolean.

GET PARAMETER ID 'ZSV2I_CHARM_AUTO_ACC' FIELD zlv_param.
IF sy-subrc > 0 OR
( sy-subrc = 0 AND zlv_param NA 'X-' ). "X = Yes, - = no
CALL FUNCTION 'POPUP_TO_CONFIRM'
EXPORTING
TITLEBAR = TEXT-001
text_question = TEXT-002
text_button_1 = TEXT-003
text_button_2 = TEXT-004
display_cancel_button = 'X'
IMPORTING
answer = lv_answer
EXCEPTIONS
text_not_found = 1
OTHERS = 2.
ELSE.
IF zlv_param = 'X'.
lv_answer = '1'. "simulate YES, accept
ELSE.
lv_answer = '2'. "simulate NO, do not accept
ENDIF.
ENDIF.
ENDENHANCEMENT.

*$*$-End: POPUP_TO_CONFIRM_TURNOUT------------------------------------------------------------$*$*
*} REPLACE
IF ( lv_answer = '2' ) OR
( lv_answer = 'A' ).
Enjoy!
h2. Preamble
The history of this blog series:   {code:html}Pep Up Your ChaRM - Part 1: HowTo Create a Smart e-Mail Action{code}  {code:html}Pep Up Your ChaRM - Part 2: a CRMD_ORDER Slimming Cure{code}     Back again from my vacation, I will go on in the implementation of our ZROL transaction type for authority role transports.  You can code how many working lists you like, users will always prefer to react to e-mail notifications. Did I say prefer? Users react +solely+ to e-mails. All other tools you give them will be diligently overseen.    But normal PPF customizing will create only *ugly* text-only *or bulky* PDF messages, depending upon your SAPConnect customizing (+transaction SCOT, selection of node SMTP, in the group "Supported address types" select "Internet" and press the "Set" button+). Here you can choose the output format for SmartForms. Obviously you would like to select "HTM", but this is not offered for SmartForms).   My users have many additional wishes (users without wishes are probably ill - +wishes are like pigeons: the more you feed them, the more they come+):  *  the e-mail notification should have an attachment with a SAP Gui for Windows short cut that opens the right transaction (+why isn't there a solution also for the Java Gui?+)0.1. when the transaction passes from the security team to the tester (status change "To Be Tested") the role administrator wants also to be informed as CC: I love to be a good Santa to my users, so I coded these wishes for them. Here I will show you how. The last two blogs did have much pictures, this one will carry a heavy abap load. This is the mail notification that is sent to the tester when the security team gives it's approval as an example of the result:Example for pretty e-mailYou can see that it's a nice html-mail, that the role administrator is inserted as CC and that the recipient can open CRMD_ORDER with the right transaction number by double-clicking on the attachment. But let's begin! h2. Preparation For the SAP Gui shortcut to open the right business transaction number we need a dedicated transaction. First we create a mini report to open CRMD_ORDER with the right business transaction number:  REPORT  zsv2i_cm02.INCLUDE lcrm_busprocessnd_bapicon.PARAMETERS:  p_crmid    TYPE crmt_object_id_db,  p_mode     TYPE crmt_component_type                DEFAULT gc_component_type-display,  p_objtyp   TYPE crmt_swo_objtyp_process                DEFAULT 'BUS2000116'.DATA:  gv_guid    TYPE crmt_object_guid,  gv_guid2   TYPE guid_32,  gt_return  TYPE TABLE OF bapiret2.START-OF-SELECTION.  SELECT SINGLE guid INTO gv_guid    FROM crmd_orderadm_h    WHERE object_id = p_crmid.  IF sy-subrc = 0.    MOVE gv_guid     TO gv_guid2.    CASE p_mode.      WHEN gc_component_type-display OR space.        CALL FUNCTION 'BAPI_BUSPROCESSND_DISPLAY'          EXPORTING            business_process = gv_guid2            object_type      = p_objtyp          TABLES            return           = gt_return.      WHEN gc_component_type-maintain.        CALL FUNCTION 'BAPI_BUSPROCESSND_CHANGEDIALOG'          EXPORTING            business_process = gv_guid          TABLES            return           = gt_return.    ENDCASE.  ENDIF.  SET SCREEN 0 +By the way, these coding text areas look best when viewd with firefox under linux because in this environmen they are displayed with a fixed font, so all formatting is well preserved. + Then create with SE93 a "Program and screen (dialog transaction)" which calls this report:Transaction to open a ChaRMNow we are ready to code a Gui Shortcut attachment (see later). h2. PPF SmartForm Mail Methods h3. The main method    We will now code the main static method which has to be inserted into the PPF-Customizing as Processing Method of the Smartform Action (please see Part 1 of this series). We call it *EXEC_SMARTFORMS_ZROL_MAIL* because it has a special status handling that is unique for this ZROL transaction type.   For this method we exploited two other methods which can be both found in the standard class *CL_DOC_PROCESSING_CRM_ORDER*:  0.1.  *CRM_SRVORDER_EXEC_SMART_FORM* for the service order handling and0.1.  *CRM_ISA_AUCTION_SMART_FORM* for the conversion to html and the e-mail handling (there is also a Blog of Pavan Bayyapu which shows exactly the same coding with the same bugs (Sending HTML Email from SAP CRM/ERP  (Sending HTML Email from SAP CRM/ERP) but without quoting this source :) ). Further we adopted the technique explained in SAP Note 616383  (https://service.sap.com/sap/support/notes/616383) to dynamically call the active smart form.    The coding of  *CRM_ISA_AUCTION_SMART_FORM* has a little drawback: when your Smartform contains graphics, some stupid mail agents implementing a proprietary version of the standard (RFC 2387) will display the html mail as an attachment and not inline as defined in the mail header (see SAP notes 730534  (https://service.sap.com/sap/support/notes/730534), 810594  (https://service.sap.com/sap/support/notes/810594), 927439  (https://service.sap.com/sap/support/notes/927439)), which dismantles the poor e-mail notification. Our solution will be to simply avoid the parameter "filename" when creating the MIME part (see down, method set_main_html).  We have also streamlined the smartform and it's corresponding function and thrown out all useless crmd_order parameters.  Our coding doesn't use customer tables or dictionary objects, so it should be correct as is. You have only to create with *SE80* the checkpoint group *ZOG_CHARM_OUT*, which is useful for debugging (switch on with transaction *SAAB*)    At first we have to create with the class builder (*SE24*) our class  *ZCL_IM_SV2I_OG_SMARTFORMS_MAIL* inheriting from *CL_SF_PROCESSING_PPF*:Create Class

When your users see for the the first time the transaction CRMD_ORDER which is used for Change Request Management they will be a little bit shocked.

Obviously you have created a document which explains which fields should be used and which fields should be ignored, but why should a developer read a documentation if he/she knows the phone number of the guy who is responsible for this?

So just as a survival action we should elminate all fields we don't need.

Create a Transaction Variant

To slim down CRMD_ORDER first we call transaction SHD0 (zero, not o) and create a suitable transaction variant for our ZROL users (see Part 1 of this blog) and press "Create":
SHD0 first screen - new

On the next screen we get the well known CRMD_ORDER; here we make only one entry, we insert "1" as IBase, because we will advance it to a constant.

When we press [ENTER] we will get the first of a series of Pop-Up dialogs "Confirm screen entries" for every sub-screen of CRMD_ORDER. These pop-up dialogs save the single screen variants; we are invited to insert a short text for the variant and get the chance to edit also the menu functions:
Creating screen variants

For example we don't want our users to delete a change transaction, so obviously we don't give them the authorization to do it, but to avoid e-mail traffic in the style "I wand to delete ChaRM 5000013500 but am not allowed to; can you please do it for me?" we will disable these menu functions and also the corresponding function keys.

To disable unneeded functions at Screen value SAPLCRM_10_MANAG_UI 0100 (the first screen we get) we press the button "Menu functions" and deactivate the functions we don't need (Yes, I am very optimistic. A really tough user would write asking why the menu function "Delete" is inactive, instead of reading our documentation ...).

One example:
SHD0 deactivate menu functions

By the way: If you have a SDHF clone which is created by a SDCR by approval it is also relaxable if you deactivate CCPY (Copy) and FLWU (Follow-Up Transaction)!

Now we press [ENTER] ("Continue") and so on, screen by screen, giving short texts to the screen variants

Here we hide the category and make the external reference obligatory:
SHD0 screen service_ui 7153

This is only an example. Making fields obligatory in CRMD_ORDER is a little bit bulky; if you have time for coding it would be better to implement for example a status dependend check (IMG SolMan -> Scenario-Specific Settings -> Change Request Management -> Extended Configuration -> Change Transaction -> Change Transaction Types -> Consistency Checks  in Change Request Management).

The most interesting screen of all is SAPLCRM_SERVICE_ROB_UI 7110! Here we make the IBase 1 a constant, make also the IBase component obligatory and hide other fields which make no sense in our transaction type:
SHD0 IBase, Subject, Product ID

After this screen we press "Exit and Save" because we have served our purpose.

We get an overview of our change transaction variant, and when we save we are asked to create the object directory entries to make all transportable.

I am wondering if it improves performance deleting in the "Transaction Variant" tab all assigned screen variants which were only inserted by the automatic recording but which did't carry any really variant... May be in a rainy day in the future...

Bind the Transaction Variant

We won only half  the battle as we have now to dig deeeeeep into the CRM customizing to make this transaction variant work. We call SPRO and open CRM -> Transactions -> Basic Settings -> Assign Transaction Types to Transactiono Variants (IMG activity CRM_BTX_TRANSVARIANT).

Here we insert our newly created transaction variant:
assign transaction variant to transaction type

Further Customizing

BAdIs

If you want to make the correlation transaction type <-> variant more dynamical you might have a look at the BAdI CRM_10_TCVARIANT (IMG -> CRM -> Transactions -> Basic Settings ->Business Add-Ins -> BAdI: External Transaction Variant Matching).

You can also make fields read only by implementing the BAdI CRM_ORDER_FIELDCHECK (depending on the user status).

Customer Categories

In our example we hid the field for the category. But we could also have created our own categories, for example we have created for another transaction type which we created to synchronize a parallel track the category "Skip Tests" (a very popular category indeed!).

In this case we left the field visible and created our own category (IMG Solution Manager -> Scenario-Specific Settings -> Service Desk -> Service Desk -> Maintain Categories and Priorities -> Maintain Categories, ID CRM_AKT_001):
Category creation

Also here, this is only half the battle. Deep in the CRM customizing we find the chance, to bing this category to our transaction type hiding all the other ones!

Calling IMG CRM -> Transactions -> Settings for Activities -> Maintain Categories, Goals, and Priorities -> Assign Categories to Transaction Types (ID CRMV_ACT_CAT_ASS) we can filter our own categories.



Introduction

Within the German User Group (DSAG) I founded 2007 a customer workforce group which aimed to ehnance the stability and the ergonomics of the Solution Manager Change Request Management (ChaRM).

During the DSAG technology days in Februay 2008 we consigned our development request to the SAP representatives.  But (freely adapted from G. W. F. Hegel) St. Anthony of Padua, as he sermonized to the fishes, achieved more than I caused with our workforce group and our detailed paper full of screen shots and explanations.

So, after 18 month of waiting for an answer I decided to implement some of the needed enhancements and to share them with you, the SDN folk. May be this will stimulate a couple of developers to open their treasure box too, so I will have less to code :-).

My First How-To: e-Mail notifications at status change

Many ChaRM users love to be notified by an e-mail if they have to do an action on a Change Document. But they don't like to receive more than one mail because of the same action.

So we have to build a PPF action which will send the notification exactly only when the status has changed.

There are many complicated method to achieve this (for example one described in note 865619), but here we want to show a rather simple method.

In our example we are designing a change transaction type for security roles transports (ZROL) and we want to notify the security team that there is a change document which needs their approval.

So the e-mail should be send exactly one time when the status changes from E0002 to E0011:
Status Schema (the only way to see the user status values (E00*) I know of is to have a look with SE16 into table TJ30).

Smartform action

First we create the PPF action for the mail:
IMG action profile edit
(or call transaction CRMC_ACTION_DEF).

First we select our action profile by double clicking on "Action Definition" in the tree:
Change action profileand then in the action definition we press the button „New Entries":
New action

The action is partner dependent, so we insert the partner function we have created for the security team(s) in our partner schema (ZOSR0002).
It is important that there can be only one unprocessed action at a time.
By the way, we have copied with transaction SMARTFORMS the smartform CRM_SLFN_ORDER_SERVICE_01 (which can be found in the action profile SLFN0001_ADVANCED in the action SLFN0001_ADVANCED_MAIL) to our name space (ZSV2I_OG_CHARM_SERVICE_06) and then we have adapted this Smartform to our needs (not so interesting in this blog).

Now we maintain the „Processing Types" to insert our smartform informations (Button „New Entries", F4-Help for the action, Selection of "Smart Forms Mail").

Now we mark the new line and press the button „Set Processing":
Add Action Smart Forms Mail

Now you can insert the technical details of the Smartform action:
Add action details

Conditions

Second important step, we have to define the conditions:
IMG Action Conditions
(or call transaction CRMC_ACTION_CONF).

We open the conditions of our action profile:
Action Condition 01

In the right screen we press on the button "Create" and we select our newly created action (you may control the details of the action definition in the first two tabs "Overview" and "Processing Details"):

Action condition 2

First we create the schedule condition itself; to do this we go to the tab "Schedule Condition":
Schedule conditions begin

We press the button "Edit Condition" and we jump into the most popular Condition Editor; we give a name for the new condition (they can be reused for other actions) and, as suggested, we simply click into the empty "Condition Definition":
Schedule condition edit
Schedule condition endWe save the new condition. Up to now this e-mail action would be executed every time you do a real save when the change document is "In development" (user status E0002).

To avoid this we go to the tab "Start Condition" and create a start condition:
Start condition begin

The editing is the same. I show only the result:
Start condition end

Result

We have now a mail action which will be scheduled only when the document is in status "In development" but started only when the status has changed to "Critical Authorization Check". You can save the transaction as many times as you want during development: the e-mail action would keep there as unprocessed (you can see it with the tab "Actions").

Here an example for the Staus E0002 "In development":
Example for actions
(you may set the SU01 user parameter CRM_ACTION_ICONBAR to X).

When the status changes to E0011 the e-mail action would start, the e-mail notification "Dear SecTeam, please Check" would be sent, but no new e-mail action "Dear SecTeam, please Check" would be created during the status E0011 (instead, while in E0011, a new e-mail action "Dear Tester, please test" would be scheduled, which will only start when the status changes to E0004 "To be tested", and so on, but further e-mail actions are not described in this blog).

We have added an "Error free flag=X" to the start condition to ensure that the e-mail notification reaches the next workflow partner only when the status change is successfully completed.

Otherwise, when the security team puts the transaction back to development (= denies it's approval) a new e-mail action "Dear SecTeam, please check" would be created during the re-development. When the role administrator has implemented the changes required by the security team and does the status change to E0011 (SecTeam check), this new e-mail notification would start, but this is not spam, because the security team has really to check a second time.

Tip

When the action weren't scheduled and you check your customizing on and on without finding an error, you might execute the consistency check of transaction SPPFCADM:
tip

Thanks for reading!

Filter Blog

By date: