Wednesday, October 12, 2022

To add dynamics default controls on UI in D365FO

 Reference Class:

SysSystemDefinedButtons


Sample code:

[ExtensionOf(classStr(SysSystemDefinedButtons))]

internal final class SysSystemDefinedButtonsCls_SAN_Extension

{

    private static str SANDE_SystemDefinedButtonsActionPane = "SystemDefinedButtonsActionPane";

    private static str SAN_SystemDefinedButtonsActionPane = "SAN_SystemDefinedButtonsActionPane";

    private static str SAN_SystemDefinedFormButtonGroup = "SAN_SystemDefinedButtonsButtonGroup_Form";

    private static str SAN_SystemDefinedWorkFlowButton = "SAN_SystemDefinedButtonWorkflow";

    private static str SAN_SystemDefinedWorkdlowActionPaneTab = "SAN_SystemDefinedWorkflow";

    private static str SAN_SystemDefinedWorkflowGroup = "SAN_SystemDefinedWorkflowGroup";


    public void addSystemDefinedButtons()

    {

        next addSystemDefinedButtons();


        if (this.isFormStyleSupportedForSystemDefinedButtons())

        {

            FormActionPaneControl actionPane;

            List listOfActionPanes;

            ListEnumerator apListEnumerator;


            listOfActionPanes = this.san_GetActionPanesForSystemButtons();

            apListEnumerator = listOfActionPanes.getEnumerator();


            while (apListEnumerator.moveNext())

            {

                actionPane = apListEnumerator.current();

                this.san_AddButtonsToActionPane(actionPane);

            }

            

        }

    }


    private List san_GetActionPanesForSystemButtons()

    {

        List listOfActionPanes = new List(Types::Class);

        FormActionPaneControl actionPane;

        Object childControl;

        FormRun form = this.getFormRun();

        

        for (int i = 1; i <= form.design().controlCount(); i++)

        {

            childControl = form.design().controlNum(i);


            if (classidget(childControl) == classnum(FormActionPaneControl))

            {

                actionPane = childControl as FormActionPaneControl;


                if (actionPane.Style() == ActionPaneStyle::Standard)

                {

                    listOfActionPanes.addEnd(actionPane);

                }

            }

        }


        if (listOfActionPanes.empty())

        {

            actionPane = form.design().addControl(FormControlType::ActionPane, SANDE_SystemDefinedButtonsActionPane);

            form.design().moveControl(actionPane.id());


            listOfActionPanes.addEnd(actionPane);

        }


        return listOfActionPanes;

    }


    private void san_AddButtonsToActionPane(FormActionPaneControl _actionPane)

    {

        FormButtonGroupControl buttonGroup;

        FormMenuButtonControl menuButton;

        FormCommandButtonControl commandButton;

        FormRun formRun = this.getFormRun();


        if (this.getFormStyle() != FormStyle::Workspace)

        {

            this.SAN_AddWorkflowsTab(_actionPane);

        }

    }


    private void SAN_AddWorkflowsTab(FormActionPaneControl _actionPane)

    {

        FormButtonGroupControl buttonGroup;

        FormMenuButtonControl menuButton;

        FormActionPaneTabControl workflowTab = _actionPane.addControl(FormControlType::ActionPaneTab, this.SAN_CreateUniqueName(SAN_SystemDefinedWorkdlowActionPaneTab));

        workflowTab.allowUserSetup(FormAllowUserSetup::No);

        FormRun form = this.getFormRun();


        workflowTab.caption("Custom Workflow");

        workflowTab.hideIfEmpty(true);


        buttonGroup = workflowTab.addControl(FormControlType::ButtonGroup, this.SAN_CreateUniqueName("SAN_SystemDefinedWorkflowGroup"));

        buttonGroup.allowUserSetup(FormAllowUserSetup::No);

        buttonGroup.caption("Workflow");


        FormFunctionButtonControl menuItemButton = buttonGroup.addControl(FormControlType::MenuFunctionButton, "SAN_WorflowButton", buttonGroup);

        menuItemButton.menuItemType(MenuItemType::Display);

        menuItemButton.menuItemName(menuItemDisplayStr(<Display menu item>));

        menuItemButton.dataSource(form.dataSource());

        menuItemButton.visible(true);

    }


    private str SAN_CreateUniqueName(str baseControlName)

