Wednesday, November 26, 2014

Custom container + SALV - PBO runs twice under Resizing option or how to reach just one horizontal bar

SALV class is really handy, simple to use. No need of manual field catalog creation is super feature. But in some cases is does something you do not expect. This article describes one of this strange behavior.

Imagine such "uncommon" situation, you place your ALV inside custom container with some certain dimensions. There is no other vertical space, so we have fixed defined height of the container. On the other side, ALV can contain many columns. It causes later on two horizontal scroll bars. What is really annoying.

Overcome two scroll bars, but...




OK, no problem, there is a solution. We can just tick "Resizing" check box for automatic horizontal or vertical growth. We should have just one scroll bar. That's nice, But there is one quite interesting BUT.



Custom container/SALV shadow behavior


In this case PBO action is to be run twice. Why? Custom container resizing capability causes to trigger PAI immediately after SALV->display( ) method. Suddenly you can see in debug loading of method IF_SALV_DISPLAY_ADAPTER~GET_COLUMNS. Container reacts with it is own event on resizing option. One more note, here the automatic screen reload depends on amount of ALV data. If you have just few rows, nothing special would happen. But with growing number of SALV rows reload occurs.

Conclusion


Now we have to choose, to have just one scroll bar with side effect of one more automatic PAI/PBO loop on screen OR to have two bars and exactly one PBO action. Sometime it takes a time to discover such a secret behind. When you have some special logic in PBO, twice run could be unwanted behavior.


In my case I had to rewrite the PBO action to reach just one horizontal bar. I had to equip the PBO with some logic calculating with second PBO run. So some checks has to be added. The result is OK afterwards.






Friday, August 29, 2014

HTML Email with tables generated by SmartForm

Intro

There are various possibilities how to work with emails in SAP. Previously I used some function module. When I obtained a task to prepare an email message with some log info content e.g. this job passed the other failed. I decided to create a HTML email message with nice colors, green for passed, red for failed tasks.

At first I decided to use Nguyen Van Thao's pattern. It uses CL_BCS class and SF. I used it by a bit by my own way. So let me introduce a clone with tables inside the smart form + some my experience notes.

Content generator Class

There is class responsible for the filling out needed tables which should be displayed inside the email. I just took a real example from my work.

*----------------------------------------------------------------------*
*       CLASS lcl_manager_email DEFINITION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS lcl_manager_email DEFINITION.
  PUBLIC SECTION.
    METHODSconstructor
              IMPORTING
                io_data_sel  TYPE REF TO lcl_data_sel
                io_data_user TYPE REF TO lcl_data_user,
             send_email_log
              IMPORTING iv_subject TYPE so_obj_des
              RAISING lcx_msg_exception.

  PRIVATE SECTION.
    DATAo_data_sel  TYPE REF TO lcl_data_sel,
          o_data_user TYPE REF TO lcl_data_user.

    METHODSget_mail_body
                RETURNING value(rt_soliTYPE soli_tab
                RAISING lcx_msg_exception" get mail body from Smart form

ENDCLASS.                    "lcl_manager_email DEFINITION

*----------------------------------------------------------------------*
*       CLASS lcl_manager_email IMPLEMENTATION
*----------------------------------------------------------------------*
* Any email stuff
*----------------------------------------------------------------------*
CLASS lcl_manager_email IMPLEMENTATION.

  METHOD constructor.
    o_data_sel  io_data_sel.
    o_data_user io_data_user.
  ENDMETHOD.                    "constructor

  METHOD send_email_log.
    " Send message only in case of real action
    IF o_data_sel->v_locka IS NOT INITIAL )    " do admin lock
        OR o_data_sel->v_lockl IS NOT INITIAL )  " do local lock
        OR o_data_sel->v_vali  IS NOT INITIAL )" set validation

      DATAlo_send_request TYPE REF TO cl_bcs,
            lo_document     TYPE REF TO cl_document_bcs,
            lo_recipient    TYPE REF TO if_recipient_bcs,
            lo_sender       TYPE REF TO cl_sapuser_bcs,
            lt_soli         TYPE soli_tab,
            lv_sent_flag    TYPE abap_bool,
            lx_oref         TYPE REF TO lcx_msg_exception,
            lx_bcf          TYPE REF TO cx_bcs,
            lv_msg          TYPE string.

      lt_soli me->get_mail_body).

      " Instantinate CL_BCS and specify options
      TRY .
          " Create persistent
          lo_send_request cl_bcs=>create_persistent).

          " Email FROM
          lo_sender cl_sapuser_bcs=>createsy-uname ).
          " Add sender to send request
          CALL METHOD lo_send_request->set_sender
            EXPORTING
              i_sender lo_sender.

          " Email TO
          lo_recipient cl_cam_address_bcs=>create_internet_addresso_data_sel->v_email ).
          " Add recipient to send request
          CALL METHOD lo_send_request->add_recipient
            EXPORTING
              i_recipient lo_recipient
              i_express   'X'.

          " Email BODY from SmartForm
          lo_document cl_document_bcs=>create_document(
              i_type        'HTM'
              i_subject     iv_subject
              i_text        lt_soli ).
          " Add document to send request
          CALL METHOD lo_send_request->set_documentlo_document ).

          " Send email
          lo_send_request->set_send_immediatelyi_send_immediately abap_true ).

          lv_sent_flag lo_send_request->sendi_with_error_screen 'X' ).
          IF lv_sent_flag EQ abap_false.
            RAISE EXCEPTION TYPE lcx_msg_exception
              EXPORTING iv_text =  'Error Sending Email!'.
          ENDIF.

          "Commit to send email
          COMMIT WORK.

        CATCH cx_bcs INTO lx_bcf.
          RAISE EXCEPTION lx_bcf.
      ENDTRY.
    ENDIF.
  ENDMETHOD.                    "send_email_log

  METHOD get_mail_body.

