Showing posts with label Forms. Show all posts
Showing posts with label Forms. Show all posts

Monday, February 24, 2020

Checks for duplicate entities that have the same names

there are different forms where we want to perform a check for duplicate entry names.An example is:

\Forms\HcmPersonalContactNew\Methods\checkDuplicateName

which is using this static method:

\Classes\DirUtility\checkDuplicate

the problem with this method is that it works only in a form which has as datasource a DirParty entity. In order to be able to use the same code also in other contexts I slightly modified the code like this:

public static boolean checkDirPartyDuplicate(Common _nameRecord, DirPartyType _partyType, str _entityName)
{
    //Enrico: I adapted the code from \Classes\DirUtility\checkDuplicate to use it also when not in a form
    
    Common common;
    DictTable partyDicttable;

    FormRun formRun;
    Args    args;
    Object  formObject;
    Common  nameRecord;
    FormDataSource  fds;

    args = new Args(formStr(DirPartyVerification));
    args.record(_nameRecord);
    args.parmEnumType(enumNum(DirPartyType));
    args.parmEnum(_partyType);
    args.parm(_entityName);
    formRun = classfactory.formRunClass(args);
    formRun.init();
    formRun.run();
    formRun.wait();


    if (formRun.closedOk() && formHasMethod(formRun, identifierStr(getName)))
    {
        formObject = formRun;
        nameRecord = formObject.getName();

        if (nameRecord.RecId)
        {
            partyDicttable = new SysDictTable(nameRecord.TableId);
            if(partyDicttable)
            {
                common = partyDicttable.makeRecord();
            }
            //we reselect the party since quick create wich uses this code path requires non pessimistic lock selection
            select common where common.RecId == nameRecord.RecId;
            _nameRecord.data(common);
            
        }
    }
    else
    {
        return false;
    }

    return true;
}


now can be used like this:

static void MYD_Functions_checkDirPartyDuplicate(Args _args)
{
    DirPersonName dirPersonName;
    boolean nameChecked = true;
    
    dirPersonName.FirstName = 'enrico';
    dirPersonName.LastName = 'fuchs';
    
    if (DirParameters::find().UseDuplicateCheck == NoYes::Yes
            && DirPersonName::nameLikeCount(dirPersonName.FirstName, dirPersonName.MiddleName, dirPersonName.LastName) > 0)
        {
            nameChecked = MYD_Functions::checkDirPartyDuplicate(dirPersonName, DirPartyType::Person, tableStr(DirPerson));
        }
    
    if (nameChecked)
        info(strFmt('%1', dirPersonName.RecId));
}

Tuesday, January 21, 2020

Date effective child form in Dynamics 2012

in a form to display the date effective filter pane you have to add this snippet in the form init method:

DateEffectivenessPaneController::constructWithForm(
        this,
        MYD_ClinicianPositions_ds);

the DateEffectivenessPaneController is responsible of creating all the user interface and the interaction.

image

if you also have a child form which is also date effective and you want it also to be filtered based on the date effective selection on the parent form you can do this:

public class FormRun extends ObjectRun
{
    SysFormSplitter_X verticalSplitter;
    DateEffectivenessPaneController effectivenessPaneController;
}

public void init()
{
    super();
    //Initialize splitter
    verticalSplitter = new SysFormSplitter_X(VSplitter, GridContainer, element, 300);

    //initialize the DateEffectivenessPaneController
    effectivenessPaneController = DateEffectivenessPaneController::constructWithForm(this, MYD_Mentor_ds);
}

then override the executeQuery method of the subform darasource:

public void executeQuery()
{
    FromDate fromDate = dateNull();
    ToDate toDate = dateMax();
    
    TransDate showAsOfDate;
    FormCheckBoxControl showAllCheckbox;
    boolean showAll;
    
    //get the selection from the parent form date effective toolbar
    showAsOfDate = effectivenessPaneController.parmShowAsOfDate();
    showAllCheckbox =  effectivenessPaneController.parmShowAllCheckbox();
    showAll = showAllCheckbox.value();
    
    if (showAll)
        this.query().validTimeStateDateRange(fromDate, toDate);
        
    if (showAsOfDate)
        this.query().validTimeStateAsOfDate(showAsOfDate);

    super();
}

Wednesday, September 4, 2019

Example of Date Filter in a form DataSource using SysQuery and DateEffectivenessCheck

The following code is an example of how to build a query range based on a Form Data Source, which displays only "daily" records.

In the example the form-dataSource is named DataSourceName is a date effective table. Depending on a check box only records should be displayed, which that are valid for todays date.

While it is quite a simple task, I want to remind how much easier and more reliable the code is if we use AX built in methods: in particular those two classes:

  • SysQuery
  • DateEffectivenessCheck
