Search This Blog

Showing posts with label Ax2012. Show all posts
Showing posts with label Ax2012. Show all posts

Friday, August 24, 2018

Useful X++ functions



//Return the value from the xmlNode
static str getXmlNodeValue(XmlNode _node)
{
    System.Text.RegularExpressions.Regex re =
    // BP deviation documented
    new System.Text.RegularExpressions.Regex('^[ \r\n\t]*((.|\n)*?)[ \r\n\t]*$');
    System.Text.RegularExpressions.Match m = re.Match(_node.text());
    str result;
    ;

    result = m.Result('$1');
    return result;
}

/// <summary>
/// Provides a lookup of dimension values.
/// </summary>
/// <param name="_ctrl">The control to provide a lookup for.</param>
/// <param name="_dimensionName">The dimension attribute to filter by.</param>
public static client void lookupDimension(FormStringControl _ctrl, Name _dimensionName)
{
    SysTableLookup          sysTableLookup = SysTableLookup::newParameters(tablenum(DimensionAttribute),_ctrl);
    Query                   query = new Query();
    QueryBuildDataSource    queryBuildDataSource = query.addDataSource(tablenum(DimensionAttribute));

    sysTableLookup.addLookupfield(fieldnum(DimensionAttribute, Name));

    queryBuildDataSource.addRange(fieldnum(DimensionAttribute, Type)).value(queryNotValue(DimensionAttributeType::MainAccount));

    sysTableLookup.parmQuery(query);
    sysTableLookup.performFormLookup();

}


/// <summary>
/// This method has the complete source file as input and will concatenate the target path with the filename
/// </summary>
/// <param name="_sourceFilename">
///  This is the full filename including the path
/// </param>
/// <param name="_targetPath">
///  the target folder
/// </param>
/// <returns>
///  It will return the target filename.
/// </returns>

static filename getTargetFilename(Filename _sourceFilename, Filepath _targetPath)
{
    Filename    targetFilename;
    ;
    new InteropPermission(InteropKind::ClrInterop).assert();

    targetFilename = System.IO.Path::Combine(_targetPath, System.IO.Path::GetFileName(_sourceFilename));

    return targetFilename;
}


// Generate nodes into container.
static container containerFromXMLNode(XmlNode n)
{
    container retval, containerToInsert;
    Common recordToInsert;
    XmlNamedNodeMap attrs;
    XmlNode typeAttr, element, recordNode, containerNode;
    int elemNo = 1;
    ;
    //validate arguments before using them
    if (n == null)
        return retval;

    // Collect all the elements ...
    element = n.firstChild();
    if (element.name() == 'container')
    {
        element = element.firstChild();
    }
    while (element)
    {
        attrs = element.attributes();
        if (attrs)
        {
            typeAttr = attrs.getNamedItem('type');

            switch (typeAttr.nodeValue())
            {
                case 'int'      :
                    retval = conins(retval, elemNo, str2int(BisTools::getXmlNodeValue(element)));
                    break;

                case 'str'      :
                    retval = conins(retval, elemNo, BisTools::getXmlNodeValue(element));
                    break;

                case 'real'     :
                    retval = conins(retval, elemNo, str2num(BisTools::getXmlNodeValue(element)));
                    break;

                case 'enum':
                    retval = conins(retval, elemNo, str2int(BisTools::getXmlNodeValue(element)));
                    break;

                case 'date'     :
                    retval = conins(retval, elemNo, str2date(BisTools::getXmlNodeValue(element), 321));
                    break;

                case 'record'   :
                    recordNode = element.firstChild();
                    recordToInsert = Global::recordFromXMLNode(recordNode);
                    retval = conins(retval, elemNo, recordToInsert);
                    break;

                case 'container':
                    containerNode = element.firstChild();
                    containerToInsert = BisTools::containerFromXMLNode(containerNode);
                    retval = conins(retval, elemNo, containerToInsert);
                    break;

                case 'blob':
                    containerToInsert = BinData::stringToData(BisTools::getXmlNodeValue(element));
                    retval = conins(retval, elemNo, containerToInsert);
                    break;
            }
        }

        element = element.nextSibling();
        elemNo += 1;
    }

    return retval;
}




//Generate html from Record
static str record2html(Common record)
{
    str html;
    DictTable   dictTable = new dictTable(record.TableId);
    DictField   dictField;
    fieldId     fieldId;


    void addField2html(str fieldName, anyType fieldValue, str htmlCode, str fieldLabel)
    {
        str newValue = strFmt('%1',fieldValue);
        if (newValue == '')
        {
            newValue = '-';
        }
        html += strFmt('<tr><td width=30%>%3%4</td><td width=50%>%3%2</td><td width=20%>%3%1</td></tr>',fieldName, newValue , htmlCode, fieldLabel);
    }
    ;
    html = '<html><b>Record values<table border width=100%>';
    addField2html('Field name','Value','<b>','Label');

    fieldId = dictTable.fieldNext(0);
    while (fieldId)
    {
        dictField = dictTable.fieldObject(fieldId);
        if (dictField.arraySize() == 1 && dictField.baseType() != Types::Container && dictField.baseType() != Types::BLOB)
        {
            addField2html(dictField.name(), record.(fieldId),"", dictField.label());
        }
        fieldId = dictTable.fieldNext(fieldId);
    }


    html+='</table></html>';
    return html;
}




//Generate record to Text
static str record2text(Common record)
{
    str         text;
    DictTable   dictTable = new dictTable(record.TableId);
    DictField   dictField;
    fieldId     fieldId;


    void addField2text(str fieldName, anyType fieldValue, str fieldLabel)
    {
        str newValue = strFmt('%1',fieldValue);
        if (newValue == '')
        {
            newValue = '-';
        }
        text += strFmt('Field \'%1\' = \'%2\', Label: \'%3\'\n',fieldName, newValue, fieldLabel);
    }
    ;
    text = strFmt("@BIS635", tableid2name(record.tableId));
    addField2text('Field name','Value', 'Label');

    fieldId = dictTable.fieldNext(0);
    while (fieldId)
    {
        dictField = dictTable.fieldObject(fieldId);
        if (dictField.arraySize() == 1)
        {
            addField2text(dictField.name(), record.(fieldId), dictField.label());
        }
        fieldId = dictTable.fieldNext(fieldId);
    }


    return text;
}


