Numerous
SAP transactions use "table controls" to display data or to let the user
enter data in tabular form. With InputAssistant you can create
additional columns in a table control, both to display data or to let
the user enter additional data to be processed later on in an
InputScript.
The
technique for displaying data is not particularly complex, but handling data
entry requires a little more attention to detail. In this tutorial we first
cover read-only; then in the second part the scenario of data entry
into our new columns.
Our sample application for
this tutorial: In transaction VA01 (order entry) we want to offer the
user a new button "Show previous order info" that, when clicked,
displays the previously ordered quantity for each material entered so
far. For each order item we have to read the previous orders for this
material from the same customer, using an SAP BAPI call. In the table
control we add 3
columns that will be used to display the quantity ordered, the order date and
the order number for this material.
For producing the images of
the example, we used SAP GUI 7.40 on an SAP
ECC 6.0 IDES system. The
example can
also be used, without any changes, on previous SAP versions, e.g. on SAP
4.6C with SAP GUI 6.20 or 6.40.
VA01 Order entry: we add a button
"Show previous order info" that
will insert three new columns
The previously ordered quantity, order
date and order number are shown in three new columns for each material
We implement
this feature in two steps. First, we implement the new button that
displays three new additional table columns:
GuiXT
// GuiXT Script SAPMV45A.E4001.TXT
// only for transaction VA01, page sales
if Q[Transaction=VA01] and Q[Page=Sales]
// show button at end of table (right of iconized button "Item details: ..")
if not V[VA_show_cols]
Pushbutton P[Item details: Configuration]+(0,15) _
"@3S@Show previous order info" process="VA_show_cols.txt"
else
Pushbutton P[Item details: Configuration]+(0,15) _
"@3T@Hide previous order info" process="VA_hide_cols.txt"
// add three new table columns to
// display previous order quantity for each item
Column "Prv.Quant." size=10 name="VA_pq" _
position=4 -readOnly -alignRight
Column "Prv.Date" size=10 name="VA_pd" _
position=5 -readOnly -alignRight
Column "Prv.OrdNo." size=10 name="VA_po" _
position=6 -readOnly -alignRight
endif
endif
We can reset the
flag V[VA_show_cols] in the inital screen of VA01, otherwise the
configuration selected by the user (show or hide the additional info)
will remain valid for the next VA01 transaction as well.
The two
InputScripts are quite simple:
GuiXT
// InputScript VA_show_cols
Set V[VA_show_cols] "X"
Return
// InputScript VA_hide_cols
Set V[VA_show_cols] ""
Return
So far we have created 3 empty columns
that the user can show or hide clicking the new button
It is also
possible to display a suitable icon in the column headers. Example:
Additional icons are displayed in the
column titles
As usual, this
is done with the notation "@xx@text..." where xx is the SAP icon id. In
this case we used the icon id @OX@.
GuiXT
// add three new table columns with icons
// to display previous order quantity for each item
Column "@OX@Prv.Quant." size=10 name="VA_pq" position=4 -readOnly -alignRight
Column "@OX@Prv.Date" size=10 name="VA_pd" position=5 -readOnly -alignRight
Column "@OX@Prv.OrdNo." size=10 name="VA_po" position=6 -readOnly -alignRight
Finally, we
need to put the required data into our new columns. The variables behind
the columns are named according to the "name=.." parameter in the Column
command, and appended with the row number. Example:
The row index
is valid for the whole table control, not only for the visible part. For
example, when the user scrolls the table control to row 4, only the
rows shown in blue in the above diagram will be visible on screen.
When you set
values into the column variables V[VA_pq.1],..., two different
approaches are possible. Either you fill all variables at the beginning
of the transaction, and do not bother about scrolling. This works fine if
the whole table is in readonly mode. In our case it would not be the
right approach, since the user can change the material number for each
item, or can delete and insert new rows. In such cases it is better to
set the column variables each time the screen is displayed, and to
set it for the visible (blue coloured) part only. Essentially you
need some coding of the following type in order to do this:
GuiXT
// loop through all visible table rows
GetTableAttribute T[All items] firstVisibleRow="fvr"
Set V[i] 1 // row number on screen (visible part only)
Set V[k] &V[fvr] // absolute row number; this would be k=4 in the example above
label prev_order_beg
// valid row left?
Set V[item] "&cell[All items,Item,&V[i]]"
if not V[item]
goto prev_order_end
endif
//process visible row i. The absolute row number is k
... Set V[colvar.&V[k]] "some value"
// next row
Set V[i] &V[i] + 1
Set V[k] &V[k] + 1
goto prev_order_beg
label prev_order_end
Finally, we
need to read the right data within this framework. For this
purpose we call "BAPI_SALESORDER_GETLIST" for each
line. The input parameters for the BAPI are the customer number, the
material number and the sales area. The BAPI then returns a table
of order items for the given customer/material/sales area. The orders
are sorted according to date, with the most recent one at the top, so the first line of
this table will already contain the most recent order.
Since the
order quantity is returned in packed format, we apply the "-unpack"
option of the "Set" command. We also delete leading zeros in the order
number, and display the date in format DD.MM.YYYY. The whole script is
as follows:
GuiXT
// GuiXT Script SAPMV45A.E4001.TXT
// only for transaction VA01, page sales
if Q[Transaction=VA01] and Q[Page=Sales]
// show button at end of table (right of iconized button "Item details: ..")
if not V[VA_show_cols]
Pushbutton P[Item details: Configuration]+(0,15) _
"@3S@Show previous order info" process="VA_show_cols.txt"
else
Pushbutton P[Item details: Configuration]+(0,15) _
"@3T@Hide previous order info" process="VA_hide_cols.txt"
// add three new table columns to
// display previous order quantity for each item
Column "Prv.Quant." size=10 name="VA_pq" position=4 -readOnly -alignRight
Column "Prv.Date" size=10 name="VA_pd" position=5 -readOnly -alignRight
Column "Prv.OrdNo." size=10 name="VA_po" position=6 -readOnly -alignRight
// loop through all visible lines
GetTableAttribute T[All items] firstVisibleRow="fvr"
Set V[i] 1
Set V[k] &V[fvr]
// delete previous values
Set V[VA_pq.*] ""
Set V[VA_pd.*] ""
Set V[VA_po.*] ""
Set V[customer] "&F[Sold-to party]"
Set V[customer] 10000000000 + &V[customer]
Set V[customer] &V[customer](2-11)
label prev_order_beg
// any item left?
Set V[item] "&cell[All items,Item,&V[i]]"
if not V[item]
goto prev_order_end
endif
Set V[matnr] "&cell[All items,Material,&V[i]]"
if not V[matnr]
goto prev_order_end
endif
// read order info via SAP BAPI
Call "BAPI_SALESORDER_GETLIST" in.CUSTOMER_NUMBER="&V[customer]" _
in.SALES_ORGANIZATION="&F[Sales area]" _
in.MATERIAL="&V[matnr]" table.SALES_ORDERS=so
// read first line, it contains the most recent order for this material
CopyText fromText="so" toString="sowa" line=1
if Q[ok] // otherwise there is no previous order for this material
// now move some fields from the returned BAPI table into our new columns
// quantity: The BAPI returns it as 'packed decimal' incl. 3 decimal places
Set V[quantity] "&V[sowa](BAPIORDERS-REQ_QTY)" -unpack
Set V[quantity] "&V[quantity]" / 1000 decimals=0
Set V[VA_pq.&V[k]] "&V[quantity]"
// date: It comes in format YYYYMM, we use DD.MM.YYYY here
Set V[date] "&V[sowa](BAPIORDERS-DOC_DATE)"
Set V[VA_pd.&V[k]] "&V[date](7-8).&V[date](5-6).&V[date](1-4)"
// order number: comes with leading 0 that we get rid of with a calculation
Set V[ordno] "&V[sowa](BAPIORDERS-SD_DOC)"
Set V[ordno] &V[ordno] + 0
Set V[VA_po.&V[k]] "&V[ordno]"
endif
Set V[i] &V[i] + 1
Set V[k] &V[k] + 1
goto prev_order_beg
label prev_order_end
endif // V[VA_show_cols]
endif // VA01 + page=Sales
Our
second example deals with data entry in transaction ME51N (Create
Purchase Requisition) using additional table columns. In this
transaction
most of the item information can be entered directly in table columns,
but some additional fields require that we open the "Detail" view for the
item, click on the right tab in the detail view, and enter the
information into a separate field on this tab.
Remark: In
relatively new SAP systems (e.g. SAP ERP2004 and upwards), the user can
choose between a "grid control" and a "table control" for data entry in
ME51N (button "Personal setting" in the toolbar). The technique that we
describe here applies to the table control only, not to the grid
control.
Standard screen: The user enters the "Purch.Org."
in the tab "Source of supply" of the detail screen for each item
For one of
these fields, the "Purchase Organization" in tab "Source of Supply", we
want to create a new column in the table control where the user can
enter the purchase organization for each item directly, without having
to open up the detail view for this item.
Enhanced table: The user enters the "Purch.Org."
into a new column in the table control.
Compared to other SAP
transactions, ME51N has certain idiosyncrasies:
There is
no initial screen, so we have to find a convenient way to reset our
variables.
The user
can hide and display various screen parts (text area, item table,
detail view).
Another
difficulty that we may experience here and in numerous other transactions
is that the
user can "save" on a popup that is displayed when he presses F3, F12 or
F15 (Return, Cancel, Leave) in the transaction. We need a way to start
our updating InputScript in these cases as well.
First let's
look at the GuiXT script:
GuiXT
if Q[Transaction=ME51N]
// if table is visible (can be hidden by user)
if T[Table]
// no entries in table? then clear all ME51N_ variables
GetTableAttribute T[Table] firstVisibleRow=fvr
if V[fvr=1]
Set V[matnr] "&cell[Table,Material,1]"
if not V[matnr]
Set V[ME51N_*] ""
endif
endif
// create new column
Column "POrg" position=8 size=4 name="ME51N_EKORG" _
keyColumn="Requisn. item" techName="MEREQ3322-EKORG"
// Additional column is active
Set V[ME51N_active] "X"
endif
// Additional column is active? else stop of script processing
if not V[ME51N_active=X]
Stop
endif
// no entry field in detail screen to avoid synchronization with table column
if F[Purch. organization]
del F[Purch. organization]
endif
// when saving call own script
on "/11" process="ME51N_save.txt"
// when checking call own script
on "/39" process="ME51N_save.txt"
using MODE = "C"
// when the user leaves the transaction, handle the "do you want to save" popup
on "/3" process="ME51N_leave.txt"
on "/12" process="ME51N_leave.txt"
on "/15" process="ME51N_leave.txt"
endif
Some comments
on the script:
We reset
the variables when the item table is empty.
Our new
column "POrg" uses the item number as key column. This is
necessary
since the user can delete items, and the absolute row number will
then change for each item above the deleted one. GuiXT uses the
value in the key column as index as soon as it is available.
We also
define a searchhelp for the new column (techName=...)
The
standard data entry field for the purchase organization is deleted
from the screen. If we were to allow data entry in this field, it
would become difficult to synchronize the field with the column
data entry
When the
user presses the "check" button, we also first transport the entered
"POrg" fields from our added column to the standard SAP fields, so
that the checking is done for these fields as well. We use the same
script "ME51N_save.txt", but provide an additional parameter MODE =
"C".
For the
exit function "/3", "/12", "/15" we start a separate InputScript
"ME51N_leave.txt".
For GuiXT
versions before version 2007 Q1 1, it was also necessary to add
On "/Menu=x,y" statements in order to
handle menu clicks that correspond to /11, /2, /12,... This is now
no longer necessary, the On "/11",...
is processed automatically in these cases.
The
"ME51N_leave.txt" script handles the popup that is displayed when the
user leaves the transaction:
GuiXT
// InputScript "ME51N_leave.txt"
// popup screen "do you want to save the document first"
Screen SAPLSPO1.0100
On "=YES" process="ME51N_save.txt"
using POPUP = "X"
using MODE = "S"
It also starts
the "save" InputScript, setting the parameter POPUP = "X". The "save"
InputScript first cancels the popup and then runs through the normal
"save" procedure. It also handles cases in which the "detail" view
is not yet opened by the user, i.e. the InputScript opens the view and
closes it at again the end.
GuiXT
// InputScript "ME51N_save.txt"
Parameter POPUP "N" // "X" means: started form leave--popup
Parameter MODE "S" // S= Save C = Check
// No return on error, otherwise entered data could be lost
ProcessingOption returnOnError=Off
// A variablle indicates whether the InputScript had to open the "detail view"
Set V[ME51N_detail] ""
// started from "do you want to save?" popup?
if U[POPUP=X]
Enter "=CANC" // cancel popup, save at end of InputScript
else
Enter
endif
// Set correct title to be displayed during InputScript processing
if U[Mode=S]
Set V[ME51N_Title] "Saving the Purchase Requisition... Please wait"
else
Set V[ME51N_Title] "Checking the Purchase Requisition... Please wait"
endif
Screen saplmegui.0014
Title "&V[ME51N_Title]"
// Item table opened?
if T[Table]
goto item_table_open
endif
// open item table
Enter "=MEV4001BUTTON"
Screen saplmegui.0014
Title "&V[ME51N_Title]"
label item_table_open
// Row index variables
Set V[absrow] 1 // Absolute row number
Set V[relrow] 1 // Relative row number
// Position details opened?
if S[REQ_ITEM_DETAIL]
goto position_details_open
endif
// open position details
Enter "=MEV4002BUTTON"
Set V[ME51N_detail] "X"
Screen saplmegui.0014
Title "&V[ME51N_Title]"
label position_details_open
GetTableAttribute T[Table] firstVisibleRow=FVisRow
if V[FVisRow=1]
goto scroll_beg_done
endif
// scroll to first line
Enter "/scrollToLine=1" table="T[Table]"
label new_screen
Screen saplmegui.0014
Title "&V[ME51N_Title]"
label scroll_beg_done
GetTableAttribute T[Table] _
firstVisibleRow=FVisRow lastVisibleRow=LVisRow lastRow=LastRow
Set V[relrow] 1
label new_row
// end of table?
if V[absrow>&V[LastRow]]
goto end_of_table
endif
// end of screen?
if V[absrow>&V[LVisRow]]
Enter "/scrollToLine=&V[absrow]" table="T[Table]"
goto new_screen
endif
Set V[item] "&cell[Table,Requisn. item,&V[relrow]]"
if not V[item]
goto end_of_table
endif
Set V[ME51N_EKORG] "&V[ME51N_EKORG.&V[item]]"
Set V[ME51N_EKORG_previous] "&V[ME51N_EKORG.&V[item]_previous]"
// no new input?
if V[ME51N_EKORG=&V[ME51N_EKORG_previous]]
Set V[absrow] &V[absrow] + 1
Set V[relrow] &V[relrow] + 1
goto new_row
endif
// Save input
Set V[ME51N_EKORG.&V[item]_previous] "&V[ME51N_EKORG]"
// Set cursor into row and choose detail view
SetCursor cell[Table,Requisn. item,&V[relrow]]
Enter "/2"
Screen SAPLMEGUI.0014
Title "&V[ME51N_Title]"
if F[Purch. organization]
goto screen_EKORG
endif
// To TAB "Source of Supply"
Enter "=TABREQDT7"
Screen SAPLMEGUI.0014
Title "&V[ME51N_Title]"
label screen_EKORG
Set F[Purch. organization] "&V[ME51N_EKORG]"
Set V[absrow] &V[absrow] + 1
Set V[relrow] &V[relrow] + 1
goto new_row
label end_of_table
// detail view opened?
if not V[ME51N_detail=X]
goto screen_collapse_done
endif
// collapse detail view again
Enter "=MEV4002BUTTON"
Screen SAPLMEGUI.0014
Title "&V[ME51N_Title]"
label screen_collapse_done
// Save or check
if U[MODE=S]
Enter "/11"
else
Enter "/39"
endif
// started from popup? else end of script
if not U[POPUP=X]
Leave
endif
// back to main screen after popup + save procedure
Screen SAPLMEGUI.0014
Enter "/3"
// popup is displayed again (but nothing to save now)
// -> press "No" to leave the transaction
Screen SAPLSPO1.0100
Enter "=NO"
When you use "goto" and
"label" in the script, please observe the difference between the
following versions (the correct one and a wrong one):
(1)
S
GuiXT
creen saplmegui.0014
// Item table opened?
if T[Table]
goto item_table_open
endif
// open item table
Enter "=MEV4001BUTTON"
Screen saplmegui.0014
label item_table_open
(2)
GuiXT
Screen saplmegui.0014
// Item table opened?
if T[Table]
goto item_table_open
endif
// open item table
Enter "=MEV4001BUTTON"
label item_table_open
Screen saplmegui.0014
The second version (label
before Screen command) would be wrong: no "Enter"
is executed for the first "Screen" command,
and therefore the InputScript will display the screen and wait for user
input instead of continuing.
Another possible error
would be to include a Screen
command into an if...endif clause:
GuiXT
Screen saplmegui.0014
// Item table opened?
if not T[Table]
// open item table
Enter "=MEV4001BUTTON"
Screen saplmegui.0014
endif
Here GuiXT would
issue a syntax error message, since if...endif
clauses have to be closed within one static Screen
block.
After these negative
examples, here is an alternative that will work: You
use the "goto" to go back to the same
Screen command, after entering a suitable function code to open
up the table or detail view.
GuiXT
...
label main_screen
Screen saplmegui.0014
Title "&V[ME51N_Title]"
// Item table opened?
if not T[Table]
// open item table
Enter "=MEV4001BUTTON"
goto main_screen
endif
// Position details opened?
if not S[REQ_ITEM_DETAIL]
// open position details
Enter "=MEV4002BUTTON"
goto main_screen
endif
GetTableAttribute T[Table] firstVisibleRow=FVisRow
if V[FVisRow=1]
goto scroll_beg_done
endif
// scroll to first line
Enter "/scrollToLine=1" table="T[Table]"
label new_screen
Screen saplmegui.0014
Title "&V[ME51N_Title]"
label scroll_beg_done
...
In this case, it is
important that you put the label "main_screen"
before the Screen command. If you put it
after the Screen command, GuiXT would
continue, after the Enter, to execute
the script. You would then end up with more than one
Enter for one screen, which makes no sense
and in fact would lead to a GuiXT syntax error message, and the first
"Enter" would be lost. So when you write complex InputScripts please
bear in mind that you perform at most one
Enter for each Screen, and in
most cases exactly one. There are only two cases where it makes sense to
have a Screen command without Enter: Either when you want to display the
Screen and still stay within the InputScript, a possibility that we used
in the "ME51N_leave.txt" InputScript above to handle the popup. Or (a
very special case) when you use the "ApplyGUIScript" statement to call
up VBScript, and your VBScript program performs an "Enter" action
itself (e.g. presses a pushbutton).