Sunday, May 19, 2019

Sequence of methods calling in FORM level

This gives the information of method calls in the form level while
1. Opening the Form.
2. Creating/Updating/Deleting the record in the Form.
3. Closing the Form.
Sequence of Methods calls while opening the Form
Form --- init ()
Form --- Datasource --- init ()
Form --- run ()
Form --- Datasource --- execute Query ()
Form --- Datasource --- active ()

Sequence of Methods calls while closing the Form
Form --- canClose ()
Form --- close ()

Sequence of Methods calls while creating the record in the Form
Form --- Datasource --- create ()
Form --- Datasource --- initValue ()
Table --- initValue ()
Form --- Datasource --- active ()

Sequence of Method calls while saving the record in the Form
Form --- Datasource --- ValidateWrite ()
Table --- ValidateWrite ()
Form --- Datasource --- write ()
Table --- insert ()

Sequence of Method calls while deleting the record in the Form
Form --- Datasource --- validatedelete ()
Table --- validatedelete ()
Table --- delete ()
Form --- Datasource --- active ()

Sequence of Methods calls while modifying the fields in the Form
Table --- validateField ()
Table --- modifiedField ()

Table Methods in AX 2012

Table Methods in Ax 2012

Methods are used for adding X++ code to your application. The code in methods is also referred to as business logic. Whenever records are changed, inserted or deleted from a table various default methods are executed.
We can change the default methods and by doing so we are overriding the default methods.To override a method go to the Methods node of a table, right click and choose Override Method. Below are few examples of Overriding commonly used Table methods:

initValue():

If we create a new record from the table browser or a form the table method initValue() is executed. It is used to set a default value for the fields
Example (1): Let’s override intiValue for MyFirstTable and set default value for custGroupId

public void initValue()
{
super();
this.custGroupId = "10";
}

After adding this method, open table MyFirstTable  through Table browser and press ctrl+n to create a new record. The field custGroupId will now have the default value 10.

modifiedField():

Each time the value of a field is changed the method modifiedField() is called. It is useful to initialize the values of other fields if the value of the current field is changed.

Example (2): Let’s now override modifiedField method for MyFirstTable and target is to set CurrencyCode to null when CustGroupId is modified.

public void modifiedField(fieldId _fieldId)
{
switch(_fieldId)
{
case fieldnum(MyFirstTable, custGroupId):
    this.CurrencyCode="";
    break;
default:
    super(_fieldId);
}
}
After adding this method, open table MyFirstTable using Table browser and try to modify custGroupId of an existing record, then you will notice that CurrencyCode is immediately set to blank.

ModifiedField() receives the field number of the active field as parameter. A switch statement is used to check which field is active. If none of the checked fields are active the super() call is executed instead.

validateField():

Method validateField() is used for validation only and will return true or false. If the return value is false, the application user will be prevented to continue changing a field value.

Example (3): Let’s override validateField for MyFirstTable to verify the condition that CustName must be have >3 characters.

public boolean validateField(fieldId _fieldIdToCheck)
{
    boolean ret;
    ret = super(_fieldIdToCheck);
    if (ret)
    {
    switch (_fieldIdToCheck)
    {
    case fieldnum(MyFirstTable, custName):
        if (strlen(this.custName) <= 3)
        ret = checkFailed("Customer name must be longer than 3 characters.");
    }
    }
    return ret;
}

After adding this method, open table MyFirstTable using Table browser and press Ctrl+N, in the new record try to enter less than 3 characters for field custName, Ax will throw warning message stating “Customer name must be longer than 3 characters.” And you will be asked to enter value again. Thus we validate the data to be entered for a specific field.

validateWrite():

Method validateWrite() will just check mandatory fields and is triggered when the record . Checks made by validateWrite() are the same as the super() call in validateField().So if your condition is not related to the value an application user enters in a specific field, you should put the validation in validateWrite().

validateDelete():

When deleting a record the method validateDelete() is first executed. If true, the method delete() will be called.

insert() and update():

Insert() and update() are rarely overridden. However, if you need to ensure a field has a certain value upon inserting a record, you can initialize your field before calling super() in insert().  Some special cases might also require overriding these methods; for example, if you need to synchronize the content of a saved record to another table.

Using X++ for entering data requires a bit more than using the user interface like forms. Only the table methods called will be executed.

Example (4): In this example, let’s see how to use the table methods to insert a record in MyFirstTable.

static void DataDic_InsertRecord(Args _args)
{
MyFirstTable myFirstTable;
;
ttsbegin;
myFirstTable.initValue();
myFirstTable.accountNum = "100";
myFirstTable.custName = "Alt. customer id 100";
myFirstTable.CurrencyCode = "USD";
if (myFirstTable.validateWrite())
myFirstTable.insert();
ttscommit;
}