*---Data declaration
    DATAlt_lines TYPE TABLE OF tline,
          ls_line  TYPE tline,
          ls_soli  TYPE soli.
    DATAlv_fname      TYPE rs38l_fnam,
          ls_job_output TYPE ssfcrescl"Structure to return value at the end of form printing
    DATAls_ctrl_form  TYPE ssfctrlop"Smart Form Control Structure
          ls_output_opt TYPE ssfcompop"Smart Form Transfer Options

*---Pass data to Smartforms to receive itab of HTML Email

    "Get Smart Form Function Module Name
    CALL FUNCTION 'SSF_FUNCTION_MODULE_NAME'
      EXPORTING
        formname           cv_sf_htm_mail
      IMPORTING
        fm_name            lv_fname
      EXCEPTIONS
        no_form            1
        no_function_module 2
        OTHERS             3.
    IF sy-subrc <> 0.
      RAISE EXCEPTION TYPE lcx_msg_exception
        EXPORTING is_syst sy.
    ENDIF.

    "Spool parameters
    ls_output_opt-tdimmed 'X'.      "Print Immediately (Print Parameters)
    ls_output_opt-tddelete 'X'.     "Delete After Printing (Print Parameters)
    ls_output_opt-tdlifetime 'X'.   "Spool Retention Period (Print Parameters)
    ls_output_opt-tddest 'LOCL'.    "Spool: Output device
    ls_output_opt-tdprinter 'SWIN'"Spool: Device type name
    ls_ctrl_form-no_dialog 'X'.     "SAP Smart Forms: General Indicator
    ls_ctrl_form-preview 'X'.       "Print preview
    ls_ctrl_form-getotf 'X'.        "Return of OTF table. No printing, display, or faxing
    ls_ctrl_form-langu 'EN'.        "Language key
    ls_ctrl_form-device 'PRINTER'.  "Output device

    "Call Smart Form Function Module
    CALL FUNCTION lv_fname
      EXPORTING
        control_parameters ls_ctrl_form
        output_options     ls_output_opt
      IMPORTING
        job_output_info    ls_job_output
      TABLES
        it_users1          o_data_user->t_users1
        it_users2          o_data_user->t_users2
        it_users3          o_data_user->t_users3
        it_users4          o_data_user->t_users4
        it_result_statuses o_data_user->t_result_statuses
        it_result_errors   o_data_user->t_result_errors

      EXCEPTIONS
        formatting_error   1
        internal_error     2
        send_error         3
        user_canceled      4
        OTHERS             5.
    IF ls_job_output-otfdata IS INITIAL.
      RAISE EXCEPTION TYPE lcx_msg_exception
        EXPORTING is_syst sy.
    ENDIF.

    "Convert OTF to TLINE
    CALL FUNCTION 'CONVERT_OTF'
      EXPORTING
        format                'ASCII'
        max_linewidth         132
      TABLES
        otf                   ls_job_output-otfdata
        lines                 lt_lines
      EXCEPTIONS
        err_max_linewidth     1
        err_format            2
        err_conv_not_possible 3
        err_bad_otf           4
        OTHERS                5.
    IF sy-subrc <> 0.
      RAISE EXCEPTION TYPE lcx_msg_exception
        EXPORTING is_syst sy.
    ENDIF.

    "Remove empty lines
    DELETE lt_lines WHERE tdline EQ space.
    "Convert itab of HTML Email to itab of sending format in class CL_BCS
    LOOP AT lt_lines INTO ls_line.
      ls_soli ls_line-tdline.
      APPEND ls_soli TO rt_soli.
      CLEAR ls_soli.
    ENDLOOP.

  ENDMETHOD.                    "get_mail_body