//Create the table record from xmlnode
// Input is <Record table="name"> <Field:field1> value </Field:field1> ... </Record>
// it's the opposite from record.xml() method
static Common xml2record(XmlNode n, Common c = null)
{
    tableId table;
    fieldId field;
    DictTable dt;
    DictField df;
    XmlNode fieldNode;
    str fieldName;
    Struct content;
    str tableName;
    Types t;

    //validate arguments before using them
    if (n == null)
        return null;
    // If we don't have an incoming buffer, one is created
    if (prmisdefault(c))
    {
        // Create a buffer of the correct type
        tableName = n.name();
       // tableName = n.attributes().getNamedItem('name');

        // Check if table node can be accessed
        if (tableName != '')
        {
            table = tablename2id(tableName);
            dt = new DictTable(table);
            c = dt.makeRecord();
        }
    }
    else
    {
        table = c.TableId;
        dt = new DictTable(table);
    }

    fieldNode = n.firstChild();
    while (fieldNode)
    {
        fieldName = fieldNode.attributes().getNamedItem('name').text();
        field = dt.fieldName2Id(fieldName);
        df = new DictField(table, field);

        t = df.baseType();
        if (t == Types::Enum) //Enums need to be treated as Integers. By defult, Enums are getting treated as a boolean and hence loosing its value.
            t = Types::Integer;

        content = BisTools::valueFromXMLNode (t, fieldNode);

        c.(field) = content.value('value');

        fieldNode = fieldNode.nextSibling();
    }
    return c;
}

//Get next working date from the date .
public static date GetNextWorkDay(date _fromDate)
{
    WorkCalendarDate    workCalendar;
    ;

    select firstOnly TransDate from workCalendar
    order by TransDate ASC
        where workCalendar.TransDate > _fromDate
           && workCalendar.WorkTimeControl == WorkTimeControl::Open;

    return workCalendar.TransDate;
}


/// <summary>
///     Attempts to find executatble for file type specified, and open file with it.
/// </summary>
/// <param name="_filename">
///     File name to show
/// </param>
public static client void showFile(Filename _filename)
{
    str filePath, fileName, fileExt, executable;
    if (System.IO.File::Exists(_filename))
    {
        [filePath, filename, fileExt] = fileNameSplit(_filename);
        executable = WinAPI::findExecutable(_filename);
        if (!executable)
        {
            error(strFmt("Windows were not able to find executable for file %1", _filename));
            return;
        }
        if (fileExt == '.msg')
            WinAPI::shellExecute(strFmt('"%1"', executable),strFmt('/f "%1"', _filename),strFmt('"%1"', filePath)); // outlook requires extra parameter  /f
        else
            WinAPI::shellExecute(strFmt('"%1"', executable),strFmt('"%1"', _filename),strFmt('"%1"', filePath));
    }
    else
    {
        error("File not found");
    }
}





/// <summary>
///     Converts enum value to enum label in language specified
/// </summary>
/// <param name="enumId">
///     Enum Id
/// </param>
/// <param name="value">
///     Enum value
/// </param>
/// <param name="languageId">
///     Language for label
/// </param>
/// <returns>
///     Label of enum value in language specified
/// </returns>
public static str enum2Label(EnumId enumId, int value, LanguageId languageId = SrsReportRunUtil::getCurrentUserLangId())
{
    DictEnum dictEnum;
    int      valueIndex, valueBuf;
    ;
    dictEnum = new DictEnum(enumId);
    if (dictEnum)
    {

        for (valueIndex = 0 ; valueIndex < dictEnum.values(); valueIndex++)
        {
            valueBuf = dictEnum.index2Value(valueIndex);
            if (valueBuf == value)
                return SysLabel::labelId2String(dictEnum.index2LabelId(valueIndex), languageId);
        }
    }
    return '';
}


/// <summary>
///     Converts time value into string with hours and minutes. Mostly used when generating file names
/// </summary>
/// <param name="time">
///     Time as integer
/// </param>
/// <returns>
///     Time converted to string in format HHMM
/// </returns>
public static TempStr time2StrHM(int time)
{
    return num2str( time div 3600       ,2,0,0,0) + num2Str0(time mod 3600 div 60,2,0,0,0);
}

/// <summary>
///     Converts any value to string. This is hardcoded conversion without using culture context
/// </summary>
/// <param name="_value">
///     The value to convert
/// </param>
/// <returns>
///     Converted value as string
/// </returns>
public static str any2String(anytype _value)
{
    switch(typeOf(_value))
    {
        // BP deviation documented
        case Types::Date: return date2str(_value, -1,-1,-1,-1,-1,-1,DateFlags::None);
        case Types::Time: return KrishhUtils::time2StrHM(_value);
        case Types::Int64, Types::Integer: return int2str(_value);
        case Types::Real: return strFmt('%1', _value);
        case Types::Enum: return strFmt('%1', _value);
        case Types::UtcDateTime: return DateTimeUtil::toStr(DateTimeUtil::applyTimeZoneOffset(_value, DateTimeUtil::getUserPreferredTimeZone())); // Hotfix 52
        default: return strFmt('%1', _value);
    }
    return "";
}


/// <summary>
///     Checks full path, and if \ is missing at the end - adds it
/// </summary>
/// <param name="path">
///     Full path to analyse
/// </param>
/// <returns>
///     Full path with \ at the end
/// </returns>
public static str fixPath(str path)
{
    str buf = strLRTrim(path);
    if (!path)
        return "";
    if (subStr(buf, strLen(buf),1) != '\\')
        buf = buf + '\\';
    return buf;
}