public void applyFilter()
{
    queryBuildRange qbr;

    qbr = sysQuery::findOrCreateRange(DataSourceName_ds.queryBuildDataSource(), fieldNum(DataSourceName, recId));

    if( !ShowExpiredCheckBox.checked())
    {
        qbr.value(
               strfmt(
                    DateEffectivenessCheck::queryRange(true,false,false),
                    DataSourceName_ds.queryBuildDataSource().name(), // queryBuildDataSource name
                    fieldstr(DataSourceName, ValidFrom), // table field from date
                    fieldstr(DataSourceName, ValidTo), // table field to   date
                    DateEffectivenessHelp::queryDate() // test date (MUST use the queryDate method for correct formatting), alternatively can use also: DateTimeUtil::toStr(DirUtility::getCurrentDateTime())
                 )                                              
                     );
    }
    else
    {
        qbr.value(SysQuery::valueUnlimited());
    }
}

how much more code would you need without using those two classes!!

Tuesday, August 27, 2019

Effective date Form datasource filter Queryrange using check boxes to select expired active future records in Dynamics Ax

I had a requirement to create create a form where the date effective selection appears as check boxes.

image

I found a similar implementation in LogisticsPostalAddress, so here the code I will show you below based is on what you can see in \Forms\LogisticsPostalAddress\Data Sources\LogisticsLocation\Methods\executeQuery

1) override the click event of each checkbox like this:

public void clicked()
{
    super();

    element.setEffectiveDateFilter();
}

2) add this method

here I added some logic to check uncheck based the checkboxes to avoid invalid selections

public void setEffectiveDateFilter()
{
    if (DisplayExpired.value() && !DisplayActive.value() && DisplayFuture.value())
        DisplayActive.value(true);
    if (!DisplayExpired.value() && !DisplayActive.value() && !DisplayFuture.value())
        DisplayActive.value(true);

    MYTable_ds.executeQuery();
}

3) override the executeQuery of the datasource

public void executeQuery()
{
    //based on the template: \Forms\LogisticsPostalAddress\Data Sources\LogisticsLocation\Methods\executeQuery
    QueryBuildRange qbrValidFrom, qbrValidTo;
    RecId curRecordRecId;
    ValidFromDate validFrom = Global::dateNull();
    ValidToDate validTo = Global::dateMax();
    boolean expired;
    boolean active;
    boolean future;
    str queryRangeStr='';

    // Get the record currently selected
    curRecordRecId = MYTable_DS.cursor().RecId;

    expired = DisplayExpired.value();
    active = DisplayActive.value();
    future = DisplayFuture.value();

    qbrValidFrom = SysQuery::findOrCreateRange(this.query().dataSourceNo(1), fieldNum(MYTable,ValidFrom));
    qbrValidTo   = SysQuery::findOrCreateRange(this.query().dataSourceNo(1), fieldNum(MYTable,ValidTo));

    if (expired && !active && !future)
    {
        queryRangeStr = '(%1.%3 <= %4)';
        MYTable_ds.query().validTimeStateDateRange(Global::dateNull(), systemDateGet());
    }
    else if (!expired && active && !future)
    {
        queryRangeStr = DateEffectivenessCheck::queryRange(true,false,false);
        MYTable_ds.query().resetValidTimeStateQueryType();
    }
    else if (!expired && !active && future)
    {
        queryRangeStr = DateEffectivenessCheck::queryRange(false,false,true);
        MYTable_ds.query().validTimeStateDateRange(systemDateGet(), dateMax());
    }
    else
    {
        queryRangeStr = DateEffectivenessCheck::queryRange(true,true,true);
        validFrom = element.calcValidFrom();
        validTo = element.calcValidTo();
        //Debug::printDebug(strFmt('validFrom %1; validTo: %2', validFrom, validTo));
        MYTable_ds.query().validTimeStateDateRange(validFrom, validTo);
    }

    MYTable_ds.validTimeStateUpdate(ValidTimeStateUpdate::Correction);

    if (queryRangeStr)
        {
            qbrValidFrom.value(
                strFmt(queryRangeStr,
                    this.query().dataSourceTable(tableNum(MYTable)).name(),
                    fieldStr(MYTable,ValidFrom),
                    fieldStr(MYTable,ValidTo),
                    DateTimeUtil::toStr(DirUtility::getCurrentDateTime())
                )
            );
        }


    super();

        //focus again on the previously selected value
    MYTable_DS.findValue(fieldname2id(MYTable.TableId, 'RecID'), int642str(curRecordRecId));
}

Wednesday, June 12, 2019

Date effective SimpleListDetails form with drop dialog for new record in Dynamics Ax 2012