ENDCLASS.                    "lcl_manager_email IMPLEMENTATION



Smart form

By above class we have some prepared data/tables which should be placed into email. Please acknowledge the data types transferred into SmartForm must be data dictionary based. Here I used also some our custom types. 



Tables

I had a bit bad experience with SmartForm's TABLE elements. The text inside the SOLI table was truncated and useless for HTML content. So I decided to use simple LOOP instead of table. Inside the loop you can achieve the same functionality. In connection with IF conditions inside the loop it gives you quite powerful tool for email generation.



In text element you can place your HTML code with inside CSS style. Inside text element you may work normally with variables as usual e.g. &GS_RESULT_STATUS-STATUS_LOCKED&.




Together it produces following tables within email. Now email dynamically shows the result of the last taken action according to the conditions within table loops inside the SmartForm.



As you see, it's some mix up of SmartForm's elements and HTML/CSS styles inside texts elements and that's all. So now is your turn...









Friday, August 1, 2014

Handy local exception class

During my exception exploration I came to such conclusion, within local local exception class is sometime handy to have both input parameters, at first message with all its attributes or simple string. Below class fulfill both cases. Below exception class have two optional input parameters, so it's up to programmer what to choose. See below usage examples.

*----------------------------------------------------------------------*
*       CLASS lcx_msg_exception DEFINITION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS lcx_msg_exception DEFINITION
  INHERITING FROM cx_static_check.

  PUBLIC SECTION.
    DATAmsgv1 TYPE symsgv READ-ONLY,
          msgv2 TYPE symsgv READ-ONLY,
          msgv3 TYPE symsgv READ-ONLY,
          msgv4 TYPE symsgv READ-ONLY.
    INTERFACES if_t100_message.
    METHODS constructor
      IMPORTING
        iv_text     TYPE clike       OPTIONAL  " simple text input
        is_t100_key TYPE scx_t100key OPTIONAL" message input
ENDCLASS.                    "lcx_msg_exception DEFINITION

*----------------------------------------------------------------------*
*       CLASS lcx_msg_exception IMPLEMENTATION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS lcx_msg_exception IMPLEMENTATION.
  METHOD constructor.
    super->constructor).

    " simple string input
    IF iv_text IS NOT INITIAL.
      cl_message_helper=>set_msg_vars_for_clikeiv_text ).
      if_t100_message~t100key-attr1 sy-msgv1.
      if_t100_message~t100key-attr2 sy-msgv2.
      if_t100_message~t100key-attr3 sy-msgv3.
      if_t100_message~t100key-attr4 sy-msgv4.
    ENDIF.

    " message input
    IF is_t100_key IS NOT INITIAL.
      MOVE-CORRESPONDING is_t100_key TO if_t100_message~t100key.
    ENDIF.

    " special cases
    IF if_t100_message~t100key-msgid IS INITIAL )
      AND  if_t100_message~t100key-msgno IS INITIAL )
      AND  if_t100_message~t100key-attr1 IS NOT INITIAL ).
      if_t100_message~t100key-msgid '00'.
      if_t100_message~t100key-msgno '001'.
    ENDIF.

    " set message attributes
    msgv1 if_t100_message~t100key-attr1.
    msgv2 if_t100_message~t100key-attr2.
    msgv3 if_t100_message~t100key-attr3.
    msgv4 if_t100_message~t100key-attr4.
    if_t100_message~t100key-attr1 'MSGV1'.
    if_t100_message~t100key-attr2 'MSGV2'.
    if_t100_message~t100key-attr3 'MSGV3'.
    if_t100_message~t100key-attr4 'MSGV4'.

  ENDMETHOD.                    "constructor