/// <summary>
///     Generates temporrary file with extension. Also creates file and saves it.
/// </summary>
/// <param name="filePrefix">
///     File prefix to use
/// </param>
/// <param name="extension">
///     Extension to use
/// </param>
/// <param name="filePath">
///     File path to use
/// </param>
/// <returns>
///     Created temporrary file name
/// </returns>
/// <remarks>
///     Creates empty file with unique name. Safe to use with multiple threads
/// </remarks>
/// <exception cref="Exception::Error">
///     When 10 attempts to create file failed
/// </exception>
/// <exception cref="Exception::Error">
///     When 10 attempts to create file failed
/// </exception>
public static str getTempFile(str filePrefix, str extension, str filePath = '')
{
    #File
    str                  tmpPath;
    str                  fileName;
    System.IO.FileStream fileStream;
    boolean              ok;
    int                  i;

    if (filePath)
        tmpPath = KrishhUtils::fixPath(filePath);
    else
    {
        new InteropPermission(InteropKind::ClrInterop).assert();
        tmpPath = System.IO.Path::GetTempPath();
        CodeAccessPermission::revertAssert();
    }
    while(!ok)
    {
        fileName = tmpPath + (filePrefix?filePrefix:filePrefix + guid2str(newGuid())) + extension; // First attempt direct
        new InteropPermission(InteropKind::ClrInterop).assert();
        while(System.IO.File::Exists(fileName))
        {
            fileName = tmpPath + filePrefix + guid2str(newGuid()) + extension;
        }
        CodeAccessPermission::revertAssert();
        try
        {
            i++;
            if (i>10)
                throw Exception::Error;
            new FileIOPermission(fileName, #IO_WRITE).assert();
            fileStream = System.IO.File::Create(fileName);
            fileStream.Dispose();
            CodeAccessPermission::revertAssert();
            ok = true;
        }
        catch (Exception::Error)
        {
            throw error("@SYS326095");
        }
        catch
        {
            exceptionTextFallThrough();
            CodeAccessPermission::revertAssert();
        }
    }

    return fileName;
}



/// <summary>
///     Returns the number associated with the specified month name.
/// </summary>
/// <param name="_monthName">
/// The name of the month.
/// </param>
/// <returns>
/// The number associated with the month name.
/// </returns>
public static int monthUSName2Num(str _monthName)
{
    int ret;
    str monthName = _monthName;
    #Define.month1('january')
    #Define.jan('jan')
    #Define.month2('february')
    #Define.feb('feb')
    #Define.month3('march')
    #Define.mar('mar')
    #Define.month4('april')
    #Define.apr('apr')
    #Define.month5('may')
    #Define.month6('june')
    #Define.jun('jun')
    #Define.month7('july')
    #Define.jul('jul')
    #Define.month8('august')
    #Define.aug('aug')
    #Define.month9('september')
    #Define.sep('sep')
    #Define.month10('october')
    #Define.oct('oct')
    #Define.month11('november')
    #Define.nov('nov')
    #Define.month12('december')
    #Define.dec('dec');

    monthName = strLwr(_monthName);

    switch(monthName)
    {
        case #month1:
        case #jan:
            ret = 1;
            break;
        case #month2:
        case #feb:
            ret = 2;
            break;
        case  #month3:
        case #mar:
            ret = 3;
            break;
        case #month4:
        case #apr:
            ret = 4;
            break;
        case #month5:
            ret = 5;
            break;
        case #month6:
        case #jun:
            ret = 6;
            break;
        case #month7:
        case #jul:
            ret = 7;
            break;
        case #month8:
        case #aug:
            ret = 8;
            break;
        case #month9:
        case #sep:
            ret = 9;
            break;
        case #month10:
        case #oct:
            ret = 10;
            break;
        case #month11:
        case #nov:
            ret = 11;
            break;
        case #month12:
        case #dec:
            ret = 12;
            break;
        default:
            ret = 0;
            break;
    }
    return ret;
}


Thursday, April 20, 2017

AX2012 CompileCIL and Refresh Services using X++



static void krishh_CompileCILRefreshServices(Args _args)
{
    #AviFiles
    #File

    #define.fileName('AxTime.txt')

    TextIo                  file;
    FileIoPermission        permission;
    SysOperationProgress    progress;
    container               fileContainer;

    int                     i;

    Dialog                  dialog;

    DialogField             dlgCompile;
    DialogField             dlgCIL;
    DialogField             dlgIncCIL;
    DialogField             dlgRefreshService;

    int                     timeStarted[2];
    int                     timeAverage[4]; //1:FUllCompileTime,2:FULLCILCompileTime,3:IncrementalCILTime,4:RefreshServicesTime
    int                     timeExpected;

    Filename                filename
    ;

    void getAverageTime()
    {
        filename = WinAPI::getCurrentDirectory() + '\\' + fileName;

        permission = new FileIoPermission(filename, #io_read+#io_write);
        permission.assert();

        if(WinAPI::fileExists(filename))
        {
            file        = new TextIo(filename, #io_read);
            fileContainer   = file.read();
            timeAverage[1]  = str2int(conPeek(fileContainer,1));
            timeAverage[2]  = str2int(conPeek(fileContainer,2));
            timeAverage[3]  = str2int(conPeek(fileContainer,3));
            timeAverage[4]  = str2int(conPeek(fileContainer,4));
            file = null;
        }

        CodeAccessPermission::revertAssert();
    }

    void setAverageTime()
    {
        permission = new FileIoPermission(filename, #io_write);
        permission.assert();

        fileContainer = conNull();
        fileContainer = conIns(fileContainer,1,int2str(timeAverage[1]));
        fileContainer = conIns(fileContainer,2,int2str(timeAverage[2]));
        fileContainer = conIns(fileContainer,3,int2str(timeAverage[3]));
        fileContainer = conIns(fileContainer,4,int2str(timeAverage[4]));

        file = new TextIo(filename, #io_write);
        file.write(fileContainer);
        file.finalize();

        file = null;

        CodeAccessPermission::revertAssert();
        permission = null;
    }

    dialog  = new Dialog("Compile/CIl/Refresh");

    dialog.addInfoImage();
    dialog.addText("Please select actions needed and please be aware that all are time consuming processes");

    dialog.addGroup("Compile application");
    dlgCompile  = dialog.addFieldValue(extendedTypeStr(NoYesId),NoYes::No,"AOT Compile");

    dialog.addGroup("Compile CIL");
    dlgCIL      = dialog.addFieldValue(extendedTypeStr(NoYesId), NoYes::No, "FULL");
    dlgIncCIL   = dialog.addFieldValue(extendedTypeStr(NoYesId), NoYes::No, "Incemental");

    dialog.addGroup("Other");
    dlgRefreshService   = dialog.addFieldValue(extendedTypeStr(NoYesId),NoYes::No,"Refresh Services");

    if (!dialog.run())
        throw error("Operation aborted");

    filename        = #fileName;

    timeAverage[1]  = 3600; // 60:00 min
    timeAverage[2]  = 1800; // 30:00 min
    timeAverage[3]  = 900;  // 15:00 min
    timeAverage[4]  = 300;  // 5:00 min

    getAverageTime();

    timeExpected += dlgCompile.value()          ? timeAverage[1] : 0;
    timeExpected += dlgCIL.value()              ? timeAverage[2] : 0;
    timeExpected += dlgIncCIL.value()           ? timeAverage[3] : 0;
    timeExpected += dlgRefreshService.value()   ? timeAverage[4] : 0;

    progress = new SysOperationProgress();
    progress.updateInterval(0);
    progress.setAnimation(#AviStopwatch);

    progress.setTotal(1 + dlgCompile.value() + (dlgCIL.value() || dlgIncCIL.value()) + dlgRefreshService.value());

    timeStarted[1] = timeNow();

    info(strFmt("Process stared by %1",curUserId()));

    //Compile the application
    startLengthyOperation();
    sleep(3);

    //AOT Compile
    if (dlgCompile.value())
    {
        progress.incCount();
        progress.setText(strfmt("AOT Compile compiling | Start time : %1 ETA : %2",time2str(timeNow(),1,1),time2str(timeAverage[1] + timeNow(),1,1)));

        //Do function
        timeStarted[2] = timeNow();

        SysCompileAll::flushClient();
        SysCompileAll::compile();

        SysCheckList::finished(classnum(SysCheckListItem_Compile));
        SysCheckList::finished(classnum(SysCheckListItem_CompileUpgrade));
        SysCheckList::finished(className2Id(classStr(SysCheckListItem_CompileServ)));
        SysCheckList::finished(classnum(SysCheckListItem_SysUpdateCodeCompilInit));

        timeAverage[1] = ((timeNow()-timeStarted[2]) + timeAverage[1])/2;
        info(strFmt("AOT Compile toke : %1*",time2str(timeAverage[1],1,1)));
    }

    //Incremntal CIL
    if (dlgIncCIL.value())
    {
        progress.incCount();
        progress.setText(strfmt("Incremental CIL Compiling | Start time : %1 ETA : %2",time2str(timeNow(),1,1),time2str(timeAverage[3] + timeNow(),1,1)));

        //Do function
        timeStarted[2] = timeNow();
        SysCompileIL::generateIncrementalIL();

        timeAverage[3] = ((timeNow()-timeStarted[2]) + timeAverage[3])/2;
        info(strFmt("Increment CIL toke : %1*",time2str(timeAverage[3],1,1)));
    }
    //Full CIL
    else if (dlgCIL.value())
    {
        progress.incCount();
        progress.setText(strfmt("FULL CIL Compiling | Start time : %1 ETA : %2",time2str(timeNow(),1,1),time2str(timeAverage[2] + timeNow(),1,1)));

        //Do function
        timeStarted[2] = timeNow();
        SysCompileIL::generateIL();
        timeAverage[2] = ((timeNow()-timeStarted[2]) + timeAverage[2])/2;
        info(strFmt("FULL CIL toke : %1*",time2str(timeAverage[2],1,1)));
    }

    // Refresh services
    if (dlgRefreshService.value())
    {
        progress.setText(strfmt("Refresh Services | Start time : %1 ETA : %2",time2str(timeNow(),1,1),time2str(timeAverage[4] + timeNow(),1,1)));
        progress.incCount();

        timeStarted[2] = timeNow();

        AifServiceGenerationManager::registerServices();

        timeAverage[4] = ((timeNow()-timeStarted[2]) + timeAverage[4])/2;
        info(strFmt("Refresh Services toke : %1*",time2str(timeAverage[4],1,1)));
    }

    setAverageTime();

    endLengthyOperation();

    //Flush all
    sysFlushAOD::main(_args);
    sysFlushData::main(_args);
    sysFlushDictionary::main(_args);
    info(strFmt("*Averagetime"));
    info(strFmt("Total time spendt : %1",time2str(timeNow()-timeStarted[1],1,1)));
}

Monday, July 13, 2015

Ax2012 Useful functions 2

Show viewhistory on form datasources if you have ValidaTimeState Enabled DateTime enabled on the tables of that form. 
create this method in Global class so you can call whereever you want in form button click as below.

void clicked()

{
    buttonHistoryClick(element, this);
    Super();
}

static public void buttonHistoryClick(FormRun _formRun, FormButtonControl _fbc)
{
    void changeDataSources(ValidTimeStateAutoQuery _from, ValidTimeStateAutoQuery _to, boolean _allowDelete)
    {
        Counter         dataSourceNo;
        FormDataSource  formDataSource;

        for (dataSourceNo=1;_formRun.dataSourceCount()>=dataSourceNo;dataSourceNo++)
        {
            formDataSource = _formRun.dataSource(dataSourceNo) as FormDataSource;
            if (formDataSource.validTimeStateAutoQuery() == _from && new DictTable(formDataSource.table()).isValidTimeStateTable())
            {
                formDataSource.validTimeStateAutoQuery(_to);
                switch (_to)
                {
                    case ValidTimeStateAutoQuery::AsOfDate:
                        formDataSource.validTimeStateAutoQuery(ValidTimeStateAutoQuery::AsOfDate);
                        formDataSource.query().resetValidTimeStateQueryType();
                        formDataSource.allowDelete(_allowDelete);
                        break;
                    case ValidTimeStateAutoQuery::DateRange:
                        formDataSource.validTimeStateAutoQuery(ValidTimeStateAutoQuery::DateRange);
                        formDataSource.query().validTimeStateDateTimeRange(DateTimeUtil::minValue(), DateTimeUtil::maxValue());
                        formDataSource.allowDelete(_allowDelete);
                        break;
                }
                formDataSource.executeQuery();
            }
        }
    }

    if (_fbc.labelText() == "@SYS110266")
    {
        changeDataSources(ValidTimeStateAutoQuery::AsOfDate, ValidTimeStateAutoQuery::DateRange, false);
        _fbc.text("Stop viewing History");
        _fbc.normalImage("10006");
    }
    else
    {
        changeDataSources(ValidTimeStateAutoQuery::DateRange, ValidTimeStateAutoQuery::AsOfDate, true);
        _fbc.Text("@SYS110266");
        _fbc.normalImage("10007");
    }

}
// this method is used to create filenameTimeStamp.

static FileName createFilenameTimeStamp()
{
    FileName    ret;
    Microsoft.Dynamics.IntegrationFramework.Adapter.FileSystem       fileSystem;
    #Aif

    fileSystem      = AifUtil::getClrObject(#FileSystemProgId);

    ret = fileSystem.GetCurrentTimestamp();

    return ret;
}


// This method is used to split the string, and returns the conatiner with the position defined in the parameter
public static str rsaStrSplit(str _splitString,str _splitchar,int _pos)
{
    List strlist=new List(Types::String);
    ListIterator    iterator;
    container       packedList;
    ;
    strlist=strSplit(_splitString,_splitchar);
    iterator = new ListIterator(strlist);
    while(iterator.more())
    {
        packedList += iterator.value();
        iterator.next();
    }
    return conPeek(packedList,_pos);

}

public static str encrypt(str _input, str _salt = '')
{
    System.Security.Cryptography.SHA512Managed  sha512managed = new System.Security.Cryptography.SHA512Managed();
    System.Text.Encoding                        encoding = System.Text.Encoding::get_UTF8();

    System.Byte[]                               inputBytes;
    System.Byte[]                               resultBytes;

    int                                         i;
    str                                         returnString;
    ;

    new InteropPermission(InteropKind::ClrInterop).assert();

    inputBytes = encoding.GetBytes(strLwr(_salt) + _input); // Convert lower case salt + input into byte array

    // The input is hashed 1024 times for attack resiliency
    for (i = 0; i < 1024; i++)
    {
        resultBytes = resultBytes ? resultBytes : inputBytes; // First loop uses input for hashing
        resultBytes = sha512managed.ComputeHash(resultBytes);
    }

    returnString = System.Convert::ToBase64String(resultBytes);

    CodeAccessPermission::revertAssert();

    return returnString;
}

private static Map fileGetList(FilePath            _filePathArchive)

{
 
    Map                 mapFiles;

    InteropPermission   interopPermission = new InteropPermission(InteropKind::ClrInterop);
    Set                 interopPermissionSet = new Set(Types::Class);
    System.Array        arrayFiles;

    int                 i;
    ;

    // Granting file permission rights
    interopPermissionSet.add(interopPermission);
    CodeAccessPermission::assertMultiple(interopPermissionSet);

    mapFiles = new Map(Types::String, Types::String); // Key = return file | Value = archive path

        if (!System.IO.Directory::Exists(_filePathArchive))
        {
             throw  error("Path doesnt exist");
        }

        arrayFiles = System.IO.Directory::GetFiles(_filePathArchive);

        // CLRInterop::getAnyTypeForObject method is used to handle difference in AX and System types (e.g. System.Int32 != int)

        for (i = 0; i < CLRInterop::getAnyTypeForObject(arrayFiles.get_Length()); i++)
        {
       mapFiles.insert(CLRInterop::getAnyTypeForObject(arrayFiles.GetValue(i)), _filePathArchive);
        }
    }

    // Reverting file permission rights
    CodeAccessPermission::revertAssert();

    return mapFiles;
}


/// <summary>
///  Gets the SenderID from AIF xml .
/// </summary>
/// <param name="messagePartsXml">
/// An <c>AifXml</c> value.
/// </param>
/// <returns>
/// An instance of the <c>str document Namespace</c> class.
/// </returns>
public static str getSenderIDValue(AifXml messagePartsXml)
{
     XmlTextReader               xmlReader;
    str value,currentElement,pureElement;

;
#Aif
    xmlReader = XmlTextReader::newXml(messagePartsXml);
    while (xmlReader.Read())
    {
        switch (xmlReader.nodeType())
        {
             case XmlNodeType::Element:
                  currentElement = xmlReader.name();
                 break;
             case XmlNodeType::Text:
                  pureElement = subStr(currentElement,strFind(currentElement,':',1,256)+1,256);
                    switch (pureElement)
                    {
                       case "SenderId":
                        {
                            value=xmlReader.value();
                            return value;
                        }
                        break;
                    }
              break;
        }
    }

    return value;
}


AX2012 Replacing Company element value in AIF using .net dll and QueryService

Scenario:
In AIF we have some data coming from externalSystem, which externalSystem doesnt have anyinformation to which company it should load, as ExternalSystem knows the information about coRegNum as we have to find the right company in AX by using coRegNum.
Solution:
so I build a .net component where we use the dll in transformation to replace the companyelement in the header to pass the file into right company.
I am using QueryService which I querying the companyInfoTable with the range coRegNum and getting the right Company and replacing in the sourceXML in transfromation in headersection.

sample xml section below.

<ns0:Envelope xmlns:ns0="http://schemas.microsoft.com/dynamics/2011/01/documents/Message">
<ns0:Header>
<ns0:MessageId>354bcae9-45a5-411e-953f-e2920a6c0229</ns0:MessageId>
<ns0:Company>123456</ns0:Company>
<ns0:Action>http://schemas.microsoft.com/dynamics/2008/01/services/GeneralJournalService/create</ns0:Action>
</ns0:Header>
<ns0:Body>
<ns0:MessageParts>
<ns0:LedgerGeneralJournal xmlns:ns0="http://schemas.microsoft.com/dynamics/2008/01/documents/LedgerGeneralJournal" xmlns:st="http://schemas.microsoft.com/dynamics/2008/01/sharedtypes">

Before writing this class add serviceReference QueryService from AX standardservice into your solution that will create app.config as below

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <system.serviceModel>
        <bindings>
            <netTcpBinding>
                <binding name="QueryServiceEndpoint" closeTimeout="00:01:00"
                    openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00"
                    transactionFlow="false" transferMode="Streamed" transactionProtocol="OleTransactions"
                    hostNameComparisonMode="StrongWildcard" listenBacklog="10"
                    maxBufferPoolSize="524288" maxBufferSize="65536" maxConnections="10"
                    maxReceivedMessageSize="65536">
                    <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
                        maxBytesPerRead="4096" maxNameTableCharCount="16384" />
                    <reliableSession ordered="true" inactivityTimeout="00:10:00"
                        enabled="false" />
                    <security mode="Transport">
                        <transport clientCredentialType="Windows" protectionLevel="EncryptAndSign" />
                        <message clientCredentialType="Windows" />
                    </security>
                </binding>
            </netTcpBinding>
        </bindings>
        <client>
            <endpoint address="net.tcp://KrishhDax:8201/DynamicsAx/Services/QueryService"
                binding="netTcpBinding" bindingConfiguration="QueryServiceEndpoint"
                contract="AXQueryService.IQueryService" name="QueryServiceEndpoint">
                <identity>
                    <servicePrincipalName value="host/KrishhDax.adep01.nordic.rsa-ins.com" />
                </identity>
            </endpoint>
        </client>
    </system.serviceModel>

</configuration>

Create a tranform class which extends from Itransform.
I am using xml.linq to read the element value in the class, so I referenced System.Xml.Linq;

using System;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Dynamics.IntegrationFramework.Transform;
using System.Xml;
using System.Xml.Linq;
using KrishhIbanToCompanyTrans.AXQueryService;
using System.ServiceModel;
using System.Data;
using System.Net;


namespace KrishhIbanToCompanyTrans
{
    public class IBANToCompanyTrans : ITransform
    {
        public void Transform(System.IO.Stream input, System.IO.Stream output, string config)
        {
            XDocument inputXml = XDocument.Load(input);

            string accStr = inputXml.Root.Descendants().Where(e => e.Name.LocalName == "Company").First().Value;
           
            string[] serviceParams = config.Split(';');

            if (serviceParams.Count() != 1 && serviceParams.Count() != 4)
                throw new ArgumentException("Invalid configuration passed. Expecting single endpoint address or endpoint address with username, password and domain, separated by ;");

            NetTcpBinding binding1 = new NetTcpBinding();
            EndpointAddress epa = new EndpointAddress(serviceParams[0]);

            binding1.Name = "QueryServiceEndpoint";
            binding1.TransactionProtocol = TransactionProtocol.OleTransactions;
            binding1.TransferMode = TransferMode.Streamed;
            binding1.Security.Mode = SecurityMode.Transport;
            binding1.HostNameComparisonMode = HostNameComparisonMode.StrongWildcard;
            binding1.Security.Transport.ClientCredentialType =  TcpClientCredentialType.Windows;
            binding1.Security.Transport.ProtectionLevel = System.Net.Security.ProtectionLevel.EncryptAndSign;
            binding1.Security.Message.ClientCredentialType = MessageCredentialType.Windows;
            binding1.ReliableSession.Enabled = false;

            QueryServiceClient serviceClient = new QueryServiceClient(binding1, epa);

            if (serviceParams.Count() == 4)
            {
                serviceClient.ClientCredentials.Windows.ClientCredential.UserName = serviceParams[1];
                serviceClient.ClientCredentials.Windows.ClientCredential.Password = serviceParams[2];
                serviceClient.ClientCredentials.Windows.ClientCredential.Domain = serviceParams[3];
            }

            QueryMetadata query = new QueryMetadata();
            query.DataSources = new QueryDataSourceMetadata[1];
            query.Name = "CompanyInfo";
            QueryDataSourceMetadata queryDS = new QueryDataSourceMetadata();
            queryDS.Name = "CompanyInfo";
            queryDS.Table = "CompanyInfo";
            queryDS.Enabled = true;
            query.DataSources[0] = queryDS;
            queryDS.DynamicFieldList = false;
            queryDS.Fields = new QueryDataFieldMetadata[2];
            QueryDataFieldMetadata fieldId = new QueryDataFieldMetadata();
            fieldId.FieldName = "DataArea";
            fieldId.SelectionField = SelectionField.Database;
            queryDS.Fields[0] = fieldId;
            QueryDataFieldMetadata fieldName = new QueryDataFieldMetadata();
            fieldName.FieldName = "CoRegNum";
            fieldName.SelectionField = SelectionField.Database;
            queryDS.Fields[1] = fieldName;
            queryDS.Ranges = new QueryDataRangeMetadata[] { new QueryDataRangeMetadata() { TableName = "CompanyInfo", FieldName = "CoRegNum", Value = accStr, Enabled = true } };

            Paging paging = new ValueBasedPaging() { RecordLimit = 25 };



            DataSet dataset = serviceClient.ExecuteQuery(query, ref paging);
            Console.Write(dataset.GetXml());

            if (dataset != null)
            {
                if (dataset.Tables.Count > 2)
                {
                    if (dataset.Tables[3].Rows.Count > 0)
                    {
                        DataRow dr = dataset.Tables[3].Rows[0];

                        var element = inputXml.Root.Descendants().Where(e => e.Name.LocalName == "Company").First();
                        if (element != null)
                            element.Value = dr["DataArea"].ToString();
                    }
                }
            }
            inputXml.Save(output);

        }

This method is used to test the above code.
/*
        static void Main(string[] args)
        {
            IBANToCompanyTrans transformClass = new IBANToCompanyTrans();

            FileStream input, output;

            // Create the two streams to pass into the assembly. You will need to change these
            // to your file locations.
            input = new FileStream("C:\\Temp\\922\\922.xml", FileMode.Open);
            output = new FileStream("C:\\Temp\\922\\922_c.xml", FileMode.OpenOrCreate);

            string paramString = "net.tcp://hssdas115:8201/DynamicsAx/Services/QueryService";
            // Passes in the customers CSV file and gets back an XML file.
            transformClass.Transform(input, output, paramString);

            // Displays the XML to the console.
            //            StreamReader sreader = new StreamReader(new FileStream("c:\\temp\\testtmpn.xml", FileMode.Open));
            //            Console.Write(sreader.ReadToEnd());
            //            Console.ReadLine();

        } */
    }
}

After building this component, go to the inboundPort and click transformation button and go to transformations and create the .net dll  transformation and provide the dll and select the class in the dropdown.
in Config file provide the app.config file for this transformation.



Thursday, June 25, 2015

AIF Outbound Read ParentAXBC while processingRecord AX2012

Scenario:

In AIF outbound document service Exporting Invoices information,
In this document we have the customization as one table which contains the printTemplates where it stores the printTemplate information like,address,bankdetails,etc.Using this printTemplate number the external system will define which printing report they have to use.
The Requirement is  The Address containes all the street,country,etc. these information we have to generate from translation tables based on the language that defined in the custinvoiceJournal.

so the datasource lookes like this.
custinvoicejour->custinvoicetrans,custTable,etc, as well printTemplateTable also outerjoins to the custinvoicejour.


I didnt find the way where I can get the parentaxbc object while processing the current record.

Solution:
I thought to get parentAXBC object always for the outbound for the current AXBC record.

See the Modification that I have build.


1. AXDBase class
             added the class variable as AXInternalBase parentAXBC;

2. AxdBaseRead class
   Open method serializeRecord add the folllowing line of code above        AXbase.ProccesingRecord(common) line in that method
axdBase.parmParentAxBC(_parentAxBC);

3. AxdBaseGenerateXSD class
   Open this class edit method addDocumentProperties and add one more case for classType as below, so that while serialization class object wont fail.
// added by krishna for to check for class type also. begins
case Types::Class:
if (typename == '')
{
typename = #xsdStringType;
typeNameSpace = #xsdNameSpace ;
}
break;

// added by krishna for to check for class type also.

Now framework was updated to get parentAXBC allways while outbound. now you can write logic whatever you want to use it.


Open AXDSalesInvoice class and update the processing record with the business logic for you to handle.
It this method i am verifying the current record in printTemplate then get the parent and get the languageId from that do my logic.

public void processingRecord(Common common)
{
 PrintTemplate PrintTemplate;
 AxCustInvoiceJour axCustInvoiceJour;
 if(common.TableId == tableNum(PrintTemplate))
 {
 axCustInvoiceJour=this.parmParentAxBC();
 PrintTemplate=common;
 PrintTemplate.CompanyCountryName=LogisticsAddressCountryRegionTranslation::find(LogisticsPostalAddress::findRecId(PrintTemplate.Address).CountryRegionId,axCustInvoiceJour.parmLanguageId()).ShortName;
 super(PrintTemplate);
 }
 else
 {
 super(common);
 }

}


If you guys likes this post and useful please like and share it.

 

Editable Multi select lookup in Grid field AX2012

Scneario: Multiple select Editable lookup  in grid

I created an extension of class from SysLookupMultiselectGrid

class KrisSysLookupMultiSelectGrid extends SysLookupMultiSelectGrid
{
#Characters
}

public void setSelected()
{
 dictfield dictField;
 Common currentDSRecord;
 FormDataSource formdatasource;
 callingControlId.text(SysOperationHelper::convertMultiSelectedValueString       (selectedId));
 formdatasource = callingControlId.dataSourceObject();
 if(formdatasource && callingControlStr.dataField())
 {
  dictfield = new dictfield(formdatasource.table(),callingControlStr.dataField());
   currentDSRecord = formdatasource.cursor();
   currentDSRecord.(dictfield.id()) = currentDSRecord.(dictfield.id()) +     SysOperationHelper::convertMultiSelectedValueString(selectedStr);
  callingControlStr.update();
 }
 else
 {
 callingControlStr.text(SysOperationHelper::convertMultiSelectedValueString(selectedStr));
 }
}

public static KrisSysLookupMultiSelectGrid construct(FormControl _ctrlId,
FormControl _ctrlStr)
{
KrisSysLookupMultiSelectGrid lookupMS;
lookupMS = new KrisSysLookupMultiSelectGrid ();
lookupMS.parmCallingControlId(_ctrlId);
lookupMS.parmCallingControlStr(_ctrlStr);
return lookupMS;

}


On form declare this class on the form level as below

KrisSysLookupMultiSelectGrid multiSelectGrid;

On form Init method initiliaze this object as below
multiSelectGrid = KrisSysLookupMultiSelectGrid ::construct(GridResults_Value,GridResults_Value);

On grid string edit field lookup method you can use this object as below

Query query = new Query();

QueryBuildDataSource queryBuildDataSource;

queryBuildDataSource = query.addDataSource(tableNum(DimensionAttribute));
queryBuildDataSource.addRange(fieldNum(DimensionAttribute,Type)).value(queryValue(DimensionAttributeType::CustomList));
queryBuildDataSource.addRange(fieldNum(DimensionAttribute,Type)).value(queryValue(DimensionAttributeType::MainAccount));
queryBuildDataSource.addRange(fieldNum(DimensionAttribute,Type)).value(queryValue(DimensionAttributeType::ExistingList));
queryBuildDataSource.addSelectionField(fieldNum(DimensionAttribute,Name));
multiSelectGrid.parmQuery(query);

multiSelectGrid.run();

you can see in form as below screenshot


Its editable and multi select lookup.



AIF Inheritance Extending AXD classes AX2012


Scenario:

I have multiple ledgerTransaction files coming from different source systems to AX, so each file import must have different business logic,business handlings regarding the dimensions, type of files ex ledger,cust,bank,vend.

I build the whole logic in the standard AXDLEdgerGeneralService class in deserializeEntity method with journalNames I handled, but its becoming more complex and to maintain the functionality and growing business requirements, its getting messing in the code.

I designed the inheritance for AIF documents, For each inbound we can have different axdclass with their own business logic implemented and I defined which axdclass that you want to run on that inbound port. It became easier to maintain the code and standard class is same as Standard.

I thought to share as it may be useful for lot of people.

abstract class AifDocument extends AfStronglyTypedDataContainer
{
    classId             axdClassId;
    AxdBase             axdInstance;

    AifXml              documentXml;
    boolean             documentXmlExists;
    boolean             deserializeNow;
}

public classId parmAXDClassId(classId _classId=axdClassId)
{
    axdClassId=_classId;

    return axdClassId;
}

Add field ClassId in table AIFInboundPort which extends classID EDT.
Create an Edit method in this table
edit className name(boolean set, Classname value)
{
     classid classID;
     if(set)
     {
         classid=classname2id(value);
         this.classid=classid;
     }
     else
    {
           value = classid2name(this.classid);
     }
}


Create an inMemmory table AifAxdClassLookup with the field ClassName of EDT Name.
Edit the form aifinboundPort and add a method at element level
Declare a variable at form level as AifAxdClassLookup aifAxdClassLookup;

Add AXDClass string edit control on details header group. define Datamethod Name

Add progress control under details header  group and name it as progress.

Create element level method as below, we will use this method in the lookup of the AXDclass string edit control.

void generateAXDClassesLookupTable()
{
    AXDBase componentInstance;
    Dictionary dictionary;
    SysDictClass dictClass;
    int i;
    int classCount;
    classId componentInterfaceId,componentInterfaceId1;

    SysTableLookup              sysTableLookup;
    ;

    dictionary = new Dictionary();
    componentInterfaceId1=classNum(AxdLedgerGeneralJournal);

    classCount = dictionary.classCnt();

    progress.rangeLo(1);
    progress.rangeHi(classCount);
    progress.pos(1);
    progress.step(1);
    progress.visible(true);
    for (i=1; i <= classCount; i++)
    {
        progress.pos(i);
        dictClass = new SysDictClass(dictionary.classCnt2Id(i));
        if (dictClass.isImplementing(componentInterfaceId1))
        {
            componentInstance = dictClass.makeObject();
            AifAxdClassLookup.clear();
            AifAxdClassLookup.ClassName = dictClass.name();
            AifAxdClassLookup.insert();
        }
    }
    progress.visible(false);
    componentLookupGenerated = true;
}

Override the lookup method of AXDClass string edit control and add below code

public void lookup()
{
   SysTableLookup          tableLookup;
    Query                   query;
    QueryBuildDataSource    queryBuildDataSource;
    ;

    if (componentLookupGenerated == false)
    {
        element.generateAXDClassesLookupTable();
    }

    query = new Query();
    queryBuildDataSource = query.addDataSource(tablenum(AifAxdClassLookup));

    tableLookup = SysTableLookup::newParameters(tablenum(AifAxdClassLookup), this);
    tableLookup.addLookupfield(fieldnum(AifAxdClassLookup, ClassName));
    tableLookup.parmQuery(query);
    //BP Deviation Documented.
    tableLookup.parmTmpBuffer(AifAxdClassLookup);
    tableLookup.parmUseLookupValue(false);

    tableLookup.performFormLookup();
}

Modify the service class ex: ledgerGeneralService class in my case its ledgerGeneralJournalService
[AifDocumentCreateAttribute, SysEntryPointAttribute(true)]
public AifEntityKeyList create(LedgerGeneralJournal _ledgerGeneralJournal)
{
    AifInboundPort aifInboundPort;
    ClassId AxdClassId;
    ;
    //Assign inheritance extension AXDclass for each port defined on the inboundPort added by krishna.
    if (operationContext != null)
    {
        AxdClassId=aifInboundPort::find(operationContext.getPortName()).ClassId;
        if(AxdClassId!=0)
        {
            _ledgerGeneralJournal.parmAXDClassId(AxdClassId);
        }
    }

    //assign inheritance extension AXDclass for each port defined on the inboundPort added by krishna.
    return this.createList(_ledgerGeneralJournal);

}

Now we will create a class which extends AXDclass ex: AXDLedgerGeneralJournal

class AxdLedgerGeneralJournal_GeneralALL extends AxdLedgerGeneralJournal
{
}

Override the queryName method and use which query you are using for your inbound AIF
In my example I am using AXDLedgerGeneralJournal

public QueryName getQueryName()
{
    return querystr(AxdLedgerGeneralJournal);
}

Now you can override whatever the method you want to overiride, in my case I am overriding deserializeentity.
This method contains all my modification logic.

public void afterDeserializeEntity(AxInternalBase _axbc, tableId _tableId, str _dataSourceName)
{
    AxdBaseProperty axdBaseProperty = new AxdBaseProperty();
    container       dimensionValue, axdBasePropertyContainer, dimensionValueConverted,bankDimensionContainer;
    recId           dimensionFieldRecId,bankDimensionFieldRecid;
    int             containerElementIndex = 1;
    int             containerLength;
    int             fieldId;
    selectableDataArea company, offsetCompany;
    BankAccountTable localBankAccountTable;
    AccountStatementRules AccountStatementRules;

    JournalNameId localJournalName;
    LogisticsPostalAddressView    locallogisticsPostalAddressView;
    LogisticsLocationParty        logisticslocationParty;
    CustTable                     localCustTable;

    MappingText                localMappingText="";
    localJournalName="";
    dimensionFieldRecId=0;

    containerLength = conLen(fieldList);

    if (containerLength == 0)
    {
        return;
    }

    if(_tableId == tableNum(LedgerJournalTrans))
    {
        ledgerJournalName = LedgerJournalName::find(_axbc.parentAxBC().fieldId(fieldNum(ledgerJournalTable, JournalName)));

    }
    if(_tableId == tableNum(LedgerJournalTable))
    {
        ledgerJournalName = LedgerJournalName::find(_axbc.fieldId(fieldNum(ledgerJournalTable, JournalName)));
    }
    if(ledgerJournalName)
    {
        ateAccountDefinitionId = ATEAccountDefinitionTable::findRecId(
            ledgerJournalName.ATEAccountDefinitionTable
            ).DefinitionId;
    }
    if (_tableId == tableNum(LedgerJournalTrans))
    {
        company         = _axbc.fieldId(fieldNum(LedgerJournalTrans, Company));
        offsetCompany   = _axbc.fieldId(fieldNum(LedgerJournalTrans, OffsetCompany));

        company         = AifLookupEntry::findInternal(SystemParameters::find().LookupTableId,company);
        offsetCompany   = AifLookupEntry::findInternal(SystemParameters::find().LookupTableId,offsetCompany);

        if(LedgerJournalName::find(_axbc.parentAxBC().fieldId(fieldNum(ledgerJournalTable, JournalName))).JournalName=="1234")
        {
            company         =curext();
            offsetCompany   =curext();
        }

        if (company)
        {
            _axbc.fieldId(fieldNum(LedgerJournalTrans, Company), company);
        }
        else
        {
            company         =curext();
            _axbc.fieldId(fieldNum(LedgerJournalTrans, Company), company);
        }

        if (offsetCompany)
        {
            _axbc.fieldId(fieldNum(LedgerJournalTrans, OffsetCompany), offsetCompany);
        }
        else
        {
            offsetCompany   =curext();
            _axbc.fieldId(fieldNum(LedgerJournalTrans, OffsetCompany), offsetCompany);
        }
         // Validate the primary and offset companies.
        this.validateCompany(_axbc.currentRecord(), tableNum(LedgerJournalTrans), fieldNum(LedgerJournalTrans, Company), company);
        this.validateCompany(_axbc.currentRecord(), tableNum(LedgerJournalTrans), fieldNum(LedgerJournalTrans, OffsetCompany), offsetCompany);
    }
    do
    {
        axdBasePropertyContainer = conPeek(fieldList, containerElementIndex);
        axdBaseProperty.unpack(axdBasePropertyContainer);
        containerElementIndex++;
        dimensionValue = conPeek(fieldList, containerElementIndex);
        containerElementIndex++;

        fieldId = axdBaseProperty.parmImplementingFieldId();

        // If the Table number and Field number match then convert the field by calling axdDimensionUtil
        // and set the corresponding field through its parm method.
        if (_tableId == tableNum(LedgerJournalTable) &&
            fieldId == fieldNum(LedgerJournalTable, OffsetLedgerDimension))
        {
            // MultiTypeDefaultAccount requires an account type to be specified.
            //return AxdDimensionUtil::getMultiTypeDefaultAccountId(_accountTypeEnumId, _accountType, _dimensionValue);
            dimensionFieldRecId = AxdDimensionUtil::getMultiTypeDefaultAccountId(enumName2Id('LedgerJournalACType'),
                                                                                 _axbc.fieldId(fieldNum(LedgerJournalTable, OffsetAccountType)),
                                                                                 dimensionValue);
            _axbc.fieldId(fieldNum(LedgerJournalTable, OffsetLedgerDimension), dimensionFieldRecId);
        }
        else if (_tableId == tableNum(LedgerJournalTrans))
        {
            if (fieldId == fieldNum(LedgerJournalTrans, LedgerDimension))
            {

                if (ateAccountDefinitionId)
                {
                        dimensionValueConverted = this.ConvertLedgerdimension_PC(
                                _axbc.fieldId(fieldNum(LedgerJournalTrans, ExternalAccountString))
                            , _axbc.fieldId(fieldNum(LedgerJournalTrans, Company))
                            , _axbc.fieldId(fieldNum(LedgerJournalTrans, CurrencyCode))
                            , LedgerJournalName::find(_axbc.parentAxBC().fieldId(fieldNum(ledgerJournalTable, JournalName))).JournalName);
                        if (BankAccountTable::exist(conPeek(dimensionValueConverted,2)))
                        {
                            _axbc.fieldId(fieldNum(LedgerJournalTrans, AccountType), LedgerJournalACType::Bank);
                            _axbc.fieldId(fieldNum(LedgerJournalTrans,DefaultDimension),BankAccountTable::find(conPeek(dimensionValueConverted,2)).DefaultDimension);
                        }
                        dimensionFieldRecId = AxdDimensionUtil::getMultiTypeAccountId(enumName2Id('LedgerJournalACType'),
                                                                                        _axbc.fieldId(fieldNum(LedgerJournalTrans, AccountType)),
                                                                                        dimensionValueConverted,
                                                                                        company);
                }
                else  //Non ATE starts
                {
                    dimensionFieldRecId = AxdDimensionUtil::getMultiTypeAccountId(enumName2Id('LedgerJournalACType'),
                                                                                    _axbc.fieldId(fieldNum(LedgerJournalTrans, AccountType)),
                                                                                    dimensionValue,
                                                                                    company);
                }// Else Non ATE closed

                _axbc.fieldId(fieldNum(LedgerJournalTrans, LedgerDimension), dimensionFieldRecId);
            }// IF ledgerJournalTrans ledgerDimensionClosed field is closed
            else if (fieldId == fieldNum(LedgerJournalTrans, OffsetLedgerDimension))
            {

                if (ateAccountDefinitionId)
                {
                    dimensionValueConverted = this.ConvertLedgerdimension_PC(
                            _axbc.fieldId(fieldNum(LedgerJournalTrans, OffsetAccountString))
                        , _axbc.fieldId(fieldNum(LedgerJournalTrans, OffsetCompany))
                        , _axbc.fieldId(fieldNum(LedgerJournalTrans, CurrencyCode))
                        ,LedgerJournalName::find(_axbc.parentAxBC().fieldId(fieldNum(ledgerJournalTable, JournalName))).JournalName);
                    dimensionFieldRecId = AxdDimensionUtil::getMultiTypeAccountId(enumName2Id('LedgerJournalACType'),
                                                                                    _axbc.fieldId(fieldNum(LedgerJournalTrans, OffsetAccountType)),
                                                                                    dimensionValueConverted,//dimensionValue,
                                                                                    offsetCompany);
                }// ATE offset closed
                else
                {
                    dimensionFieldRecId = AxdDimensionUtil::getMultiTypeAccountId(enumName2Id('LedgerJournalACType'),
                                                                                    _axbc.fieldId(fieldNum(LedgerJournalTrans, OffsetAccountType)),
                                                                                    dimensionValue,
                                                                                    offsetCompany);
                }//ELse non ATE  offset closed

                _axbc.fieldId(fieldNum(LedgerJournalTrans, OffsetLedgerDimension), dimensionFieldRecId);
            }//Else if OffsetLedger dimension closed
            else if (fieldId == fieldNum(LedgerJournalTrans, DefaultDimension))
            {
                dimensionFieldRecId = AxdDimensionUtil::getDimensionAttributeValueSetId(dimensionValue, company);
                _axbc.fieldId(fieldNum(LedgerJournalTrans, DefaultDimension), dimensionFieldRecId);
            }//Else if Default dimension closed
            else if (fieldId == fieldNum(LedgerJournalTrans, OffsetDefaultDimension))
            {
                // OffsetDefaultDimension requires a Legal entity to be specified to support intercompany transactions.
                dimensionFieldRecId = AxdDimensionUtil::getDimensionAttributeValueSetId(dimensionValue, offsetCompany);
                _axbc.fieldId(fieldNum(LedgerJournalTrans, OffsetDefaultDimension), dimensionFieldRecId);
            }//Else if OffsetDefault dimension closed
        }//IF ledgerJournalTrans table check closed
    }//Do while closed
    while (containerElementIndex < containerLength);
    fieldList = conNull();
}




 If you guys likes this post please share it and like this post.


if you have any queries please contact and message me.