Commit inicial: fuentes MBS ERP (Genero 6) + .gitignore + docs/SETUP_PC_MBS.md

This commit is contained in:
2026-08-18 20:59:52 -04:00
commit 454973e269
5978 changed files with 2664094 additions and 0 deletions
+58
View File
@@ -0,0 +1,58 @@
# Property of Four Js*
# (c) Copyright Four Js 1995, 2019. All Rights Reserved.
# * Trademark of Four Js Development Tools Europe Ltd
# in the United States and elsewhere
#
# Four Js and its suppliers do not warrant or guarantee that these
# samples are accurate and suitable for your purposes. Their inclusion is
# purely for information purposes only.
IMPORT FGL donations
DEFINE fname,last VARCHAR(50)
DEFINE m_details RECORD
clubmember INT,
otherdetail CHAR(50)
END RECORD
MAIN
OPEN FORM f FROM "Folder"
OPTIONS INPUT WRAP
DISPLAY FORM f
LET fname="Willi"
CALL donations.fill()
DIALOG ATTRIBUTES(UNBUFFERED)
INPUT BY NAME fname,last ATTRIBUTES(WITHOUT DEFAULTS)
AFTER INPUT
--some checking if we changed things
IF FIELD_TOUCHED(fname) OR FIELD_TOUCHED(last) THEN
DISPLAY "Update customer in the database"
CALL DIALOG.setFieldTouched("fname",0)
CALL DIALOG.setFieldTouched("last",0)
END IF
END INPUT
SUBDIALOG donations
INPUT m_details.* FROM details.*
AFTER FIELD otherdetail
--just have a uselesse contraint here to check we come thru
--in case of leaving the folder
IF m_details.otherdetail<>'o' THEN
ERROR "otherdetail must be 'o'"
NEXT FIELD otherdetail
END IF
AFTER INPUT
--some checking if we changed things
IF FIELD_TOUCHED(details.*) THEN
DISPLAY "Update detail in the database"
CALL DIALOG.setFieldTouched("details.*",0)
END IF
END INPUT
ON ACTION accept
DISPLAY "accept"
ACCEPT DIALOG
ON ACTION cancel
EXIT DIALOG
END DIALOG
END MAIN
+51
View File
@@ -0,0 +1,51 @@
# Property of Four Js*
# (c) Copyright Four Js 1995, 2019. All Rights Reserved.
# * Trademark of Four Js Development Tools Europe Ltd
# in the United States and elsewhere
#
# Four Js and its suppliers do not warrant or guarantee that these
# samples are accurate and suitable for your purposes. Their inclusion is
# purely for information purposes only.
ACTION DEFAULTS
ACTION cancel(VALIDATE=NO)
END
LAYOUT
VBOX
GROUP(TEXT="Customer (Master Record)")
GRID
{
First Name:[fname ] Last Name:[last ]
}
END
END --GROUP
FOLDER
PAGE(TEXT="Donations",COMMENT="edits the customers donations")
FORM "donations"
END --PAGE
PAGE(TEXT="More Details",COMMENT="edits some more customer details")
GROUP(TEXT="some data")
GRID
{
Member in the organization [clubmember]
Other detail [otherdetail ]
}
END
END
END
END
END
ATTRIBUTES
fname = FORMONLY.fname;
last = FORMONLY.last,NOT NULL;
CHECKBOX clubmember = FORMONLY.clubmember,NOT NULL;
otherdetail = FORMONLY.otherdetail,REQUIRED;
INSTRUCTIONS
SCREEN RECORD cr(FORMONLY.fname,FORMONLY.last);
SCREEN RECORD details(FORMONLY.clubmember THRU FORMONLY.otherdetail);
+61
View File
@@ -0,0 +1,61 @@
# Property of Four Js*
# (c) Copyright Four Js 1995, 2019. All Rights Reserved.
# * Trademark of Four Js Development Tools Europe Ltd
# in the United States and elsewhere
#
# Four Js and its suppliers do not warrant or guarantee that these
# samples are accurate and suitable for your purposes. Their inclusion is
# purely for information purposes only.
IMPORT FGL donations
DEFINE fname,last VARCHAR(50)
DEFINE m_details RECORD
clubmember INT,
otherdetail CHAR(50)
END RECORD
MAIN
DEFINE i INT
OPTIONS INPUT WRAP
FOR i=1 TO 2
IF i=1 THEN
OPEN FORM f FROM "Folder_unrolled"
ELSE
OPEN FORM f FROM "Folder"
END IF
DISPLAY FORM f
LET fname="Willi"
CALL donations.fill()
DIALOG ATTRIBUTES(UNBUFFERED)
INPUT BY NAME fname,last ATTRIBUTES(WITHOUT DEFAULTS)
END INPUT
SUBDIALOG donations
INPUT m_details.* FROM details.*
AFTER FIELD otherdetail
--just have a uselesse contraint here to check we come thru
--in case of leaving the folder
IF m_details.otherdetail<>'o' THEN
ERROR "otherdetail must be 'o'"
NEXT FIELD otherdetail
END IF
AFTER INPUT
END INPUT
ON ACTION accept
ACCEPT DIALOG
ON ACTION cancel
EXIT DIALOG
AFTER DIALOG
--do complete database handling here
DISPLAY "AFTER DIALOG:save customer to database"
FOR i=1 TO arr_count()
DISPLAY "eventually save donation row :",i
END FOR
IF FIELD_TOUCHED(details.*) THEN
DISPLAY "Update detail in the database"
END IF
END DIALOG
CLOSE FORM f
END FOR
END MAIN
+125
View File
@@ -0,0 +1,125 @@
# Property of Four Js*
# (c) Copyright Four Js 1995, 2019. All Rights Reserved.
# * Trademark of Four Js Development Tools Europe Ltd
# in the United States and elsewhere
#
# Four Js and its suppliers do not warrant or guarantee that these
# samples are accurate and suitable for your purposes. Their inclusion is
# purely for information purposes only.
DEFINE fname,last VARCHAR(50)
DEFINE donations DYNAMIC ARRAY OF RECORD
p_date DATE,
p_amount MONEY,
p_reason VARCHAR(250)
END RECORD
DEFINE m_details RECORD
clubmember INT,
otherdetail CHAR(50)
END RECORD
MAIN
DEFINE state STRING
DEFINE flag INT
OPTIONS INPUT WRAP
OPEN FORM f FROM "Folder_old"
DISPLAY FORM f
CALL fill_arrays()
--manage the 'state' variable to jump into different dialogs depending
--on the state value
LET fname="Willi"
LET state="master" --initially go to the master input
WHILE state="master" OR state="page1" OR state="page2"
LET int_flag=FALSE
CASE state
--master input
WHEN "master"
LET state="invalid"
INPUT BY NAME fname, last WITHOUT DEFAULTS
--no master
ON ACTION page1 LET state="page1" ACCEPT INPUT
ON ACTION page2 LET state="page2" ACCEPT INPUT
ON ACTION accept LET state="ok" ACCEPT INPUT
AFTER INPUT
IF int_flag THEN
LET state="cancel"
EXIT INPUT
END IF
--some checking if we changed things
IF FIELD_TOUCHED(fname) OR FIELD_TOUCHED(last) THEN
DISPLAY "AFTER INPUT master, save to the database"
END IF
END INPUT
--donations input
WHEN "page1"
LET state="invalid"
INPUT ARRAY donations WITHOUT DEFAULTS FROM donations.* ATTRIBUTES(UNBUFFERED)
ON ACTION master LET state="master" ACCEPT INPUT
--no page1
ON ACTION page2 LET state="page2" ACCEPT INPUT
ON ACTION accept LET state="ok" ACCEPT INPUT
AFTER FIELD p_amount
IF donations[arr_curr()].p_amount<2.0 THEN
ERROR "must be at least 2 dollar:-)"
NEXT FIELD CURRENT
END IF
AFTER ROW
DISPLAY "AFTER ROW donations arr_curr:",arr_curr(),",arr_count:",arr_count()
IF int_flag THEN --check int_flag in AFTER ROW in contradiction to
--checking int_flag for INPUT in AFTER INPUT
LET state="cancel"
EXIT INPUT
END IF
IF arr_curr()<=arr_count() THEN
DISPLAY "AFTER ROW donations:check row and save to database"
END IF
AFTER INPUT
DISPLAY "AFTER INPUT donations,state:",state
END INPUT
--more details input
WHEN "page2"
LET state="invalid"
INPUT m_details.* FROM details.* ATTRIBUTES(UNBUFFERED,WITHOUT DEFAULTS=flag)
ON ACTION master LET state="master" ACCEPT INPUT
ON ACTION page1 LET state="page1" ACCEPT INPUT
--no page2
ON ACTION accept LET state="ok" ACCEPT INPUT
AFTER FIELD otherdetail
--just have a uselesse contraint here to check we come thru
--in case of leaving the folder
IF m_details.otherdetail<>'o' THEN
ERROR "otherdetail must be 'o'"
NEXT FIELD otherdetail
END IF
AFTER INPUT
IF int_flag THEN
LET state="cancel"
EXIT INPUT
END IF
DISPLAY "AFTER INPUT details,state:",state
--some checking if we changed things
IF FIELD_TOUCHED(details.*) THEN
DISPLAY "Update detail in the database"
LET flag=1
END IF
END INPUT
END CASE
END WHILE
CASE state
WHEN "ok"
DISPLAY "save"
WHEN "cancel"
DISPLAY "cancel"
WHEN "invalid"
DISPLAY "error occured"
END CASE
END MAIN
FUNCTION fill_arrays()
DEFINE i INT
FOR i=1 TO 5
LET donations[i].p_date = TODAY -10 +i
LET donations[i].p_amount = i+1
END FOR
END FUNCTION
@@ -0,0 +1,65 @@
# Property of Four Js*
# (c) Copyright Four Js 1995, 2019. All Rights Reserved.
# * Trademark of Four Js Development Tools Europe Ltd
# in the United States and elsewhere
#
# Four Js and its suppliers do not warrant or guarantee that these
# samples are accurate and suitable for your purposes. Their inclusion is
# purely for information purposes only.
LAYOUT
VBOX
GROUP(TEXT="Customer (Master Record)")
GRID
{
First Name:[fname ] Last Name:[last ] [bmaster]
}
END --GRID
END --GROUP
FOLDER
PAGE(TEXT="Donations",COMMENT="edits the customers donations",ACTION=page1)
TABLE
{
DATE Amount Reason
[p_date][p_amount ][p_reason ]
[p_date][p_amount ][p_reason ]
[p_date][p_amount ][p_reason ]
[p_date][p_amount ][p_reason ]
[p_date][p_amount ][p_reason ]
[p_date][p_amount ][p_reason ]
[p_date][p_amount ][p_reason ]
[p_date][p_amount ][p_reason ]
[p_date][p_amount ][p_reason ]
}
END
END --PAGE
PAGE(TEXT="More Details",COMMENT="edits some more customer details",ACTION=page2)
GROUP(TEXT="some data")
GRID
{
Member in the organization [clubmember]
Other detail [otherdetail ]
}
END --GRID
END --GROUP
END --PAGE
END --FOLDER
END --VBOX
ATTRIBUTES
fname = FORMONLY.fname;
last = FORMONLY.last,NOT NULL;
BUTTON bmaster:master,TEXT="Edit Master";
p_date = FORMONLY.p_date,NOT NULL,DEFAULT=TODAY;
p_amount = FORMONLY.p_amount,NOT NULL;
p_reason = FORMONLY.p_reason,NOT NULL;
CHECKBOX clubmember = FORMONLY.clubmember,NOT NULL,DEFAULT="";
otherdetail = FORMONLY.otherdetail,REQUIRED;
INSTRUCTIONS
SCREEN RECORD cr(FORMONLY.fname,FORMONLY.last);
SCREEN RECORD donations(FORMONLY.p_date THRU FORMONLY.p_reason);
SCREEN RECORD details(FORMONLY.clubmember THRU FORMONLY.otherdetail);
@@ -0,0 +1,44 @@
# Property of Four Js*
# (c) Copyright Four Js 1995, 2019. All Rights Reserved.
# * Trademark of Four Js Development Tools Europe Ltd
# in the United States and elsewhere
#
# Four Js and its suppliers do not warrant or guarantee that these
# samples are accurate and suitable for your purposes. Their inclusion is
# purely for information purposes only.
LAYOUT(TEXT="Folders unrolled to a plain form")
VBOX
GROUP(TEXT="Customer (Master Record)")
GRID
{
First Name:[fname ] Last Name:[last ]
}
END
END --GROUP
GROUP (TEXT="Donations")
FORM "donations"
END --GROUP
GROUP(TEXT="some data")
GRID
{
Member in the organization [clubmember]
Other detail [otherdetail ]
}
END --GRID
END --GROUP
END --VBOX
ATTRIBUTES
fname = FORMONLY.fname;
last = FORMONLY.last,NOT NULL;
CHECKBOX clubmember = FORMONLY.clubmember,NOT NULL;
otherdetail = FORMONLY.otherdetail,REQUIRED;
INSTRUCTIONS
SCREEN RECORD cr(FORMONLY.fname,FORMONLY.last);
SCREEN RECORD details(FORMONLY.clubmember THRU FORMONLY.otherdetail);
+21
View File
@@ -0,0 +1,21 @@
# Property of Four Js*
# (c) Copyright Four Js 1995, 2019. All Rights Reserved.
# * Trademark of Four Js Development Tools Europe Ltd
# in the United States and elsewhere
#
# Four Js and its suppliers do not warrant or guarantee that these
# samples are accurate and suitable for your purposes. Their inclusion is
# purely for information purposes only.
MODULES = \
Folder.42m \
Folder_old.42m\
Folder2.42m
FORMS = \
donations.42f \
Folder.42f\
Folder_old.42f\
Folder_unrolled.42f
include ../../Makeincl
+57
View File
@@ -0,0 +1,57 @@
Folder example
--------------
This example shows how to use a master record and multiple sub dialogs to input details in several folder pages.
To show how complex it was before, there is a Folder_old.4gl example that compiles with older versions and does basically the same as the Folder.4gl sample.
Each sub dialog contains some useful validation code to prove that we are coming thru when jumping from one page to the other.
Folder_old.4gl:
A big while loop was needed with page actions in each page to leave the current interaction statement, set the state, and jump into the next dialog. The difficulty in leaving the dialogs to move to another page is in using the ACCEPT INPUT statement properly (introduced for this purpose). Otherwise, the AFTER FIELD/AFTER ROW/AFTER INPUT triggers are not called (exiting the current dialog with EXIT INPUT will cause this to happen, and you will need to call your validations again for each page action).
You need to set the correct state before each ACCEPT INPUT, also for the 'accept' action, because if a validation in between fails, state still has the value of the last clicked action. In the cancel case, we need to check int_flag.
If you want to add another sub dialog, you must edit all existing dialog statements to add the new action for activating the new sub dialog.
It's annoying that it is not possible for the user to simply click into the master dialog if the focus is in one of the pages.
You cant't tab simply from the master to the details.
When leaving a particular INPUT, you should check if something has been changed for the insert/update case.
It's obvious that this programming style is only a vehicle to make things happen, and the visual results are also not fully satisfying.
Folder.4gl
All those headaches now disappear when you use the DIALOG statement.
Each page can be reached without the need for an action to raise it:
the master record is always reachable with this mode. The AFTER FIELD/(AFTER ROW)/AFTER INPUT triggers of one sub dialog are called when you move to another sub dialog. In the AFTER INPUT trigger you can place database instructions as in the Folder_old sample.
But, just like in the old sample, a sub dialog can be visited multiple times, so it must be checked in case something has to be inserted/updated.
If we want to reset the internal flags that indicate a field of a sub dialog has been changed, we must call the DIALOG.setTouchedFlag() function (of course, there are also other methods to check whether a field has changed: make a record copy or use ON CHANGE).
To indicate that a validation has gone wrong, the NEXT FIELD statement is used (as usual) to interrupt the DIALOG's internal state machine and stay in the current (invalid) sub dialog.
Folder2.4gl
The Folder2 sample shows that it's also possible to fill in all data in the sub dialogs first, and to do the database activity later in the AFTER DIALOG. This lets the database code run at one central place of the multiple dialog in a transaction. It also avoids checking whether a sub dialog has been entered/left twice.
The 'ok' action then starts the transaction, the 'cancel' action cancels everything (with no need to cleanup things done earlier in the dialog).
The Folder2 sample also shows that there is no difference in how the sub dialogs work if they are not placed inside folders, by running the same code again in another form (with no folder at all).
Source code splitting:
------------------------------
In the Folder_old.4gl it was possible to put the code for the individual (sub) dialogs into different source files (not actually done in the sample )
For example:
WHEN "page1"
LET state="invalid"
INPUT ARRAY donations WITHOUT DEFAULTS FROM donations.* ATTRIBUTES(UNBUFFERED)
...
END INPUT
could be coded by using a function call to perform the INPUT ARRAY
WHEN "page1"
LET state="invalid"
CALL input_donations()
and "input_donations" could reside in an extra source code module. This could be done for all other dialogs used in the WHILE loop. This helps to prevent a huge monolithic source code module, regardless of the fact that the modules have a strong affinity in terms of the folder states.
Now, with multiple dialogs and SUBDIALOGs and embeddable FORM's this is done but in a much cleaner way.
Each SUBDIALOG can be moved into an individual module and the form belonging to that source code module can be in a separate form file which is then included via "FORM" in the master form.
In the example this is done for the "donations" sub DIALOG. It resides in a module called "donations.4gl" and the form for that module is in "donations.per".
Extra sugar: donations.4gl contains a MAIN function which can call the individual dialog standalone for testing (just do fglrun donations)
This shows that there is no relation to the master dialog anymore,
it helps much for splitting the work for individual dialogs into separate testable pieces.
+48
View File
@@ -0,0 +1,48 @@
# Property of Four Js*
# (c) Copyright Four Js 1995, 2019. All Rights Reserved.
# * Trademark of Four Js Development Tools Europe Ltd
# in the United States and elsewhere
#
# Four Js and its suppliers do not warrant or guarantee that these
# samples are accurate and suitable for your purposes. Their inclusion is
# purely for information purposes only.
DEFINE donations DYNAMIC ARRAY OF RECORD
p_date DATE,
p_amount MONEY,
p_reason VARCHAR(250)
END RECORD
FUNCTION fill()
DEFINE i INT
FOR i=1 TO 5
LET donations[i].p_date = TODAY -10 +i
LET donations[i].p_amount = i+1
END FOR
END FUNCTION
DIALOG donations()
INPUT ARRAY donations FROM donations.*
AFTER FIELD p_amount
IF donations[arr_curr()].p_amount<2.0 THEN
ERROR "must be at least 2 dollar:-)"
NEXT FIELD CURRENT
END IF
AFTER ROW
IF arr_curr()<=arr_count() THEN
DISPLAY "AFTER ROW donations:check row and save to database"
END IF
END INPUT
END DIALOG
FUNCTION MAIN() -- This MAIN is for testing only.
OPEN FORM f FROM "donations"
DISPLAY FORM f
CALL FILL()
DIALOG
SUBDIALOG donations
ON ACTION ACCEPT
ACCEPT DIALOG
END DIALOG
END FUNCTION
+31
View File
@@ -0,0 +1,31 @@
# Property of Four Js*
# (c) Copyright Four Js 1995, 2019. All Rights Reserved.
# * Trademark of Four Js Development Tools Europe Ltd
# in the United States and elsewhere
#
# Four Js and its suppliers do not warrant or guarantee that these
# samples are accurate and suitable for your purposes. Their inclusion is
# purely for information purposes only.
LAYOUT
TABLE
{
DATE Amount Reason
[p_date][p_amount ][p_reason ]
[p_date][p_amount ][p_reason ]
[p_date][p_amount ][p_reason ]
[p_date][p_amount ][p_reason ]
[p_date][p_amount ][p_reason ]
[p_date][p_amount ][p_reason ]
[p_date][p_amount ][p_reason ]
[p_date][p_amount ][p_reason ]
[p_date][p_amount ][p_reason ]
}
END
END
ATTRIBUTES
p_date = FORMONLY.p_date,NOT NULL,DEFAULT=TODAY;
p_amount = FORMONLY.p_amount,NOT NULL;
p_reason = FORMONLY.p_reason,NOT NULL;
INSTRUCTIONS
SCREEN RECORD donations(FORMONLY.*);