ENDCLASS.                    "lcx_msg_exception IMPLEMENTATION


START-OF-SELECTION.

  DATAlx_oref TYPE REF TO lcx_msg_exception,
        ls_msg  TYPE scx_t100key.

* example 1 - simple success message
  ls_msg-msgid 'VL'.
  ls_msg-msgno '017'.
  TRY.
      RAISE EXCEPTION TYPE lcx_msg_exception
        EXPORTING
          is_t100_key ls_msg.
    CATCH lcx_msg_exception INTO lx_oref.
      MESSAGE lx_oref TYPE 'S'.
  ENDTRY.

* example 2 - error message with attributes
  ls_msg-msgid 'VL'.
  ls_msg-msgno '046'.
  ls_msg-attr1 '41000064'" some VBELN
  ls_msg-attr2 'IT007'.    " some sy-uname user

  TRY.
      " ...some coding raising custom exception
      RAISE EXCEPTION TYPE lcx_msg_exception
        EXPORTING
          is_t100_key ls_msg.
    CATCH lcx_msg_exception INTO lx_oref.
      MESSAGE lx_oref TYPE 'E'.
  ENDTRY.

* example 3 - simple error text message
  DATAlv_text TYPE string.
  TRY.
      " ...some coding raising custom exception
      lv_text 'Some ugly error occcured in program 1! Some stupid error occcured in program 2! Some silly error occcured in program 3!'.
      RAISE EXCEPTION TYPE lcx_msg_exception
        EXPORTING
          iv_text lv_text.
    CATCH lcx_msg_exception INTO lx_oref.
      MESSAGE lx_oref TYPE 'E'.
  ENDTRY.

Wednesday, July 2, 2014

Local Exception class & Message


Once I decided to a bit improve my simple custom exception object and equip it with message attributes. I needed local class not global one where you can just click checkbox "With message class". Many functions within SAP works with return attributes like sy-msgv1, sy-msgv2... as e.g. function module 'ENQUEUE_EVVBLKE'. Messages are well designed for this purpose. So why to discover wheel once again.

Note: For final solution roll down till the end :)

I knew exceptions and messages work with interface if_t100_message. I read some articles on net, I looked at James Wood book.  The closest one was on Naimesh Patel site. Btw this site is always helpful.

What I looked for was this, just one filled structure scx_t100key as constructor parameter and nothing else. I did not want to use inside the exception class hardcoded constants with prepared messages key/text.

At first I tried below simple solution

*----------------------------------------------------------------------*
*       CLASS lcx_msg_exception DEFINITION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS lcx_msg_exception DEFINITION
  INHERITING FROM cx_static_check.

  PUBLIC SECTION.
     INTERFACES if_t100_message.
    METHODS constructor IMPORTING is_t100_key TYPE scx_t100key.
ENDCLASS.                    "lcx_msg_exception DEFINITION

*----------------------------------------------------------------------*
*       CLASS lcx_msg_exception IMPLEMENTATION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS lcx_msg_exception IMPLEMENTATION.
  METHOD constructor.
    super->constructor).
    if_t100_message~t100key is_t100_key.
  ENDMETHOD.                    "constructor
ENDCLASS.                    "lcx_msg_exception IMPLEMENTATION


The usage:


START-OF-SELECTION.

  DATAlx_oref TYPE REF TO lcx_msg_exception,
        ls_msg TYPE scx_t100key.

* test example 1 - simple success message
  ls_msg-msgid 'VL'.
  ls_msg-msgno '017'.
  TRY.
      RAISE EXCEPTION TYPE lcx_msg_exception
        EXPORTING
          is_t100_key ls_msg.
    CATCH lcx_msg_exception INTO lx_oref.
      MESSAGE lx_oref TYPE 'S'.
  ENDTRY.

