ABAP log

March 22, 2007

Converting material quantities to different unit of measure in ABAP.

Filed under: ABAP, SAP — abaplog @ 4:44 pm

Each material in SAP has its standard, base unit of measure (stored in MARA-MEINS). To allow using alternative units, those can be maintained per material in table MARM. A common requirement for ABAPer is to convert material quantity from one unit to another, most likely from an alternative unit to the base one, to be able to summarize the report results.

To do the conversion, SAP provides the function module MATERIAL_UNIT_CONVERSION. Its parameter names are not self-explaining, and for my own purposes I have a simple wrapper form that I use to convert quantities from alternative to base UoM. The form is using data caching technique that I described in one of my earlier posts.

form convert_to_base_uom 
  using    pf_matnr     type matnr 
           pf_menge_in  type gsmng 
           pf_meins_in  type meins 
  changing pf_menge_out type gsmng 
           pf_meins_out type meins. 

* define internal table to cache the base UOM 
  types: begin of lty_meins_rec, 
             matnr type matnr, 
             meins type meins, 
           end of lty_meins_rec. 

  types: 
    lty_meins_tab type hashed table of lty_meins_rec 
          with unique key matnr. 
  data: 
    ls_wa type lty_meins_rec. 

  statics: 
    lt_meins type lty_meins_tab. 

* first, find the base UOM 
  clear pf_meins_out. 
  read table lt_meins into ls_wa 
    with table key matnr = pf_matnr. 
  if sy-subrc = 0. 
    pf_meins_out = ls_wa-meins. 
  else. 
    select single meins 
      from mara 
      into ls_wa-meins 
      where matnr = pf_matnr. 
    if sy-subrc  0.  "doesn't exist. try PC 
      ls_wa-meins = 'ST'. 
    endif. 
    ls_wa-matnr = pf_matnr. 
    pf_meins_out = ls_wa-meins. 
    insert ls_wa into table lt_meins. 
  endif. 

* now convert the qty 
  if pf_meins_in = pf_meins_out. 
    pf_menge_out = pf_menge_in. 
  else. 
    call function 'MATERIAL_UNIT_CONVERSION' 
         exporting 
              input                = pf_menge_in 
              kzmeinh              = 'X' 
              matnr                = pf_matnr 
              meinh                = pf_meins_in 
              meins                = pf_meins_out 
              type_umr             = '3' 
         importing 
              output               = pf_menge_out 
         exceptions 
              conversion_not_found = 1 
              input_invalid        = 2 
              material_not_found   = 3 
              meinh_not_found      = 4 
              meins_missing        = 5 
              no_meinh             = 6 
              output_invalid       = 7 
              overflow             = 8 
              others               = 9. 

  endif. 

endform.

March 15, 2007

Working with SAP plant (factory) calendars in ABAP.

Filed under: ABAP, SAP — abaplog @ 8:01 pm

Every plant in SAP can have its own calendar that defines plant working days. This calendar is used by planning functions to determine whether a particular day is working one or not. You can see the effects if, for example, you try to create a delivery schedule on Sunday, and the system says that actually the next working day is another one.

Very ofter we have to account for working days and exclude weekends and holidays in our ABAP. To do that, SAP provides two functions modules that are used to convert between the “normal” date and the enumerated “factory day”. The factory day is a number assigned to each working day in plant calendar. The functions are FACTORYDATE_CONVERT_TO_DATE and DATE_CONVERT_TO_FACTORYDATE and they are documented directly in SAP, in SAP standalone help (BC Extended Applications Function Library) and, of course, at se37.com.
The typical use of those functions is to add a number of days to a given date, skipping holidays and weekends. This is often asked on SAP-related forums and is one of the subjects in SAPfans ABAP FAQ.

I use those functions also for simple checks whether a day is working or not, and to move a date to a working day (forwards or backwards). Below are forms that I use. The factory calendar (FABKL) can be read directly from the table T001W. The parameter pf_correct should be ‘+’ to move forward or ‘-‘ to move backwards.

