Showing posts with label batch jobs. Show all posts
Showing posts with label batch jobs. Show all posts

Tuesday, May 25, 2021

Set Financial Dimensions by X++ code in AX 2012/Setting one Dimension value in the combination

    /// <summary>
    /// replace specific financial dimension value in DefaultDimension based on the LedgerParameters setup
    /// </summary>
    /// <param name = "_defaultDimensionFrom">DefaultDimension recId the value should be taken from</param>
    /// <param name = "_defaultDimensionTo">DefaultDimension recId the value should be assigned to</param>
    /// <returns>returns new DefaultDimension recId if conditions are met</returns>
    public static DimensionDefault replaceDefaultDim(DimensionDefault _defaultDimensionFrom, DimensionDefault _defaultDimensionTo)
    {
        if(!_defaultDimensionFrom)
        {
            return _defaultDimensionTo;
        }

        LedgerParameters ledgerParameters = LedgerParameters::find();

        if (ledgerParameters.DepartmentSetFinancialDimension &&
            ledgerParameters.DepartmentDimensionAttribute)
        {
            DimensionAttribute                  dimAttr;
            DimensionAttributeValue             dimAttrValue;
            DimensionAttributeValueSetStorage   davss;

            davss = DimensionAttributeValueSetStorage::find(_defaultDimensionTo);

            dimAttr = DimensionAttribute::find(ledgerParameters.DepartmentDimensionAttribute);

            DimensionAttributeValueSetStorage dimStorage = DimensionAttributeValueSetStorage::find(_defaultDimensionFrom);
            DimensionValue dimValue = dimStorage.getDisplayValueByDimensionAttribute(dimAttr.RecId);

            dimAttrValue = DimensionAttributeValue::findByDimensionAttributeAndValue(dimAttr, dimValue);

            if(dimAttrValue && !davss.containsDimensionAttributeValue(dimAttrValue.RecId))
            {
                davss.addItem(dimAttrValue);

                return davss.save();
            }
        }

        return _defaultDimensionTo;
    }

Monday, April 26, 2021

UserConnection in D365fo

Its used when we need to commit our transaction wehen standared code doesn't Commit.
example :SalesQuotationEditLinesForm_Sales_Send > checkSales() , COC and try to write 
custom insert or update operation here while validation is failed our transactions doesn't commit

static void KlForRecordInserted(Args _args)
{
    UserConnection userConnection;
    CustTable custTable;
    ;
   
    ttsbegin;
   
    userConnection = new userConnection();
   
    custTable.clear();
    custTable.initValue();
    custTable.AccountNum = "000020";
    custTable.Name = "My Test Customer";
    custTable.setConnection(userConnection); // set userconnection
    custTable.insert();
   
    throw error("An error that causes a rollback");
    ttscommit;
}

Saturday, April 24, 2021

Sysoperations frameworks Tips and tricks in AX

    protected ClassDescription defaultCaption()
    {
        return "@CashManagement:CashFlowTimeSeriesInitializeControllerCaption";
    }

    public ClassDescription caption()
    {
        return this.defaultCaption();
    }

    /// <summary>
    /// Indicates if the class must run in batch or not.
    /// </summary>
    /// <returns>
    /// Always returns false.
    /// </returns>
    /// <remarks>
    /// This method must be in this class because it is called from the <c>dialogRunbase</c> class.
    /// </remarks>
    public boolean mustGoBatch()
    {
        return false;
    }

    /// <summary>
    /// Determines whether the job can be executed in batch.
    /// </summary>
    /// <returns>
    /// false if the job cannot be executed in batch; otherwise, true.
    /// </returns>
    public boolean canGoBatch()
    {
        return false;
    }

    /// <summary>
    /// Sets whether to show the batch tab or not.
    /// </summary>
    /// <param name = "_showBatchTab">Flag to identify whether to show the batch tab or not.</param>
    /// <returns>False for batch tab to be invisible</returns>
    public boolean showBatchTab(boolean _showBatchTab = showBatchTab)
    {
        return false;
    }
	
	public boolean showBatchRecurrenceButton(boolean _showBatchRecurrenceButton = showBatchRecurrenceButton)
    {
        return false;
    }

Thursday, April 22, 2021

How to get the number of elements in the list in AX

{ 
    List il = new List(Types::Integer); 
 
    il.addStart(1); 
    il.addStart(2); 
    il.addStart(3); 
    if (il.elements() != 3) 
    { 
        print "Something is wrong..."; 
    } 
}

Tuesday, April 13, 2021

How to use RecordInsertList in AX

/// <summary>
/// The <c>BankCheckStubDP</c> class declares the variables and tables that are required for the
/// <c>BankCheckStub</c> report.
/// </summary>
[
    SRSReportParameterAttribute(classStr(BankCheckStubContract))
]
public class BankCheckStubDP extends SRSReportDataProviderBase
{
    BankCheckStubTmp  BankCheckStubTmp;
    /// <summary>
    ///    Fetches the <c>BankCheckStubTmp</c> temporary table.
    /// </summary>
    /// <returns>
    ///    The <c>BankCheckStubTmp</c> temporary table.
    /// </returns>
    [
        SRSReportDataSetAttribute(tablestr(BankCheckStubTmp))
    ]
    public BankCheckStubTmp getBankCheckStubTmp()
    {
        select  BankCheckStubTmp;
    
        return  BankCheckStubTmp;
    }

    /// <summary>
    ///    Fetches the required data for the <c>BankCheckStub</c> report.
    /// </summary>
    public void processReport()
    {
        RecordInsertList            tmpTableRecordList;
        BankTrans             BankTrans;
        BankChequeTable             bankChequeTable;
        CompanyBankAccountId        curBankAccountIdGroup;
        BankChequeNum               curChequeNumGroup;
        int                         lineNumInCheck;
        RefRecId                    SSNType;
        HcmIdentificationNumber     BankSSN;
    
        BankCheckStubContract contract        = this.parmDataContract() as BankCheckStubContract;
        BankChequeNum               chequeNum       = contract.parmChequeNum();
        TransDate                   transDate       = contract.parmChequeDate();
        CompanyBankAccountId        bankAccountId   = contract.parmBankAccountId();
        ShowSSN                  showSSN         = contract.parmShowSSN();
    
        tmpTableRecordList = new RecordInsertList(tableNum(BankCheckStubTmp), true, true, true, false, true, BankCheckStubTmp);
    
        SSNType = BankAccountingParameters::find().SSNIdentificationType;
        if (!Global::hasTableAccess(tableNum(HcmPersonIdentificationNumber))
        ||  !Global::hasFieldAccess(tableNum(HcmPersonIdentificationNumber), fieldNum(HcmPersonIdentificationNumber, IdentificationNumber)))
        {
            showSSN = false;
        }
    
        while select BankTrans order by BankAccountId, BankChequeNum
            where (BankTrans.JournalEntryType == JournalEntryType::Refund
              ||   BankTrans.JournalEntryType == JournalEntryType::Stipend
              ||   BankTrans.JournalEntryType == JournalEntryType::SubsidiaryRefund)
              &&   BankTrans.SISPaymentType   == SISPaymentType::Check
              &&   BankTrans.BankChequeNum
              &&  (!chequeNum     || (chequeNum     && BankTrans.BankChequeNum  == chequeNum))
              &&  (!bankAccountId || (bankAccountId && BankTrans.BankAccountId  == bankAccountId))
            join TransDate from bankChequeTable
                where bankChequeTable.AccountID     == BankTrans.BankAccountId
                  &&  bankChequeTable.ChequeNum     == BankTrans.BankChequeNum
                  && (!transDate  || (transDate     && bankChequeTable.TransDate == transDate))
        {
            if (curBankAccountIdGroup != BankTrans.BankAccountId || curChequeNumGroup != BankTrans.BankChequeNum)
            {
                curBankAccountIdGroup = BankTrans.BankAccountId;
                curChequeNumGroup     = BankTrans.BankChequeNum;
                lineNumInCheck        = 1;
            }
    
            BankSSN  = "";
            if (showSSN)
            {
                BankSSN  = HcmPersonIdentificationNumber::findByPersonAndType(Bank::find(BankTrans.Bank).Person, SSNType).IdentificationNumber;
            }
    
            BankCheckStubTmp.BankAccountId   = BankTrans.BankAccountId;
            BankCheckStubTmp.ChequeNum       = BankTrans.BankChequeNum;
            BankCheckStubTmp.ChequeDate      = bankChequeTable.TransDate;
            BankCheckStubTmp.LineNum         = strFmt('%1', lineNumInCheck);
            BankCheckStubTmp.BankId       = strFmt('%1', BankTrans.BankIdInSIS);
            BankCheckStubTmp.BankName     = BankTrans.BankName();
            BankCheckStubTmp.BankSSN      = BankSSN;
            BankCheckStubTmp.FundSource      = FundSource::findByRecId(BankTrans.FundSource).Description;
            BankCheckStubTmp.Amount          = BankTrans.AmountCur;
    
            tmpTableRecordList.add(BankCheckStubTmp);
            lineNumInCheck++;
        }
    
        tmpTableRecordList.insertDatabase();
    }
}

How to create RunBaseBatch class in AX : Sample code

See the code

/// <summary>
///    The <c>LedgerJournalEntryPost</c> class creates and posts to general ledger transactions specified in
///    the <c>LedgerJournalEntryContract</c> contract class.
/// </summary>
class LedgerJournalEntryPost extends RunBaseBatch
{
    LedgerJournalEntryContract           ledgerJournalEntryContract;
    LedgerJournalEntryPostStatusContract ledgerJournalEntryPostStatusContract;
    Set                                     studentTransRecIdPostedSet;

