For the purpose of providing an example, independent requirements history information will be used (tables PBHI and PBIM).
1. Run transaction SE11. 2. Select Database table and enter the name of the table : PBHI 3. Click on Display
4. You now get the list of fields in this table. 5. Take note of the fields that you are interested in, and the data element associated with each. For our example PDATU, PLNMG, DBMNG, LAEDA, UZEIT, and AENAM.
6. We are also interested in the WERKS and MATNR fields from the PBIM table. Repeat steps 1 through 5 above and take note of the data elements associated with those fields.
1. Run transaction SE11. 2. Select Data type. 3. Give your structure a name. Custom objects in SAP must start with Z. So for example, Z505_INDREQHISTORY. 4. Click on Create. 5. When prompted, select Structure.
6. Enter a description of the purpose of the structure in the Short description field. 7. Click on the Components tab if it is not already selected. 8. Enter the component fields that are in the structure. You can name these however you wish, or simple use the same names as the fields from the table which holds the source data. 9. Specify the component types for each of these fields, based on the data elements that you recorded during the design and dicovery phase. 10. Press enter and you should see a result similar to the figure at right.
In SAP, some data types such as QUAN and CURR represent numerical values that only make sense in the context of the associated unit of measure. With CURR for example, the unit of measure is the currency (EUR, CAD, USD etc.) SAP requires that fields of this type be linked to the data fields that hold the unit of measure. With our example here, the forecast amount fields relate to the unit of measure for the material master. 11. Click on the Currency / Quantity fields tab 12. Enter the reference table where the unit of measure is stored. If you are going to include the unit of measure in the structure definition, you can self-reference the structure here. For our example, the referenced table is the material master MARA. 13. Enter the reference field from the referenced table that contains the unit of measure. For our example, the referenced field is MEINS.
14. Click on to save the structure. When prompted, provide package $tmp to place the object in your users local object space. 15. Click on to activate the structure. This effectively publishes your structure and allows other users and programs to use it. You may be prompted Warnings Occurred During Activation. You can typically ignore these, but errors that prevent activation must be resolved.
1. Run transaction SE37. 2. From the menu select Goto / Function Groups / Create Group 3. Enter a name, again starting with Z as all custom objects must. 4. Enter a description of the group of functions. 5. Click on Save. The Create Object Directory Entry dialog appears. 6. Click on Local Object.
7. You are returned to the Function Builder: Initial screen. 8. Enter a name for the function we will create, again starting with Z. For example Z505_GET_INDREQHIST. 9. Click on Create.
The Create Function Module dialog appears. 10. Enter the function group that this function will belong to. Use the function group created in steps 2 through 6 above. 11. Enter a description of the purpose of the function in the Short Text field. 12. Click on Save. 13. Click past the information message that appears.
The Function Builder: Change screen appears. 14. Click on the Attributes tab. 15. Under Processing Type select the Remote-Enabled Module option. This setting is what allows a regular ABAP function to be called remotely.
The tabs Import, Export, Changing and Tables allow you to define the input and output parameters of the function. We will be returning tabular data in our example function. 16. Click on the Tables tab. 17. Enter a name for the parameter, the Type Specification value of LIKE and in the Associated Type column enter the name of your structure that defines your output data.
Were now ready to write our code! Its a good practice to document code with its purpose and history. 18. Click on the Source code tab. 19. After the comment block that shows the functions parameter interfaces, add another comment block with a description of the purpose of the function, and some information about when and who created it.
FUNCTION Z505_GET_INDREQSHIST. *"---------------------------------------------------------------*"*"Local Interface: *" TABLES *" HISTORY STRUCTURE Z505_ST_INDREQSHIST *"---------------------------------------------------------------* Retrieves the history of independant requirements for all plants ****************************************************************** * 2009-01-29: DVL, Created ****************************************************************** ENDFUNCTION.
To fetch the data we need to write a SELECT statement. We can fetch the data and put it directly into the output table by using the INTO TABLE construct. 20. Write your select statement.Pay attention to the following: Unlike the SELECT construct in SQL, the ABAP SELECT construct does not separate fields with commas. The order of the fields selected is important. The position is matched one for one with the fields of the destination table, so make sure the field selection order is the same as the order of the fields in the table (as defined by the structure we created previously). When selecting data from multiple tables the INNER JOIN construct defines how the data in one table relates to another. Note that the fields are resolved to their associated tables with the use of the ~ character. Before we can use the function, we need to check, save and activate it. 21. Click on or hit CTRL+F2 to check the syntax of your code. Resolve all errors and warnings. Highlight a word and hit the F1 key for extra information. 22. Click on or hit CTRL+S to save the function. 23. Click on or hit CTRL+F3 to activate the function.
FUNCTION Z505_GET_INDREQSHIST. *"---------------------------------------------------------------*"*"Local Interface: *" TABLES *" HISTORY STRUCTURE Z505_ST_INDREQSHIST *"---------------------------------------------------------------* Retrieves the history of independant requirements for all plants ****************************************************************** * 2009-01-29: DVL, Created ****************************************************************** SELECT pbim~werks pbim~matnr pbhi~pdatu pbhi~plnmg pbhi~dbmng pbhi~laeda pbhi~uzeit pbhi~aenam INTO TABLE history FROM pbim INNER JOIN pbhi ON pbhi~bdzei = pbim~bdzei. ENDFUNCTION.
10
Unit testing the function to make sure it behaves as we would like it to, is also a good idea. 24. Click on or hit F8 to enter test/direct execute mode. 25. Click on or hit F8 to execute the function. 26. In the tables section of the output display, to the right of Result: click on to display the content of the results table.
11
1. Run transaction SE37. 2. Enter the name of the function module to modify.
3. Click on Change 4. Click on the Import tab. Here we will create an input parameter. 5. Enter the Parameter Name as PLANT, the Type as TYPE, and the Associated Type as WERKS_D. This specifies a single value parameter for plant, and links it to the WERKS object in the SAP dictionary. 6. Select (check) the Optional field. This allows the parameter to be unspecified (empty) by the calling code. 7. Select (check) the Pass Value field. All parameters for remotely callable functions must be passed by value.
12
8. Click on the Source code tab. Note the extra IMPORTING parameter in the interface comment block. 9. Revise the description of purpose. 10. Add an entry in the history log for the change.
FUNCTION Z505_GET_INDREQSHIST. *"-------------------------------------------------------------*"*"Local Interface: *" IMPORTING *" VALUE(PLANT) TYPE WERKS_D OPTIONAL *" TABLES *" HISTORY STRUCTURE Z505_ST_INDREQSHIST *"-------------------------------------------------------------* Retrieves the history of independant requirements, for all * plants, or if the PLANT parameter is provided as input, only * the history for that plant. **************************************************************** * 2009-01-29: DVL, Created * 2009-02-12: DVL, Added plant filtering **************************************************************** **************************************************************** * 2009-01-29: DVL, Created * 2009-01-30: DVL, Added plant filtering **************************************************************** DATA: filter TYPE string. SELECT pbim~werks pbim~matnr pbhi~pdatu pbhi~plnmg pbhi~dbmng pbhi~laeda pbhi~uzeit pbhi~aenam INTO TABLE history FROM pbim INNER JOIN pbhi ON pbhi~bdzei = pbim~bdzei WHERE (filter). ENDFUNCTION.
To use this parameter and dynamically filter the results returned from the SELECT statement we will need to build a filter string that has the form similar to an SQL WHERE condition. First we must define a local variable to hold this value. 11. Define a local variable of TYPE string with the DATA construct. 12. Add the WHERE condition to the end of the select statement. Note that ABAP allows for the WHERE condition to be passed from a variable. When you are editing long ABAP statements, pay attention to adding and removing statement terminating periods . so that the syntax remains correct.
13
An empty string passed into the WHERE condition has no effect, just as if no condition was specified. This is the desired behaviour for our function if no plant paramater has been specified. We need to check if a value was provided, and if so build the WHERE condition into the local string variable. 13. Add an IF construct, testing the value of the input parameter plant based on whether a value was provided. The ABAP construct IS INITIAL (and the negation IS NOT INITIAL) returns whether a variable is empty. Its good practice to comment the code block with the nature of the test condition and the intended behaviour of the code executed if the condition is true. Dont forget the ENDIF. to close the code block. It is also good practice to comment which condition the ENDIF corresponds to. For longer code blocks and nested IF conditions, it can be easy to lose track. 14. Populate the value of the filter local variable using the CONCATENATE construct. CONCATENATE assembles multiple source strings into a destination string. The source strings can variables or literals, specified by containing the value of the string within single quotes ' . The WHERE condition must respect the syntax of the SELECT construct so table and field identifiers must match those that are in the actual SELECT itself. For tests of equality against string literals, the literals must be properly encapsulated in quotes. Note that in order to define a string literal that contains the quote character itself, we need to escape it or the ABAP compiler will think we have specified the end of string and not be able to understand the rest of the line. We do this by typing the quote
**************************************************************** * 2009-01-29: DVL, Created * 2009-01-30: DVL, Added plant filtering **************************************************************** DATA: filter TYPE string. IF plant IS NOT INITIAL. " If a plant parameter was supplied, construct a filter " (SQL WHERE condition) to restrict the data selected. ENDIF. "plant parameter provided SELECT pbim~werks pbim~matnr pbhi~pdatu pbhi~plnmg pbhi~dbmng pbhi~laeda pbhi~uzeit pbhi~aenam INTO TABLE history FROM pbim INNER JOIN pbhi ON pbhi~bdzei = pbim~bdzei WHERE (filter). ENDFUNCTION.
FUNCTION Z505_GET_INDREQSHIST. *"-------------------------------------------------------------*"*"Local Interface: *" IMPORTING *" VALUE(PLANT) TYPE WERKS_D OPTIONAL *" TABLES *" HISTORY STRUCTURE Z505_ST_INDREQSHIST *"-------------------------------------------------------------* Retrieves the history of independant requirements, for all * plants, or if the PLANT parameter is provided as input, only * the history for that plant. **************************************************************** * 2009-01-29: DVL, Created * 2009-01-30: DVL, Added plant filtering **************************************************************** DATA: filter TYPE string. IF plant IS NOT INITIAL. " If a plant parameter was supplied, construct a filter " (SQL WHERE clause) to restrict the data selected. CONCATENATE 'pbim~werks = ''' plant '''' INTO filter. ENDIF. SELECT pbim~werks pbim~matnr pbhi~pdatu pbhi~plnmg pbhi~dbmng pbhi~laeda pbhi~uzeit pbhi~aenam
14
character twice where we want it in the string literal. Thus, we arrive at ' ' ' ' to define a string literal that contains a single quote character! Once again, before we can use the function, we need to check, save and activate it. 15. Click on or hit CTRL+F2 to check the syntax of your code. Resolve all errors and warnings. 16. Click on or hit CTRL+S to save the function. 17. Click on or hit CTRL+F3 to activate the function.
INTO TABLE history FROM pbim INNER JOIN pbhi ON pbhi~bdzei = pbim~bdzei WHERE (filter). ENDFUNCTION.
Finally, we need to unit testing the function to make sure it behaves as we would like it to. 18. Click on or hit F8 to enter test/direct execute mode. 19. In the Import parameters section, to the right of PLANT enter a valid plant to return only data for that plant, or leave it empty to return data for all plants. 20. Click on or hit F8 to execute the function and validate the results.
15