* test example 2 - error message with attributes
  ls_msg-msgid 'VL'.
  ls_msg-msgno '046'.
  ls_msg-attr1 '41000064'" some VBELN
  ls_msg-attr2 'IT007'.    " some sy-uname user

  TRY.
      " ...some coding raising custom exception
      RAISE EXCEPTION TYPE lcx_msg_exception
        EXPORTING
          is_t100_key ls_msg.
    CATCH lcx_msg_exception INTO lx_oref.
      MESSAGE lx_oref TYPE 'E'.
  ENDTRY.

OK, it's pretty easy, everything looks very well unless you do not try to involve attributes 1-4 of the message. If you do so, it looks strange. Attributes are placed at proper places but surrounded by ampersand characters '&'. Ouu, it does not look very well. Hmm, what to do now?



I debugged the part of SAP code responsible for displaying the message and discovered what's wrong.

There is used below method of the class CL_MESSAGE_HELPER.

SET_MSG_VARS_FOR_IF_T100_MSG (CL_MESSAGE_HELPER)
    CALL METHOD set_single_msg_var
      EXPORTING
        arg    = text->t100key-attr1
        obj    = text
      IMPORTING
        target = sy-msgv1.

The wrong thing is done inside the method  SET_SINGLE_MSG_VAR (CL_MESSAGE_HELPER).



I realized, it looks just for exception attribute inside the class and nothing else. It's pretty clear, that below code would not work any more. There is no attribute named with the vbeln number or username.

Working sample code


Finally I did small modification of my exception class to destroy unwanted ampersands. And voila, it works! Look at the below code.

*----------------------------------------------------------------------*
*       CLASS lcx_msg_exception DEFINITION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS lcx_msg_exception DEFINITION
  INHERITING FROM cx_static_check.

  PUBLIC SECTION.
    DATAmsgv1 TYPE symsgv READ-ONLY,
          msgv2 TYPE symsgv READ-ONLY,
          msgv3 TYPE symsgv READ-ONLY,
          msgv4 TYPE symsgv READ-ONLY.
    INTERFACES if_t100_message.
    METHODS constructor IMPORTING is_t100_key TYPE scx_t100key.
ENDCLASS.                    "lcx_msg_exception DEFINITION

*----------------------------------------------------------------------*
*       CLASS lcx_msg_exception IMPLEMENTATION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS lcx_msg_exception IMPLEMENTATION.
  METHOD constructor.
    super->constructor).
    if_t100_message~t100key is_t100_key.
    msgv1 is_t100_key-attr1.
    msgv2 is_t100_key-attr2.
    msgv3 is_t100_key-attr3.
    msgv4 is_t100_key-attr4.
    if_t100_message~t100key-attr1 'MSGV1'.
    if_t100_message~t100key-attr2 'MSGV2'.
    if_t100_message~t100key-attr3 'MSGV3'.
    if_t100_message~t100key-attr4 'MSGV4'.
  ENDMETHOD.                    "constructor
ENDCLASS.                    "lcx_msg_exception IMPLEMENTATION


Now the result looks as follows.



Wednesday, June 11, 2014

Selection screens and error - Message DB655 - Place the cursor on a selection

Let me present to you small issue concerning behavior of Selection screens. Hopefully it could saves a time to some one else.

Sometime is necessary to use custom toolbar with icons in connection with Selection screens. OK, it's no problem. Just introduce within your program your own custom GUI status and link it in PBO like shown below.

AT SELECTION-SCREEN OUTPUT.

  " set your PF status
  DATA lt_exclude TYPE STANDARD TABLE OF rsexfcode.
  CALL FUNCTION 'RS_SET_SELSCREEN_STATUS'
    EXPORTING
      p_status  'BEC'
    TABLES
      p_exclude lt_exclude.



Everything is fine and works well except one small thing. Error message declared in a standard way starts to cause troubles.

        MESSAGE e000 WITH text-008.





Yes, error is displayed in proper place in proper time as expected. But in this case if you are not willing to change content of e.g. select option or parameter and you want to just leave transaction by icon in top menu, you are no longer allowed. Every click or key press you have to face another new error standard message "Place the cursor on a selection". There is almost no escape from this for end user!