InitValue() is called and will set the value of the field custGroupId. The record will only be inserted if validateWrite() is true. As all mandatory fields have a value, the record will be inserted.

Instead of calling insert() you could call write(). This will update an existing record, but if the record does not exist, a new record will be inserted.

The select keywords delete_from, insert_recordset and update_recordset make only one call to the database from the client when processing multiple records.

ValidateDelete():

While deleting a record if we want to put any validation we can use this method. Here once I delete a record populating a info that deleted record.

public boolean validateDelete()
{
boolean ret;
ret = super();
info(this.AccountNum);
return ret;
}


ValidateWrite():

This method will get to fire when we update a record. here I am using to check mandatory field for address AccountNum

public boolean validateWrite()
{
boolean ret;
;
if(this.Address != "")
ret = super();
else
warning(" Please fill the address value");
return ret;
}

find() :-

All tables should have at least one find method that selects and returns one record
from the table that matches the unique index specified by the input parameters.
The last input parameter in a find method should be a Boolean variable called
'forupdate' or 'update' that is defaulted to false. When it is set to true, the caller object
can update the record that is returned by the find method.
See the next example from the InventTable:

static InventTable find(ItemId itemId, boolean update = false)
{
InventTable inventTable;
;
inventTable.selectForUpdate(update);
if (itemId)
{
select firstonly inventTable
index hint ItemIdx
where inventTable.ItemId == itemId;
}
return inventTable;
}

exists() :-

As with the find method, there should also exist an exists method.
It basically works the same as the find method, except that it just returns true if a
record with the unique index specified by the input parameter(s) is found.
In the next example from the InventTable you can see that it returns true if the
input parameter has a value AND the select statement returns a value.

static boolean exist(ItemId itemId)
{
return itemId && (select RecId from inventTable
index hint ItemIdx
where inventTable.ItemId == itemId
).RecId != 0;
}

Display Method:

         Indicates that the methods return value is to be displayed on a forms (or) Reports .The value cannot be altered in the form or report

Take the new method in a table, and then drag that method into the grid and set data source properties. In that field is non-editable.

We can create display method on the
1. Table methods
2. Form methods
3. Form data source methods
4. Report methods
5. Report design methods

Display Name names ()
{
    CustTable   custTable;
    ;
    return  CustTable::find(this.CustAccount).Name;
}

Edit Method:

        Indicates that the methods return type is to be use to provide information for a field that is used in a form only

 We can create edit method on the

1. Table methods
2. Form methods
3. Form datasoruce methods

        Take the new method in the table, and then drag that method into the grid and set data source properties. In that field is user can edit it and accept the values to the user and save it CustTable.

 Edit Name name(boolean _set , Name _name)
{
    Name    name    = _name;
    CustTable   custTable;
    ;
    if(_set)
    {
        if(name)
        {
            ttsbegin;
            custTable   = CustTable::find(this.CustAccount,true);
            custTable.Name  = name;
            custTable.update();
            ttscommit;
        }
    }
    else
    {
        name    = CustTable::find(this.CustAccount).Name;
    }
    return name;
}


ModifiedFieldValue() : 

this method takes field name and array index as arguments

public void modifiedFieldValue(FieldName _fieldName, int _arrayIndex = 1)
{
    super(_fieldName, _arrayIndex);

    if(_fieldName == fieldStr(HD_BankCustomersTable, AccountType))
    {
        switch(this.AccountType)
        {
            case HD_AccountType::Current:
                this.MinBalance = 5000;
                break;

            case HD_AccountType::Fixed:
                this.MinBalance = 10000;
                break;

            case HD_AccountType::Recurring:
                this.MinBalance = 500;
                break;

            case HD_AccountType::Savings:
                this.MinBalance = 1000;
                break;
        }
    }

}

ValidateFieldValue():

public boolean validateFieldValue(FieldName _fieldName, int _arrayIndex = 1)
{
    boolean ret;

    ret = super(_fieldName, _arrayIndex);

    if(_fieldName == fieldStr(HD_BankCustomersTable, DOAC))
    {
        //info("");
    }

    return ret;
}

Workflow process in AX 2012


Step1: Create approval status (Enum type)
Step2: Add into respective Table
Step3: Add this table into respective workflow Form
            OR Sync the Form datasource if existing table
Step4: Override the “CanSubmitToWorkflow”  method in table
Table Level:

public boolean canSubmitToWorkflow(str _workflowType = '')
{
    boolean ret;
   
    if (!this.ApprovalStatus == ApprovalStatus::NotSubmitted)

    return false;

    else

    return true;
 
}
Step 5: Create AOT query
Step 6: Create Workflow category and select the module which is required for workflow
Step 7: Create Workflow type through wizard

