Function orditems_dialog
This is the most important function of the program. It implements the multiple dialog instruction to control order and items input simultaneously.
The function uses the opflag
variable to determine the state of the operations
for items
:
N
- no current operationT
- temporary row was createdI
- row insertion was done in the listM
- row in the list was modified
Function orditems_dialog
(orders.4gl)
001
FUNCTION
orditems_dialog()
002
DEFINE
query_ok SMALLINT
,
003
id INTEGER
,
004
name LIKE
customer.store_name,
005
opflag CHAR
(1),
006
curr_pa INTEGER
007
008
DIALOG ATTRIBUTES(UNBUFFERED)
009
010
INPUT BY NAME
order_rec.*, order_total
011
ATTRIBUTES
(WITHOUT DEFAULTS
, NAME
="order")
012
013
ON ACTION
find
014
IF NOT
order_update(DIALOG
) THEN NEXT FIELD CURRENT END IF
015
CALL
order_query()
016
017
ON ACTION
new
018
IF NOT
order_update(DIALOG
) THEN NEXT FIELD CURRENT END IF
019
IF NOT
order_new() THEN
020
EXIT PROGRAM
021
END IF
022
023
ON ACTION
save
024
IF NOT
order_update(DIALOG
) THEN NEXT FIELD CURRENT END IF
025
026
ON CHANGE
store_num
027
IF NOT
order_check_store_num() THEN NEXT FIELD CURRENT END IF
028
029
ON ACTION
zoom1
030
CALL
display_custlist() RETURNING
id, name
031
IF
id > 0 THEN
032
LET
order_rec.store_num = id
033
LET
order_rec.store_name = name
034
CALL DIALOG
.setFieldTouched("store_num", TRUE
)
035
END IF
036
037
AFTER INPUT
038
IF NOT
order_update(DIALOG
) THEN NEXT FIELD CURRENT END IF
039
040
ON ACTION
first
041
IF NOT
order_update(DIALOG
) THEN NEXT FIELD CURRENT END IF
042
CALL
order_move(move_first)
043
ON ACTION
previous
044
IF NOT
order_update(DIALOG
) THEN NEXT FIELD CURRENT END IF
045
CALL
order_move(move_prev)
046
ON ACTION
next
047
IF NOT
order_update(DIALOG
) THEN NEXT FIELD CURRENT END IF
048
CALL
order_move(move_next)
049
ON ACTION
last
050
IF NOT
order_update(DIALOG
) THEN NEXT FIELD CURRENT END IF
051
CALL
order_move(move_last)
052
053
END INPUT
054
055
INPUT ARRAY
arr_items FROM
sa_items.*
056
ATTRIBUTES (WITHOUT DEFAULTS, INSERT ROW
=FALSE)
057
058
BEFORE INPUT
059
MESSAGE
msg19
060
061
BEFORE ROW
062
LET
opflag = "N"
063
LET
curr_pa = DIALOG
.getCurrentRow("sa_items")
064
CALL DIALOG
.setFieldActive("stock_num", FALSE
)
065
066
BEFORE INSERT
067
LET
opflag = "T"
068
LET
arr_items[curr_pa].quantity = 1
069
CALL DIALOG
.setFieldActive("stock_num", TRUE
)
070
071
AFTER INSERT
072
LET
opflag = "I"
073
074
BEFORE DELETE
075
IF
opflag="N" THEN
076
IF NOT
item_delete(curr_pa) THEN
077
CANCEL DELETE
078
END IF
079
END IF
080
081
AFTER DELETE
082
LET
opflag="N"
083
084
ON ROW CHANGE
085
IF
opflag != "I" THEN LET
opflag = "M" END IF
086
087
AFTER ROW
088
IF
opflag == "I" THEN
089
IF NOT
item_insert(curr_pa) THEN
090
NEXT FIELD CURRENT
091
END IF
092
CALL
items_line_total(curr_pa)
093
END IF
094
IF
opflag == "M" THEN
095
IF NOT
item_update(curr_pa) THEN
096
NEXT FIELD CURRENT
097
END IF
098
CALL
items_line_total(curr_pa)
099
END IF
100
101
ON ACTION
zoom2
102
LET
id = display_stocklist()
103
IF
id > 0 THEN
104
IF NOT
get_stock_info(curr_pa,id) THEN
105
LET
arr_items[curr_pa].stock_num = NULL
106
ELSE
107
LET
arr_items[curr_pa].stock_num = id
108
END IF
109
CALL DIALOG
.setFieldTouched("stock_num", TRUE
)
110
END IF
111
112
ON CHANGE
stock_num
113
IF NOT
get_stock_info(curr_pa,
114
arr_items[curr_pa].stock_num) THEN
115
LET
arr_items[curr_pa].stock_num = NULL
116
CALL
__mbox_ok(title2,msg07,"stop")
117
NEXT FIELD
stock_num
118
ELSE
119
CALL
items_line_total(curr_pa)
120
END IF
121
122
ON CHANGE
quantity
123
IF
arr_items[curr_pa].quantity <= 0 THEN
124
CALL
__mbox_ok(title2,msg13,"stop")
125
NEXT FIELD
quantity
126
ELSE
127
CALL
items_line_total(curr_pa)
128
END IF
129
130
END INPUT
131
132
BEFORE DIALOG
133
IF NOT
order_select("1=1") THEN
134
CALL
order_query()
135
END IF
136
137
ON ACTION
about
138
CALL
__mbox_ok(title1,msg18,"information")
139
140
ON ACTION
quit
141
EXIT DIALOG
142
143
END DIALOG
144
145
END FUNCTION
Note:
- Lines
002
thru006
define the variables used by this function. - Lines
008
thru143
define aDIALOG
instruction implementing the controller of the form.- Lines
010
thru053
implement theINPUT BY NAME
sub-dialog, controlling theorder_rec
record input. All actions triggers declared inside theINPUT BY NAME
sub-dialog will only be activated if the focus is in this sub-dialog. Data validation will occur when focus is lost by this sub-dialog, or when the user presses the Save button.- Lines
013
thru015
implement thefind
ON ACTION
trigger, to execute a Query By Example with theorder_query()
function. Before calling the query function, we must validate and save current modifications in the order record with theorder_update()
function. If the validation/save fails, the cursor remains in the current field (when the user clicks an action view, such as a Toolbar icon, the focus does not change.) - Lines
017
thru021
implement thenew
ON ACTION
trigger, to create a new order record. Before calling the new function, we must validate and save current modifications in the order record with theorder_update()
function. - Lines
023
thru024
implement thesave
ON ACTION
trigger, to validate and save current modifications in the order record with theorder_update()
function. - Lines
026
thru027
declare theON CHANGE
trigger for thestore_num
field, to check if the number is a valid store identifier with theorder_check_store_num()
function. If the function returnsFALSE
, we execute aNEXT FIELD
to stay in the field. - Lines
029
thru035
implement thezoom1
ON ACTION
trigger for thef01
field, to open a typical "zoom" window with thedisplay_custlist()
function. If the user selects a customer from the list, we mark the field as touched with theDIALOG.setFieldTouched()
method. This simulates a real user input. - Lines
037
thru038
implement theAFTER INPUT
trigger, to validate and save current modifications with theorder_update()
function when the focus is lost by the order header sub-dialog. - Lines
040
thru051
implement theON ACTION
triggers for the four navigation actions to move in the order list with theorder_move()
function. Before calling the query function, we must validate and save current modifications with theorder_update()
function.
- Lines
- Lines
055
thru130
implement theINPUT ARRAY
sub-dialog, controlling thearr_items
array input. All actions triggers declared inside theINPUT ARRAY
sub-dialog will only be activated if the focus is in this sub-dialog. The sub-dialog uses theopflag
technique to implement SQL instructions inside the dialog code and update the database on the fly.- Lines
058
thru059
implement theBEFORE INPUT
trigger, to display information message to the user, indicating that item row data will be validated and saved in the database when the user moves to another row or when the focus is lost by the item list. - Lines
061
thru064
implement theBEFORE ROW
trigger, initialize theopflag
operation flag to "N" (no current operation), save the current row index incurr_pa
variable and disable thestock_num
field (only editable when creating a new line). - Lines
066
thru069
implement theBEFORE INSERT
trigger, to set theopflag
to "T" (meaning a temporary row was created). A row will be fully validated and ready for SQLINSERT
when we reach theAFTER INSERT
trigger, there we will setopflag
to "I". The code initializes the quantity to 1 and enables thestock_num
field for user input. - Lines
071
thru072
implement theAFTER INSERT
trigger, to set theopflag
to "I" (row insertion done in list). Data is now ready to be inserted in the database. This is done in theAFTER ROW
trigger, according toopflag
. - Lines
074
thru079
implement theBEFORE DELETE
trigger. We execute the SQLDELETE
only ifopflag
equals "N", indicating that we are in a normal browse mode (and not inserting a new temporary row, which can be deleted from the list without any associated SQL instruction). - Lines
081
thru082
implement theAFTER DELETE
trigger, to reset theopflag
to "N" (no current operation). This is done to clean the flag after deleting a new inserted row, when data validation or SQL insert failed inAFTER ROW
. In that case,opflag
equals "I" in the nextAFTER DELETE
/AFTER ROW
sequence and would invoke validation rules again. - Lines
084
thru085
implement theON ROW CHANGE
trigger, to set theopflag
to "M" (row was modified), but only if we are not currently doing a row insertion: Row insertion can have failed inAFTER ROW
andAFTER INSERT
would not be executed again, butON ROW CHANGE
would. The real SQLUPDATE
will be done later inAFTER ROW
. - Lines
087
thru099
implement theAFTER ROW
trigger, executingINSERT
orUPDATE
SQL instructions according to theopflag
flag. If the SQL statement fails (for example, because a constraint is violated), we set the focus back to the current field withNEXT FIELD CURRENT
and keep theopflag
value as is. If the SQL instruction succeeds,opflag
will be reset to "N" in the nextBEFORE ROW
. - Lines
101
thru103
implement thezoom2
ON ACTION
trigger for thef08
field, to open a typical "zoom" window with thedisplay_stocklist()
function. If the user selects a stock from the list, we mark the field as touched with theDIALOG.setFieldTouched()
method. This simulates a real user input. - Lines
112
thru120
declare theON CHANGE
trigger for thestock_num
field, to check if the number is a valid stock identifier with theget_stock_info()
lookup function. If the function returnsFALSE
, we execute aNEXT FIELD
to stay in the field, otherwise we recalculate the line total withitems_line_total()
. - Lines
122
thru128
declare theON CHANGE
trigger for thequantity
field, to check if the value is greater than zero. If the value is invalid, we execute aNEXT FIELD
to stay in the field, otherwise we recalculate the line total withitems_line_total()
.
- Lines
- Lines
132
thru134
implement theBEFORE DIALOG
trigger, to fill the list of orders with an initial result set. - Lines
137
thru138
implement theabout
ON ACTION
trigger, to display a message box with the version of the program. - Lines
140
thru141
implement thequit
ON ACTION
trigger, to leave the dialog (and quit the program).
- Lines