For me small workaround worked. I changed declaration of error messages into this format:

        MESSAGE s000 WITH text-008 DISPLAY LIKE 'E'.
        EXIT.


Miracle is done, everything works now.

Do you know about any other solution how to prevent disconnection from GUI status functionality by such error message?


Tuesday, May 20, 2014

How to get VIA carrier/forwarder address by shipment number?

I just want to share simple topic for the others. This is simple query how to get address of VIA forwarder. You know, some shipments does not contain just receiving end address but are delivered by more than one leg. Sometime we need to pickup address of let's say middle forwarders and this is our case.

Open SQL


  DATA gv_address_via_carrier TYPE adrc.

  CLEAR gv_address_via_carrier.
  IF vttkvb-tknum IS NOT INITIAL" Shipment Number
    SELECT SINGLE *
    FROM vtpa
    INNER JOIN adrc
      ON vtpa~adrnr adrc~addrnumber
    INTO CORRESPONDING FIELDS OF gv_address_via_carrier
    WHERE vbeln  vttkvb-tknum
    AND   posnr '000000'
    AND   parvw  'SV'.
  ENDIF.

Of course in case of more than one VIA forwarder do not use SELECT SINGLE, but fill internal table with just SELECT clause.


SAP SCRIPT form


In my case address had to be displayed by some old fashion SAP script, by window of following content.

/: ADDRESS PARAGRAPH AS
/:  NAME     &GV_ADDRESS_VIA_CARRIER-NAME1&, &GV_ADDRESS_VIA_CARRIER-NAME2
/:  STREET   &GV_ADDRESS_VIA_CARRIER-STREET&
/:  CITY     &GV_ADDRESS_VIA_CARRIER-CITY1(29)&
/:  POSTCODE &GV_ADDRESS_VIA_CARRIER-POST_CODE1(10)&
/:  COUNTRY  &GV_ADDRESS_VIA_CARRIER-COUNTRY&
/:  REGION   &GV_ADDRESS_VIA_CARRIER-REGION&

/: ENDADDRESS


Thursday, April 24, 2014

SAP Smartforms + KYOCERA printer = DMC, QR codes work

Once I had to solve following task, print DMC square codes on Kyocera printers without any third party software. It is a reasonable step to replace all line bar codes with one square code containing all needed.

Because SAP does not support internally these codes, it is a bit challenge. The task did not allow usage of any software due to CPU time consumption during code rendering on server side.
Kyocera printers comes with interesting "option". You can print QR, DMC and really long list of various codes on their printers IF, If you buy small additional piece of hardware so called flash module. It allows you to trigger printer internal PCL commands producing bar codes as you wish. OK, it seems to be a solution. And you can suspect here, if there is some article concerning the topic, the way is not blind. Yes, it works! :)

So, what's needed?


At first we need plug a flash module into the printer. Kyocera produces various types of compact flash cards, types A, B, C... Here be careful, there is a list of supported cards for every printer. It means, you need to have proper card for your Kyocera printer. Note: flash card can be possibly flashed to upper version.

You need device driver supporting used printer language. You can choose standard PCL or Kyocera proprietary language called PRESCRIBE. This article is focused on usage of Prescribe.

In my case I used KYOAAA1C driver for my Kyocera FS-2020D.

List of suitable drivers:

  •       KYOAAA1C   KYO FS2000/3900/4000 PCL POSS
  •       KYOAAB1C   KYO FS95XX PCL POSS
  •       KYOAAC1C   KYO KMX050 PCL POSS
  •       KYOAAD1C   KYO FSC5400/FSC5300 PCL POSS
  •       KYOAAE1C   KYO FS1028/1128MFP PCL POSS
  •       KYOAAF1C   KYO TASKalfa XXXci PCL POSS  


For full list look at: http://www.stechno.net/sap-notes.html?view=sapnote&id=1135057#sthash.EMTwTPm8.dpuf

Now we can move on


Thing is not too complex. Some base explanation of DMC parameters is given just here. I recommend to download PDF from Kyocera website to understand usage of wanted code in depth. By the same way you can use QRs, DMCs and so on...

In general we need just some text element with proper font style. Style is very important, because SAP text element automatic line breaks destroy Prescribe command. So keep in mind you need to have:

  1. Window with enough space, usually simply MAIN window is a good option.
  2. Whole command must be in preview visible on ONE line. No breaks are possible. That's why we use for text element special very small font size as protection against automatic line breaks. 