WorkFlow Type Classes:
Workflow Submit method:
public static void main(Args args)
{
    // Variable declaration.
    recId recId = args.record().RecId;
    WorkflowCorrelationId workflowCorrelationId;
    // Hardcoded type name
    WorkflowTypeName workflowTypeName =workflowtypestr(RecruitmentProj);
    // Initial note is the information that users enter when they

    // submit the document for workflow.
    WorkflowComment note ="";
    WorkflowSubmitDialog workflowSubmitDialog;
    HRMRecruitingTable  hrmRecruitingTable;

    // Opens the submit to workflow dialog.
    workflowSubmitDialog =
    WorkflowSubmitDialog::construct(args.caller().getActiveWorkflowConfiguration());
    workflowSubmitDialog.run();
    if (workflowSubmitDialog.parmIsClosedOK())
    {
        recId = args.record().RecId;

        hrmRecruitingTable = args.record();
        // Get comments from the submit to workflow dialog.
        note = workflowSubmitDialog.parmWorkflowComment();
        try
        {
            ttsbegin;
            workflowCorrelationId =Workflow::activateFromWorkflowType(workflowTypeName,recId,note,NoYes::No);
            hrmRecruitingTable.ApprovalStatus = ApprovalStatus::Submitted;

            // Send an Infolog message.
            info("Submitted to workflow.");
            ttscommit;
        }
        catch(exception::Error)
        {
            info("Error on workflow activation.");
        }
    }
    args.caller().updateWorkFlowControls();
}

Approved event handler:
public void completed(WorkflowEventArgs _workflowEventArgs)
{
    HRMRecruitingTable hrmrecruitingTable;
    select forupdate hrmrecruitingTable where hrmrecruitingTable.RecId == _workflowEventArgs.parmWorkflowContext().parmRecId();
    if(hrmrecruitingTable.RecId)
    {
        hrmrecruitingTable.ApprovalStatus = ApprovalStatus::Approved;
        hrmrecruitingTable.update();
    }
}

Step 8: Create Workflow Approval through wizard:
Approval Classes:
Resubmit :
public static void main(Args args)
{
    // Variable declaration.
    recId recId = args.record().RecId;
    WorkflowCorrelationId _workflowCorrelationId;
    // Hardcoded type name
    WorkflowTypeName _workflowTypeName = workflowtypestr(RecruitmentProj);
    // Initial note is the information that users enter when they
    // submit the document for workflow.
    WorkflowComment _initialNote ="";
    WorkflowWorkItemActionDialog
    WorkflowWorkItemActionDialog;
    HRMRecruitingTable  hrmRecruitingTable;
    ;
    // Opens the submit to workflow dialog.
    workflowWorkItemActionDialog = WorkflowWorkItemActionDialog::construct(args.caller().getActiveWorkflowWorkItem(),
                                                                            WorkflowWorkItemActionType::Resubmit,
                                                                            new MenuFunction(menuitemactionstr(RecruitmentProjApprResubmitMenuItem),
                                                                            MenuItemType::Action));
    workflowWorkItemActionDialog.run();
    if (WorkflowWorkItemActionDialog.parmIsClosedOK())
    {
        recId = args.record().RecId;
        hrmRecruitingTable = args.record();
        // Get comments from the submit to workflow dialog.
        _initialNote = workflowWorkItemActionDialog.parmWorkflowComment();
        try
        {
            ttsbegin;
            WorkflowWorkItemActionManager::dispatchWorkItemAction(args.caller().getActiveWorkflowWorkItem(),
                                                                    _initialNote,
                                                                    curUserId(),
                                                                    WorkflowWorkItemActionType::Resubmit,
                                                                    args.menuItemName(),
                                                                    false);
            hrmRecruitingTable.ApprovalStatus = ApprovalStatus::Submitted;
            // Send an Infolog message.
            info("Resubmitted to workflow.");
            ttscommit;
        }
        catch(exception::Error)
        {
        info("Error on workflow activation.");
        }
    }
    args.caller().updateWorkFlowControls();
}

Returned (Rejected) Logic:
public void returned(WorkflowElementEventArgs _workflowElementEventArgs)
{
    HRMRecruitingTable hrmrecruitingTable;
    select forupdate hrmrecruitingTable where hrmrecruitingTable.RecId == _workflowElementEventArgs.parmWorkflowContext().parmRecId();
    if(hrmrecruitingTable.RecId)
    {
        hrmrecruitingTable.ApprovalStatus = ApprovalStatus::Rejected;
        hrmrecruitingTable.update();
    }
}
Step 9: Drag And Drop workflow approval element from workflow approvals in to supported elements under workflow type
Step 10: Apply this workflow to our form by going to design properties
Workflow enabled: Yes
Worflow Datasource:
Workflow Type:
Step 11:
Create New Menu item (Check the document).
Step 12:
Configuring Workflow