form move_to_working
  using
    pf_fabkl   type fabkl
    pf_correct type cind
  changing
    pf_date    type datum.

  data:
    lf_newdate type datum.

  check not pf_fabkl is initial.
  call function 'DATE_CONVERT_TO_FACTORYDATE'
       exporting
            correct_option               = pf_correct
            date                         = pf_date
            factory_calendar_id          = pf_fabkl
       importing
            date                         = lf_newdate
       exceptions
            calendar_buffer_not_loadable = 1
            correct_option_invalid       = 2
            date_after_range             = 3
            date_before_range            = 4
            date_invalid                 = 5
            factory_calendar_not_found   = 6
            others                       = 7.
  if sy-subrc = 0.
    pf_date = lf_newdate.
  endif.

endform.

form is_working_day
  using
    pi_werks like pbim-werks
    pi_date  like sy-datum
    pi_fabkl   type fabkl
  changing
    po_working like space.

  data:
    w_work  like SCAL-INDICATOR,
    w_fabkl like t001w-fabkl.

  clear po_working.
  call function 'DATE_CONVERT_TO_FACTORYDATE'
       EXPORTING
            date                         = pi_date
            factory_calendar_id          = pi_fabkl
       IMPORTING
            workingday_indicator         = w_work
       EXCEPTIONS
            calendar_buffer_not_loadable = 1
            correct_option_invalid       = 2
            date_after_range             = 3
            date_before_range            = 4
            date_invalid                 = 5
            factory_calendar_not_found   = 6
            others                       = 7.
  if sy-subrc = 0 and w_work is initial.
    po_working = c_x.
  endif.

endform.

March 13, 2007

Fighting ABAP PBOs and PAIs.

Filed under: ABAP, SAP — abaplog @ 7:47 pm

Last year I had to solve one interesting problem of unusual screen sequence processing.

That was a dialog program. I had to implement a screen behaviour that is similar to operation PRT screen of CO02. I have, let’s say, a screen A with a table control. To add new entries, I click a button and get a popup screen B. After entering some values I can either click one button to add an entry and get back to screen A (with a new line in the table control), or click another button so that a new line will be added to the table control (and shown there), but popup screen B remains so that I can input values for one more line.

The problem, is: If in PAI of the popup screen I just add a new line in appropriate internal table, screen A is not updated because I stay in screen B (and PBO of screen A is not run). I could probably use DYNP_VALUES_UPDATE from screen B to force the update of screen A, but with table control I will have to handle scrolling – this is too complicated. I tried to look at CO02 code to understand how SAP does that but it’s one of those programs where they use screen sequence control functions, making it extremely difficult to analyse.

I have solved my problem by setting a global variable in PAI of screen B to some value corresponding to popup call, then checking the variable in PBO of screen A (after the LOOP is over and table control is updated to show the new line), and calling the function SAPGUI_SET_FUNCTIONCODE if necessary, to get the popup B back. The only annoying thing (for user) is that the popup can be moved to another screen position, but if I call it again from A, it comes in its original position.

I didn’t check the function, whether it works in background mode (i.e. with BDC), but from its name, it looks like it’s not. Anyways, it can be very useful in some tricky situations to prevent overcomplicated processing with DYNP_VALUES_UPDATE, though the latter is the SAP-blessed way and it not difficult to use for most of tasks.

March 9, 2007

SAP APO interface (CIF): Adding new parameters into the selection screen of CFM1 (RIMODGEN)

Filed under: ABAP, APO, CIF, SAP — abaplog @ 8:26 pm

The standard transaction to generate a CIF integration model, CFM1, offers a huge set of select options, but even this has to be extended sometimes. If you need to have additional parameters on the selection screen of CFM1, OSS Note 511434 describes what has to be done. Note that the only way (and the one described in the note) is a modification of SAP code. You are going to modify the selection screen, PAI modules and function modules called by CIF. That means, during system upgrade you will have to check the source code again new changes from SAP. We went through that twice already: it’s no fun but you don’t do this often.

March 6, 2007

Fun with SAP update tasks.

Filed under: ABAP, SAP — abaplog @ 8:44 pm

Note: this was first posted on SAPfans ABAP forum.

