27 April 2015

How to check if record in valid time state table is valid now

Working on data synchronisation with legacy system I faced interesting question in valid time state table area. Please find the details below.

Problem description
Create a method to check whether a record in valid time state table is valid now.

Steps to reproduce
1. Find or create new valid time state table
2. Create 3 records: valid in past, valid now, valid in future.
3. Test the method on each record

Hints
There are at least two solutions:
1. Try to select the same record from database. Kernel adds Date or DateTime ranges and nothing is returned if the record is not valid now.
2. Compare values of ValidFrom and ValidTo fields with now. Analyse and define now for Date and DateTime.

Solution
1. Run additional select statement, but use kernel generated now value:
public static boolean isRecordValidNow(Common _record)
{
    boolean                 ret;
    DictTable               dictTable;
    Common                  buffer;
    
    dictTable = new DictTable(_record.TableId);

    // run check only if table is valid time state
    if (dictTable && dictTable.isValidTimeStateTable())
    {
        // as kernel logic for date and dateTime ranges is hidden -> run select: costs more, but is safe
        buffer = dictTable.makeRecord();

        select firstOnly RecId from buffer
            where buffer.RecId == _record.RecId;

        if (buffer.RecId)
        {
            ret = true;
        }
    }
    
    return ret;
}

2. Do not run additional select statement, but use calculated now value:
public static boolean isRecordValidNow(Common _record)
{
    boolean                 ret;
    DictTable               dictTable;
    FieldId                 validFromFieldId, validToFieldId;
    DictField               dictField;
    utcdatetime             currentDateTime;
    date                    currentDate;
    
    dictTable = new DictTable(_record.TableId);

    // run check only if table is valid time state
    if (dictTable && dictTable.isValidTimeStateTable())
    {
        validFromFieldId = dictTable.getValidTimeStateValidFromFieldId();
        validToFieldId = dictTable.getValidTimeStateValidToFieldId();

        dictField = new DictField(_record.TableId, validFromFieldId);

        if (dictField)
        {
            // compare valid fields based on base type
            if (dictField.baseType() == Types::UtcDateTime)
            {
                currentDateTime = DateTimeUtil::utcNow();

                if (_record.(validFromFieldId) <= currentDateTime && _record.(validToFieldId) >= currentDateTime)
                {
                    ret = true;
                }
            }
            else if (dictField.baseType() == Types::Date)
            {
                currentDate = DateTimeUtil::date(DateTimeUtil::applyTimeZoneOffset(DateTimeUtil::utcNow(), DateTimeUtil::getUserPreferredTimeZone()));

                if (_record.(validFromFieldId) <= currentDate && _record.(validToFieldId) >= currentDate)
                {
                    ret = true;
                }
            }
        }
    }
    
    return ret;
}

The most complicated part is to generate now for Date type. Actually there is an example in standard AX in method \Classes\DateEffectivenessPaneController\showCurrent

No comments:

Post a Comment