    #IntegrationServiceFaults
    /// <summary>
    ///     Checks if the Ledger journal can be posted or not.
    /// </summary>
    /// <param name="_ledgerJournalTable">
    ///     Record of the <c>LedgerJournalTable</c> table to verify.
    /// </param>
    /// <returns>
    ///     True if Ledger journal can be posted; otherwise, false.
    /// </returns>
    protected boolean canPostLedgerJournal(LedgerJournalTable  _ledgerJournalTable)
    {
        LedgerJournalTrans  ledgerJournalTrans;
        VendPaymModeTable   vendPaymModeTable;
    
        select firstOnly RecId from ledgerJournalTrans
            where ledgerJournalTrans.JournalNum == _ledgerJournalTable.JournalNum;
    
        if (!ledgerJournalTrans.RecId)
        {
            return false;
        }
    
        if (_ledgerJournalTable.JournalType == LedgerJournalType::Payment)
        {
            select firstOnly RecId from ledgerJournalTrans
                where ledgerJournalTrans.JournalNum        == _ledgerJournalTable.JournalNum
                 &&   ledgerJournalTrans.AccountType       == LedgerJournalACType::Vend
                 &&   ledgerJournalTrans.OffsetAccountType == LedgerJournalACType::Bank
                 &&  (!ledgerJournalTrans.BankChequeNum
                 ||  ledgerJournalTrans.PaymentStatus      != CustVendPaymStatus::Sent)
            exists join vendPaymModeTable
                where vendPaymModeTable.PaymMode        == ledgerJournalTrans.PaymMode
                   && vendPaymModeTable.PaymentType     == PaymentType::Check;
    
            if(ledgerJournalTrans.RecId)
            {
                return false;
            }
        }
    
        return true;
    }

    /// <summary>
    ///     Creates a ledger journal for the specified ledger journal entry.
    /// </summary>
    /// <param name="_ledgerJourEntryLines">
    ///     List of <c>LedgerJournalEntryLineContract</c> contract classes.
    /// </param>
    /// <param name="_journalEntryType">
    ///     The type of the journal to create.
    /// </param>
    /// <returns>
    ///     Created <c>LedgerJournalTable</c> table.
    /// </returns>
    protected LedgerJournalTable createJournal(List                 _ledgerJourEntryLines,
                                               JournalEntryType  _journalEntryType)
    {
        LedgerJournalTable              ledgerJournalTable;
        LedgerJournalCreate          ledgerJournalCreate;
        LedgerJournalEntryContract   entryContract;
    
        entryContract = new LedgerJournalEntryContract();
        entryContract.parmLedgerJourEntryLines(_ledgerJourEntryLines);
    
        ledgerJournalCreate = LedgerJournalCreate::construct(entryContract, _journalEntryType);
        ledgerJournalCreate.run();
    
        ledgerJournalTable = ledgerJournalCreate.parmLedgerJournalTable();
    
        return  ledgerJournalTable;
    }

    /// <summary>
    ///     Finds or creates a ledger journal for the specified ledger journal entry.
    /// </summary>
    /// <param name="_ledgerJourEntryLines">
    ///     List of <c>LedgerJournalEntryLineContract</c> contract classes.
    /// </param>
    /// <param name="_journalEntryType">
    ///     The type of the journal entry.
    /// </param>
    /// <param name="_paymentType">
    ///     The payment type of the journal entry.
    /// </param>
    /// <returns>
    ///     Found or created <c>LedgerJournalTable</c> table.
    /// </returns>
    protected LedgerJournalTable findOrCreateJournal(List                 _ledgerJourEntryLines,
                                                     JournalEntryType  _journalEntryType,
                                                     SISPaymentType    _paymentType)
    {
        LedgerJournalTable  ledgerJournalTable;
    
        ledgerJournalTable = this.findRelatedJournal(_ledgerJourEntryLines, _journalEntryType, _paymentType);
    
        if (!ledgerJournalTable)
        {
            ledgerJournalTable = this.createJournal(_ledgerJourEntryLines, _journalEntryType);
        }
    
        return  ledgerJournalTable;
    }

    /// <summary>
    ///     Finds the ledger journal for the specified ledger journal entry.
    /// </summary>
    /// <param name="_ledgerJourEntryLines">
    ///     List of <c>LedgerJournalEntryLineContract</c> contract classes.
    /// </param>
    /// <param name="_journalEntryType">
    ///     The type of the journal entry.
    /// </param>
    /// <param name="_paymentType">
    ///     The payment type of the journal entry.
    /// </param>
    /// <returns>
    ///     Found <c>LedgerJournalTable</c> table.
    /// </returns>
    protected LedgerJournalTable findRelatedJournal(List                 _ledgerJourEntryLines,
                                                    JournalEntryType  _journalEntryType,
                                                    SISPaymentType    _paymentType)
    {
        LedgerJournalEntryLineContract   ledgerJournalEntryLineContract;
        ListEnumerator                      ledgerJourEntryLinesEnum;
        LedgerJournalTable                  ledgerJournalTable;
    
        if (StudentTrans::isBankChequeProcess(_journalEntryType, _paymentType))
        {
            ledgerJourEntryLinesEnum = _ledgerJourEntryLines.getEnumerator();
    
            while (ledgerJourEntryLinesEnum.moveNext())
            {
                ledgerJournalEntryLineContract = ledgerJourEntryLinesEnum.current();
    
                //if (ledgerJournalEntryLineContract.parmBankChequeNum())
                //{
                ledgerJournalTable = ledgerJournalTable.FindByStudentTransIdInSIS(ledgerJournalEntryLineContract.parmTransIdInSIS(),
                                                                                        ledgerJournalEntryLineContract.parmJournalEntryType());
                if (ledgerJournalTable)
                {
                    return  ledgerJournalTable;
                }
                //}
            }
        }
    
        return  ledgerJournalTable;
    }

