Tuesday, July 17, 2007

Step by step learning ABAP

ABAP stands for Advanced Business Applicatian Programming. The ABAP programming language was originally used by SAP developers to develop the SAP R/3 platform. It was also intended to be used by SAP customers to enhance SAP applications customers can develop custom reports and interfaces with ABAP programming. The language is fairly easy to learn for programmers but it is not a tool for direct use by non-programmers. Good programming skills, including knowledge of relational database design and preferably also of object-oriented concepts, are required to create ABAP programs.


If you are new to ABAP, there are 2 point you should learn first, in following order:
1. Explore Data Dictionary
Data dictionary is a workplace for defining table, define data type, display table content.
Go to transaction code SE11 (SAP Menu->Tools->ABAP Workbench->Development->Data Dictionary).
Then enjoy exploring data dictionary.
2. Create ABAP Report
Go to transaction code SE38 (SAP Menu->Tools->ABAP Workbench->Development->ABAP Editor), and try to write your first program.

Here are other useful links for beginner:
ABAP Overview in Wikipedia
Blog Series in SAP Developer Network

Read More......

Dynamic Table Maintenance

It is a good sample of how to create dynamic table maintenance by utilized SAP function module "STC1_FULLSCREEN_TABLE_CONTROL".
I copy this code from ITToolbox

You can use it to replace funtion of SM31 with additional benefit.
1. Because it is written in as customer program we can add additional feature, for example change history.
2. There is no need to create screen maintenance for all table because screen will automatically generated.

But, remember, this is only a demonstration of how to use STC1_FULLSCREEN_TABLE_CONTROL. Use it carefully and only for customer table (Z*).


Because there is difficulty in write "<" and ">" in blogger, I replace "<" with "{" and ">" with "}" in this sample code. Copy this sample code, then replace all "{" with "<" then replace all "}" with ">".


REPORT ZAALGAL002 NO STANDARD PAGE HEADING.

TYPE-POOLS: rsds.

DATA: is_x030l TYPE x030l,
it_dfies TYPE TABLE OF dfies,
is_dfies TYPE dfies,
it_fdiff TYPE TABLE OF field_dif,
is_fdiff TYPE field_dif.

DATA: w_selid TYPE rsdynsel-selid,
it_tables TYPE TABLE OF rsdstabs,
is_tables TYPE rsdstabs,
it_fields TYPE TABLE OF rsdsfields,
it_expr TYPE rsds_texpr,
it_ranges TYPE rsds_trange,
it_where TYPE rsds_twhere,
is_where TYPE rsds_where,
w_active TYPE i.

DATA: it_content TYPE REF TO data,
it_modif TYPE REF TO data,
it_fcat TYPE lvc_t_fcat.

DATA: w_okcode TYPE sy-ucomm.


FIELD-SYMBOLS: {itab} TYPE STANDARD TABLE,
{ntab} TYPE STANDARD TABLE.


* Macros
DEFINE table_error.
message e398(00) with 'Table' p_table &1.
END-OF-DEFINITION.

DEFINE fixed_val.
is_fdiff-fieldname = is_dfies-fieldname.
is_fdiff-fixed_val = &1.
is_fdiff-no_input = 'X'.
append is_fdiff to it_fdiff.
END-OF-DEFINITION.


* Selection screen
SELECTION-SCREEN: BEGIN OF BLOCK b01 WITH FRAME.
PARAMETERS: p_table TYPE tabname OBLIGATORY "table
MEMORY ID dtb
MATCHCODE OBJECT dd_dbtb_16.
SELECTION-SCREEN: BEGIN OF LINE,
PUSHBUTTON 33(20) selopt USER-COMMAND sel,
COMMENT 55(15) selcnt,
END OF LINE.
SELECTION-SCREEN: SKIP.
PARAMETERS: p_rows TYPE i. "rows
SELECTION-SCREEN: END OF BLOCK b01,
SKIP,
BEGIN OF BLOCK b02 WITH FRAME.
PARAMETERS: p_displ TYPE c AS CHECKBOX. "display
SELECTION-SCREEN: END OF BLOCK b02.

* Initialization
INITIALIZATION.
MOVE '@4G@ Filter records' TO selopt.

* PBO
AT SELECTION-SCREEN OUTPUT.
IF w_active IS INITIAL.
CLEAR: selcnt.
ELSE.
WRITE w_active TO selcnt LEFT-JUSTIFIED.
ENDIF.

