This example shows the creation of an RF form to draw quantities from an item series corresponding to a stock movement.

The RF form accesses the movement, which displays the first item to be moved, the location code and the quantity to be extracted; using a scanner, the location code is captured to confirm extraction, after which the information of the next item to be extracted is displayed to follow the same steps. Finally the stock of the bin and the status of the movement is updated. This form must validate each field before moving on to the next or displaying an error message, and it must revert the changes if the extraction process is not completed.

1 Execute stock movement with a task

The user extracts the items that correspond to a stock movement, one by one until the end..

1.1 Analysis

1.1.1 Process flow

The flow that the task will follow is shown below.

1.1.2 Low-level mockup

This is the low level mockup of the form:

1.2 Process flow

The flow that the task will follow is shown below.

1.3 Data for example

The following defines the structure of the tables and the data required for this example.

Copy
-- CREATION OF THE ARTICLE MASTER
CREATE TABLE devtest_garticul (
    codigo  char(16)        primary key,
    nomart  varchar(100)    not null
);

ALTER TABLE devtest_garticul LOCK MODE (ROW);
INSERT INTO devtest_garticul VALUES ('1000001', 'Mechanical keyboards');
INSERT INTO devtest_garticul VALUES ('1000002', 'Ergonomic mouse');
INSERT INTO devtest_garticul VALUES ('1000003', 'Panoramic monitors');


-- CREATION OF THE WAREHOUSE MASTER
CREATE TABLE devtest_galmacen (
    codigo  char(5)         primary key,
    nomalm  varchar(100)    not null
);

ALTER TABLE devtest_galmacen LOCK MODE (ROW);
INSERT INTO devtest_galmacen VALUES ('D0001', 'Central warehouse');
INSERT INTO devtest_galmacen VALUES ('D0002', 'Auxiliary warehouse');


-- CREATION OF THE LOCATION MASTER
CREATE TABLE devtest_galmubic (
    codigo  char(5)         primary key,
    codalm  char(5)         not null,
    nomubi  varchar(100)    not null
);

ALTER TABLE devtest_galmubic LOCK MODE (ROW);
INSERT INTO devtest_galmubic VALUES ('10001', 'D0001', 'D0001 - 01');
INSERT INTO devtest_galmubic VALUES ('10002', 'D0001', 'D0001 - 02');
INSERT INTO devtest_galmubic VALUES ('10003', 'D0002', 'D0002 - 01');
INSERT INTO devtest_galmubic VALUES ('10004', 'D0002', 'D0002 - 02');


-- STOCK BY LOCATION
CREATE TABLE devtest_galmstku (
    codart  char(16)    not null,
    codubi  char(5)     not null,
    stkact  integer     not null	default 0
);

ALTER TABLE devtest_galmstku LOCK MODE (ROW);
INSERT INTO devtest_galmstku VALUES ('1000001', '10001', 10);
INSERT INTO devtest_galmstku VALUES ('1000002', '10002', 20);
INSERT INTO devtest_galmstku VALUES ('1000002', '10003', 15);
INSERT INTO devtest_galmstku VALUES ('1000003', '10003',  5);
INSERT INTO devtest_galmstku VALUES ('1000003', '10002', 30);

-- CREATION OF MOVEMENT HEADER
CREATE TABLE devtest_galmmovh (
    cabid   integer     primary key,
    fecha   date        not null,
    coduser char(16)    not null,
    codalm  char(5)     not null,
    estado  char(1)     not null
);

ALTER TABLE devtest_galmmovh LOCK MODE (ROW);
INSERT INTO devtest_galmmovh VALUES (1, '01-01-2020', 'USER1', 'D0001', 'V');
INSERT INTO devtest_galmmovh VALUES (2, '01-01-2020', 'USER1', 'D0002', 'V');
INSERT INTO devtest_galmmovh VALUES (3, '01-01-2020', 'USER2', 'D0002', 'P');