    /// <summary>
    ///     Initializes the map of transaction types and transactions from
    ///     the <c>LedgerJournalEntryContract</c> contract class.
    /// </summary>
    /// <returns>
    ///     An instance of the map of transaction types and transactions.
    /// </returns>
    public Map getJournalEntryLinesMap()
    {
        List                              entryLineList;
        ListEnumerator                    ledgerJournalEntryLinesEnum;
        LedgerJournalEntryLineContract entryLineContract;
        container                         entryTypeKeyCon;
        int                               transGroupCounter;
        Map                               entryLinesMap = new Map(Types::Container, Types::Class);
    
        #define.TransGroupUniqueIdentifier("TransGroupUniqueIdentifier")
    
        ledgerJournalEntryLinesEnum     = ledgerJournalEntryContract.parmLedgerJourEntryLines().getEnumerator();
    
        while (ledgerJournalEntryLinesEnum.moveNext())
        {
            entryLineContract = ledgerJournalEntryLinesEnum.current();
    
            if (StudentTrans::isBankChequeProcess(entryLineContract.parmJournalEntryType(), entryLineContract.parmSISPaymentType())
             && entryLineContract.parmMasterChequeGroup())
            {
                entryTypeKeyCon = [entryLineContract.parmJournalEntryType(), entryLineContract.parmSISPaymentType(), entryLineContract.parmMasterChequeGroup()];
            }
            else
            {
                transGroupCounter++;
                entryTypeKeyCon = [entryLineContract.parmJournalEntryType(), entryLineContract.parmSISPaymentType(), strFmt("%1%2", #TransGroupUniqueIdentifier, transGroupCounter)];
            }
    
            if (!entryLinesMap.exists(entryTypeKeyCon))
            {
                entryLineList = new List(Types::Class);
                entryLineList.addEnd(entryLineContract);
    
                entryLinesMap.insert(entryTypeKeyCon, entryLineList);
            }
            else
            {
                entryLineList = entryLinesMap.lookup(entryTypeKeyCon);
                entryLineList.addEnd(entryLineContract);
    
                entryLinesMap.insert(entryTypeKeyCon, entryLineList);
            }
        }
    
        return entryLinesMap;
    }

    /// <summary>
    ///    Gets student transaction SIS Ids.
    /// </summary>
    /// <param name="_ledgerJourEntryLines">
    ///     List of <c>LedgerJournalEntryLineContract</c> contract classes.
    /// </param>
    /// <returns>
    ///     Container of student transaction SIS Ids.
    /// </returns>
    protected container getStudentTransIds(List _ledgerJourEntryLines)
    {
        LedgerJournalEntryLineContract   ledgerJournalEntryLineContract;
        container                           ret;
        ListEnumerator                      ledgerJournalEntryLinesEnum = _ledgerJourEntryLines.getEnumerator();
    
        while (ledgerJournalEntryLinesEnum.moveNext())
        {
            ledgerJournalEntryLineContract = ledgerJournalEntryLinesEnum.current();
    
            ret += ledgerJournalEntryLineContract.parmTransIdInSIS();
        }
    
        return  ret;
    }

    /// <summary>
    ///     Initializes <c>LedgerJournalEntryPostStatusContract</c> contract class.
    /// </summary>
    protected void initEntryPostStatusContract()
    {
        ledgerJournalEntryPostStatusContract = new LedgerJournalEntryPostStatusContract();
        ledgerJournalEntryPostStatusContract.parmPostedJournals(new List(Types::String));
        ledgerJournalEntryPostStatusContract.initializeMessages();
    }

    public static void markPostedTrans(Map _postedTransMap)
    {
        new SISIntegrationServiceAdapter().sendPostedStudentTrans(_postedTransMap);
    }

    public void new()
    {
        super();
    
        studentTransRecIdPostedSet = new Set(Types::Int64);
    }

    /// <summary>
    ///     Gets or sets the value of the <c>LedgerJournalEntryContract</c> class parameter.
    /// </summary>
    /// <param name="_ledgerJournalEntryContract">
    ///     The new value of the <c>LedgerJournalEntryContract</c> class parameter; optional.
    /// </param>
    /// <returns>
    ///     The current value of the <c>LedgerJournalEntryContract</c> class parameter.
    /// </returns>
    public LedgerJournalEntryContract parmLedgerJournalEntryContract(LedgerJournalEntryContract _ledgerJournalEntryContract = ledgerJournalEntryContract)
    {
        ledgerJournalEntryContract = _ledgerJournalEntryContract;
        return ledgerJournalEntryContract;
    }

    /// <summary>
    ///     Gets or sets the value of the <c>LedgerJournalEntryPostStatusContract</c> class parameter.
    /// </summary>
    /// <param name="_ledgerJournalEntryPostStatusContract">
    ///     The new value of the <c>LedgerJournalEntryPostStatusContract</c> class parameter; optional.
    /// </param>
    /// <returns>
    ///     The current value of the <c>LedgerJournalEntryPostStatusContract</c> class parameter.
    /// </returns>
    public LedgerJournalEntryPostStatusContract parmLedgerJournalEntryPostStatusContract(LedgerJournalEntryPostStatusContract _ledgerJournalEntryPostStatusContract = ledgerJournalEntryPostStatusContract)
    {
        ledgerJournalEntryPostStatusContract = _ledgerJournalEntryPostStatusContract;
        return  ledgerJournalEntryPostStatusContract;
    }

    /// <summary>
    ///     Gets or sets the value of the <c>studentTransRecIdPostedSet</c> parameter.
    /// </summary>
    /// <param name="_studentTransRecIdPostedSet">
    ///     The new value of the <c>studentTransRecIdPostedSet</c> parameter; optional.
    /// </param>
    /// <returns>
    ///     The current value of the <c>studentTransRecIdPostedSet</c> parameter.
    /// </returns>
    public Set parmStudentTransRecIdPostedSet(Set _studentTransRecIdPostedSet = studentTransRecIdPostedSet)
    {
        studentTransRecIdPostedSet = _studentTransRecIdPostedSet;
        return studentTransRecIdPostedSet;
    }

    /// <summary>
    ///     Posts the ledger journal.
    /// </summary>
    /// <param name="_ledgerJournalTable">
    ///     Ledger journal to post.
    /// </param>
    protected void postJournal(LedgerJournalTable   _ledgerJournalTable)
    {
        LedgerJournalCheckPost  ledgerJournalCheckPost;
        LedgerJournalTable      ledgerJournalTable;
    
        if (!_ledgerJournalTable)
        {
            throw error("@1401");
        }
    
        ledgerJournalCheckPost = LedgerJournalCheckPost::newLedgerJournalTable(_ledgerJournalTable, NoYes::Yes);
    
        if (this.canPostLedgerJournal(_ledgerJournalTable))
        {
            ledgerJournalCheckPost.parmSkipBlockedForManualEntryCheck(true);
            ledgerJournalCheckPost.runOperation();
        }
    
        ledgerJournalTable = ledgerJournalTable::find(_ledgerJournalTable.JournalNum);
    
        if (!ledgerJournalTable.Posted)
        {
            throw error("@1402");
        }
    }

    /// <summary>
    ///    Posts student transactions.
    /// </summary>
    /// <param name="_journalNum">
    ///     Ledger journal Id.
    /// </param>
    /// <param name="_ledgerJourEntryLines">
    ///     List of <c>LedgerJournalEntryLineContract</c> contract classes.
    /// </param>
    protected void postStudentTrans(LedgerJournalId   _journalNum,
                                    List              _ledgerJourEntryLines)
    {
        LedgerJournalEntryLineContract   ledgerJournalEntryLineContract;
        StudentTrans                     studentTrans;
        container                           mapKey;
        ListEnumerator                      ledgerJournalEntryLinesEnum = _ledgerJourEntryLines.getEnumerator();
        Map                                 transLedgerJournalIdMap     = new Map(Types::Container, Types::Class);
        Set                                 journalNumSet               = new Set(Types::String);
    
        journalNumSet.add(_journalNum);
    
        while (ledgerJournalEntryLinesEnum.moveNext())
        {
            ledgerJournalEntryLineContract = ledgerJournalEntryLinesEnum.current();
    
            mapKey = [ledgerJournalEntryLineContract.parmTransIdInSIS(), ledgerJournalEntryLineContract.parmJournalEntryType()];
    
            transLedgerJournalIdMap.insert(mapKey, journalNumSet);
    
            studentTrans        = StudentTrans::find(ledgerJournalEntryLineContract.parmTransIdInSIS(),
                                                        ledgerJournalEntryLineContract.parmJournalEntryType(),
                                                        true);
            studentTrans.Posted = true;
            if(studentTrans.SISPaymentType == SISPaymentType::Check)
                studentTrans.PendingChequeInSIS = false;
    
            if (!studentTrans.validateWrite())
            {
                throw error("@SYS18447");
            }
    
            studentTrans.updateSkipDatabaseLog(true);
    
            if (studentTrans.isValidForFundSourceTrans())
            {
                if (FundSourceTrans::findByStudentTrans(studentTrans.RecId))
                {
                    FundSourceTrans::updateExist(studentTrans);
                }
                else
                {
                    FundSourceTrans::create(studentTrans);
                }
            }
    
            if (StudentAccountingParameters::isCampusNexusMode())
            {
                LedgerJournalEntryPost::markPostedTrans(transLedgerJournalIdMap);
            }
    
            studentTransRecIdPostedSet.add(studentTrans.RecId);
        }
    }

    /// <summary>
    ///     Executes business logic of the class.
    /// </summary>
    public void run()
    {
        LedgerJournalTable      ledgerJournalTable;
        JournalEntryType     journalEntryType;
        SISPaymentType       paymentType;
        AifInfoLog              aifInfoLog;
        List                    ledgerJourEntryLines;
        Name                    groupName;
        boolean                 exceptionThrown;
        MapEnumerator           entryLinesMapEnum;
    
        this.initEntryPostStatusContract();
    
        entryLinesMapEnum = this.getJournalEntryLinesMap().getEnumerator();
    
        while (entryLinesMapEnum.moveNext())
        {
            [journalEntryType, paymentType, groupName]  = entryLinesMapEnum.currentKey();
            ledgerJourEntryLines                        = entryLinesMapEnum.currentValue();
            aifInfoLog                                  = new AifInfoLog();
    
            try
            {
                ttsBegin;
    
                this.validateLedgerJourEntryLines(ledgerJourEntryLines);
    
                ledgerJournalTable = this.findOrCreateJournal(ledgerJourEntryLines, journalEntryType, paymentType);
    
                this.postJournal(ledgerJournalTable);
                this.postStudentTrans(ledgerJournalTable.JournalNum, ledgerJourEntryLines);
    
                ttsCommit;
    
                if (ledgerJournalTable.Posted)
                {
                    ledgerJournalEntryPostStatusContract.parmPostedJournals().addEnd(ledgerJournalTable.JournalNum);
                }
            }
            catch (Exception::Error)
            {
                exceptionThrown = true;
                this.updateEntryPostStatus(aifInfoLog, LedgerJournalCreatePostStatus::Error, this.getStudentTransIds(ledgerJourEntryLines));
            }
            catch (Exception::CLRError)
            {
                exceptionThrown = true;
                error(AifUtil::getClrErrorMessage());
                this.updateEntryPostStatus(aifInfoLog, LedgerJournalCreatePostStatus::Error, this.getStudentTransIds(ledgerJourEntryLines));
            }
            catch
            {
                exceptionThrown = true;
                this.updateEntryPostStatus(aifInfoLog, LedgerJournalCreatePostStatus::Error, this.getStudentTransIds(ledgerJourEntryLines));
            }
        }
    
        if (!exceptionThrown && !ledgerJournalEntryPostStatusContract.parmPostedJournals().empty())
        {
            ledgerJournalEntryPostStatusContract.parmStatus(LedgerJournalCreatePostStatus::Posted);
        }
    }

    /// <summary>
    ///     Updates <c>LedgerJournalEntryPostStatusContract</c> contract class.
    /// </summary>
    /// <param name="_aifInfoLog">
    ///     An object of <c>AifInfoLog</c> class.
    /// </param>
    /// <param name="_postStatus">
    ///     Operation status.
    /// </param>
    /// <param name="_studentTransIdCon">
    ///     Container of student transaction SIS Ids.
    /// </param>
    protected void updateEntryPostStatus(AifInfoLog                         _aifInfoLog,
                                         LedgerJournalCreatePostStatus   _postStatus,
                                         container                          _studentTransIdCon)
    {
        SysInfologEnumerator infologEnum;
    
        if (!ledgerJournalEntryPostStatusContract)
        {
            this.initEntryPostStatusContract();
        }
    
        ledgerJournalEntryPostStatusContract.parmStatus(_postStatus);
    
        AifFault::fault(strFmt("@1403", "@141", con2str(_studentTransIdCon, ', ')), #LedgerJournalTableCreationFailed);
    
        infologEnum = SysInfologEnumerator::newData(_aifInfoLog.getInfoLogData());
    
        while (infologEnum.moveNext())
        {
            ledgerJournalEntryPostStatusContract.addMessage(IntegrationServiceProvider::trimLeadingTabs(infologEnum.currentMessage()));
        }
    }

    /// <summary>
    ///     Validates ledger journal entry lines.
    /// </summary>
    /// <param name="_ledgerJourEntryLines">
    ///     List of <c>LedgerJournalEntryLineContract</c> contract classes.
    /// </param>
    protected void validateLedgerJourEntryLines(List    _ledgerJourEntryLines)
    {
        LedgerJournalEntryLineContract ledgerJournalEntryLineContract;
        StudentTrans                   studentTrans;
        ListEnumerator                    ledgerJournalEntryLinesEnum = _ledgerJourEntryLines.getEnumerator();
    
        while (ledgerJournalEntryLinesEnum.moveNext())
        {
            ledgerJournalEntryLineContract = ledgerJournalEntryLinesEnum.current();
            studentTrans                    = StudentTrans::find(ledgerJournalEntryLineContract.parmTransIdInSIS(), ledgerJournalEntryLineContract.parmJournalEntryType());
    
            if (studentTrans.Posted)
            {
                throw error(strfmt("@1399", studentTrans.description()));
            }
    
            if (StudentTrans::isBankChequeProcess(studentTrans.JournalEntryType, studentTrans.SISPaymentType)
             && !studentTrans.BankChequeNum)
            {
                throw error(strFmt("@1400", studentTrans.description()));
            }
        }
    }

    /// <summary>
    ///     Creates a new instance of the <c>LedgerJournalEntryPost</c> class.
    /// </summary>
    /// <param name="_ledgerJournalEntryContract">
    ///     Value of the <c>LedgerJournalEntryContract</c> contract class.
    /// </param>
    /// <returns>
    ///    Created instance of the <c>LedgerJournalEntryPost</c> class.
    /// </returns>
    public static server LedgerJournalEntryPost construct(LedgerJournalEntryContract _ledgerJournalEntryContract)
    {
        LedgerJournalEntryPost   ledgerJournalEntryPost = new LedgerJournalEntryPost();
    
        ledgerJournalEntryPost.parmLedgerJournalEntryContract(_ledgerJournalEntryContract);
    
        return  ledgerJournalEntryPost;
    }

    /// <summary>
    ///     Creates an object of <c>LedgerJournalEntryContract</c> contract class.
    /// </summary>
    /// <param name="_studentTransRecIdPacked">
    ///     Packed set of <c>StudentTrans</c> record Ids.
    /// </param>
    /// <returns>
    ///     An object of <c>LedgerJournalEntryContract</c> contract class.
    /// </returns>
    public static server LedgerJournalEntryContract createJournalEntryContractList(container   _studentTransRecIdPacked)
    {
        StudentTrans                 studentTrans;
        StudentTrans                 studentTransMasterCheque;
        LedgerJournalEntryContract   ledgerJournalEntryContract  = new LedgerJournalEntryContract();
        Set                             masterChequeGroup           = new Set(Types::String);
        Set                             studentTransRecIdSet        = Set::create(_studentTransRecIdPacked);
        SetEnumerator                   se                          = studentTransRecIdSet.getEnumerator();
    
        ledgerJournalEntryContract.parmLedgerJourEntryLines(new List(Types::Class));
    
        while (se.moveNext())
        {
            studentTrans = StudentTrans::findRecId(se.current());
    
            if (studentTrans.MasterChequeGroup && !masterChequeGroup.in(studentTrans.MasterChequeGroup))
            {
                masterChequeGroup.add(studentTrans.MasterChequeGroup);
    
                while select studentTransMasterCheque
                    where studentTransMasterCheque.MasterChequeGroup == studentTrans.MasterChequeGroup
                {
                    ledgerJournalEntryContract.parmLedgerJourEntryLines().addEnd(studentTransMasterCheque.ledgerJournalEntryLineContract());
                }
            }
            else if (!studentTrans.MasterChequeGroup)
            {
                ledgerJournalEntryContract.parmLedgerJourEntryLines().addEnd(studentTrans.ledgerJournalEntryLineContract());
            }
        }
    
        return  ledgerJournalEntryContract;
    }

    /// <summary>
    ///     Performs transaction posting from user interface.
    /// </summary>
    /// <param name="_args">
    ///     Parameters object.
    /// </param>
    public static void main(Args _args)
    {
        LedgerJournalEntryPost   ledgerJournalEntryPost;
        StudentTrans             studentTrans;
        FormDataSource              ds;
        Set                         studentTransRecIdSet = new Set(Types::Int64);
    
        if (!_args || !_args.dataset())
        {
            throw Error(Error::wrongUseOfFunction(funcName()));
        }
    
        if (FormDataUtil::isFormDataSource(_args.record()))
        {
            ds              = FormDataUtil::getFormDataSource(_args.record());
            studentTrans    = ds.getFirst(true) ? ds.getFirst(true) : ds.cursor();
    
            while (studentTrans)
            {
                studentTransRecIdSet.add(studentTrans.RecId);
                studentTrans = ds.getNext();
            }
        }
        else
        {
            studentTrans = _args.record();
            studentTransRecIdSet.add(studentTrans.RecId);
        }
    
        ledgerJournalEntryPost = LedgerJournalEntryPost::newFromLedgerJournalEntryContract(LedgerJournalEntryPost::createJournalEntryContractList(studentTransRecIdSet.pack()));
        ledgerJournalEntryPost.runOperation();
    
        info(strFmt("@561", ledgerJournalEntryPost.parmStudentTransRecIdPostedSet().elements()));
    
        if (ds)
        {
            ds.research(true);
        }
    }

    /// <summary>
    ///     Creates a new instance of the <c>LedgerJournalEntryPost</c> class and initilizes its parameters.
    /// </summary>
    /// <param name="_ledgerJournalEntryContract">
    ///     Value of the <c>LedgerJournalEntryContract</c> contract class.
    /// </param>
    /// <returns>
    ///    Created instance of the <c>LedgerJournalEntryPost</c> class.
    /// </returns>
    public static server LedgerJournalEntryPost newFromLedgerJournalEntryContract(LedgerJournalEntryContract _ledgerJournalEntryContract)
    {
        LedgerJournalEntryPost ledgerJournalEntryPost = new LedgerJournalEntryPost();
    
        LedgerJournalEntryPost::validateLedgerJournalEntryContract(_ledgerJournalEntryContract);
    
        ledgerJournalEntryPost.parmLedgerJournalEntryContract(_ledgerJournalEntryContract);
    
        return ledgerJournalEntryPost;
    }

    /// <summary>
    ///     Validates the <c>LedgerJournalEntryContract</c> contract class.
    /// </summary>
    /// <param name="_ledgerJournalEntryContract">
    ///     An instance of the <c>LedgerJournalEntryContract</c> contract class.
    /// </param>
    public static void validateLedgerJournalEntryContract(LedgerJournalEntryContract _ledgerJournalEntryContract)
    {
        if (!_ledgerJournalEntryContract)
        {
            throw error(strFmt("@35", classStr(LedgerJournalEntryContract)));
        }
    
        if (!_ledgerJournalEntryContract.parmLedgerJourEntryLines()
         || _ledgerJournalEntryContract.parmLedgerJourEntryLines().empty())
        {
            throw error("@36");
        }
    }

    protected boolean canRunInNewSession()
    {
        return false;
    }

}

How to pass marked records from grid to sysoperations framework in AX

Controller class

/// <summary>
/// 
/// </summary>
class Sales_UpdateMoDSalesOrderController extends SysOperationServiceController
{
    public static Sales_UpdateMoDSalesOrderController construct(Args _args)
    {
        Sales_UpdateMoDSalesOrderController  controller = new Sales_UpdateMoDSalesOrderController(classStr( Sales_UpdateMoDSalesOrderService ),
                                                                                                        methodStr( Sales_UpdateMoDSalesOrderService, updateMoDSalesOrder ),
            SysOperationExecutionMode::Synchronous);

        controller.parmArgs( _args );

        return controller;
    }

    public static void main(Args _args)
    {
        Set                                     recordSet;
        SalesTable                              salesTable;
        MultiSelectionHelper                    multiselectionHelper;
        Sales_UpdateMoDSalesOrderContract    dataContract;
        Sales_UpdateMoDSalesOrderController  controller;

        controller = Sales_UpdateMoDSalesOrderController::construct( _args );

        // Get marked records from calling form
        if (_args && _args.caller() is FormRun)
        {
            recordSet = new Set(Types::Record);
            multiselectionHelper = MultiSelectionHelper::createFromCaller(_args.caller());
        
            salesTable = multiselectionHelper.getFirst();

            while (salesTable)
            {
                recordSet.add(salesTable);
            
                salesTable = multiselectionHelper.getNext();
            }
        }

        // Put records from calling datasource into dataContract
        dataContract = controller.getDataContractObject();

        if (dataContract is Sales_UpdateMoDSalesOrderContract)
        {
            dataContract.parmRecordCon(recordSet.pack());
        }

        controller.startOperation();
    }
}

Contract class

/// <summary>
/// The data contract for Intercompany update of Mode of delivery
/// </summary>
[
    DataContract,
    SysOperationGroup('GeneralGroup',"@SYS81043",'1',FormArrangeMethod::Vertical)
]
class Sales_UpdateMoDSalesOrderContract implements SysOperationInitializable, SysOperationValidatable
{
    UpsModeOfDelivery upsModeOfDelivery;
    container            recordCon;

    /// <summary>
    /// Indicates whether the contract is valid.
    /// </summary>
    /// <returns>
    /// A Boolean value that indicates whether the contract is valid.
    /// </returns>
    public boolean validate()
    {
        boolean isValid = true;
        return isValid;
    }

    /// <summary>
    /// Initailizes the default values to parameters.
    /// </summary>
    public void initialize()
    {
    }

    /// <summary>
    /// Method used to specify the data memmber attribute
    /// </summary>
    /// <param>
    /// <name>parmShipmentDate</name>is used to set and get the shipmentDate
    /// </param>
    [
         DataMember,
         SysOperationGroupMember('GeneralGroup'),
         SysOperationDisplayOrder('1'),
         SysOperationLabelAttribute(literalstr("@Warehouse:UpsModeOfDelivery"))
    ]
    public UpsModeOfDelivery parmUpsModeOfDelivery( UpsModeOfDelivery _upsModeOfDelivery = upsModeOfDelivery )
    {
        upsModeOfDelivery  =  _upsModeOfDelivery;

        return upsModeOfDelivery;
    }

    /// <summary>
    /// Method used to specify the data memmber attribute
    /// </summary>
    /// <param name = "_recordCon"></param>
    /// <returns></returns>
    [DataMemberAttribute, SysOperationControlVisibilityAttribute(false)]
    public container parmRecordCon(container _recordCon = recordCon)
    {
        recordCon = _recordCon;

        return recordCon;
    }

}

Service class

class Sales_UpdateMoDSalesOrderService
{
    /// <summary>
    /// Creates transfer order for from and to wareshouse combination
    /// </summary>
    /// <param name = "_contract">TransferOrderCreateContract from dialog</param>
    public void updateMoDSalesOrder(Sales_UpdateMoDSalesOrderContract _contract)
    {
        Set                     recordSet;
        Common                  record;
        SalesTable              salesTable;
        SetEnumerator           se;
        ModeOfDeliverySetup  smModeOfDeliverySetup;

        // Process records
        if (conLen(_contract.parmRecordCon()) > 0)
        {
            recordSet = Set::create(_contract.parmRecordCon());
            se = recordSet.getEnumerator();
            while (se.moveNext())
            {
                record = se.current();

                switch (record.TableId)
                {
                    case tableNum(SalesTable):
                        salesTable = record;
                        salesTable.DlvMode = _contract.parmUpsModeOfDelivery();

                        info(strFmt("%1 %2", salesTable.SalesId, salesTable.DlvMode));
                        break;

                    default:
                        break;
                }
            }
        }
    }

}

Sysoperations framework sample

UIBuilder class

/// <summary>
/// The <c>TransferOrderCreateProposalUIBuilder</c> The data contract for Transfer order creation.
/// </summary>
class TransferOrderCreateProposalUIBuilder extends SysOperationAutomaticUIBuilder
{
    DialogField                                 toDate;
    DialogField                                 timeFence;
    DialogField                                 fromSite;
    DialogField		                            fromWarehouse,toWarehouses;
    DialogField                                 proposalModel;
    DialogField                                 recalculateQuantities;
    DialogField                                 replaceCurrentProposals;
    

    SysLookupMultiSelectCtrl                    ctrlSources;
    
    /// <summary>
    /// 
    /// </summary>
    public void postBuild()
    {
        TransferOrderCreateProposalContract contract	= this.dataContractObject() as TransferOrderCreateProposalContract;

        toDate                       = this.bindInfo().getDialogField(contract, methodStr(TransferOrderCreateProposalContract, parmToDate));
        timeFence                    = this.bindInfo().getDialogField(contract, methodStr(TransferOrderCreateProposalContract, parmTimeFence));
        fromSite                     = this.bindInfo().getDialogField(contract, methodStr(TransferOrderCreateProposalContract, parmInventSiteId));
        fromWarehouse                = this.bindInfo().getDialogField(contract, methodStr(TransferOrderCreateProposalContract, parmInventLocationIdFrom));
        toWarehouses	             = this.bindInfo().getDialogField(contract, methodStr(TransferOrderCreateProposalContract, parmInventLocationIdTo));
        proposalModel	             = this.bindInfo().getDialogField(contract, methodStr(TransferOrderCreateProposalContract, parmProposalModel));
        recalculateQuantities        = this.bindInfo().getDialogField(contract, methodStr(TransferOrderCreateProposalContract, parmRecalculateQuantities));
        replaceCurrentProposals      = this.bindInfo().getDialogField(contract, methodStr(TransferOrderCreateProposalContract, parmReplaceCurrentProposal));
        
        replaceCurrentProposals.allowEdit(false);
        recalculateQuantities.visible(false);
        toWarehouses.lookupButton(FormLookupButton::Always);

        switch (this.controller().parmArgs().menuItemName())
        {
            case menuItemActionStr(TransferOrderCreateProposal):
                replaceCurrentProposals.value(true);
                recalculateQuantities.value(false);
                toDate.value(DateTimeUtil::getSystemDate(DateTimeUtil::getUserPreferredTimeZone()));
                break;
            case menuItemActionStr(TransferOrderEditProposal):
                TransferOrderProposal    transferOrderProposal = this.controller().parmArgs().record();

                fromSite.allowEdit(false);
                fromWarehouse.allowEdit(false);
                proposalModel.allowEdit(false);

                recalculateQuantities.value(false);
                replaceCurrentProposals.value(false);
                toDate.value(transferOrderProposal.ToDate);
                fromSite.value(transferOrderProposal.InventSiteIdFrom);
                timeFence.value(transferOrderProposal.timeFence);
                proposalModel.value(transferOrderProposal.ProposalModel);
                fromWarehouse.value(transferOrderProposal.InventLocationIdFrom);
                break;

            case menuItemActionStr(TransferOrderRecalculateQty):
                toDate.visible(false);
                fromSite.visible(false);
                fromWarehouse.visible(false);
                timeFence.visible(false);
                toWarehouses.visible(false);
                replaceCurrentProposals.visible(false);

                recalculateQuantities.value(true);
                replaceCurrentProposals.value(false);
                break;

            default:
                break;
        }
    }

    /// <summary>
    /// 
    /// </summary>
    public void postRun()
    {
        if ( this.controller().parmArgs().menuItemName() == menuItemActionStr(TransferOrderCreateProposal) )
        {
            this.WarehouseLookup(false);
        }
        else if ( this.controller().parmArgs().menuItemName() == menuItemActionStr(TransferOrderEditProposal) )
        {
            this.WarehouseLookup(true);
        }
    }

    /// <summary>
    /// Multi select lookup for warehouse
    /// </summary>
    /// <param name = "_preselectValues">true for preselect lookup values</param>
    public void WarehouseLookup(boolean _preselectValues)
    {
        Query		            query		    = new Query();
        QueryBuildDataSource    qbdsWarehouses  = query.addDataSource(tablenum(InventLocation));

        container selectedFields = [tableNum(InventLocation), fieldNum(InventLocation, InventLocationId)];

        qbdsWarehouses.fields().addField(fieldNum(InventLocation, InventLocationId));
        qbdsWarehouses.fields().addField(fieldNum(InventLocation, Name));

        ctrlSources = SysLookupMultiSelectCtrl::constructWithQuery(this.dialog().formRun(),
                                                                   toWarehouses.control(),
                                                                   query,
                                                                   true,
                                                                   selectedFields);
        if (_preselectValues)
        {
            TransferOrderProposal    transferOrderProposal, transferOrderProposalLoc = this.controller().parmArgs().record();
            InventLocation              inventLocation;

            container selectedRecIds;
            container selectedValues;

            while select InventLocationIdTo from transferOrderProposal group by InventLocationIdTo
                where transferOrderProposal.ProposalModel == transferOrderProposalLoc.ProposalModel
            {
                inventLocation = InventLocation::find(transferOrderProposal.InventLocationIdTo);

                selectedRecIds += inventLocation.RecId;
                selectedValues += inventLocation.InventLocationId;
            }

            ctrlSources.set([selectedRecIds, selectedValues]);
        }
    }

}

Service class

/// <summary>
/// The <c>TransferOrderCreationProposalService</c> is used to create Transfer order proposals
/// for planned orders.
/// </summary>
class TransferOrderCreateProposalService
{
    List                                    toWareHouse;
    Query                                   query;
    counter                                 timeFence, lineNum;
    boolean                                 replaceCurrentProposal;
    String20                                proposalModel;
    TransDate                               fromDate,toDate;
    InventTable                             inventTable;
    InventSiteId                            fromInventSite;
    InventLocationId                        fromWarehouse;
    Enumerator                              enumerator;
    TransferOrderCreateProposalContract  contract;

    /// <summary>
    /// Entry point for creating Transfer order propsal lines based on proposal model
    /// </summary>
    /// <param name = "_contract">TransferOrderCreateProposalContract passed from dialog</param>
    public void createTransferOrderProposal(TransferOrderCreateProposalContract _contract)
    {
        contract = _contract;
       
        this.initializeQuery();
        this.initializeParameters();
        
        ttsbegin;

        this.deleteTranferProposalsLines(proposalModel, replaceCurrentProposal);
        this.createTransferOrderProposalLines();

        ttscommit;
    }

    /// <summary>
    /// Method is used to delete the Transfer order propsal lines based on proposal model
    /// </summary>
    /// <param name = "_proposalModel">from dialog</param>
    /// <param name = "_replaceCurrentProposal">true if creating new transfer order proposal</param>
    public void deleteTranferProposalsLines(ProposalModelId _proposalModel, boolean _replaceCurrentProposal)
    {
        if (_replaceCurrentProposal)
        {
            TransferOrderProposal    transferOrderProposal;

            delete_from transferOrderProposal
                where transferOrderProposal.ProposalModel == _proposalModel;
        }
    }

    /// <summary>
    /// intilalize parameters
    /// </summary>
    public void initializeParameters()
    {
        toDate                  = contract.parmToDate();
        timeFence               = contract.parmTimeFence();

        fromDate                = contract.parmToDate() - timeFence;

        toWareHouse             = contract.parmInventLocationIdTo();
        fromWarehouse           = contract.parmInventLocationIdFrom();
        proposalModel           = contract.parmProposalModel();
        fromInventSite          = contract.parmInventSiteId();
        replaceCurrentProposal  = contract.parmReplaceCurrentProposal();
    }

    /// <summary>
    /// initialize query object
    /// </summary>
    public void initializeQuery()
    {
        query = contract.parmQuery();
    }

    /// <summary>
    /// Method is used to create the Transfer order propsal lines based on proposal model
    /// </summary>
    public void createTransferOrderProposalLines()
    {
        Real                        workingdays;
        InventLocation              inventLocation;
        InventQtyTotal              inventQty;
        RecordInsertList            transferOrderProposalInsertList = null;
        TransferOrderProposal    transferOrderProposal;

        QueryRun queryRun = new QueryRun(query);

        while (queryRun.next())
        {
            transferOrderProposalInsertList = new RecordInsertList(tablenum(TransferOrderProposal));

            inventTable =   queryRun.get(tablenum(InventTable));
            enumerator  =   toWareHouse.getEnumerator();

            try
            {         
                ttsbegin;

                while (enumerator.moveNext())
                {
                    if (!replaceCurrentProposal)
                    {
                        if (TransferOrderProposal::exist(inventTable.ItemId, enumerator.current(), proposalModel))
                        {
                            lineNum++;
                            continue;
                        }
                    }

                    transferOrderProposal.clear();

                    lineNum++;

                    transferOrderProposal.LineNum                   = lineNum;
                    transferOrderProposal.ItemId                    = inventTable.ItemId;
                    transferOrderProposal.ItemName                  = inventTable.itemName();
                    transferOrderProposal.ToDate                    = toDate;
                    transferOrderProposal.TimeFence                 = timeFence;
                    transferOrderProposal.InventSiteIdFrom          = fromInventSite;

                    inventLocation = InventLocation::find(fromWarehouse);

                    transferOrderProposal.InventLocationIdFrom      = inventLocation.InventLocationId;
                    transferOrderProposal.InventLocationIdFromName  = inventLocation.Name;
                    transferOrderProposal.InventSiteIdTo            = fromInventSite;

                    inventLocation = InventLocation::find(enumerator.current());

                    transferOrderProposal.InventLocationIdTo        = inventLocation.InventLocationId;
                    transferOrderProposal.InventLocationIdToName    = inventLocation.Name;
                    transferOrderProposal.ProposalModel             = proposalModel;
                    transferOrderProposal.CoverageGroup             = inventTable.ReqGroupId;
                    
                    transferOrderProposal.RefillAvailablePhysical   = this.getRefillItemAvailPhysicalBySiteAndWarehouse(transferOrderProposal.ItemId,
                                                                                                                        transferOrderProposal.InventSiteIdFrom,
                                                                                                                        transferOrderProposal.InventLocationIdFrom);
                    inventQty = 0;
                    inventQty = this.getItemTotalSalesBySiteAndWarehouse(transferOrderProposal.ItemId,
                                                                         transferOrderProposal.InventSiteIdFrom,
                                                                         transferOrderProposal.InventLocationIdFrom,
                                                                         fromDate,
                                                                         toDate);
                    workingdays = 0;
                    workingdays = this.getNumOfWorkingdays(transferOrderProposal.InventLocationIdFrom, fromDate, toDate);

                    transferOrderProposal.RefillSalesPerDay = workingdays ? inventQty / workingdays : 0;

                    transferOrderProposal.RefillCoverageDays = transferOrderProposal.RefillSalesPerDay ? transferOrderProposal.RefillAvailablePhysical / transferOrderProposal.RefillSalesPerDay : 0;

                    transferOrderProposal.DCAvailablePhysical   = this.getDCItemAvailPhysicalBySiteAndWarehouse(transferOrderProposal.ItemId,
                                                                                                                transferOrderProposal.InventSiteIdTo,
                                                                                                                transferOrderProposal.InventLocationIdTo);
                    inventQty = 0;
                    inventQty = this.getItemTotalSalesBySiteAndWarehouse(transferOrderProposal.ItemId,
                                                                         transferOrderProposal.InventSiteIdTo,
                                                                         transferOrderProposal.InventLocationIdTo,
                                                                         fromDate,
                                                                         toDate);
                    workingdays = 0;
                    workingdays = this.getNumOfWorkingdays(transferOrderProposal.InventLocationIdTo,fromDate, toDate);

                    transferOrderProposal.DCSalesPerDay = workingdays ? inventQty / workingdays : 0;

                    transferOrderProposal.DCCoverageDays = transferOrderProposal.DCSalesPerDay ? transferOrderProposal.DCAvailablePhysical / transferOrderProposal.DCSalesPerDay : 0;

                    transferOrderProposalInsertList.add(transferOrderProposal);
                }

                transferOrderProposalInsertList.insertDatabase();

                ttscommit;
                
            }
            catch(Exception::Error)
            {
                throw error( "@Planning:TransferOrderPropsalCreationError");
            }
            catch(Exception::Deadlock )
            {
                if(xSession::currentRetryCount() >= Planning_Constants::MaxOCCRetryCount)
                {
                    throw Exception::Deadlock;
                }
                else
                {
                    retry;
                }
            }
            catch(Exception::UpdateConflict)
            {
                if (appl.ttsLevel() == 0)
                {
                    if (xSession::currentRetryCount() >= Planning_Constants::MaxOCCRetryCount)
                    {
                        throw Exception::UpdateConflictNotRecovered;
                    }
                    else
                    {
                        retry;
                    }
                }
                else
                {
                    throw Exception::UpdateConflict;
                }
            }

            info(strFmt("@Planning:TransferOrderProposalCreationSuccess", lineNum, proposalModel));
        }
    }

    /// <summary>
    /// Calculate total sales between daterange for each item based on site and warehouse
    /// </summary>
    /// <param name = "_itemId"></param>
    /// <param name = "_inevntSiteId"></param>
    /// <param name = "_inventLocationId"></param>
    /// <returns></returns>
    public InventQtyTotal getItemTotalSalesBySiteAndWarehouse(ItemId _itemId, 
                                                              InventSiteId _inventSiteId,
                                                              InventLocationId _inventLocationId,
                                                              FromDate _fromDate,
                                                              ToDate _toDate)
    {
        InventDim           inventDim;
        InventTrans         inventTrans;
        InventTransOrigin   inventTransOrigin;


        select sum(Qty) from inventTrans
                where inventTrans.ItemId == _itemId
                    && inventTrans.DatePhysical >= _fromDate
                    && inventTrans.DatePhysical <= _toDate
                    exists join inventTransOrigin
                    where inventTransOrigin.RecId == inventTrans.InventTransOrigin
                        && inventTransOrigin.ReferenceCategory == InventTransType::Sales
                        exists join inventDim
                        where inventDim.inventDimId == inventTrans.inventDimId
                            && inventDim.InventSiteId == _inventSiteId
                            && inventDim.InventLocationId == _inventLocationId;

        return abs(inventTrans.Qty);
    }

    /// <summary>
    /// calculates number of working days based on warehouse or Legal entity base calender
    /// </summary>
    /// <param name = "_inventLocationId"></param>
    /// <returns></returns>
    public Real getNumOfWorkingdays(InventLocationId _inventLocationId, FromDate _fromDate, ToDate _toDate)
    {
        Real                workingdays;
        CalendarId          calenderId;
        WorkCalendarDate    WorkCalendarDate;

        if (InventLocation::find(_inventLocationId).ReqCalendarId)
        {
            calenderId = InventLocation::find(_inventLocationId).ReqCalendarId;
        }
        else
        {
            calenderId = CompanyInfo::find().ShippingCalendarId;
        }

        select count(RecId) from WorkCalendarDate
            where WorkCalendarDate.CalendarId       == calenderId
                && (WorkCalendarDate.TransDate      >= _fromDate
                && WorkCalendarDate.TransDate       <= _toDate)
                && WorkCalendarDate.WorkTimeControl == WorkTimeControl::Open;

        workingdays = any2Real(WorkCalendarDate.RecId);

        if (!calenderId)
        {
            Real noOfDays    = _toDate - _fromDate;

            //Formula for calculating working days if No base calender is present
            workingdays = (abs(noOfDays) / Planning_Constants::NumOfDaysInAWeek ) * Planning_Constants::MinWorkingDaysInAWeek;
        }
        
        return abs(workingdays);
    }

    /// <summary>
    /// Calculate avaialable physical inventory for each item based on site and warehouse
    /// </summary>
    /// <param name = "_itemId"></param>
    /// <param name = "_inevntSiteId"></param>
    /// <param name = "_inventLocationId"></param>
    /// <returns>Refill warehouse avail physical</returns>
    public InventQtyAvailPhysical getRefillItemAvailPhysicalBySiteAndWarehouse(ItemId _itemId, InventSiteId _inventSiteId, InventLocationId _inventLocationId)
    {
        InventDim       inventDim;
        InventDimParm   inventDimParm;
      
        inventDim = this.initInventDim(_inventSiteId, _inventLocationId);

        inventDimParm.initFromInventDim(inventDim);

        return abs(InventOnhand::newParameters(_itemId, inventDim, inventDimParm).availPhysical());
    }

    /// <summary>
    /// Calculate avaialable physical inventory for each item based on site and warehouse
    /// </summary>
    /// <param name = "_itemId"></param>
    /// <param name = "_inevntSiteId"></param>
    /// <param name = "_inventLocationId"></param>
    /// <returns>DC warehouse avail physical</returns>
    public InventQtyAvailPhysical getDCItemAvailPhysicalBySiteAndWarehouse(ItemId _itemId, InventSiteId _inventSiteId, InventLocationId _inventLocationId)
    {
        InventDim           inventDim;
        InventTrans         inventTrans;
        InventDimParm       inventDimParm;
        inventTransOrigin   InventTransOrigin;
        InventQty           totalAvailPhysical;
      
        inventDim = this.initInventDim(_inventSiteId, _inventLocationId);

        inventDimParm.initFromInventDim(inventDim);

        totalAvailPhysical = abs(InventOnhand::newParameters(_itemId, inventDim, inventDimParm).availPhysical());

        inventDim.clear();

        select sum(Qty) from inventTrans
                where inventTrans.ItemId == _itemId
                    && inventTrans.DatePhysical == dateNull()
                    && inventTrans.StatusIssue == StatusIssue::ReservPhysical
                    exists join inventTransOrigin
                    where inventTransOrigin.RecId == inventTrans.InventTransOrigin
                        && (inventTransOrigin.ReferenceCategory == InventTransType::TransferOrderShip
                            || inventTransOrigin.ReferenceCategory == InventTransType::TransferOrderReceive)
                            exists join inventDim
                            where inventDim.inventDimId   == inventTrans.inventDimId
                            && inventDim.InventSiteId     == _inventSiteId
                            && inventDim.InventLocationId == _inventLocationId;

        return totalAvailPhysical + abs(inventTrans.Qty);
    }

    /// <summary>
    /// Initilalize InevntDim by site and warehouse
    /// </summary>
    /// <param name = "_inevntSiteId">SiteId from proposal line</param>
    /// <param name = "_inventLocationId">LocationId from proposal line</param>
    /// <returns>InventDim buffer</returns>
    public InventDim initInventDim(InventSiteId _inevntSiteId, InventLocationId _inventLocationId)
    {
        InventDim inventDim;
      
        inventDim.InventSiteId      = _inevntSiteId;
        inventDim.InventLocationId  = _inventLocationId;

        inventDim = InventDim::findOrCreate(inventDim);
        
        return inventDim;
    }

    /// <summary>
    /// Recalculates and updates avail physical quanties
    /// </summary>
    /// <param name = "_contract">TransferOrderCreateProposalContract from dialog</param>
    public void recalculateQuanties(TransferOrderCreateProposalContract _contract)
    {
        TransferOrderProposal    transferOrderProposal;
        InventQtyTotal              inventQty;
        Real                        workingdays;

        while select forupdate transferOrderProposal
            where transferOrderProposal.ProposalModel == _contract.parmProposalModel()
        {
            try
            {
                ttsbegin;
                transferOrderProposal.RefillAvailablePhysical   = this.getRefillItemAvailPhysicalBySiteAndWarehouse(transferOrderProposal.ItemId,
                                                                                                                    transferOrderProposal.InventSiteIdFrom,
                                                                                                                    transferOrderProposal.InventLocationIdFrom);

                inventQty = 0;
                inventQty = this.getItemTotalSalesBySiteAndWarehouse(transferOrderProposal.ItemId,
                                                                     transferOrderProposal.InventSiteIdFrom,
                                                                     transferOrderProposal.InventLocationIdFrom,
                                                                     transferOrderProposal.ToDate - transferOrderProposal.TimeFence,
                                                                     transferOrderProposal.ToDate);
                workingdays = 0;
                workingdays = this.getNumOfWorkingdays(transferOrderProposal.InventLocationIdFrom, transferOrderProposal.ToDate - transferOrderProposal.TimeFence, transferOrderProposal.ToDate);

                transferOrderProposal.RefillCoverageDays = transferOrderProposal.RefillSalesPerDay ? transferOrderProposal.RefillAvailablePhysical / transferOrderProposal.RefillSalesPerDay : 0;

                transferOrderProposal.DCAvailablePhysical   = this.getDCItemAvailPhysicalBySiteAndWarehouse(transferOrderProposal.ItemId,
                                                                                                            transferOrderProposal.InventSiteIdTo,
                                                                                                            transferOrderProposal.InventLocationIdTo);
                inventQty = 0;
                inventQty = this.getItemTotalSalesBySiteAndWarehouse(transferOrderProposal.ItemId,
                                                                     transferOrderProposal.InventSiteIdTo,
                                                                     transferOrderProposal.InventLocationIdTo,
                                                                     transferOrderProposal.ToDate - transferOrderProposal.TimeFence,
                                                                     transferOrderProposal.ToDate);
                workingdays = 0;
                workingdays = this.getNumOfWorkingdays(transferOrderProposal.InventLocationIdFrom, transferOrderProposal.ToDate - transferOrderProposal.TimeFence, transferOrderProposal.ToDate);


                transferOrderProposal.DCCoverageDays = transferOrderProposal.DCSalesPerDay ? transferOrderProposal.DCAvailablePhysical / transferOrderProposal.DCSalesPerDay : 0;

                transferOrderProposal.update();

                ttscommit;
            }
            catch(Exception::Error)
            {
                throw error( "@Planning:TransferOrderPropsalCreationError");
            }
            catch(Exception::Deadlock )
            {
                if(xSession::currentRetryCount() >= Planning_Constants::MaxOCCRetryCount)
                {
                    throw Exception::Deadlock;
                }
                else
                {
                    retry;
                }
            }
            catch(Exception::UpdateConflict)
            {
                if (appl.ttsLevel() == 0)
                {
                    if (xSession::currentRetryCount() >= Planning_Constants::MaxOCCRetryCount)
                    {
                        throw Exception::UpdateConflictNotRecovered;
                    }
                    else
                    {
                        retry;
                    }
                }
                else
                {
                    throw Exception::UpdateConflict;
                }
            }
        }
    }

}

Controller class

/// <summary>
/// The controller for handling bulk Transfer order proposal creation.
/// </summary>
class TransferOrderCreateProposalController  extends SysOperationServiceController
{
    /// <summary>
    /// Constructs a new instance of the <c>TransferOrderCreateProposalController</c>.
    /// </summary>
    /// <param name = "_args">A set of arguments that is used for Transfer order proposal creation.</param>
    /// <returns>A new instance of the <c>TransferOrderCreateProposalController</c>.</returns>
    public static TransferOrderCreateProposalController construct(Args _args)
    {
        TransferOrderCreateProposalController  controller;

        switch (_args.menuItemName())
        {
            case menuItemActionStr(TransferOrderEditProposal):
            case menuItemActionStr(TransferOrderCreateProposal):
                controller = new TransferOrderCreateProposalController(classStr( TransferOrderCreateProposalService ),
                                                                          methodStr( TransferOrderCreateProposalService, createTransferOrderProposal ),
                                                                          SysOperationExecutionMode::Synchronous);
                break;

            case menuItemActionStr(TransferOrderRecalculateQty):
                controller = new TransferOrderCreateProposalController(classStr( TransferOrderCreateProposalService ),
                                                                          methodStr( TransferOrderCreateProposalService, recalculateQuanties ),
                                                                          SysOperationExecutionMode::Synchronous);
                break;

            default:
                break;
        }

        controller.parmArgs( _args );

        return controller;
    }

    public static void main(Args _args)
    {
        TransferOrderCreateProposalController  controller = TransferOrderCreateProposalController::construct( _args );

        controller.startOperation();
        
        //Only run if in Non batch mode
        if (controller.startResult == SysOperationStartResult::Started)
        {
            controller.RefreshCallingForm(_args);
        }
    }

    /// <summary>
    /// Refresh TransferOrderProposal from when not running in batch
    /// </summary>
    /// <param name = "_args"></param>
    private void RefreshCallingForm(args _args)
    {
        if (_args && _args.caller() && _args.caller() is formRun)
        {
            TransferOrderCreateProposalContract contract = this.getDataContractObject();

            FormStringControl proposalModel;

            FormRun callerFormRun = _args.caller() as formRun;

            proposalModel = callerFormRun.design().controlName(formControlStr(TransferOrderProposal, ProposalModel));

            proposalModel.Text(contract.parmProposalModel());
            proposalModel.modified();

            callerFormRun.dataSource(1).research(true);
            callerFormRun.dataSource(1).refresh();

            callerFormRun.dataSource(2).research(true);
            callerFormRun.dataSource(2).refresh();
        }
    }

    protected boolean canRunInNewSession()
    {
        return true;
    }

}

Contract class

/// <summary>
/// The data contract for Transfer order creation.
/// </summary>
[
    DataContract,
    SysOperationGroup("HistoricalHorizoGroup","@:HistoricalHorizon","1",FormArrangeMethod::Vertical),
    SysOperationGroup("ReplaceCurrentProposalGroup","@:ReplaceCurrentProposal","2",FormArrangeMethod::Vertical),
    SysOperationContractProcessing(classStr(TransferOrderCreateProposalUIBuilder))
]
public class TransferOrderCreateProposalContract implements SysOperationInitializable, SysOperationValidatable
{
    Query                   query;
    str                     packedQuery;
    TransDate               fromDate,toDate;
    NoYesId                 replaceCurrentProposal;
    NoYesId                 recalculateQuantities;

    InventSiteId            inventSiteId;
    InventLocationId        inventLocationIdFrom;
    Integer                 timeFence;
    ProposalModelId      proposalModel;

    List                    inventLocationIdTo;
    
    /// <summary>
    /// Indicates whether the contract is valid.
    /// </summary>
    /// <returns>
    /// A Boolean value that indicates whether the contract is valid.
    /// </returns>
    public boolean validate()
    {
        boolean isValid = true;        

        if (!proposalModel)
        {
            isValid = checkFailed(strFmt("@SYS135209", "@:ProposalModel"));
        }
        else if (!this.confirmReplaceCurrentProposal(proposalModel, replaceCurrentProposal) && !recalculateQuantities)
        {
            isValid = false;
        }

        if (!replaceCurrentProposal && !recalculateQuantities)
        {
            isValid = this.checkProposalExists();
        }

        return isValid;
    }

    /// <summary>
    /// check for transfer order proposals exists
    /// </summary>
    /// <returns>A Boolean value that indicates whether the contract is valid</returns>
    public boolean checkProposalExists()
    {
        Query                       queryVal;
        Counter                     lineNum;
        container                   results;
        Enumerator                  enumerator;
        InventTable                 inventTable;
        
        boolean                     isValid =  true;

        if (query == null && packedQuery)
        {
            queryVal = new Query( SysOperationHelper::base64Decode( packedQuery ) );
        }
        else
        {
            queryVal = query;
        }

        QueryRun queryRun   = new QueryRun(queryVal);

        while (queryRun.next())
        {
            inventTable =   queryRun.get(tablenum(InventTable));
            enumerator  =   inventLocationIdTo.getEnumerator();

            while (enumerator.moveNext())
            {
                if (TransferOrderProposal::exist(inventTable.ItemId, enumerator.current(), proposalModel))
                {
                    lineNum++;

                    results += strFmt("@:ProposalExistsValidation", inventTable.ItemId, enumerator.current());

                    if (lineNum >= 100)
                    {
                        break;
                    }
                }
            }
        }

        if (conLen(results) > 0)
        {
            warning(con2Str(results));

            DialogButton    diagBut;

            str strMessage  = "@:TransferOrderAddlinesConfirmation";
            str strTitle    = "@ApplicationPlatform:SystemNotificationTitle";

            diagBut = Box::okCancel(strMessage,
                                    DialogButton::Cancel, // Initial focus is on the Cancel button.
                                    strTitle);

            if (diagBut == DialogButton::Cancel)
            {
                isValid = false;
            }
            else
            {
                isValid = true;
            }
        }

        return isValid;
    }

    /// <summary>
    /// confirm from user to replace Marked/modifeied transfer order proposals
    /// </summary>
    /// <param name = "_proposalModel">user selected value</param>
    /// <param name = "_replaceCurrentProposal">true</param>
    /// <returns>A Boolean value that indicates whether the contract is valid </returns>
    public boolean confirmReplaceCurrentProposal(ProposalModelId _proposalModel, boolean _replaceCurrentProposal)
    {
        boolean ret = true;
        
        if(_proposalModel && _replaceCurrentProposal)
        {
            TransferOrderProposal    transferOrderProposal;

            select firstonly RecId from transferOrderProposal
                    where transferOrderProposal.ProposalModel   == _proposalModel
                        && (transferOrderProposal.AddToShipment == NoYes::Yes
                            || transferOrderProposal.CaseQty != 0);

            if (transferOrderProposal.RecId)
            {
                DialogButton    diagBut;

                str strMessage  = "@:PropsalReplaceConfirmationText";
                str strTitle    = "@ApplicationPlatform:SystemNotificationTitle";

                diagBut = Box::okCancel(strMessage,
                                        DialogButton::Cancel, // Initial focus is on the Cancel button.
                                        strTitle);

                if (diagBut == DialogButton::Cancel)
                {
                    ret = false;
                }
                else
                {
                    ret = true;
                }
            }
        }
        else
        {
            ret = true;
        }

        return ret;
    }

    /// <summary>
    /// Initailizes the default values to parameters.
    /// </summary>
    public void initialize()
    {
        query = new Query( queryStr( InventTableQuery ) );
    }

    /// <summary>
    /// load query from syslast value
    /// </summary>
    /// <param name = "_packedQuery"></param>
    /// <returns> packed query string</returns>
    [
         DataMember,
         AifQueryTypeAttribute('_packedQuery', queryStr( InventTableQuery ) )
    ]
    public str parmPackedQuery( str _packedQuery = packedQuery)
    {
        packedQuery = _packedQuery;

        return packedQuery;
    }

    /// <summary>
    /// Encode/decode the query and set or get
    /// </summary>
    /// <param name = "_query"></param>
    /// <returns>query object</returns>
    public Query parmQuery( Query _query = query )
    {
        if ( prmisDefault( _query ) && query == null )
        {
            query = new Query( SysOperationHelper::base64Decode( packedQuery ) );
        }
        else
        {
            packedQuery  = SysOperationHelper::base64Encode( _query.pack() );
            query = _query;
        }

        return query;
    }

    /// <summary>
    /// Method used to specify the data memmber attribute
    /// </summary>
    /// <param>
    /// <name>parmFromDate</name>is used to set and get the FromDate
    /// </param>
    [
         DataMember,
         SysOperationGroupMember("HistoricalHorizoGroup"),
         SysOperationDisplayOrder("1"),
         SysOperationLabelAttribute(literalstr("@:TransferProposalModel"))
    ]
    public ProposalModelId parmProposalModel( ProposalModelId _proposalModel = proposalModel )
    {
        proposalModel  =   _proposalModel;

        return proposalModel;
    }

    /// <summary>
    /// Method used to specify the data member attribute
    /// </summary>
    /// <param>
    /// <name>parmTimeFence</name>is used to set and get the historical time
    /// </param>
    [
         DataMember,
         SysOperationGroupMember("HistoricalHorizoGroup"),
         SysOperationDisplayOrder("2"),
         SysOperationLabelAttribute(literalstr("@SYS315566"))
    ]
    public Integer parmTimeFence(Integer _timeFence = timeFence  )
    {
        timeFence  =   _timeFence;

        return timeFence;
    }

    /// <summary>
    /// Method used to specify the data member attribute
    /// </summary>
    /// <param>
    /// <name>parmToDate</name>is used to set and get the ToDate
    /// </param>
    [
         DataMember,
         SysOperationGroupMember("HistoricalHorizoGroup"),
         SysOperationDisplayOrder("3"),
         SysOperationLabelAttribute(literalstr("@:ToDate"))
    ]
    public TransDate parmToDate( TransDate _toDate = toDate )
    {
        toDate  =   _toDate;

        return toDate;
    }

    /// <summary>
    /// Method used to specify the data member attribute
    /// </summary>
    /// <param>
    /// <name>parmReplaceCurrentProposal</name>is used to set and get the parameter value
    /// </param>
    [
         DataMember,
         SysOperationGroupMember("ReplaceCurrentProposalGroup"),
         SysOperationDisplayOrder("4"),  
         SysOperationLabelAttribute(literalstr("@:ReplaceCurrentProposal"))
    ]
    public NoYesId parmReplaceCurrentProposal( NoYesId _replaceCurrentProposal = replaceCurrentProposal )
    {
        replaceCurrentProposal  =   _replaceCurrentProposal;

        return replaceCurrentProposal;
    }

    /// <summary>
    /// Method used to specify the data memmber attribute
    /// </summary>
    /// <param>
    /// <name>parmToDate</name>is used to set and get the ToDate
    /// </param>
    [
         DataMember,
         SysOperationGroupMember("ReplaceCurrentProposalGroup"),
         SysOperationDisplayOrder("5"),
         SysOperationLabelAttribute(literalstr("@SYS106955"))
    ]
    public InventSiteId parmInventSiteId( InventSiteId _inventSiteId = inventSiteId )
    {
        inventSiteId  =   _inventSiteId;

        return inventSiteId;
    }

    /// <summary>
    /// Method used to specify the data memmber attribute
    /// </summary>
    /// <param>
    /// <name>parmToDate</name>is used to set and get the ToDate
    /// </param>
    [
         DataMember,
         SysOperationGroupMember("ReplaceCurrentProposalGroup"),
         SysOperationDisplayOrder("6"),
         SysOperationLabelAttribute(literalstr("@SYS25253"))
    ]
    public InventLocationId parmInventLocationIdFrom( InventLocationId _inventLocationIdFrom = inventLocationIdFrom )
    {
        inventLocationIdFrom  =   _inventLocationIdFrom;

        return inventLocationIdFrom;
    }

    /// <summary>
    /// Method used to specify the data memmber attribute
    /// </summary>
    /// <param>
    /// <name>parmToDate</name>is used to set and get the ToDate
    /// </param>
    [
         DataMember,
         SysOperationGroupMember("ReplaceCurrentProposalGroup"),
         SysOperationDisplayOrder("7"),
         SysOperationLabelAttribute(literalstr("@SYS8519")),
         AifCollectionType('return', Types::String)
    ]
    public List parmInventLocationIdTo( List _inventLocationIdTo = inventLocationIdTo )
    {
        inventLocationIdTo  =   _inventLocationIdTo;

        return inventLocationIdTo;
    }

    /// <summary>
    /// Method used to specify the data memmber attribute
    /// </summary>
    /// <param>
    /// <name>parmReplaceCurrentProposal</name>is used to set and get the parameter value
    /// </param>
    [
         DataMember,
         SysOperationGroupMember("ReplaceCurrentProposalGroup"),
         SysOperationDisplayOrder("8"),
         SysOperationLabelAttribute(literalstr("@SYS40695"))
    ]
    public NoYesId parmRecalculateQuantities( NoYesId _recalculateQuantities = recalculateQuantities )
    {
        recalculateQuantities  =   _recalculateQuantities;

        return recalculateQuantities;
    }

}

Table browser URL in D365FO

Critical Thinking icon icon by Icons8