* PAI
AT SELECTION-SCREEN.
IF p_table NE is_x030l-tabname.
CALL FUNCTION 'DDIF_NAMETAB_GET'
EXPORTING
tabname = p_table
IMPORTING
x030l_wa = is_x030l
TABLES
dfies_tab = it_dfies
EXCEPTIONS
OTHERS = 1.
IF is_x030l IS INITIAL.
table_error 'does not exist or is not active'.
ELSEIF is_x030l-tabtype NE 'T'.
table_error 'is not selectable'.
ELSEIF is_x030l-align NE 0.
table_error 'has alignment - cannot continue'.
ENDIF.

* Default values for system fields
REFRESH: it_fdiff.
is_fdiff-tabname = p_table.
LOOP AT it_dfies INTO is_dfies.
IF is_dfies-datatype = 'CLNT'.
fixed_val sy-mandt.
ELSEIF is_dfies-rollname = 'ERDAT'
OR is_dfies-rollname = 'ERSDA'
OR is_dfies-rollname = 'AEDAT'
OR is_dfies-rollname = 'LAEDA'.
fixed_val sy-datum.
ELSEIF is_dfies-rollname = 'ERTIM'
OR is_dfies-rollname = 'AETIM'.
fixed_val sy-uzeit.
ELSEIF is_dfies-rollname = 'ERNAM'
OR is_dfies-rollname = 'AENAM'.
fixed_val sy-uname.
ENDIF.
ENDLOOP.

* Prepare free selection on table
REFRESH it_tables.
is_tables-prim_tab = p_table.
APPEND is_tables TO it_tables.

CLEAR: w_selid.
ENDIF.

IF sy-ucomm = 'SEL'.
IF w_selid IS INITIAL.
* Init free selection dialog
CALL FUNCTION 'FREE_SELECTIONS_INIT'
EXPORTING
expressions = it_expr
IMPORTING
selection_id = w_selid
expressions = it_expr
TABLES
tables_tab = it_tables
EXCEPTIONS
OTHERS = 1.
ENDIF.

* Display free selection dialog
CALL FUNCTION 'FREE_SELECTIONS_DIALOG'
EXPORTING
selection_id = w_selid
title = 'Selection'
status = 1
as_window = 'X'
IMPORTING
expressions = it_expr
field_ranges = it_ranges
number_of_active_fields = w_active
TABLES
fields_tab = it_fields
EXCEPTIONS
OTHERS = 1.
ENDIF.


* Start of processing
START-OF-SELECTION.

PERFORM f_create_table USING p_table.

PERFORM f_select_table.

PERFORM f_display_table.


*---------------------------------------------------------------------*
* FORM f_create_table *
*---------------------------------------------------------------------*
FORM f_create_table USING in_tabname.