I was in debugger, having set the time zone in my profile to one different with our server time zone. There is a function call in my program that is done in update task. The reason to debug was that document creation time was not the local time but rather server time.

Imagine that: you have a debugger window with the value of sy-timlo of, say 14:30. You enable update task debugging, step into the function, a new window is opened for update task debugging, you type sy-timlo there and oooppps! It shows 15:30!

But! OSS have all the answers for us ready! Just read the Note 534054 – “SY-TIMLO and SY-DATLO incorrect in update”.

Symptom
The SY-TIMLO and SY-DATLO values in the update do not match the values in the dialog box or the debugging.

Other terms
SY-TIMLO SY-DATLO update

Reason and Prerequisites
Up to Release 4.6D (incl.), when creating an update request, the system does not store any information in the update request about the time zone of the user who has generated the update request. Therefore, the SY-TIMLO and SY-DATLO fields contain the same values as SY-UZEIT and SY-DATE when updating.

Now! That’s really encouraging! We are on 4.6C and the only general solution for us is to upgrade. Until then we have to be careful about dates and times. As I wrote in February, we already had some surprises with time zones, but this one is especially good, and it doesn’t look like it’s our fault. Well… whaever happens, I can always say: “it could be worse”…

March 5, 2007

Doing checks on SAP transport release.

Filed under: ABAP, SAP — abaplog @ 9:42 pm

At my company, we are heavily censored on what can we put into a transport description.  If you want to pressure your developers too and have some naming checks and other procedures that run when you release a transport, you can use the BADI CTS_REQUEST_CHECK. You can check the objects included into the transport in this BADI and prevent the transport from being released. (Actually, what it does generate is a good amount of curses when someone is clicking the release button :).

March 1, 2007

Reading other program’s data using field symbols in ABAP.

Filed under: ABAP, SAP — abaplog @ 7:30 pm

One of the first questions we ask when we are going to implement a new logic in an SAP user exit is: what kind of data is available as input and what can I modify as output? Though limited, most of the time the parameters of user exit functions let us do what we want. But sometimes we get stuck because some field is not provided. The field can be either some global field of the calling program or a global field in a function group that is used by calling program. (You should remember that in latter case, the data is still sitting in the memory until we exit the main program or transaction, and can be used by any subsequent calls).

There is a simple trick that allows you read and modify the global data of any module loaded by a running program. It is using the ABAP’s dynamic assignment feature of field-symbols. The best way is to show it with an example.

The user exit ZXCO1U06 is running when we save a production order in the transaction CO02. In this user exit you can do some additional checks, modify data, probably issue some messages and so on. Unfortunately, only header data of the order is provided as its parameter. Reading the database is not an option because any updated data (new operations, new status flags) is not yet written to the database. If you want to read, say, order operations or their status, you either call the same functions that are called by CO02 (as the same global data is used), or access the data directly. If we want to check the status of the order and ist operations, we could read the global data (internal tables) of the function group BSVA, that is used to manage the status in CO02. The table that contains the status flags is called JEST_BUF and we can get the table content in out user exit in the following way:

* See declarations in LBSVATOP
* This type should match the one used in SAP program!
types: begin of t_jest.
            include structure jest_upd.
types:
            mod,
            inact_old like jest-inact,
          end of t_jest.

data:
  lf_text(40)   type c,
  lt_jest       type standard table of t_jest.

field-symbols:
  <ls_jest_buf>      type any table.

lf_text = '(SAPLBSVA)JEST_BUF[]'.
assign (lf_text) to <ls_jest_buf>.
check sy-subrc = 0.
lt_jest[] = <ls_jest_buf>.  "now everything is in lt_jest !

If we want to do some changes of the global data, we could do a “reversed” assignment to the field-symbol:

<ls_jest_buf> = lt_jest[].

Finding the needed program and variable names is not a straightforward task, but can be done with debugger. The best motivation is that there is rarely some alternative solution (that is less ugly than using dynamic ABAP assignments).

Important note: Using user exits is a kind of advanced task because you can easily screw up the SAP program’s internal data. But this trick gives you even more chances of doing that, so everything should be done with a special care.

Create a free website or blog at WordPress.com.