Create date effective Table

clip_image002

When you set the ValidTimeStateFieldType property it will automatically create the ValidFrom/to fields

clip_image004

 

clip_image005

 

Crete a new form from template SimpleListDetails

Drag the table to the datasource

It will set the date effective query to the default:

clip_image007

Then set the grid datasource and add fields to the grid

clip_image009

Create the groups possibly based on the table groups (otherwise drag fields from the datasource one by one)

clip_image011

clip_image013

clip_image015

 

Add in the init

public void init()
{
    super();
    //Initialize splitter
    verticalSplitter = new SysFormSplitter_X(VSplitter, GridContainer, element, 300);
 
    //For Dates
    //DateEffectivenessPaneController::constructWithForm(this, EF_DateEffectiveTrial1_ds);
 

    //For DateTime
    DateEffectivenessPaneController::constructWithForm(this, EF_DateEffectiveTrial1_ds, true, true, true);
}
 

The form will look like this

clip_image016

 


 

Change the properties of the datasource like this:

clip_image018

 

This allows to change the effective dates manually


 

Create a new Drop Dialog:

Create a new form from template Drop Dialog

 

clip_image020

 

clip_image022

                                                                                                                clip_image023

 

Add those two methods

clip_image024

private ValidFromDateTime getEffectiveDate()
{
    return effectiveDate.dateTimeValue();
}
 
public void init()
{
    ValidFromDateTime           validFromDefaultDate;
    ValidToDateTime             validToDefaultDate;
    Timezone                    userTimeZone;
    EF_DateEffectiveTrial1      common;
 
    super();
 
    common = element.args().record();
    userTimeZone = DateTimeUtil::getUserPreferredTimeZone();
    validFromDefaultDate = DateTimeUtil::applyTimeZoneOffset(DateTimeUtil::utcNow(), userTimeZone); //common.ValidFrom;
    effectiveDate.dateTimeValue(validFromDefaultDate);
 
    //expirationDate.dateValue(validToDefaultDate);
    //set the \Forms\EF_DropDialogEffectiveDate\Designs\Design\[Group:DialogCommit]\[ButtonGroup:ButtonGroup]\CommandButton:OKButton
    //AutoDeclaration = Yes
 
    OKButton.helpText(strFmt("@SYS327712",tableId2pname(common.TableId)));
}
 


 

Create a new menuItem Display

 

clip_image026

 

Create a new DropDialog Button

clip_image027

clip_image028

clip_image029

clip_image030

 

Override the dialogClosed method

clip_image031

 

public void dialogClosed(FormRun _formRun)
{
    Object                          formRunObj;
    ValidFromDateTime               effectiveDate;
    EF_DateEffectiveTrial1          record, recordNew;
    
    super(_formRun);
    
    formRunObj = _formRun;
    
    if (_formRun.closedOk())
    {
        if (formHasMethod(formRunObj, 'getEffectiveDate'))
        {
            effectiveDate = formRunObj.getEffectiveDate();
        }
    
        record = EF_DateEffectiveTrial1_ds.cursor();
        buf2Buf(record, recordNew);
        recordNew.ValidFrom = effectiveDate;
        recordNew.insert();
 
        EF_DateEffectiveTrial1_ds.research(true);
    }
}
 

The form will look like this

clip_image033

 

Sunday, June 2, 2019

forms and tables methods call sequences in Dynamics Ax 2012

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 ()

Init()   
The first event fired. This is where you will populate default values or add runtime controls.
Think of this as the starting point for everything. It is what happens first.
You can also populate variables that you will use to alter programmability throughout your class.

ds init()   
Each form has a connection to data known as the data source.
Here you can make changes to the way that the form grabs data without actually changing the core data source information.
So maybe, for just this one form,
you want to filter customers by their groups – easily done by going into this method (aka event) and changing things.

Run   
Tells the form to get busy.
You can often dynamically change data sources here, so you could choose to load one data source
based on a set of circumstances

Ds execute Query()
This is where you will often make changes to just to just an individual data source.
For example, in this example we add a queryfilter which acts like a where clause on the Dynamics AX generated query.

canClose()   
Do users want to close the form. If so certain things need to pass such as validate those values as actually true

Close()   
After a form closes, do you want to do anything special?
Maybe you want to open up a new form after the form closes or something else.

I found here a very nice slide: https://www.slideshare.net/HamdaouiAmine/microsoft-dynamics-ax2012-forms-and-tables-methods-call-sequences-30159669

I copied it here because for those like me that can’t access slideshare from work due to the company’s firewall rules:

image

image

image

image

image

image

image

image

image

image

image

image

image

image

image

image

image

image

image

image

image

image

image

image

image

image

image

image