FIELD-SYMBOLS: {fcat> TYPE lvc_s_fcat.

CALL FUNCTION 'LVC_FIELDCATALOG_MERGE'
EXPORTING
i_structure_name = in_tabname
CHANGING
ct_fieldcat = it_fcat
EXCEPTIONS
OTHERS = 1.
IF sy-subrc = 0.
* Complete field catalog
LOOP AT it_fcat ASSIGNING {fcat>.
{fcat>-tabname = in_tabname.
ENDLOOP.
CALL FUNCTION 'LVC_FIELDCAT_COMPLETE'
CHANGING
ct_fieldcat = it_fcat
EXCEPTIONS
OTHERS = 1.
ELSE.
WRITE: 'Error building field catalog'.
STOP.
ENDIF.

* Create dynamic table for data
CALL METHOD cl_alv_table_create=>create_dynamic_table
EXPORTING
it_fieldcatalog = it_fcat
IMPORTING
ep_table = it_content.
IF sy-subrc = 0.
ASSIGN it_content->* TO {itab}.
ELSE.
WRITE: 'Error creating internal table'.
STOP.
ENDIF.

* Create dynamic table for modif
CALL METHOD cl_alv_table_create=>create_dynamic_table
EXPORTING
it_fieldcatalog = it_fcat
IMPORTING
ep_table = it_modif.
IF sy-subrc = 0.
ASSIGN it_modif->* TO {ntab}.
ELSE.
WRITE: 'Error creating internal table'.
STOP.
ENDIF.

ENDFORM.


*---------------------------------------------------------------------*
* FORM f_select_table *
*---------------------------------------------------------------------*
FORM f_select_table.

IF w_active = 0.
SELECT * FROM (p_table)
INTO CORRESPONDING FIELDS OF TABLE {itab}
UP TO p_rows ROWS.
ELSE.
* Selection with parameters
CALL FUNCTION 'FREE_SELECTIONS_RANGE_2_WHERE'
EXPORTING
field_ranges = it_ranges
IMPORTING
where_clauses = it_where.
READ TABLE it_where INTO is_where WITH KEY tablename = p_table.

SELECT * FROM (p_table)
INTO CORRESPONDING FIELDS OF TABLE {itab}
UP TO p_rows ROWS
WHERE (is_where-where_tab).
ENDIF.

IF sy-dbcnt = 0.
WRITE: 'No record selected'.
STOP.
ENDIF.
ENDFORM.


*---------------------------------------------------------------------*
* FORM f_display_table *
*---------------------------------------------------------------------*
FORM f_display_table.
DATA: l_answer TYPE c,
l_eflag TYPE c.

CLEAR: w_okcode.
REFRESH: {ntab}.
* Display table contents
CALL FUNCTION 'STC1_FULLSCREEN_TABLE_CONTROL'
EXPORTING
header = p_table
tabname = p_table
display_only = p_displ
endless = 'X'
no_button = space
IMPORTING
okcode = w_okcode
TABLES
nametab = it_dfies
table = {itab}
fielddif = it_fdiff
modif_table = {ntab}
EXCEPTIONS
OTHERS = 1.
IF sy-subrc = 0.
IF p_displ IS INITIAL AND w_okcode = 'SAVE'.
* Confirm update
CALL FUNCTION 'POPUP_TO_CONFIRM'
EXPORTING
titlebar = p_table
text_question = 'Do you want to update table ?'
default_button = '2'
display_cancel_button = ' '
IMPORTING
answer = l_answer
EXCEPTIONS
OTHERS = 1.
IF l_answer = '1'.
* Apply modifications
IF NOT {ntab}[] IS INITIAL.
PERFORM f_add_system USING space.
MODIFY (p_table) FROM TABLE {ntab}.
IF sy-subrc NE 0.
l_eflag = 'X'.
ENDIF.
ENDIF.
* Apply deletions
IF l_eflag IS INITIAL.
REFRESH: {ntab}.
CALL FUNCTION 'STC1_GET_DATA'
TABLES
deleted_data = {ntab}
EXCEPTIONS
OTHERS = 1.
IF NOT {ntab}[] IS INITIAL.
DELETE (p_table) FROM TABLE {ntab}.
IF sy-subrc NE 0.
ROLLBACK WORK.
l_eflag = 'X'.
ENDIF.
ENDIF.
ENDIF.
* Apply creations
IF l_eflag IS INITIAL.
REFRESH: {ntab}.
CALL FUNCTION 'STC1_GET_DATA'
TABLES
new_data = {ntab}
EXCEPTIONS
OTHERS = 1.
IF NOT {ntab}[] IS INITIAL.
PERFORM f_add_system USING 'X'.
INSERT (p_table) FROM TABLE {ntab}.
IF sy-subrc NE 0.
ROLLBACK WORK.
l_eflag = 'X'.
ENDIF.
ENDIF.
ENDIF.
IF l_eflag IS INITIAL.
COMMIT WORK.
MESSAGE s261(53).
ELSE.
MESSAGE s075(3i).
PERFORM f_select_table.
ENDIF.
ENDIF.
* Display table again
PERFORM f_display_table.
ENDIF.
ENDIF.

ENDFORM.


*---------------------------------------------------------------------*
* FORM f_add_system *
*---------------------------------------------------------------------*
FORM f_add_system USING new TYPE c.

FIELD-SYMBOLS: {irec} TYPE ANY,
{upd} TYPE ANY.

LOOP AT it_fdiff INTO is_fdiff.
READ TABLE it_dfies INTO is_dfies
WITH KEY fieldname = is_fdiff-fieldname.
LOOP AT {ntab} ASSIGNING {irec}.
ASSIGN COMPONENT is_fdiff-fieldname OF STRUCTURE {irec} TO {upd}.
IF is_dfies-datatype = 'CLNT'.
{upd} = sy-mandt.
ELSE.
CASE is_dfies-rollname.
WHEN 'AENAM'.
{upd} = sy-uname.
WHEN 'AEDAT' OR 'LAEDA'.
{upd} = sy-datum.
WHEN 'AETIM'.
{upd} = sy-uzeit.
WHEN OTHERS.
ENDCASE.
ENDIF.
ENDLOOP.
ENDLOOP.

ENDFORM.


Read More......

FTP



SAP provide sample code to connect to FTP.

It provided in SAP function module, FTP_CONNECT (connect to FTP), FTP_COMMAND (send command by FTP), FTP_DISCONNECT (disconnect),FTP_R3_TO_SERVER (put file to FTP),FTP_SERVER_TO_R3 (get file from FTP).

Instead of writing a new code, I will try to give you explanation on SAP sample code.

I will explore program RSFTP002.


Program RSFTP002 demonstrate how to send command to FTP.



You can send any FTP command by this program.
For RFC destination use SAPFTP or SAPFTPA. Those are standard RFC destination to connect to FTP. SAPFTP run on client, and SAPFTPA run on application server.

First step of this program is using FTP_CONNECT, don't forget to use scrambled password.
Then we send a command to FTP by using FTP_COMMAND.
To disconnect, use FTP_DISCONNECT.

To copy, or get a file from SAP to/from FTP, you can explore RSFTP002. It demonstrate how to use FTP_R3_TO_SERVER (put file to FTP) & FTP_SERVER_TO_R3 (get file from FTP).
Other way is send put command using FTP_COMMAND. To put a file, do this steps, change FTP directory using "cd dir", change local directory using "lcd localdir", then send put command "put file".

Read More......

Simple ALV

ALV is very an useful tools in reporting. Just pass the data to ALV, than it will display interactive report easy to sort, filter, calculate total, etc.

There are two ALV model, list report (function REUSE_ALV_LIST_DISPLAY) and grid report (function REUSE_ALV_GRID_DISPLAY). Please read the function module documentation for complete guidance.

There are two main part of simple ALV report.
1. Create field catalog.
Field catalog containing descriptions of the list output fields.
2. Pass data and field catalog to ALV function (function REUSE_ALV_LIST_DISPLAY or REUSE_ALV_GRID_DISPLAY).

You can also playing with ALV format, find it in "Change Format in ALV".

This is a simple sample of how to use ALV.


REPORT ZAALGAL0001.
*-----------------------------------------
*Data declaration
TABLES: mara,
makt.

* Data output
DATA: BEGIN OF t_report OCCURS 3,
matnr LIKE mara-matnr,
mtart LIKE mara-mtart,
maktx LIKE makt-maktx,
END OF t_report.

* Field desciption / field catalog
TYPE-POOLS: SLIS.
data t_fcat type SLIS_T_FIELDCAT_ALV.

*-
DATA: d_repid LIKE sy-repid.

*-----------------------------------------
*--Selection Screen
SELECT-OPTIONS: s_matnr FOR mara-matnr,
s_mtart FOR mara-mtart.

*-----------------------------------------
START-OF-SELECTION.
*-Read data
SELECT * FROM mara
WHERE matnr IN s_matnr AND
mtart IN s_mtart.
CLEAR makt.
SELECT SINGLE *
FROM makt
WHERE matnr = mara-matnr AND
spras = sy-langu.
MOVE: mara-matnr TO t_report-matnr,
mara-mtart TO t_report-mtart,
makt-maktx TO t_report-maktx.
APPEND t_report.
ENDSELECT.

IF sy-subrc NE 0.
WRITE 'No data found'.
EXIT.
ENDIF.

*-----------------------------------------
*-Create Field Catalog

* Store report name
d_repid = sy-repid.

* Create Fieldcatalogue from internal table
* Use capital letter for I_INTERNAL_TABNAME
CALL FUNCTION 'REUSE_ALV_FIELDCATALOG_MERGE'
EXPORTING
I_PROGRAM_NAME = d_repid
I_INTERNAL_TABNAME = 'T_REPORT'
I_INCLNAME = d_repid
CHANGING
CT_FIELDCAT = t_fcat
EXCEPTIONS
INCONSISTENT_INTERFACE = 1
PROGRAM_ERROR = 2
OTHERS = 3.

IF SY-SUBRC <> 0.
write: / 'Error:',sy-subrc,
'when Create Field Catalog'.
EXIT.
ENDIF.

* Call ALV List Display
CALL FUNCTION 'REUSE_ALV_LIST_DISPLAY'
EXPORTING
I_CALLBACK_PROGRAM = d_repid
IT_FIELDCAT = t_fcat
TABLES
T_OUTTAB = t_report
EXCEPTIONS
PROGRAM_ERROR = 1
OTHERS = 2.

IF SY-SUBRC <> 0.
write: / 'Error:',sy-subrc,
'when Call ALV List Display'.
EXIT.
ENDIF.

Read More......

Processing Internal Tables

Internal Table is a main part of ABAP programming. In ABAP, internal tables fulfill the function of arrays. It is a data that have a structure and could contain more than one row.

Please refer to Data declaration for creating an internal table.

These are how to process internal table.

1. Sort Internal Table

SORT inttab BY field1 field2 ... field-n.

2. Loop At internal Table
LOOP AT inttab.
ENDLOOP.

3. Modify
3.1. Modify in a LOOP.
LOOP AT inttab.
MOVE ... TO inttab-field1.
MODIFY inttab.
ENDLOOP.

3.2. MODIFY BY index
MODIFY inttab INDEX int_index.

3.3. MODIFY BY condition
MODIFY inttab WHERE field1 = ....

4. Insert / Append
APPEND inttab.

5. Delete
Delete have variant similar to modify, delete in a loop, delete by index, and delete by criteria.

Read More......

Data Declaration

Declare single value variable:
Variable can be declared by two ways, first by declaring based on data type, second by declared it refer to table field.


Data d_data1 TYPE type. " berdasarkan type data
Data d_data2 LIKE customer-customerno. " refer ke field tertentu

Data types:
C (character)
N (numeric)
D (date)
T (Time)
X (byte / hexadecimal)
I (integer)
P (packed number)
F (floating point number)

Internal Table
Internal tables provide a means of taking data from a fixed structure and storing it in working memory in ABAP. The data is stored line by line in memory, and each line has the same structure. In ABAP, internal tables fulfill the function of arrays.
DATA: BEGIN OF t_report OCCURS 10,
field1 LIKE customer-customerno,
field2 TYPE I,
field3(20) TYPE C,
END OF t_report.

In above example, we define internal table contatin 3 fields, field-1 refer to field customer-customerno, field-2 type Integer, field-3 type character with field length 10 character. OCCURS 10 means that it reserve 10 line of memory at initialization, in run time memory will expand automatically when data exceed the limit.

Read More......

Monday, July 16, 2007

my first ABAP program

No, it's not a "hello world" program ;p

One of main job of an ABAPer is create ABAP report.
Report content 4 basic component.
1. Data declaration.
2. Selection screen.
3. Select Data.
4. Write Report.


I assume you already familiar with data dictionary. For an example, we have a table "SFLIGHT", with following fields:
1. CARRID (Airline carrier ID)
2. CONNID (Flight connection Id)
3. FLDATE (Flight date).
4.SEATSMAX (Maximum capacity).
We wan to create a report that can be filtered based on Airline carrier ID and Flight connection Id.
Go to transaction code SE38 (SAP Menu->Tools>ABAP Workbench->Development->ABAP Editor), enter program name with prefix Z, for example ZTEST0001, then choose "Create" button.


Then, enter title for program, and choose 1 "Executable Program" for program type. If screen input for development class appear, click "Local Object".

Then, go to following steps.
1. Data declaration



TABLES: sflight.

DATA: BEGIN OF t_report OCCURS 3,
carrid LIKE sflight-carrid,
connid LIKE sflight-connid,
fldate LIKE sflight-fldate,
seatsmax LIKE sflight-seatsmax,
END OF t_report.

2. Selection screen



SELECT-OPTIONS s_carrid FOR sflight-carrid.
SELECT-OPTIONS s_connid FOR sflight-connid.

It will generate selection screen like picture below.


3. Select data



SELECT * FROM sflight
WHERE carrid IN s_carrid AND
connid IN s_connid.
t_report-carrid = sflight-carrid.
t_report-connid = sflight-connid.
t_report-fldate = sflight-fldate.
t_report-seatsmax = sflight-seatsmax.
APPEND t_report.
ENDSELECT.
IF sy-subrc NE 0. "sy-subrc = return code
WRITE 'Data not found'.
ENDIF.

4. Write data



LOOP AT t_report.
skip. "comment:Go to next line
WRITE t_report-carrid.
WRITE t_report-connid.
WRITE t_report-fldate.
WRITE t_report-seatsmax.
ENDLOOP.

The result :


Here is the complete program:


REPORT ZTEST0001 .
*Data Declaration
tables: sflight.

DATA: BEGIN OF t_report OCCURS 3,
carrid LIKE sflight-carrid,
connid LIKE sflight-connid,
fldate LIKE sflight-fldate,
seatsmax LIKE sflight-seatsmax,
END OF t_report.

*Selection Screen
SELECT-OPTIONS s_carrid FOR sflight-carrid.
SELECT-OPTIONS s_connid FOR sflight-connid.

*Get Data
SELECT * FROM sflight
WHERE carrid IN s_carrid AND
connid IN s_connid.
t_report-carrid = sflight-carrid.
t_report-connid = sflight-connid.
t_report-fldate = sflight-fldate.
t_report-seatsmax = sflight-seatsmax.
APPEND t_report.
ENDSELECT.
IF sy-subrc NE 0.
WRITE 'Data not found'.
ENDIF.

*Write Data
LOOP AT t_report.
skip. "comment:Go to next line
WRITE t_report-carrid.
WRITE t_report-connid.
WRITE t_report-fldate.
WRITE t_report-seatsmax.
ENDLOOP.

Read More......