Setup style


Style is setup in transaction Smartforms. Use font size 1 pt to save a space.


Setup global variables for DMC code


We can include whole DMC code string into one variable. But SAP limits length of text string used in SF up to 255 characters. That's why is better choice to separate prefix and suffix of the code to gain more space for the content itself.


Preparation of DMC content in initialization part


You can call some custom routines placed directly in SF to make a content of the code. Here we are preparing also Prescribe command itself, I mean prefix and suffix.



Whole code of init can looks like:


* DMC code properties (printed via Prescribe)
DATAlv_code_type       TYPE string" type of square code
      lv_dmc_symbol_from TYPE string,
      lv_dmc_symbol_to   TYPE string,
      lv_dmc_position_x  TYPE string,
      lv_dmc_position_y  TYPE string,
      lv_dmc_module_size TYPE string.

* DMC dimensions
lv_code_type        '100'" 100 means DMC
lv_dmc_module_size  '13'.  " size of the small squares with dimension of 13 dots (pixels)
lv_dmc_symbol_from  '11'.  " min. size
lv_dmc_symbol_to    '19'.  " max size
lv_dmc_position_x   '738'" horizontal in px
lv_dmc_position_y   '960'" vertical in px

PERFORM get_dmccode_content
  USING    label_data2
  CHANGING gv_dmc_content.

" Prescribe DMC prefix + suffix definition
CONCATENATE '!R! UNIT D; MAP ' " Note: UNIT D = pixels, MAP = position
            lv_dmc_position_x ','
            lv_dmc_position_y
            '; BARC ' lv_code_type " BARC = print barcode
            ',' lv_dmc_module_size
            ',' lv_dmc_symbol_from
            ',' lv_dmc_symbol_to
            ',0,0,"'
INTO gv_dmc_prefix RESPECTING BLANKS.
gv_dmc_suffix   '";EXIT;'.


DMC size on paper


The "module size" is the size of the small squares from which the bar code is built. If you use the command "UNIT D;" the unit is set to dots (pixels), e.g. the value 15 here means 52 x 52 rows. Final size of the DMC code depends on the length of content. If you set up min - max range for symbol attribute of DMC, system  tries to use the smallest possible one according to content length.

Display DMC code


Display gained global variables in text element via proper style. Prescribe command should be the very first thing sent to the printer, see hierarchy below.


Remember the used style above is too small to understand the idea. If I would enlarged version of picture above and view it by bigger font style, it would look something like below. In real we are inserting three different lines in order prefix, next row of content and finally suffix row.



How to overcome the limits


With system bar code (SE73) you can encode max. 255 characters in Smart Forms and max. 70 characters in SAPScript. With bar code formatted as text, the case of here described solution,  you can encode as much as you can place in one line. Maximum length of a field in Smart Forms is 255 characters.
Therefore you have to split the barcode data into several fields, if you want to encode more than 255 characters. 

Text element content

&DMC_PREFIX&
&DMC_DATA_FIELD_1&&DMC_DATA_FIELD_2&&DMC_DATA_FIELD_3&
&DMC_SUFFIX& 

Addition
See the SAP note Sap note 497380 - Maximum bar code length

Troubleshooting part 


You can test the setting of printer including the message  "codes not loaded" by following Prescribe command: "!R! CALL BSTP; EXIT;" Simply place the command into new text element and try to print out. By this command you would able to see any printer start up error. It would be nice to see if module is working properly.

The proper print driver could be tested by following commands. If print out would be successful, you know, driver works. But it is not telling you anything about bar code module yet.

Example 1

!R! UNIT C; MRP 3, 3;
SFNT "Univers-MdCd", 12;
MRP 3, 3;
CIR .35;

Example 2

!R! RES; PSRC 1;
SFNT "Helvetica", 10;
MZP 3, 3;
RTTX 15, " ----- Text1...";
RTTX 45, " ----- Text2...";
RTTX 75, " ----- Text3...";
PAGE; EXIT;

Finally many thanks to Mr. Norbert Volk-Klee for his precious Prescribe support.

Wish you happy printing cool codes!