-- CREATION OF MOVEMENT LINE
CREATE TABLE devtest_galmmovl (
    seqno   serial      primary key,
    cabid   integer     not null,
    codart  char(16)    not null,
    codubi  char(5)     not null,
    canmov  integer     not null	default 0,
    estmov  smallint    not null	default 0
);

ALTER TABLE devtest_galmmovl LOCK MODE (ROW);
INSERT INTO devtest_galmmovl VALUES (0, 1, '1000001', '10001',  5, 0);
INSERT INTO devtest_galmmovl VALUES (0, 1, '1000002', '10002', 10, 0);
INSERT INTO devtest_galmmovl VALUES (0, 1, '1000003', '10002',  8, 0);
INSERT INTO devtest_galmmovl VALUES (0, 2, '1000003', '10003',  2, 0);

-- DROP TABLE IF EXISTS devtest_garticul;
-- DROP TABLE IF EXISTS devtest_galmacen;
-- DROP TABLE IF EXISTS devtest_galmubic;
-- DROP TABLE IF EXISTS devtest_galmstku;
-- DROP TABLE IF EXISTS devtest_galmmovh;
-- DROP TABLE IF EXISTS devtest_galmmovl;

Important

Following the definition of the Program execution, the tables of the example must be compiled in the database corresponding to "-dbdata".

1.4 Form definition

1.4.1 RF Form

The following defines the data required for the form.

Field name Content
form_name devtest_galmmov
form_desc Extraction movement

JS Client Initial Code: The variable "var_codubi" is defined, whose value will be obtained during the code execution of the "codart" field and will be used in the validation of the "codubi" field, the initial value of the variable "var_cabid" is also defined.
JS Form Server Rollback: The reversal code for lines with status changed in the process is defined. This code is activated when the process execution is interrupted or after 60 seconds of not pressing any key.

Copy
var var_codubi = "";
var var_cabid = 0;
Copy
if (fields.var_cabid > 0) {
    //Reverse line status
    Ax.db.update("devtest_galmmovl",
        {
            estmov : 0
        },
        {
            cabid : fields.var_cabid
        }
    );
}



1.4.2 Fields

The following defines the fields required for the form.

field_order field_name field_desc field_title field_type field_scale field_noentry field_required
2 cabid Identifier Movement identifier I (Integer) 0 0 (NO) 1 (YES)
4 desmov Description Movement description S (String) 0 1 (YES) 0 (NO)
6 codart Item code Item code S (String) 0 0 (NO) 1 (YES)
8 nomart Item name Item name S (String) 0 1 (YES) 0 (NO)
10 codubi Loc. code Location code S (String) 0 0 (NO) 1 (YES)
12 canmov Quantity Quantity of movement I (Integer) 0 1 (YES) 0 (NO)
14 confirm Confirm Confirm movement S (String) 1 0 (NO) 1 (YES)

In the "confirm" field, the size of text entered is restricted to one letter by the value of field_scale. This field must receive the values "Y" or "N".

a) The "cabid" field has the following logic:

Server: Obtains the movement data, if it exists, display its data in the field "desmov" (having a field called "desmov", equal to the property of the object used, the field automatically adopts this value without the need to assign it), otherwise, returns an error message in the variable "errmsg" (returning the object "result" with a property called "errmsg", automatically creates or updates a variable with this name and value).
Client: Checks if there is any message in the variable "errmsg", if there is, it displays the message and positions itself in the same field (preventing advancing until a correct value is entered). The movement identifier is stored in the "var_cabid" variable (used from the ROLLBACK section) by adopting the value of the property of the "result" object with the same name and the RF Terminal advances to the next field where data can be entered.

For this example it is not necessary to define any code in the "BEFORE SERVER CODE" section or in "BEFORE CLIENT CODE".

Copy
var result = {
    desmov : "",
    errmsg : ""
};