    {

        str candidateName = baseControlName;

        int i = 1;


        if(this.SAN_isControlFound(candidateName))

        {

            do

            {

                candidateName = strFmt("%1%2", baseControlName, i);

                i++;

            }

            while (this.SAN_isControlFound(candidateName));

        }

        

        return candidateName;

    }


    private boolean SAN_isControlFound(str controlName)

    {

        FormRun form = this.getFormRun();


        boolean isControlFound = false;


        if (form.controlId(controlName) > 0)

        {

            isControlFound = true;

        }

              

        return isControlFound;

    }


}

Friday, October 7, 2022

Globals in D365FO (Implementation samples)

Samples


/// <summary>

    /// Convert the date input value to the string format YYYYMMDD.

    /// </summary>

    /// <param name="_input">Date input value; use today's date, if input is empty.</param>

    /// <returns>Returns the date input value in the string format YYYYMMDD.</returns>

    public static str YYYYMMDD(Date _input = DateTimeUtil::date(DateTimeUtil::getSystemDateTime()))

    {

        str dateString;

        

        dateString  = date2str(_input,

                                321,

                                DateDay::Digits2,

                                DateSeparator::None,

                                DateMonth::Digits2,

                                DateSeparator::None,

                                DateYear::Digits4);


        return dateString;

    }


    /// <summary>

    /// Convert the time input value to the string format hhmmss.

    /// </summary>

    /// <param name="_input">Time input value; use the current time, if the input is empty.</param>

    /// <returns>Returns the time input value in the string format hhmmss.</returns>

    public static str hhmmss(TimeOfDay _input = DateTimeUtil::time(DateTimeUtil::getSystemDateTime()))

    {

        str timeValue;

        str timeString;

        

        timeValue   = time2str( _input,

                            TimeSeparator::Dot,

                            TimeFormat::Hour24);


        timeString  =   substr(timeValue,1,2) +

                    substr(timeValue,4,2) +

                    substr(timeValue,7,2);


        return  timeString;

    }


    /// <summary>

    /// Convert the date and time input to the string format YYYYMMDD_hhmmss.

    /// </summary>

    /// <param name="_input">Date and time input value; use the current system date and time, if the input is empty.</param>

    /// <returns>Returns the date and time input in the string format YYYYMMDD_hhmmss.</returns>

    public static str YYYYMMDD_hhmmss(utcdatetime _dateTime = DateTimeUtil::getSystemDateTime())

    {

        Date        dateValue;

        TimeOfDay   timeValue;

        

        dateValue = DateTimeUtil::date(_dateTime);

        timeValue = DateTimeUtil::time(_dateTime);


        return strfmt('%1_%2', Global::YYYYMMDD(dateValue), Global::hhmmss(timeValue));

    }


    /// <summary>

    /// Convert the date and time input to the string format YYMMDD.

    /// </summary>

    /// <param name="_input">Date and time input value; use the current system date and time, if the input is empty.</param>

    /// <returns>Returns the date and time input in the string format YYMMDD.</returns>

    static str YYMMDD(Date _input = DateTimeUtil::date(DateTimeUtil::getSystemDateTime()))

    {

        str dateString;

        

        dateString  = date2str(_input,

                                321,

                                DateDay::Digits2,

                                DateSeparator::None,

                                DateMonth::Digits2,

                                DateSeparator::None,

                                DateYear::Digits2);


        return dateString;

    }


    public static date getCompanyDate(utcdatetime _input = DateTimeUtil::utcNow())

    {

        return DateTimeUtil::date(DateTimeUtil::applyTimeZoneOffset(_input, DateTimeUtil::getCompanyTimeZone()));

    }


    static str removeTabLineBreaks(str _input)

    {

        #File


        _input  = strreplace(_input, #delimiterEnter, #delimiterSpace);

        _input  = strreplace(_input, #delimiterTab, #delimiterSpace);

        _input  = strreplace(_input, #delimiterCRLF, #delimiterSpace);


        return _input;

    }


public static void setVisibilityForControls(FormRun _formrun, List _listOfControls, boolean isVisible)

    {

        if (_formrun && _listOfControls && !_listOfControls.empty())

        {

            ListIterator iterator = new ListIterator(_listOfControls);

            while(iterator.more())

            {

                FormControlName controlName = iterator.value();

                FormControl control = Global::getFormControl(_formrun, controlName);

                if (Control)

                {

                    control.visible(isVisible);

                }


                iterator.next();

            }

        }

    }


    private static FormControl getFormControl(FormRun _formrun, FormControlName _controlName)

    {

        return _formrun != null ? _formrun.control(_formrun.controlId(_controlName)) : null;

    }



Friday, September 9, 2022

Online store transaction new field flow to Sales order in D365FO

Set extension property for commerce order 

using Microsoft.Dynamics.Commerce.Runtime.Services.CustomerOrder;

using Microsoft.Dynamics.Commerce.Runtime.DataModel;

/// <summary>

/// Extension of <b>RetailTransactionTransformer</b> class

/// </summary>

[ExtensionOf(classStr(RetailTransactionTransformer))]

final class RetailTransactionTransformerCls_POL_Extension

{

/// <summary>

    /// Convert retail sales transaction into <b>ItemInfo</b> object

    /// </summary>

    public static ItemInfo ReadOneTransactionSalesTrans(RetailTransactionTable transactionTable, RetailTransactionSalesTrans salesTrans)

    {

        ItemInfo itemInfo = next ReadOneTransactionSalesTrans(transactionTable, salesTrans);

        ExtensionPropertyCollection extensionPropertyCollection = itemInfo.ExtensionProperties;

        CommerceProperty splitPropery = new Microsoft.Dynamics.Commerce.Runtime.DataModel.CommerceProperty(fieldStr(RetailTransactionSalesTrans, <CustomField>), enum2int(salesTrans.<CustomField>));

        CommerceProperty comment            = new Microsoft.Dynamics.Commerce.Runtime.DataModel.CommerceProperty(fieldStr(RetailTransactionSalesTrans, comment), salesTrans.comment);

        extensionPropertyCollection.Add(splitPropery );

        extensionPropertyCollection.Add(comment);

        return itemInfo;

    }


    /// <summary>

    /// This method is used to read sales transactions for return.

    /// </summary>

    public static ItemInfo ReadOneTransactionSalesTransForReturn(

                RetailTransactionTable transactionTable,

                RetailTransactionSalesTrans salesTrans)

    {

        ItemInfo itemInfo = next ReadOneTransactionSalesTransForReturn(transactionTable, salesTrans);


        ExtensionPropertyCollection extensionPropertyCollection = itemInfo.ExtensionProperties;


        CommerceProperty customLineNumber   = new Microsoft.Dynamics.Commerce.Runtime.DataModel.CommerceProperty(fieldStr(RetailTransactionSalesTrans, customPortalLineNum), salesTrans.customPortalLineNum);        

        extensionPropertyCollection.Add(customLineNumber   );

        return itemInfo;

    }


    /// <summary>

    /// Convert a transaction data into customer order info.

    /// </summary>

    public static CustomerOrderInfo ConvertTransactionToCustomerOrderInfo(RetailTransactionTable transactionTable)

    {

        CustomerOrderInfo customerOrderInfo =  next ConvertTransactionToCustomerOrderInfo(transactionTable);

        var extensionPropertyCollection = customerOrderInfo.ExtensionProperties;

        CommerceProperty custPurchaseOrder  = new Microsoft.Dynamics.Commerce.Runtime.DataModel.CommerceProperty(fieldStr(RetailTransactionTable, CustPurchaseOrder), transactionTable.CustPurchaseOrder);

        CommerceProperty  isImport= new Microsoft.Dynamics.Commerce.Runtime.DataModel.CommerceProperty(fieldStr(RetailTransactionTable, isImport), enum2Str(transactionTable.isImport));        

        extensionPropertyCollection.Add(custPurchaseOrder);

        extensionPropertyCollection.Add(isImport);

        return customerOrderInfo;

    }

}


using Microsoft.Dynamics.Commerce.Runtime.Services.CustomerOrder;

/// <summary>

    /// To update sales order while creating through sync orders from retail

    /// </summary>

    [SubscribesTo(classStr(RetailTransactionServiceOrders), staticDelegateStr(RetailTransactionServiceOrders, beforeCreatingRetailOrderLines))]

    public static void RetailTransactionServiceOrders_beforeCreatingRetailOrderLines(SalesTable _salesTable, Microsoft.Dynamics.Commerce.Runtime.Services.CustomerOrder.CustomerOrderInfo _customerOrderInfo)

    {

        var extensionPropertyCollection = _customerOrderInfo.ExtensionProperties;

        Microsoft.Dynamics.Commerce.Runtime.DataModel.CommercePropertyValue propertyValue;

        boolean                 update = false;

        for (int i=0; i < extensionPropertyCollection.get_Count(); i++)

        {

            var commerceProperty = extensionPropertyCollection.get_Item(i) as Microsoft.Dynamics.Commerce.Runtime.DataModel.CommerceProperty;

            switch(commerceProperty.Key)

            {

                case fieldStr(RetailTransactionTable, custPurchaseOrder):

                     propertyValue = commerceProperty.Value;

                    _salesTable.PurchOrderFormNum = propertyValue.StringValue;

                    update = true;

                    break;

                case fieldStr(RetailTransactionTable, <CustomField>): //Enum

                    propertyValue = commerceProperty.Value;

                    NoYesId noYesId;

                    _salesTable.<CustomField> = str2Enum(noYesId,propertyValue.StringValue);

                    update = true;

                    break;

                case fieldStr(RetailTransactionTable, <CustomField>):

                    propertyValue = commerceProperty.Value;

                     _salesTable.<CustomField>= propertyValue.StringValue;

                    break;

            }

             

        }

        if(update)

        {

            _salesTable.doUpdate();

        }

    }

Thursday, September 8, 2022

Power Automate (Flow) Expression usage samples


Get list items from Array

item()?['weborder']

Get compose output body content

outputs('Get_file_content')?['body']

Get Blob content

outputs('Get_blob_content_using_path_(V2)')?['body']

outputs('Get_blob_content_using_path_(V2)')?['value']


Split string by comma

split(variables('<var name>'),',')


Decode CSV file from Blob DECODE URI:

split(outputs('Get_blob_content_using_path_(V2)')?['body'], decodeUriComponent('%0D%0A'))

Skip output line 1

skip(outputs('splitNewLine'),2)

Get output value from list

outputs('OutputJSON')?['WebOrderNo']

outputs('D365FOSelectOut')?['body']

Find length of array

length(body('D365FOSelectOut'))

Concat string

concat(variables('OutputArrayResult'),outputs('D365FOSelectOut')?['body'])

Append array variables (Reference Blog) using Append to array variable (Action)

https://www.enjoysharepoint.com/power-automate-array-variable/

Get output Body/Value

outputs('Lists_items_present_in_table')?['body/value']

Date time format: (Reference Blog)
https://sharepains.com/2018/11/12/formatdatetime-power-automate/


Convert: (while using HTTP request output content type is octet stream, but excepted should be in Text/csv. Follow below

Header; Add in addition to existing header
"x-ms-access-tier-inferred": true

output:
{
"$content-type":  "application/octet-stream",
"$content":  "Ww0KICB7DQogICCJyZWNlaXZlciI6ICIgMTIzODUiLA0KICAgICJwYXlsb2FkIjogIiB7J21lc3NhZ2UnOiAndGVzdCAxJyIsDQogICAgIm9wZXJhdG9yIjogIiAnRW5naW5lSWQnOiAzIiwNCiAgICAic2VuZGVyIjogIiAnUGVyc29uSWQnOiAxIg0KICB9LA0KICB7DQogICAgImlkIjogIjIiLA0KICAgICJyZWNlaXZlciI6ICIgMTIzNDciLA0KICAgICJwYXlsb2FkIjogIiB7J21lc3NhZ2UnOiAndGVzdCAyJyIsDQogICAgIm9wZXJhdG9yIjogIiAnRW5naW5lSWQnOiAzIiwNCiAgICAic2VuZGVyIjogIiAnUGVyc29uSWQnOiAyIg0KICB9DQpd"
}

then we use

string(triggerBody()) ex: string(outputs('HTTPGetBlobContent')?['body'])

Date difference:
div(sub(ticks({EndDateTime}),ticks({StartDateTime})),864000000000)
div(sub(ticks({EndDateTime}),ticks({StartDateTime})),36000000000)
div(sub(ticks({EndDateTime}),ticks({StartDateTime})),600000000)
div(sub(ticks({EndDateTime}),ticks({StartDateTime})),10000000)

Wednesday, August 17, 2022

To extend the constructor to instantiate the extended (Custom) class in D365FO


    [PostHandlerFor(classStr(<Std class name>), staticMethodStr(<Std class name>, construct))]

    public static void <Std class name>_Post_construct(XppPrePostArgs args)

    {

        <Std class name>  objCls;

        objCls= args.getReturnvalue();       

        args.setReturnValue(<Custom class name>::construct(args.getArg(identifierStr(<Argument name>)),args.getArg(identifierStr(<Argument name>))));

    }

Wednesday, July 27, 2022

Monday, July 25, 2022

Useful script for D365FO

 


Reference:

https://github.com/TrudAX/TRUDScripts/blob/master/D365FO/UsefulScripts.ps1


List:

https://github.com/d365collaborative/d365fo.tools/wiki

#MaintenanceMod

#SYNC

#INSTALL LICENCE 

#DOWNLOAD DB FROM LCS

#BACKUP TIER1

#RESTORE TIER1 DB on TIER1

#SQL update userinfo set enable= 1

#TRANSFER TO TIER2

#DEPLOY REPORTS

#RESTORE TIER2 TO TIER1

#prepare the database

#IMPORT USERS

#RUN JOB

Tuesday, July 5, 2022

Batch job clean up X++ D365FO

  Connection                      connection;

        Statement                       statement;

        SqlStatementExecutePermission   permission;

        str                             deleteStm;


        if (!Global::isSystemAdministrator())

        {

            error("@SYS130561");

            return;

        }


        connection  = new Connection();

        connection.ttsbegin();


        statement   = connection.createStatement();

        deleteStm = '(SELECT RECID FROM ' + ReleaseUpdateDB::backendTableName(tableNum(Batch)) + ' WHERE GROUPID = \'' + 'TT_BT' + '\')';

        deleteStm = 'DELETE FROM ' + ReleaseUpdateDB::backendTableName(tableNum(BatchConstraints)) + ' WHERE BATCHID IN ' + deleteStm +

            ' OR DEPENDSONBATCHID IN ' + deleteStm + ';';

        permission  = new SqlStatementExecutePermission(deleteStm);

        permission.assert();

        statement.executeUpdate(deleteStm);

        statement.close();

        CodeAccessPermission::revertAssert();


        statement   = connection.createStatement();

        deleteStm = 'DELETE FROM ' + ReleaseUpdateDB::backendTableName(tableNum(Batch)) + ' WHERE GROUPID = \'' + 'TT_BT' + '\';';

        permission  = new SqlStatementExecutePermission(deleteStm);

        permission.assert();

        statement.executeUpdate(deleteStm);

        statement.close();

        CodeAccessPermission::revertAssert();


statement   = connection.createStatement();

        deleteStm = 'DELETE FROM ' + ReleaseUpdateDB::backendTableName(tableNum(BatchJobHistory)) + ' WHERE STATUS != \'' + 3 + '\';';

        permission  = new SqlStatementExecutePermission(deleteStm);

        permission.assert();

        statement.executeUpdate(deleteStm);

        statement.close();

        CodeAccessPermission::revertAssert();


        connection.ttscommit();

        connection = null;

Wednesday, June 22, 2022

Postman Odata request for filters and Pre request script for dates

Postman: (Get request time rely on server timezone)

Request: GET ->

https://<D365FO URL>/data/BatchJobs?$filter=Status eq Microsoft.Dynamics.DataEntities.BatchStatus'Executing' and StartDate eq {{currentdate}} and StartTime gt {{currentTime}} &cross-company=true


or

https://<D365FO URL>/data/RetailTransactions?$filter=ChannelReferenceId eq '' and CustomerAccount eq '' and TransactionDate eq 2022-08-23 &cross-company=true


Pre-Request script:

var moment = require('moment');

pm.globals.set('currentdate', moment().format(("YYYY-MM-DD")));

pm.globals.set("currentTime"new Date().setTime(new Date().getTime()-10800)); (As per postman installed machine time Zone GMT)

//setting

postman.setEnvironmentVariable("currentdate", moment().format(("YYYY-MM-DD")));


Set Global variables:

var jsonData = JSON.parse(responseBody);
postman.setEnvironmentVariable("access_token"jsonData.access_token);

Select field list
&$select=CustomerAccount,OrganizationName

Test samples:
pm.test("Status code is 200"function () {
    pm.response.to.have.status(200);
});
var json = JSON.parse(responseBody);
tests["<Collection request name>"= !json.error && responseBody !== '' && responseBody !== '{}' && json.Id !== '';
postman.setEnvironmentVariable("<Global variable name>"json.AmountDue);

var json = JSON.parse(responseBody);
tests["<Collection request name>"= !json.error && responseBody !== '' && responseBody !== '{}' && json.CartLines !== '';
postman.setEnvironmentVariable("<Global variable name>"json.CartLines[0].LineId);

Tuesday, May 10, 2022

Create agreement header & lines and link with Sales order X++

            //Process Started


  select firstOnly agreementClassification

                where agreementClassification.AgreementRelationType == tableNum(SalesAgreementHeader);


            row =1;

            worksheetSysHeader = worksheets.itemFromName(worksheetHeader);

            cells = worksheetSysHeader.cells();

            do

            {

                row++;

                salesAgreementHeader = SalesAgreementHeader::findAgreementId(cells.item(row, 1).value().bStr());

                if(!salesAgreementHeader)

                {

                    salesAgreementHeader.clear();

                    salesAgreementHeader.initValue();

                    salesAgreementHeader.SalesNumberSequence   = cells.item(row, 1).value().bStr();

                    salesAgreementHeader.CustAccount   =  cells.item(row, 2).value().bStr();

                    salesAgreementHeader.initFromCustTable();

                    salesAgreementHeader.AgreementClassification = agreementClassification.RecId;

                    salesAgreementHeader.Currency  = cells.item(row, 9).value().bStr();

                    salesAgreementHeader.AgreementState = str2enum(agreementState, cells.item(row, 10).value().bStr());

                    salesAgreementHeader.DefaultAgreementLineEffectiveDate = str2Date(this.COMVariant2Str(cells.item(row, 5).value(), 0),213);

                    salesAgreementHeader.DefaultAgreementLineExpirationDate = str2Date(this.COMVariant2Str(cells.item(row, 6).value(), 0),213);


                    if (salesAgreementHeader.validateWrite())

                    {

                        salesAgreementHeader.insert();

                    }

                }

                else

                {

                    salesAgreementHeader.selectForUpdate(true);

                    salesAgreementHeader.Currency  = cells.item(row, 9).value().bStr();

                    salesAgreementHeader.AgreementState = str2enum(agreementState, cells.item(row, 10).value().bStr());

                    salesAgreementHeader.DefaultAgreementLineEffectiveDate = str2Date(this.COMVariant2Str(cells.item(row, 5).value(), 0),213);

                    salesAgreementHeader.DefaultAgreementLineExpirationDate = str2Date(this.COMVariant2Str(cells.item(row, 6).value(), 0),213);

                    if (salesAgreementHeader.validateWrite())

                    {

                        salesAgreementHeader.update();

                    }

                }


                if(salesAgreementHeader)

                {

                    if(!conFind(salesAgreementIds, salesAgreementHeader.SalesNumberSequence))

                    {

                        salesAgreementIds += salesAgreementHeader.SalesNumberSequence;

                    }


                    salesAgreementHeaderDefault = SalesAgreementHeaderDefault::findSalesAgreementHeader(salesAgreementHeader.RecId);

                    if(salesAgreementHeaderDefault)

                    {

                        salesAgreementHeaderDefault.selectForUpdate(true);

                        salesAgreementHeaderDefault.CustomerRequisitionNumber = cells.item(row, 12).value().bStr();

                        salesAgreementHeaderDefault.update();

                    }

                    else

                    {

                        salesAgreementHeaderDefault.clear();

                        salesAgreementHeaderDefault.initValue();

                        salesAgreementHeaderDefault.SalesAgreementHeader = salesAgreementHeader.RecId;

                        salesAgreementHeaderDefault.CustomerRequisitionNumber = cells.item(row, 12).value().bStr();

                        salesAgreementHeaderDefault.insert();

                    }


                    agreementHeaderDefault  = AgreementHeaderDefault::findAgreementHeader(salesAgreementHeader.RecId);

                    if(agreementHeaderDefault)

                    {

                        agreementHeaderDefault.selectForUpdate(true);

                        agreementHeaderDefault.DeliveryPostalAddress = CustTable::find(cells.item(row, 2).value().bStr()).postalAddress().RecId;

                        agreementHeaderDefault.DeliveryName = CustTable::find(cells.item(row, 2).value().bStr()).name();

                        agreementHeaderDefault.ContactPerson = cells.item(row, 4).value().bStr();

                        agreementHeaderDefault.ExternalReference = cells.item(row, 11).value().bStr();

                        agreementHeaderDefault.DeliveryTerm = cells.item(row, 8).value().bStr();

                        agreementHeaderDefault.PaymentTerms = cells.item(row, 7).value().bStr();

                        agreementHeaderDefault.ContactPersonDataAreaId = curext();

                        agreementHeaderDefault.PaymentTermsDataAreaId = curext();

                        agreementHeaderDefault.DeliveryTermDataAreaId = curext();

                        agreementHeaderDefault.ContactPersonDataAreaId = curext();

                        agreementHeaderDefault.update();

                    }

                    else

                    {

                        agreementHeaderDefault.clear();

                        agreementHeaderDefault.initValue();

                        agreementHeaderDefault.AgreementHeader = salesAgreementHeader.RecId;

                        agreementHeaderDefault.ContactPerson = cells.item(row, 4).value().bStr();

                        agreementHeaderDefault.ExternalReference = cells.item(row, 11).value().bStr();

                        agreementHeaderDefault.DeliveryTerm = cells.item(row, 8).value().bStr();

                        agreementHeaderDefault.PaymentTerms = cells.item(row, 7).value().bStr();

                        agreementHeaderDefault.DeliveryPostalAddress = CustTable::find(cells.item(row, 2).value().bStr()).postalAddress().RecId;

                        agreementHeaderDefault.DeliveryName = CustTable::find(cells.item(row, 2).value().bStr()).name();

                        agreementHeaderDefault.ContactPersonDataAreaId = curext();

                        agreementHeaderDefault.PaymentTermsDataAreaId = curext();

                        agreementHeaderDefault.DeliveryTermDataAreaId = curext();

                        agreementHeaderDefault.insert();

                    }

                }

                type = cells.item(row+1, 1).value().variantType();

            }

            while (type != COMVariantType::VT_EMPTY);


            row =1;

            cells = null;

            worksheetSysHeader = worksheets.itemFromName(worksheetLine);

            cells = worksheetSysHeader.cells();

            do

            {

                row++;

                salesAgreementHeader =  SalesAgreementHeader::findAgreementId(cells.item(row, 1).value().bStr());

                agreementHeader = AgreementHeader::find(salesAgreementHeader.RecId);


                agreementHeaderDefault = AgreementHeaderDefault::findAgreementHeader(agreementHeader.RecId);

                salesAgreementHeaderDefault = SalesAgreementHeaderDefault::findSalesAgreementHeader(salesAgreementHeader.RecId);

                if(salesAgreementHeader && agreementHeader)

                {

                     select firstonly agreementLineQty

                        where agreementLineQty.Agreement == agreementHeader.RecId

                            && agreementLineQty.ItemId == cells.item(row, 2).value().bStr();


                    if(!agreementLineQty)

                    {

                        agreementLineQty.clear();

                        agreementLineQty.initValue();

                        agreementLineQty.initFromAgreementHeader(agreementHeader);

                        agreementLineQty.Agreement = agreementHeader.RecId;

                        agreementLineQty.AgreementLineProduct   = AgreementLineProduct::Item;

                        agreementLineQty.AgreementLineType = CommitmentType::ProductQuantity;

                        agreementLineQty.ItemId = cells.item(row, 2).value().bStr();

                        agreementLineQty.initFromInventTable();

                        inventDim = agreementLineQty.inventDim();

                        switch (agreementLineQty.agreementModuleType())

                        {

                            case ModuleSalesPurch::Sales:

                                inventDim.initFromInventTable(agreementLineQty.inventTable(), InventItemOrderSetupType::Sales, inventDim);

                                break;


                            case ModuleSalesPurch::Purch:

                                inventDim.initFromInventTable(agreementLineQty.inventTable(), InventItemOrderSetupType::Purch, inventDim);

                                break;

                        }

                        inventDim.InventDimId = InventDim::findOrCreate(inventDim).InventDimId;

                        agreementLineQty.setInventDimId(inventDim.InventDimId);

                        agreementLineQty.InventDimDataAreaId = curext();

                        agreementLineQty.ExpirationDate = str2Date(this.COMVariant2Str(cells.item(row, 14).value(), 0),213);

                        agreementLineQty.CommitedQuantity =  str2num(this.COMVariant2Str(cells.item(row, 4).value(), 2));

                        agreementLineQty.ProductUnitOfMeasure = cells.item(row, 5).value().bStr();

                        agreementLineQty.PricePerUnit = str2num(this.COMVariant2Str(cells.item(row, 6).value(), 2));

                        agreementLineQty.LineDiscountAmount =str2num(this.COMVariant2Str(cells.item(row, 7).value(), 2));

                        agreementLineQty.LineDiscountPercent =str2num(this.COMVariant2Str(cells.item(row, 8).value(), 2));

                        agreementLineQty.LineNumber = AgreementLine::lastLineNum(agreementHeader.RecId) + 1;

                        if (agreementLineQty.validateWrite())

                        {

                            agreementLineQty.insert();

                            agreementLineQty.salesAgreementHeader().update();

                        }

                    }

                    else

                    {

                        agreementLineQty.selectForUpdate(true);

                        agreementLineQty.ExpirationDate = str2Date(this.COMVariant2Str(cells.item(row, 14).value(), 0),213);

                        agreementLineQty.CommitedQuantity =  str2num(this.COMVariant2Str(cells.item(row, 4).value(), 2));

                        agreementLineQty.ProductUnitOfMeasure = cells.item(row, 5).value().bStr();

                        agreementLineQty.PricePerUnit = str2num(this.COMVariant2Str(cells.item(row, 6).value(), 2));

                        agreementLineQty.LineDiscountAmount =str2num(this.COMVariant2Str(cells.item(row, 7).value(), 2));

                        agreementLineQty.LineDiscountPercent =str2num(this.COMVariant2Str(cells.item(row, 8).value(), 2));

                        agreementLineQty.update();


                        agreementLineQty.salesAgreementHeader().update();

                    }


                    

                    if(agreementLineQty)

                    {

                        agreementLineDefault = AgreementLineDefault::findAgreementLine(agreementLineQty.RecId);

                        if(!agreementLineDefault)

                        {

                            agreementLineDefault.clear();

                            agreementLineDefault.initValue();

                            agreementLineDefault.AgreementLine = agreementLineQty.RecId;

                            agreementLineDefault.initFromAgreementHeaderDefault(agreementHeaderDefault);

                            agreementLineDefault.initFromSalesAgreementHeaderDefault(salesAgreementHeaderDefault);

                            agreementLineDefault.insert();

                        }

                    }

                }

                else

                {

                    info(strFmt("%1 Invalid sales agreement header reference",cells.item(row, 1).value().bStr()));

                }

                type = cells.item(row+1, 1).value().variantType();

            }

            while (type != COMVariantType::VT_EMPTY);


            row =1;

            cells = null;

            worksheetSysHeader = worksheets.itemFromName(worksheetRef);

            cells = worksheetSysHeader.cells();

            do

            {

                row++;

                salesAgreementHeader.clear();

                agreementHeader.clear();

                salesAgreementHeader =  SalesAgreementHeader::findAgreementId(cells.item(row, 1).value().bStr());

                agreementHeader = AgreementHeader::find(salesAgreementHeader.RecId);

                

                agreementLine.clear();

                select firstOnly agreementLine

                    where agreementLine.Agreement == agreementHeader.RecId

                        && agreementLine.ItemId == cells.item(row, 3).value().bStr();

                

                if(agreementLine)

                {

                    salesLine.clear();

                    select firstOnly salesLine

                        where salesLine.SalesId == cells.item(row, 2).value().bStr()

                            && salesLine.ItemId == cells.item(row, 3).value().bStr(); 

                    if(salesLine)

                    {

                        salesTable = salesLine.salesTable();

                        if(salesTable)

                        {

                            salesTable.selectForUpdate(true);

                            salesTable.initFromSalesAgreementHeader(salesAgreementHeader);

                            salesTable.update();

                        }

                        SalesTableForm::createAgreementLinkServer(salesLine, agreementLine);

                    }

                    else

                    {

                        info(strFmt("%1 %2 combination of Sales order and item number doesnot exist", 

                        cells.item(row, 2).value().bStr(),

                        cells.item(row, 3).value().bStr()));

                    }

                }

                else

                {

                    info(strFmt("%1 %2 combination of Sales agreement and item number doesnot exist", 

                        cells.item(row, 1).value().bStr(),

                        cells.item(row, 3).value().bStr()));

                }

                type = cells.item(row+1, 1).value().variantType();

            }

            while (type != COMVariantType::VT_EMPTY);


            ttsCommit;

            //Process ended

WMS Mobile app flow - Adding Detour fields for Process guided framework custom implementation

 WMS Mobile app flow => Adding Detour fields for Process guided framework custom implementation Before fix: Adding code fix to get thos r...