If you ever wanted to use the Application Log:
Generate the LOG:
DATA: L_VAR_LOGHNDL TYPE BALLOGHNDL,
L_VAR_MESSAGE_DUMMY TYPE CHAR255,
L_WA_MSG TYPE BAL_S_MSG.
"Generate the log
DATA: L_WA_LOG TYPE BAL_S_LOG.
"Basisdaten
L_WA_LOG-EXTNUMBER = SY-CPROG.
L_WA_LOG-ALUSER = SY-UNAME.
L_WA_LOG-ALPROG = SY-REPID.
L_WA_LOG-ALDATE = SY-DATUM.
L_WA_LOG-ALTIME = SY-UZEIT.
L_WA_LOG-ALTCODE = SY-TCODE.
L_WA_LOG-OBJECT = 'YARTSTAMM'.
L_WA_LOG-SUBOBJECT = 'STMMDWL'.
"Modus setzen
IF SY-BATCH EQ 'X'.
L_WA_LOG-ALMODE = 'B'.
ELSEIF SY-BINPT EQ 'X'.
L_WA_LOG-ALMODE = 'I'.
ELSE.
L_WA_LOG-ALMODE = 'D'.
ENDIF.
"Create
CALL FUNCTION 'BAL_LOG_CREATE'
EXPORTING
I_S_LOG = L_WA_LOG
IMPORTING
E_LOG_HANDLE = L_VAR_LOGHNDL
EXCEPTIONS
OTHERS = 1.
IF SY-SUBRC <> 0.
" Ignore Error
ENDIF.
Add Messages like this:
"Insert Message
MESSAGE E180(YI) WITH I_VAR_MATNR I_VAR_MATKL
INTO L_VAR_MESSAGE_DUMMY.
CLEAR L_WA_MSG.
L_WA_MSG-MSGTY = 'E'.
L_WA_MSG-MSGID = SY-MSGID.
L_WA_MSG-MSGNO = SY-MSGNO.
L_WA_MSG-MSGV1 = SY-MSGV1.
L_WA_MSG-MSGV2 = SY-MSGV2.
L_WA_MSG-MSGV3 = SY-MSGV3.
L_WA_MSG-PROBCLASS = '1'.
CALL FUNCTION 'BAL_LOG_MSG_ADD'
EXPORTING
I_S_MSG = L_WA_MSG
EXCEPTIONS
LOG_NOT_FOUND = 1
MSG_INCONSISTENT = 2
LOG_IS_FULL = 3
OTHERS = 4.
IF SY-SUBRC <> 0.
"Ignore Errors
ENDIF.
Don't forget to save the Log in the End:
* SAVE LOG
DATA L_IT_LOG_HANDEL TYPE BAL_T_LOGH.
APPEND L_VAR_LOGHNDL TO L_IT_LOG_HANDEL.
CALL FUNCTION 'BAL_DB_SAVE'
EXPORTING
I_T_LOG_HANDLE = L_IT_LOG_HANDEL
EXCEPTIONS
OTHERS = 1.
IF SY-SUBRC <> 0.
"Ignore Errors
ENDIF.
In Programms you can easily encapsulate everything inside Forms. Inside functions i would recommend creating a helper class and instanciate it.
We also are using function pools as Log Helper. The problem with them might be, that only instance exists. So if you use any kind of reset method and keep a handle inside the pool it might get reset by nested calls inside different functions.
This is a day to day SAP and ABAP hands on work blog. I will publish my experiences with certain programming problems and how to overcome them in ABAP. I will mostly cover plain ABAP, BSP and WebDynpro.
Monday, November 10, 2014
QRFC - Background task Queues
A quick HowTo on Background-Task queues for functions.
**Background Queue variables
DATA: L_TCODE_ID TYPE ARFCTID,
L_QNAME TYPE TRFCQOUT-QNAME..
* Generate Name
CONCATENATE SY-TCODE '_' SY-DATUM '_' SY-UZEIT INTO L_QNAME.
CONDENSE L_QNAME NO-GAPS.
* Set Queue name in Programm
CALL FUNCTION 'TRFC_SET_QUEUE_NAME'
EXPORTING
QNAME = L_QNAME.
* Start your queue Transaction
CALL FUNCTION 'TRANSACTION_BEGIN'
IMPORTING
TRANSACTION_ID = L_TCODE_ID.
...... Do some Codng in your programm, and somewhere start your function in Background Task:
CALL FUNCTION 'ARTICLE_RECLASSIFY_LITE_RETAIL' IN BACKGROUND TASK
EXPORTING
I_MATNR = MARA-MATNR
I_NEWWG = SET_MATKL
I_TEST = P_TEST
I_NEWPROFIL = DMY_NEWPROF
....
CALL FUNCTION 'Y_ISR_SET_REKLA_YPOSDWL' IN BACKGROUND TASK
EXPORTING
I_VAR_MATNR = MARA-MATNR
I_VAR_MATKL = SET_MATKL.
..... Do some more Coding in the programm and close the Transaction somewhere
CALL FUNCTION 'TRANSACTION_END'
EXPORTING
TRANSACTION_ID = L_TCODE_ID.
Call SMQ1 to se open Queues, for e.g. if some error occured.
**Background Queue variables
DATA: L_TCODE_ID TYPE ARFCTID,
L_QNAME TYPE TRFCQOUT-QNAME..
* Generate Name
CONCATENATE SY-TCODE '_' SY-DATUM '_' SY-UZEIT INTO L_QNAME.
CONDENSE L_QNAME NO-GAPS.
* Set Queue name in Programm
CALL FUNCTION 'TRFC_SET_QUEUE_NAME'
EXPORTING
QNAME = L_QNAME.
* Start your queue Transaction
CALL FUNCTION 'TRANSACTION_BEGIN'
IMPORTING
TRANSACTION_ID = L_TCODE_ID.
...... Do some Codng in your programm, and somewhere start your function in Background Task:
CALL FUNCTION 'ARTICLE_RECLASSIFY_LITE_RETAIL' IN BACKGROUND TASK
EXPORTING
I_MATNR = MARA-MATNR
I_NEWWG = SET_MATKL
I_TEST = P_TEST
I_NEWPROFIL = DMY_NEWPROF
....
CALL FUNCTION 'Y_ISR_SET_REKLA_YPOSDWL' IN BACKGROUND TASK
EXPORTING
I_VAR_MATNR = MARA-MATNR
I_VAR_MATKL = SET_MATKL.
..... Do some more Coding in the programm and close the Transaction somewhere
CALL FUNCTION 'TRANSACTION_END'
EXPORTING
TRANSACTION_ID = L_TCODE_ID.
Call SMQ1 to se open Queues, for e.g. if some error occured.
Friday, November 7, 2014
ALV Grids in Reports
Sometimes you want to use an ALV Grid directly as output in a report (not a Dynpro).
The magic function to this is:
**ALVGrid
CALL FUNCTION 'REUSE_ALV_GRID_DISPLAY'
EXPORTING
IT_FIELDCAT = L_IT_FIELDCAT
I_GRID_TITLE = L_VAR_TITLE
TABLES
T_OUTTAB = <L_VAR_OUTTAB>
EXCEPTIONS
PROGRAM_ERROR = 1
OTHERS = 2.
IF SY-SUBRC <> 0.
MESSAGE ID SY-MSGID TYPE SY-MSGTY NUMBER SY-MSGNO
WITH SY-MSGV1 SY-MSGV2 SY-MSGV3 SY-MSGV4.
ENDIF.
You can generate your Fieldcat wth another Helpful function:
**Generate Fieldcat
CALL FUNCTION 'REUSE_ALV_FIELDCATALOG_MERGE'
EXPORTING
I_PROGRAM_NAME = SY-CPROG
I_INTERNAL_TABNAME = L_VAR_TABNAME
I_INCLNAME = SY-CPROG
CHANGING
CT_FIELDCAT = L_IT_FIELDCAT
EXCEPTIONS
INCONSISTENT_INTERFACE = 1
PROGRAM_ERROR = 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.
ENDIF.
As you can see here,the Fieldcat is generated from a local internam table. It is mandatory to give the include the where the table is defined. If the data structure is not in DDIC but local as well you need to give the include where it is defined, or include it in TOP. Very important is, that local structures are only read correctly when defined with LIKE and INCLUDE structure as Datatypes. TYPES and normalINCLUDE wont work, since the ddic information is not read there. Its also written in the Manual of the function. So always RTFM cause i did it way too late ;)
Here a sample as an MBEWH Extension is locally defined:
DATA: BEGIN OF TP_MBEWH_EXTENDED.
" MBEWH
INCLUDE STRUCTURE MBEWH.
" MARA with Key MATNR
DATA: YYBEZBE LIKE MARA-YYBEZBE,
MTART LIKE MARA-MTART,
MATKL LIKE MARA-MATKL,
MEINS LIKE MARA-MEINS,
"T001 with Key BUKRS from T001K with Key BWKEY
WAERS LIKE T001-WAERS,
"T023T with Key MATKL
WGBEZ LIKE T023T-WGBEZ.
DATA: END OF TP_MBEWH_EXTENDED.
I also discussed reordering the Catalog from the selection screen here:
http://abapify.blogspot.de/2014/10/alv-sorting-with-reordering-of-fieldcat.html
As Update here is a small piece of Code to dynamically alocate Tables and Fieldcats to 3 different Tables:
FORM BUILD_ALV.
CHECK P_TABLE IS NOT INITIAL.
DATA: L_IT_FIELDCAT TYPE SLIS_T_FIELDCAT_ALV,
L_VAR_TABNAME TYPE SLIS_TABNAME,
L_VAR_TITLE TYPE LVC_TITLE,
L_VAR_LINE_CNT_OUT TYPE C LENGTH 20.
FIELD-SYMBOLS: <L_VAR_OUTTAB> TYPE STANDARD TABLE.
**Je nach Auwahl der Tabelle wird die Struktur für den Feldkatalog und
* die zugehörige Ergebnis iTab für das ALV gewählt.
CASE P_TABLE.
WHEN 'S31'.
L_VAR_TABNAME = 'TP_S031_EXTENDED'.
ASSIGN IT_S031_EXTENDED TO <L_VAR_OUTTAB>.
WHEN 'S32'.
L_VAR_TABNAME = 'TP_S032_EXTENDED'.
ASSIGN IT_S032_EXTENDED TO <L_VAR_OUTTAB>.
WHEN 'MBH'.
L_VAR_TABNAME = 'TP_MBEWH_EXTENDED'.
ASSIGN IT_MBEWH_EXTENDED TO <L_VAR_OUTTAB>.
ENDCASE.
**Feldkatalog schlicht nach Tabelle erstellen
CALL FUNCTION 'REUSE_ALV_FIELDCATALOG_MERGE'
EXPORTING
I_PROGRAM_NAME = SY-CPROG
I_INTERNAL_TABNAME = L_VAR_TABNAME
I_INCLNAME = SY-CPROG
CHANGING
CT_FIELDCAT = L_IT_FIELDCAT
EXCEPTIONS
INCONSISTENT_INTERFACE = 1
PROGRAM_ERROR = 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.
ENDIF.
"Feldkatalog individuelle Sortierung
CASE P_TABLE.
WHEN 'S31'.
PERFORM REORDER_FIELDCAT_S031 CHANGING L_IT_FIELDCAT.
WHEN 'S32'.
PERFORM REORDER_FIELDCAT_S032 CHANGING L_IT_FIELDCAT.
WHEN 'MBH'.
PERFORM REORDER_FIELDCAT_MBEWH CHANGING L_IT_FIELDCAT.
ENDCASE.
*Anzahl der Zeilen
DESCRIBE TABLE <L_VAR_OUTTAB> LINES L_VAR_LINE_CNT_OUT.
***Tabellenname in den Titel nehmen
* CONCATENATE TEXT-100 L_VAR_TABNAME L_VAR_LINE_CNT_OUT TEXT-101
* INTO L_VAR_TITLE RESPECTING BLANKS.
**ALVGrid generieren.
CALL FUNCTION 'REUSE_ALV_GRID_DISPLAY'
EXPORTING
IT_FIELDCAT = L_IT_FIELDCAT
I_GRID_TITLE = L_VAR_TITLE
TABLES
T_OUTTAB = <L_VAR_OUTTAB>
EXCEPTIONS
PROGRAM_ERROR = 1
OTHERS = 2.
IF SY-SUBRC <> 0.
MESSAGE ID SY-MSGID TYPE SY-MSGTY NUMBER SY-MSGNO
WITH SY-MSGV1 SY-MSGV2 SY-MSGV3 SY-MSGV4.
ENDIF.
ENDFORM. "DISPLAY_ALV_REPORT
Then at last you might want to reorder the Fieldcat positions in your Output afterwards. Therem ight be better ways to do this (comments welcome), but most of what i tried before was very complicated an not error prone. The problem are some Entry which are also hidden an not seen and mostly have empty Tabnames. So i just went and took the First entry i knew, reordered everything from this Sy-Tabix on forward and renumerated everythin in the end.
*&---------------------------------------------------------------------*
*& Form REORDER_FIELDCAT_MBEWH
*&---------------------------------------------------------------------*
* Feldkatalog anpassungen:
*----------------------------------------------------------------------*
* <--P_L_IT_FIELDCAT Feldcatalog zu ändern
*----------------------------------------------------------------------*
FORM REORDER_FIELDCAT_MBEWH CHANGING C_IT_FIELDCAT
TYPE SLIS_T_FIELDCAT_ALV.
DATA: L_WA_FIELDCAT_TMP TYPE SLIS_FIELDCAT_ALV,
L_VAR_TABIX TYPE SY-INDEX,
L_VAR_COL_POS_CNT TYPE I VALUE 1.
FIELD-SYMBOLS <FS_WA_FIELDCAT_POS> TYPE SLIS_FIELDCAT_ALV.
"Index der Material Spalte lesen (MATNR)
READ TABLE C_IT_FIELDCAT
WITH KEY FIELDNAME = 'MATNR' TRANSPORTING NO FIELDS.
L_VAR_TABIX = SY-TABIX + 1 .
"WGBEZ
READ TABLE C_IT_FIELDCAT
INTO L_WA_FIELDCAT_TMP
WITH KEY FIELDNAME = 'WGBEZ'.
IF SY-SUBRC = 0.
"Löschen und neu einfügen
DELETE C_IT_FIELDCAT
WHERE FIELDNAME = 'WGBEZ'.
INSERT L_WA_FIELDCAT_TMP INTO C_IT_FIELDCAT INDEX L_VAR_TABIX.
ENDIF.
"MATKL verschieben
READ TABLE C_IT_FIELDCAT
INTO L_WA_FIELDCAT_TMP
WITH KEY FIELDNAME = 'MATKL'.
IF SY-SUBRC = 0.
"Löschen und neu einfügen
DELETE C_IT_FIELDCAT
WHERE FIELDNAME = 'MATKL'.
INSERT L_WA_FIELDCAT_TMP INTO C_IT_FIELDCAT INDEX L_VAR_TABIX.
ENDIF.
"MTART
READ TABLE C_IT_FIELDCAT
INTO L_WA_FIELDCAT_TMP
WITH KEY FIELDNAME = 'MTART'.
IF SY-SUBRC = 0.
"Löschen und neu einfügen
DELETE C_IT_FIELDCAT
WHERE FIELDNAME = 'MTART'.
INSERT L_WA_FIELDCAT_TMP INTO C_IT_FIELDCAT INDEX L_VAR_TABIX.
ENDIF.
"MAKTX
READ TABLE C_IT_FIELDCAT
INTO L_WA_FIELDCAT_TMP
WITH KEY FIELDNAME = 'MAKTX'.
IF SY-SUBRC = 0.
"Löschen und neu einfügen
DELETE C_IT_FIELDCAT
WHERE FIELDNAME = 'MAKTX'.
INSERT L_WA_FIELDCAT_TMP INTO C_IT_FIELDCAT INDEX L_VAR_TABIX.
ENDIF.
"Index der Periode Spalte lesen (LFMON)
READ TABLE C_IT_FIELDCAT
WITH KEY FIELDNAME = 'LFMON' TRANSPORTING NO FIELDS.
L_VAR_TABIX = SY-TABIX + 1 .
"WAERS
READ TABLE C_IT_FIELDCAT
INTO L_WA_FIELDCAT_TMP
WITH KEY FIELDNAME = 'WAERS'.
IF SY-SUBRC = 0.
"Löschen und neu einfügen
DELETE C_IT_FIELDCAT
WHERE FIELDNAME = 'WAERS'.
INSERT L_WA_FIELDCAT_TMP INTO C_IT_FIELDCAT INDEX L_VAR_TABIX.
ENDIF.
"MEINS
READ TABLE C_IT_FIELDCAT
INTO L_WA_FIELDCAT_TMP
WITH KEY FIELDNAME = 'MEINS'.
IF SY-SUBRC = 0.
"Löschen und neu einfügen
DELETE C_IT_FIELDCAT
WHERE FIELDNAME = 'MEINS'.
INSERT L_WA_FIELDCAT_TMP INTO C_IT_FIELDCAT INDEX L_VAR_TABIX.
ENDIF.
"Positionen neu schreiben
LOOP AT C_IT_FIELDCAT ASSIGNING <FS_WA_FIELDCAT_POS>
WHERE TABNAME NE ''.
<FS_WA_FIELDCAT_POS>-COL_POS = L_VAR_COL_POS_CNT.
L_VAR_COL_POS_CNT = L_VAR_COL_POS_CNT + 1.
ENDLOOP.
ENDFORM. " REORDER_FIELDCAT_MBEWH
The magic function to this is:
**ALVGrid
CALL FUNCTION 'REUSE_ALV_GRID_DISPLAY'
EXPORTING
IT_FIELDCAT = L_IT_FIELDCAT
I_GRID_TITLE = L_VAR_TITLE
TABLES
T_OUTTAB = <L_VAR_OUTTAB>
EXCEPTIONS
PROGRAM_ERROR = 1
OTHERS = 2.
IF SY-SUBRC <> 0.
MESSAGE ID SY-MSGID TYPE SY-MSGTY NUMBER SY-MSGNO
WITH SY-MSGV1 SY-MSGV2 SY-MSGV3 SY-MSGV4.
ENDIF.
You can generate your Fieldcat wth another Helpful function:
**Generate Fieldcat
CALL FUNCTION 'REUSE_ALV_FIELDCATALOG_MERGE'
EXPORTING
I_PROGRAM_NAME = SY-CPROG
I_INTERNAL_TABNAME = L_VAR_TABNAME
I_INCLNAME = SY-CPROG
CHANGING
CT_FIELDCAT = L_IT_FIELDCAT
EXCEPTIONS
INCONSISTENT_INTERFACE = 1
PROGRAM_ERROR = 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.
ENDIF.
As you can see here,the Fieldcat is generated from a local internam table. It is mandatory to give the include the where the table is defined. If the data structure is not in DDIC but local as well you need to give the include where it is defined, or include it in TOP. Very important is, that local structures are only read correctly when defined with LIKE and INCLUDE structure as Datatypes. TYPES and normalINCLUDE wont work, since the ddic information is not read there. Its also written in the Manual of the function. So always RTFM cause i did it way too late ;)
Here a sample as an MBEWH Extension is locally defined:
DATA: BEGIN OF TP_MBEWH_EXTENDED.
" MBEWH
INCLUDE STRUCTURE MBEWH.
" MARA with Key MATNR
DATA: YYBEZBE LIKE MARA-YYBEZBE,
MTART LIKE MARA-MTART,
MATKL LIKE MARA-MATKL,
MEINS LIKE MARA-MEINS,
"T001 with Key BUKRS from T001K with Key BWKEY
WAERS LIKE T001-WAERS,
"T023T with Key MATKL
WGBEZ LIKE T023T-WGBEZ.
DATA: END OF TP_MBEWH_EXTENDED.
I also discussed reordering the Catalog from the selection screen here:
http://abapify.blogspot.de/2014/10/alv-sorting-with-reordering-of-fieldcat.html
As Update here is a small piece of Code to dynamically alocate Tables and Fieldcats to 3 different Tables:
FORM BUILD_ALV.
CHECK P_TABLE IS NOT INITIAL.
DATA: L_IT_FIELDCAT TYPE SLIS_T_FIELDCAT_ALV,
L_VAR_TABNAME TYPE SLIS_TABNAME,
L_VAR_TITLE TYPE LVC_TITLE,
L_VAR_LINE_CNT_OUT TYPE C LENGTH 20.
FIELD-SYMBOLS: <L_VAR_OUTTAB> TYPE STANDARD TABLE.
**Je nach Auwahl der Tabelle wird die Struktur für den Feldkatalog und
* die zugehörige Ergebnis iTab für das ALV gewählt.
CASE P_TABLE.
WHEN 'S31'.
L_VAR_TABNAME = 'TP_S031_EXTENDED'.
ASSIGN IT_S031_EXTENDED TO <L_VAR_OUTTAB>.
WHEN 'S32'.
L_VAR_TABNAME = 'TP_S032_EXTENDED'.
ASSIGN IT_S032_EXTENDED TO <L_VAR_OUTTAB>.
WHEN 'MBH'.
L_VAR_TABNAME = 'TP_MBEWH_EXTENDED'.
ASSIGN IT_MBEWH_EXTENDED TO <L_VAR_OUTTAB>.
ENDCASE.
**Feldkatalog schlicht nach Tabelle erstellen
CALL FUNCTION 'REUSE_ALV_FIELDCATALOG_MERGE'
EXPORTING
I_PROGRAM_NAME = SY-CPROG
I_INTERNAL_TABNAME = L_VAR_TABNAME
I_INCLNAME = SY-CPROG
CHANGING
CT_FIELDCAT = L_IT_FIELDCAT
EXCEPTIONS
INCONSISTENT_INTERFACE = 1
PROGRAM_ERROR = 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.
ENDIF.
"Feldkatalog individuelle Sortierung
CASE P_TABLE.
WHEN 'S31'.
PERFORM REORDER_FIELDCAT_S031 CHANGING L_IT_FIELDCAT.
WHEN 'S32'.
PERFORM REORDER_FIELDCAT_S032 CHANGING L_IT_FIELDCAT.
WHEN 'MBH'.
PERFORM REORDER_FIELDCAT_MBEWH CHANGING L_IT_FIELDCAT.
ENDCASE.
*Anzahl der Zeilen
DESCRIBE TABLE <L_VAR_OUTTAB> LINES L_VAR_LINE_CNT_OUT.
***Tabellenname in den Titel nehmen
* CONCATENATE TEXT-100 L_VAR_TABNAME L_VAR_LINE_CNT_OUT TEXT-101
* INTO L_VAR_TITLE RESPECTING BLANKS.
**ALVGrid generieren.
CALL FUNCTION 'REUSE_ALV_GRID_DISPLAY'
EXPORTING
IT_FIELDCAT = L_IT_FIELDCAT
I_GRID_TITLE = L_VAR_TITLE
TABLES
T_OUTTAB = <L_VAR_OUTTAB>
EXCEPTIONS
PROGRAM_ERROR = 1
OTHERS = 2.
IF SY-SUBRC <> 0.
MESSAGE ID SY-MSGID TYPE SY-MSGTY NUMBER SY-MSGNO
WITH SY-MSGV1 SY-MSGV2 SY-MSGV3 SY-MSGV4.
ENDIF.
ENDFORM. "DISPLAY_ALV_REPORT
Then at last you might want to reorder the Fieldcat positions in your Output afterwards. Therem ight be better ways to do this (comments welcome), but most of what i tried before was very complicated an not error prone. The problem are some Entry which are also hidden an not seen and mostly have empty Tabnames. So i just went and took the First entry i knew, reordered everything from this Sy-Tabix on forward and renumerated everythin in the end.
*&---------------------------------------------------------------------*
*& Form REORDER_FIELDCAT_MBEWH
*&---------------------------------------------------------------------*
* Feldkatalog anpassungen:
*----------------------------------------------------------------------*
* <--P_L_IT_FIELDCAT Feldcatalog zu ändern
*----------------------------------------------------------------------*
FORM REORDER_FIELDCAT_MBEWH CHANGING C_IT_FIELDCAT
TYPE SLIS_T_FIELDCAT_ALV.
DATA: L_WA_FIELDCAT_TMP TYPE SLIS_FIELDCAT_ALV,
L_VAR_TABIX TYPE SY-INDEX,
L_VAR_COL_POS_CNT TYPE I VALUE 1.
FIELD-SYMBOLS <FS_WA_FIELDCAT_POS> TYPE SLIS_FIELDCAT_ALV.
"Index der Material Spalte lesen (MATNR)
READ TABLE C_IT_FIELDCAT
WITH KEY FIELDNAME = 'MATNR' TRANSPORTING NO FIELDS.
L_VAR_TABIX = SY-TABIX + 1 .
"WGBEZ
READ TABLE C_IT_FIELDCAT
INTO L_WA_FIELDCAT_TMP
WITH KEY FIELDNAME = 'WGBEZ'.
IF SY-SUBRC = 0.
"Löschen und neu einfügen
DELETE C_IT_FIELDCAT
WHERE FIELDNAME = 'WGBEZ'.
INSERT L_WA_FIELDCAT_TMP INTO C_IT_FIELDCAT INDEX L_VAR_TABIX.
ENDIF.
"MATKL verschieben
READ TABLE C_IT_FIELDCAT
INTO L_WA_FIELDCAT_TMP
WITH KEY FIELDNAME = 'MATKL'.
IF SY-SUBRC = 0.
"Löschen und neu einfügen
DELETE C_IT_FIELDCAT
WHERE FIELDNAME = 'MATKL'.
INSERT L_WA_FIELDCAT_TMP INTO C_IT_FIELDCAT INDEX L_VAR_TABIX.
ENDIF.
"MTART
READ TABLE C_IT_FIELDCAT
INTO L_WA_FIELDCAT_TMP
WITH KEY FIELDNAME = 'MTART'.
IF SY-SUBRC = 0.
"Löschen und neu einfügen
DELETE C_IT_FIELDCAT
WHERE FIELDNAME = 'MTART'.
INSERT L_WA_FIELDCAT_TMP INTO C_IT_FIELDCAT INDEX L_VAR_TABIX.
ENDIF.
"MAKTX
READ TABLE C_IT_FIELDCAT
INTO L_WA_FIELDCAT_TMP
WITH KEY FIELDNAME = 'MAKTX'.
IF SY-SUBRC = 0.
"Löschen und neu einfügen
DELETE C_IT_FIELDCAT
WHERE FIELDNAME = 'MAKTX'.
INSERT L_WA_FIELDCAT_TMP INTO C_IT_FIELDCAT INDEX L_VAR_TABIX.
ENDIF.
"Index der Periode Spalte lesen (LFMON)
READ TABLE C_IT_FIELDCAT
WITH KEY FIELDNAME = 'LFMON' TRANSPORTING NO FIELDS.
L_VAR_TABIX = SY-TABIX + 1 .
"WAERS
READ TABLE C_IT_FIELDCAT
INTO L_WA_FIELDCAT_TMP
WITH KEY FIELDNAME = 'WAERS'.
IF SY-SUBRC = 0.
"Löschen und neu einfügen
DELETE C_IT_FIELDCAT
WHERE FIELDNAME = 'WAERS'.
INSERT L_WA_FIELDCAT_TMP INTO C_IT_FIELDCAT INDEX L_VAR_TABIX.
ENDIF.
"MEINS
READ TABLE C_IT_FIELDCAT
INTO L_WA_FIELDCAT_TMP
WITH KEY FIELDNAME = 'MEINS'.
IF SY-SUBRC = 0.
"Löschen und neu einfügen
DELETE C_IT_FIELDCAT
WHERE FIELDNAME = 'MEINS'.
INSERT L_WA_FIELDCAT_TMP INTO C_IT_FIELDCAT INDEX L_VAR_TABIX.
ENDIF.
"Positionen neu schreiben
LOOP AT C_IT_FIELDCAT ASSIGNING <FS_WA_FIELDCAT_POS>
WHERE TABNAME NE ''.
<FS_WA_FIELDCAT_POS>-COL_POS = L_VAR_COL_POS_CNT.
L_VAR_COL_POS_CNT = L_VAR_COL_POS_CNT + 1.
ENDLOOP.
ENDFORM. " REORDER_FIELDCAT_MBEWH
Monday, November 3, 2014
Smartforms: Asterisk in Page numbering
I recently had the Problem that when used page numbering in Smartform like this
&SFSY-FORMPAGES& / &SAPSCRIPT-FORMPAGES&
in long documents it showed:
1/*
2/*
but later
10/25
11/25
It seems that the length of the second part FORMPAGES is related to the length of the first part, and that why there is not enough space anymore for the 25. * is typically used as a starting char, when there is content longer than the space available.
So i found an override for this with formatting options.
&SFSY-FORMPAGES(3ZC)& / &SAPSCRIPT-FORMPAGES(3ZC)&
where :
3 = output length of data
Z = suppress leading zeroes
C = compress blank spaces
Of course i want to credit the source where i found it:
http://searchsap.techtarget.com/answer/When-asterisks-attack-in-the-page-numbering-window
&SFSY-FORMPAGES& / &SAPSCRIPT-FORMPAGES&
in long documents it showed:
1/*
2/*
but later
10/25
11/25
It seems that the length of the second part FORMPAGES is related to the length of the first part, and that why there is not enough space anymore for the 25. * is typically used as a starting char, when there is content longer than the space available.
So i found an override for this with formatting options.
&SFSY-FORMPAGES(3ZC)& / &SAPSCRIPT-FORMPAGES(3ZC)&
where :
3 = output length of data
Z = suppress leading zeroes
C = compress blank spaces
Of course i want to credit the source where i found it:
http://searchsap.techtarget.com/answer/When-asterisks-attack-in-the-page-numbering-window
Thursday, October 16, 2014
ALV Sorting with reordering of Fieldcat
We recently had a requests in a report to offer sorting options at selection time (not in the ALV Grid later).
So basically what you do is offer Parameters for Sortorder or even better a restricted Select-Option if you have a Domain of the Columns.
Then you have a iTab representing the Sort Order in the ata Definition.
TYPES: BEGIN OF SORT_HELP,
POS TYPE N LENGTH 2,
TABNAME TYPE YI_BDSCOLS.
TYPES: END OF SORT_HELP.
DATA: IT_SORTLIST TYPE TABLE OF SORT_HELP,
VAR_SORTITEM TYPE SORT_HELP.
You can write a Function to add Columns to the sorting
*&---------------------------------------------------------------------*
*& Form ADD_SORTITEM
*&---------------------------------------------------------------------*
* text
*----------------------------------------------------------------------*
* -->F_POS Position of Col in Sorting
* -->F_TABNAME Col Name
*----------------------------------------------------------------------*
FORM CUST_ADD_SORTITEM USING F_POS TYPE N
F_TABNAME TYPE CHAR20.
IF F_POS > 0 .
CLEAR VAR_SORTITEM.
READ TABLE IT_SORTLIST WITH KEY POS = F_POS TRANSPORTING NO FIELDS.
"Wenn Schlüssel schon vorhanden haben wir eine doppelte Zeile
IF SY-SUBRC = 0.
MESSAGE E685(yb).
ELSE.
VAR_SORTITEM-TABNAME = F_TABNAME.
VAR_SORTITEM-POS = F_POS.
APPEND VAR_SORTITEM TO IT_SORTLIST.
SORT IT_SORTLIST BY POS ASCENDING.
ENDIF.
ENDIF.
ENDFORM. " ADD_SORTITEM
And wherever you fill your ALV Grid you generate the Sorting upfront:
*# Sort
DATA L_WA_SORT TYPE LVC_S_SORT. "#EC *
CLEAR C_T_SORT. REFRESH C_T_SORT.
LOOP AT IT_SORTLIST INTO VAR_SORTITEM.
CLEAR: L_WA_SORT.
L_WA_SORT-SPOS = SY-TABIX. "Level of Sortierung
L_WA_SORT-FIELDNAME = VAR_SORTITEM-TABNAME. "Sortcolumn
L_WA_SORT-UP = 'X'. "Sortierung ascending
L_WA_SORT-DOWN = ' '. "Sortierung descending
APPEND L_WA_SORT TO C_T_SORT.
ENDLOOP.
The neat thing now is, that you also are able to redo the Fieldcat of the ALV Grid in Order of the Sorting upfront.
I did it like this, there may be a better way. Comments are welcome.
DATA: L_IT_FIELDCAT_NEW TYPE LVC_T_FCAT,
L_VAR_COL_POS_CNT TYPE I VALUE 1.
FIELD-SYMBOLS <L_WA_FIELDCAT_COL> TYPE LVC_S_FCAT.
"Copy all FieldCat Fields not associated with viewable Cols
LOOP AT C_T_FIELDCAT ASSIGNING <L_WA_FIELDCAT_COL>
WHERE TABNAME EQ ''.
APPEND <L_WA_FIELDCAT_COL> TO L_IT_FIELDCAT_NEW.
DELETE C_T_FIELDCAT.
ENDLOOP.
"Insert Cols from the SortList and remove them from the initial Fieldcat
LOOP AT IT_SORTLIST INTO VAR_SORTITEM.
READ TABLE C_T_FIELDCAT
WITH KEY FIELDNAME = VAR_SORTITEM-TABNAME
INTO L_WA_FIELDCAT.
IF SY-SUBRC = 0.
DELETE C_T_FIELDCAT
WHERE FIELDNAME = VAR_SORTITEM-TABNAME.
ENDIF.
APPEND L_WA_FIELDCAT TO L_IT_FIELDCAT_NEW.
ENDLOOP.
"Now add all Cols from the Initial Fieldcat after Sorted Ones
LOOP AT C_T_FIELDCAT ASSIGNING <L_WA_FIELDCAT_COL> .
APPEND <L_WA_FIELDCAT_COL> TO L_IT_FIELDCAT_NEW.
ENDLOOP.
"At last you have to assign new Col_Positions for all Entriew in the FieldCat
LOOP AT L_IT_FIELDCAT_NEW ASSIGNING <L_WA_FIELDCAT_COL>
WHERE TABNAME NE ''.
<L_WA_FIELDCAT_COL>-COL_POS = L_VAR_COL_POS_CNT.
L_VAR_COL_POS_CNT = L_VAR_COL_POS_CNT + 1.
ENDLOOP.
C_T_FIELDCAT = L_IT_FIELDCAT_NEW.
There you go :)
So basically what you do is offer Parameters for Sortorder or even better a restricted Select-Option if you have a Domain of the Columns.
Then you have a iTab representing the Sort Order in the ata Definition.
TYPES: BEGIN OF SORT_HELP,
POS TYPE N LENGTH 2,
TABNAME TYPE YI_BDSCOLS.
TYPES: END OF SORT_HELP.
DATA: IT_SORTLIST TYPE TABLE OF SORT_HELP,
VAR_SORTITEM TYPE SORT_HELP.
You can write a Function to add Columns to the sorting
*&---------------------------------------------------------------------*
*& Form ADD_SORTITEM
*&---------------------------------------------------------------------*
* text
*----------------------------------------------------------------------*
* -->F_POS Position of Col in Sorting
* -->F_TABNAME Col Name
*----------------------------------------------------------------------*
FORM CUST_ADD_SORTITEM USING F_POS TYPE N
F_TABNAME TYPE CHAR20.
IF F_POS > 0 .
CLEAR VAR_SORTITEM.
READ TABLE IT_SORTLIST WITH KEY POS = F_POS TRANSPORTING NO FIELDS.
"Wenn Schlüssel schon vorhanden haben wir eine doppelte Zeile
IF SY-SUBRC = 0.
MESSAGE E685(yb).
ELSE.
VAR_SORTITEM-TABNAME = F_TABNAME.
VAR_SORTITEM-POS = F_POS.
APPEND VAR_SORTITEM TO IT_SORTLIST.
SORT IT_SORTLIST BY POS ASCENDING.
ENDIF.
ENDIF.
ENDFORM. " ADD_SORTITEM
And wherever you fill your ALV Grid you generate the Sorting upfront:
*# Sort
DATA L_WA_SORT TYPE LVC_S_SORT. "#EC *
CLEAR C_T_SORT. REFRESH C_T_SORT.
LOOP AT IT_SORTLIST INTO VAR_SORTITEM.
CLEAR: L_WA_SORT.
L_WA_SORT-SPOS = SY-TABIX. "Level of Sortierung
L_WA_SORT-FIELDNAME = VAR_SORTITEM-TABNAME. "Sortcolumn
L_WA_SORT-UP = 'X'. "Sortierung ascending
L_WA_SORT-DOWN = ' '. "Sortierung descending
APPEND L_WA_SORT TO C_T_SORT.
ENDLOOP.
The neat thing now is, that you also are able to redo the Fieldcat of the ALV Grid in Order of the Sorting upfront.
I did it like this, there may be a better way. Comments are welcome.
DATA: L_IT_FIELDCAT_NEW TYPE LVC_T_FCAT,
L_VAR_COL_POS_CNT TYPE I VALUE 1.
FIELD-SYMBOLS <L_WA_FIELDCAT_COL> TYPE LVC_S_FCAT.
"Copy all FieldCat Fields not associated with viewable Cols
LOOP AT C_T_FIELDCAT ASSIGNING <L_WA_FIELDCAT_COL>
WHERE TABNAME EQ ''.
APPEND <L_WA_FIELDCAT_COL> TO L_IT_FIELDCAT_NEW.
DELETE C_T_FIELDCAT.
ENDLOOP.
"Insert Cols from the SortList and remove them from the initial Fieldcat
LOOP AT IT_SORTLIST INTO VAR_SORTITEM.
READ TABLE C_T_FIELDCAT
WITH KEY FIELDNAME = VAR_SORTITEM-TABNAME
INTO L_WA_FIELDCAT.
IF SY-SUBRC = 0.
DELETE C_T_FIELDCAT
WHERE FIELDNAME = VAR_SORTITEM-TABNAME.
ENDIF.
APPEND L_WA_FIELDCAT TO L_IT_FIELDCAT_NEW.
ENDLOOP.
"Now add all Cols from the Initial Fieldcat after Sorted Ones
LOOP AT C_T_FIELDCAT ASSIGNING <L_WA_FIELDCAT_COL> .
APPEND <L_WA_FIELDCAT_COL> TO L_IT_FIELDCAT_NEW.
ENDLOOP.
"At last you have to assign new Col_Positions for all Entriew in the FieldCat
LOOP AT L_IT_FIELDCAT_NEW ASSIGNING <L_WA_FIELDCAT_COL>
WHERE TABNAME NE ''.
<L_WA_FIELDCAT_COL>-COL_POS = L_VAR_COL_POS_CNT.
L_VAR_COL_POS_CNT = L_VAR_COL_POS_CNT + 1.
ENDLOOP.
C_T_FIELDCAT = L_IT_FIELDCAT_NEW.
There you go :)
Wednesday, October 15, 2014
Restricting Select-Options
If you ever wanted to restrict the possibilities of Select-Options, there is good news.
The FM 'SELECT_OPTIONS_RESTRICT' is the way to go.
#---------------------------------------------------------------------*
*# Sortierung-Options restrict to EQ
DATA: L_WA_RESTRICT TYPE SSCR_RESTRICT,
L_WA_OPTLIST TYPE SSCR_OPT_LIST,
L_WA_ASS TYPE SSCR_ASS.
* Only 'EQ'
L_WA_OPTLIST-NAME = 'OBJECTKEY1'.
L_WA_OPTLIST-OPTIONS-EQ = 'X'.
APPEND L_WA_OPTLIST TO L_WA_RESTRICT-OPT_LIST_TAB.
L_WA_ASS-KIND = 'S'.
L_WA_ASS-NAME = 'S_SORT'.
L_WA_ASS-SG_MAIN = 'I'.
L_WA_ASS-SG_ADDY = SPACE.
L_WA_ASS-OP_MAIN = 'OBJECTKEY1'.
APPEND L_WA_ASS TO L_WA_RESTRICT-ASS_TAB.
CALL FUNCTION 'SELECT_OPTIONS_RESTRICT'
EXPORTING
RESTRICTION = L_WA_RESTRICT.
IF SY-SUBRC <> 0.
* Implement suitable error handling here
ENDIF.
Friday, October 10, 2014
Date Conflicts, Intersections and Co.
Often you will have to deal with Dates and Ranges. Lets have a look at a tricky case that often occurs when looking for date intersections ( conflicting dates ). The best and fastest way to solve this is actually not to test if a date (range) is inside the allowed date intevall, but to test if it is not outside the intervall.
Here is sample of intersection tests (green) on date ranges.
As you can see, the green ones are intersections the red ones are not. So it the easiest way to this as a Select statement would be:
SELECT * FROM t1 WHERE NOT ( data.start_date > start_date OR data.end_date < end_date )
which could also be expressed as:
SELECT * FROM t1 WHERE data.end_date >= start_date AND data.start_date <= end_date
Here is sample of intersection tests (green) on date ranges.
As you can see, the green ones are intersections the red ones are not. So it the easiest way to this as a Select statement would be:
SELECT * FROM t1 WHERE NOT ( data.start_date > start_date OR data.end_date < end_date )
which could also be expressed as:
SELECT * FROM t1 WHERE data.end_date >= start_date AND data.start_date <= end_date
Monday, January 13, 2014
ABAP2XLS
Whenever you have the urge to export an Excel File from ABAP Data i can only recommend to use a Package like ABAP2XLS. They do a really great job and a lot of work is prebuild and even auto recognized on the data structures you provide.
Check it out at:
http://ivanfemia.github.io/abap2xlsx/
Its a little tricky to get into it, but totally worth the time if you have more than a plain .csv/excel you want to export.
Check it out at:
http://ivanfemia.github.io/abap2xlsx/
Its a little tricky to get into it, but totally worth the time if you have more than a plain .csv/excel you want to export.
Use Domains
I recently helped a co worker who tried to solve a problem with a WebDynpro filter. She coded the filter by hand and was wondering why the filtered values where not met. The answer was pretty simple. The column used a primitive data type and the filter she programmed used value, text pairs. She thought it would filter on the text as well as the value, which it did not. Why this is a classic beginner mistake which happended to me a lot as well in the beginning, the real lesson here ist to use proper datatypes with domains. They then have the same text value pairs. You do not even need to programm your filter, cause it can bge configured, and localisation is for free as well.
It always appears faster to use primitive data types at first, but i can assure you, the bigger the project is, the more changes will come in later. Having build proper datatypes at that point saves you a lot more time than you will invest in the beginning.
I do also hat to have one data type for one single component of a structure which is really only used once in the programm still it pays of.
While this may come naturally to programmers who only lived in SAP/ABAP their whole life, lateral entires from other programming languages are having a harder time to understand the benefit behind this super redundancy, since they are normally drilled to use standard components.
It always appears faster to use primitive data types at first, but i can assure you, the bigger the project is, the more changes will come in later. Having build proper datatypes at that point saves you a lot more time than you will invest in the beginning.
I do also hat to have one data type for one single component of a structure which is really only used once in the programm still it pays of.
While this may come naturally to programmers who only lived in SAP/ABAP their whole life, lateral entires from other programming languages are having a harder time to understand the benefit behind this super redundancy, since they are normally drilled to use standard components.
Subscribe to:
Posts (Atom)