var mObjGalmmovh = Ax.db.executeQuery(`
        SELECT *
        FROM devtest_galmmovh
        WHERE 
            cabid   = ?  AND 
            coduser = ?  AND 
            codalm  = ?  AND 
            estado  = 'V'`, fields.cabid, config.USER, config.CODALM).toOne();

if (mObjGalmmovh.cabid != null){
    result.desmov = `Mov >> ${mObjGalmmovh.cabid}. Warehouse [${mObjGalmmovh.codalm}]`;
    result.var_cabid = mObjGalmmovh.cabid;
} else {
    result.errmsg = "No movement or not correspond!";
}

return result;
Copy
if (errmsg != "") {
    form.setFocus("cabid", errmsg);
}



b) The "desmov" field is descriptive only, so it has no execution code.





c) The "codart" field has the following logic:

Server: Moving to this field automatically retrieves the data of the first item ("codart", "nomart", "codubi" and "canmov") of the movement, whose status is 0, without requiring data entry; it then moves to the "codubi" field to confirm the location of the extracted item or to the "confirm" field in case there are no more items to be extracted.
This is achieved by executing the code in the BEFORE SERVER CODE section.
Client: In this process, the data of the item location is saved in the variable "var_codubi", declared in the form, to be used during the validation of the "codubi" field during the execution of the code in section BEFORE CLIENT CODE.

For this example it is not necessary to define any code in the "AFTER SERVER CODE" section or in "AFTER CLIENT CODE".

Copy
var result = {
    codubi : "",
    errmsg : ""
};

var mIntCabid = fields.cabid;

if (mIntCabid > 0) {
    var mObjGalmmovl = Ax.db.executeQuery(`
        SELECT 
            FIRST 1    
            devtest_galmmovl.seqno,
            devtest_galmmovl.codart,
            devtest_garticul.nomart,
            devtest_galmmovl.codubi,
            devtest_galmmovl.canmov
        FROM devtest_galmmovl
            JOIN devtest_garticul
                ON devtest_galmmovl.codart = devtest_garticul.codigo
        WHERE 
           cabid = ? AND estmov = 0`, mIntCabid).toOne();
    
    if (mObjGalmmovl.seqno != null) {
        result.codart       = mObjGalmmovl.codart;
        result.nomart       = `Loc.[${mObjGalmmovl.codubi}]. Article: ${mObjGalmmovl.nomart}`;
        result.codubi_var   = mObjGalmmovl.codubi;
        result.canmov       = mObjGalmmovl.canmov;

        Ax.db.update("devtest_galmmovl",
            {
                estmov : 1
            },
            {
                seqno : mObjGalmmovl.seqno
            }
        );
    } else {
        result.codart = "-"
        result.nomart = "Extracted articles!"
    }
}

return result;
Copy
if (errmsg != "") {
    form.setFocus("codart", errmsg);
} else if (codart == "-") {
    form.setFocus("confirm", "");
} else {
    form.setFocus("codubi", "");
}




d) The "nomart" field is descriptive only, so it has no execution code.





e) The "codubi" field has the following logic:

Server: Validates that the location entered is equal to the value of the variable "var_codubi", otherwise, it displays an error message.

For this example it is not necessary to define any code in the "BEFORE SERVER CODE" section, "BEFORE CLIENT CODE" or in "AFTER SERVER CODE".

AFTER CLIENT CODE

Copy
if (var_codubi != codubi) {
    form.setFocus("codubi", "Location does not correspond!");
} else {
    form.setFocus("codart", "");
}




f) The "canmov" field is descriptive only, so it has no execution code.





g) The "confirm" field has the following logic:

Server: Validates that the value is Y (Yes) or N (No), otherwise it displays an error message.
In case it is Y (movement confirmation), the list of items with movement status 1 is obtained to discount the stock of each one in the corresponding location, then the movement status is updated and the form fields are reset.
In the case of N (movement cancellation), a "STOP" message is sent.
Client: Checks if there is any message in the variable "errmsg", if there is, it displays the message and positions itself in the same field (preventing advancing until a correct value is entered), otherwise, it resets the variables "var_codubi" and "var_cabid" and the RF Terminal returns to the initial field.

