I have not had that much opportunity to work with SmartForms till very recently. I had already switched to Eclipse & ADT as my primary programming tool and thought I could get away this, not having to go back to SAPGui based development – and then I encounter SmartForms! I can’t even use normal day-to-day ABAP Editor tools, can’t use normal breakpoints, can’t do a where-used, several drill-throughs don’t work – what did I just get myself into!
After the first one that I volunteered making changes to, we realized I had to do one from scratch. Here is an opportunity – I moved all the code out to a class and called the class from within the SmartForm. This way I have all the tools that SAP & ABAP provide to work with code, I can use the ADT environment, test the data output independent of the SmartForm, use editor-based breakpoints, etc, etc…
Here is a step by step sample of a pick list printed from a warehouse transfer order.
CLASS ztestclass_pick_list DEFINITION
PUBLIC
FINAL
CREATE PUBLIC .
PUBLIC SECTION.
DATA:
g_lgnum TYPE lgnum,
g_ltak TYPE ltak,
gi_ltap TYPE SORTED TABLE OF ltap WITH UNIQUE DEFAULT KEY,
g_vbeln TYPE vbeln,
g_company TYPE char15.
METHODS constructor
IMPORTING
lgnum TYPE lgnum
tanum TYPE tanum.
PROTECTED SECTION.
PRIVATE SECTION.
ENDCLASS.
CLASS ZTESTCLASS_PICK_LIST IMPLEMENTATION.
* <SIGNATURE>------------------------------------------------------------+
* | Instance Public Method ZTESTCLASS_PICK_LIST->CONSTRUCTOR
* +----------------------------------------------------------------------+
* | [--->] LGNUM TYPE LGNUM
* | [--->] TANUM TYPE TANUM
* +-----------------------------------------------------------</SIGNATURE>
METHOD constructor.
" Select TO header
SELECT SINGLE * FROM ltak
WHERE lgnum = @lgnum
AND tanum = @tanum
INTO @g_ltak.
IF sy-subrc = 0.
" Select TO line
SELECT * FROM ltap
WHERE lgnum = @lgnum
AND tanum = @tanum
INTO TABLE @gi_ltap.
"Populate stand alone attributes from various sources
g_lgnum = lgnum.
g_vbeln = g_ltak-vbeln.
g_company = 'ACME WIDGET Co'.
ELSE.
" Raise error here
ENDIF.
ENDMETHOD.
ENDCLASS.
In this class declare public attributes for the data that you will be retrieving from the SmartForm. In this example, I will be retrieving the Transfer Order number, a Company name and Transfer Order Item details.
When creating the SmartForm, create the layout and design as you normally would. The difference is in the code and declarations. First in the form interface, declare only the variables that are already available to the calling program. If the calling program does not already have the data, don’t bother collecting the data and passing it in – that is the job of the class. In this case, I have the warehouse and transfer order number. From this the class can get the data needed for the report.
After the first one that I volunteered making changes to, we realized I had to do one from scratch. Here is an opportunity – I moved all the code out to a class and called the class from within the SmartForm. This way I have all the tools that SAP & ABAP provide to work with code, I can use the ADT environment, test the data output independent of the SmartForm, use editor-based breakpoints, etc, etc…
Here is a step by step sample of a pick list printed from a warehouse transfer order.
STEP 1 – Create class to collect data
CLASS ztestclass_pick_list DEFINITION
PUBLIC
FINAL
CREATE PUBLIC .
PUBLIC SECTION.
DATA:
g_lgnum TYPE lgnum,
g_ltak TYPE ltak,
gi_ltap TYPE SORTED TABLE OF ltap WITH UNIQUE DEFAULT KEY,
g_vbeln TYPE vbeln,
g_company TYPE char15.
METHODS constructor
IMPORTING
lgnum TYPE lgnum
tanum TYPE tanum.
PROTECTED SECTION.
PRIVATE SECTION.
ENDCLASS.
CLASS ZTESTCLASS_PICK_LIST IMPLEMENTATION.
* <SIGNATURE>------------------------------------------------------------+
* | Instance Public Method ZTESTCLASS_PICK_LIST->CONSTRUCTOR
* +----------------------------------------------------------------------+
* | [--->] LGNUM TYPE LGNUM
* | [--->] TANUM TYPE TANUM
* +-----------------------------------------------------------</SIGNATURE>
METHOD constructor.
" Select TO header
SELECT SINGLE * FROM ltak
WHERE lgnum = @lgnum
AND tanum = @tanum
INTO @g_ltak.
IF sy-subrc = 0.
" Select TO line
SELECT * FROM ltap
WHERE lgnum = @lgnum
AND tanum = @tanum
INTO TABLE @gi_ltap.
"Populate stand alone attributes from various sources
g_lgnum = lgnum.
g_vbeln = g_ltak-vbeln.
g_company = 'ACME WIDGET Co'.
ELSE.
" Raise error here
ENDIF.
ENDMETHOD.
ENDCLASS.
In this class declare public attributes for the data that you will be retrieving from the SmartForm. In this example, I will be retrieving the Transfer Order number, a Company name and Transfer Order Item details.
Step 2 – Create the SmartForm
When creating the SmartForm, create the layout and design as you normally would. The difference is in the code and declarations. First in the form interface, declare only the variables that are already available to the calling program. If the calling program does not already have the data, don’t bother collecting the data and passing it in – that is the job of the class. In this case, I have the warehouse and transfer order number. From this the class can get the data needed for the report.
In the global definitions, I have a single variable (OB_PICK_DATA) declared with reference to the class I have created. This is the variable that will be used throughout the SmartForm for access to data.
I also have a Field Symbol declared that will be used to get the line item details for the table LTAP.
And here is the only code that goes into the entire SmartForm! It is hard to imagine why anyone would want to put a break point here!
If you are writing this in pre-7.4 ABAP, you would write this as
CREATE OBJECT ob_pick_data
EXPORTING
lgnum = lgnum
tanum = tanum.
Note that in the output parameters, there is also the field-symbol <LTAP> even though there is no data being set. This is prevent subsequent error / warning messages stating “Field <ltap>-matnr has no defined value“.
In the individual text elements, the data can be accessed from the attributes of the class directly or as an element of a structure. In this case, I have used…
Company name: &OB_PICK_DATA->G_COMPANY&
Transfer Order Number: &OB_PICK_DATA->G_LTAK-TANUM&
Warehouse to pick from: &OB_PICK_DATA->G_LTAK-LGNUM&
For a tabular output itself, you have to reference the attribute as an internal table. In this case, OB_PICK_DATA->GI_LTAP is a table of Transfer Order Lines that I am assigning to the field-symbol <LTAP>. Another alternative here is to declare a Global Field and have the data going into it instead of assigning. If you want to avoid any variable on the SmartForm, you can create an attribute in the class and send the data to that variable. While this is possible, I feel that a field-symbol being a pointer is the most efficient way to access this data.
In the individual cells, you reference the field-symbol or local variable in this case instead of the object.
"Using Field-Symbol
&<LTAP>-TAPOS&
&<LTAP>-MATNR&
"OR
"Using a variable
&L_LTAP-TAPOS&
&L_LTAP-MATNR&
And step 3 – there is no step 3… just test and use! Another advantage that I have not used yet is that you could set up a test class so that you are covered for immediate testing as well as future regression testing. Try that with standard SmartForm code!
This comment has been removed by the author.
ReplyDeleteJust WOW! Bookmarked for future reference.
ReplyDelete