For this example it is not necessary to define any code in the "BEFORE SERVER CODE" section or in "BEFORE CLIENT CODE".

Copy
var result = {
    errmsg  : ""
};

var mStrConfirm = fields.confirm,
    mIntCabid   = fields.cabid;

if (mStrConfirm == "y" || mStrConfirm == "Y") {
    var mRsGalmmovl = Ax.db.executeQuery(`
            SELECT
                devtest_galmmovl.codart,
                devtest_galmmovl.codubi,
                devtest_galmmovl.canmov,
                devtest_galmstku.stkact
            FROM devtest_galmmovl
                JOIN devtest_galmstku
                    ON  (devtest_galmmovl.codart = devtest_galmstku.codart)
                    AND (devtest_galmmovl.codubi = devtest_galmstku.codubi)
            WHERE cabid = ? AND estmov = 1`, mIntCabid).toMemory();

    mRsGalmmovl.forEach(function(mRow){
        //Reduce stock at origin location
        Ax.db.update("devtest_galmstku",
            {
                stkact : mRow.stkact - mRow.canmov
            },
            {
                codart : mRow.codart,
                codubi : mRow.codubi
            }
        );
    });

    //Movement status update
    Ax.db.update("devtest_galmmovh",
        {
            estado : "F"
        },
        {
            cabid : mIntCabid,
        }
    );

    //Field cleaning
    result.cabid    =  0;
    result.desmov   = "";
    result.codart   = "";
    result.nomart   = "";
    result.codubi   = "";
    result.canmov   =  0;
    result.confirm  = "";
    
    //Reset variables
    result.var_codubi =  "";
    result.var_cabid  =  0;

} else if (mStrConfirm == "n" || mStrConfirm == "N") {
    result.errmsg = "STOP";
    
    if (mIntCabid > 0) {
        //Reverse line status
        Ax.db.update("devtest_galmmovl",
            {
                estmov : 0
            },
            {
                cabid : mIntCabid
            }
        );
    }
} else {
    result.errmsg = "Incorrect value (Y/N)";
}

return result;
Copy
if (errmsg == "STOP") {
    form.stop()
} else if (errmsg != "") {
    form.setFocus("confirm", errmsg);
}

1.5 Process RF

1.5.1 Case 1

Extract the items reported in movement number 1.
User: USER1
Warehouse: D0001

RF Terminal

a) RF Terminal (login): Log in with the indicated data



b) RF Terminal: Access the "devtest_galmmov" form through the menu.



c) RF Terminal (cabid): Enter the movement identifier. If there is a controlled error, the following message is displayed.

Incorrect value:



Correct value:

The first item to be moved will be displayed



d) RF Terminal (codubi): Enter the location code. If there is a controlled error, the following message is displayed.

Incorrect value:



Correct value:



After entering the correct value for the location, the second item to be moved will be displayed



After entering the correct value for the location, the third and last item to be moved will be displayed



After entering the correct value for the location, if there are no more items, it displays a message in the "nomart" field and is positioned in the confirmation field.



e) RF Terminal (confirm): Enter the confirmation code (Y/N). If there is a controlled error, the following message is displayed.

Incorrect value:



Correct value:



1.6 After example

Important

If the form created is only an example:

  • Delete the form reference in the menu.
  • Delete form fields
  • Delete the form
  • Delete the SoftReference (if it is related only to the created form).
  • Delete created tables.
Copy
-- AFTER EXAMPLE
DROP TABLE IF EXISTS devtest_garticul;
DROP TABLE IF EXISTS devtest_galmacen;
DROP TABLE IF EXISTS devtest_galmubic;
DROP TABLE IF EXISTS devtest_galmstku;
DROP TABLE IF EXISTS devtest_galmmovh;
DROP TABLE IF EXISTS devtest_galmmovl;