Showing posts with label SysOperations. Show all posts
Showing posts with label SysOperations. Show all posts

Tuesday, April 23, 2024

Sysoperation framework with Aot query

public class UpdatePriceFormulaIdOnItemsService__Custom extends SysOperationServiceBase
{
    #OCCRetrycount
    public void processOperation(UpdatePriceFormulaIdOnItemsContract__Custom _contract)
    {
        Query               orderQuery;

        orderQuery      = _contract.getQuery();
        container       compCon = str2con(_contract.parmCompany(), SysAppUtilities__Custom::semiColon);
        QueryRun    queryRun = new QueryRun(orderQuery);
        while (queryRun.Next())
        {
            InventTable inventTable = queryRun.get(tableNum(InventTable));
            try
            {
                PriceFormulaId__Custom  priceFormulaIdMaster = this.getPriceFormulaId(inventTable);

                //DSSE
                if (inventTable &&
                    inventTable.PriceFormulaIdMaster__Custom != priceFormulaIdMaster)
                {
                    ttsbegin;
                    inventTable.selectForUpdate(true);
                    inventTable.PriceFormulaIdMaster__Custom = priceFormulaIdMaster;
                    inventTable.PriceFormulaId__Custom = priceFormulaIdMaster;
                    inventTable.doUpdate();
                    ttscommit;
                }

                for (int i=1; i<=conLen(compCon); i++)
                {
                    DataAreaId  company = conPeek(compCon, i);
                    changecompany(company)
                    {
                        InventTable inventTableSales = InventTable::find(inventTable.ItemId);
                        PriceFormulaId__Custom  priceFormulaId = this.getPriceFormulaId(inventTableSales);

                        if (inventTableSales &&
                            inventTableSales.PriceFormulaId__Custom != priceFormulaId)
                        {
                            ttsbegin;
                            inventTableSales.selectForUpdate(true);
                            inventTableSales.PriceFormulaIdMaster__Custom = priceFormulaIdMaster;
                            inventTableSales.PriceFormulaId__Custom = priceFormulaId;
                            inventTableSales.doUpdate();
                            ttscommit;
                        }
                    }
                }

                info(strfmt("@_CustomtITServices:SucessUpdateItem", inventTable.ItemId));
            }
            catch (Exception::Deadlock)
            {
                retry;
            }
            catch (Exception::UpdateConflict)
            {
                if (appl.ttsLevel() == 0)
                {
                    if (xSession::currentRetryCount() >= #RetryNum)
                    {
                        warning(strFmt("@_CustomtITServices:FaliedUpdateItem", inventTable.ItemId));
                        continue;
                    }
                    else
                    {
                        retry;
                    }
                }
                else
                {
                    warning(strFmt("@_CustomtITServices:FaliedUpdateItem", inventTable.ItemId));
                    continue;
                }
            }
            catch (Exception::Error)
            {
                warning(strFmt("@_CustomtITServices:FaliedUpdateItem", inventTable.ItemId));
                continue;
            }
        }
    }

    public PriceFormulaId__Custom getPriceFormulaId(InventTable _inventTable)
    {
        DimensionValue      brandDim;
        EcoResCategoryId    ecoResCategoryId;
        container           catCon  = conNull();

        if (_inventTable)
        {
            brandDim            = _CustomtITServicesUtility__Custom::getDimension_CustomplayValue(_inventTable.DefaultDimension, SysAppUtilities__Custom::dimensionAttributeNameBrand);
            catCon              = _CustomtITServicesUtility__Custom::getProdCategories(_inventTable.ItemId);
        }

        ItemPriceFormula__Custom    itemPriceFormula;
        
        if (_inventTable.ItemId)
        {
            itemPriceFormula    = ItemPriceFormula__Custom::findByItem(_inventTable.ItemId);
        }
           
        if (!itemPriceFormula && catCon != conNull() && brandDim)
        {
            for (int i=1; i<=conLen(catCon); i++)
            {
                ecoResCategoryId    = EcoResCategory::find(conPeek(catCon, i)).RecId;
                itemPriceFormula    = ItemPriceFormula__Custom::findByCategoryBrand(ecoResCategoryId, brandDim);
                if (itemPriceFormula)
                {
                    break;
                }
            }
        }

        if (!itemPriceFormula && brandDim)
        {
            itemPriceFormula    = ItemPriceFormula__Custom::findByBrand(brandDim);
        }
        
        if (!itemPriceFormula && catCon != conNull())
        {
            for (int i=1; i<=conLen(catCon); i++)
            {
                ecoResCategoryId    = conPeek(catCon, i);
                itemPriceFormula    = ItemPriceFormula__Custom::findByCategory(ecoResCategoryId);
                if (itemPriceFormula)
                {
                    break;
                }
            }
        }

        return itemPriceFormula.PriceFormulaId;
    }

}
=====================
public class UpdatePriceFormulaIdOnItemsController__Custom extends SysOperationServiceController
{
    // <summary>
    /// Creates a new instance of <c>UpdateEndOfLifeOnItemsController__Custom</c> class.
    /// </summary>
    /// <param name = "_args">A controller arguments.</param>
    /// <returns>A instance of <c>SysOperationController</c> class.</returns>
    public static UpdatePriceFormulaIdOnItemsController__Custom construct(Args _args)
    {
        UpdatePriceFormulaIdOnItemsController__Custom controller = new UpdatePriceFormulaIdOnItemsController__Custom();
        controller.parmArgs(_args);

        return controller;
    }

    /// <summary>
    /// Instantiate controller.
    /// </summary>
    protected void new()
    {
        super(classStr(UpdatePriceFormulaIdOnItemsService__Custom), methodStr(UpdatePriceFormulaIdOnItemsService__Custom, processOperation));

        this.parmDialogCaption("@_CustomtITServices:UpdatePriceFormulaIdItem");
    }

    /// <summary>
    /// Runs the class with the specified arguments.
    /// </summary>
    /// <param name = "_args">The specified arguments.</param>
    public static void main(Args _args)
    {
        UpdatePriceFormulaIdOnItemsController__Custom controller = UpdatePriceFormulaIdOnItemsController__Custom::newFromArgs(_args);
        controller.parmExecutionMode(SysOperationExecutionMode::Synchronous);
        controller.startOperation();
    }

    /// <summary>
    /// Instantiate and initialize controller class.
    /// </summary>
    /// <param name = "_args">The specified arguments.</param>
    /// <returns>
    /// returns controller class.
    /// </returns>
    public static UpdatePriceFormulaIdOnItemsController__Custom newFromArgs(Args _args)
    {
        UpdatePriceFormulaIdOnItemsController__Custom controller = UpdatePriceFormulaIdOnItemsController__Custom::construct(_args);
        return controller;
    }

}
==================
[DataContractAttribute, SysOperationContractProcessingAttribute(ClassStr(UpdatePriceFormulaIdOnItemsUIbuilder__Custom))]
public class UpdatePriceFormulaIdOnItemsContract__Custom
{
    str     packedQuery;
    Str                     company;
    /// <summary>
    ///    Initialize query
    /// </summary>
    public void initQuery()
    {
        Query   newQuery;
        newQuery = new Query(queryStr(InventTable));
        this.setQuery(newQuery);
    }

    /// <summary>
    ///     Get/Set the packed query
    /// </summary>
    /// <param name = "_packedQuery">query</param>
    /// <returns>string</returns>
    [
    DataMemberAttribute,
    AifQueryTypeAttribute('_packedQuery', queryStr(InventTable))
    ]
    public str parmPackedQuery(str _packedQuery = packedQuery)
    {
        packedQuery = _packedQuery;

        return packedQuery;
    }

    /// <summary>
    ///     Get the query
    /// </summary>
    /// <returns>Query</returns>
    public Query getQuery()
    {
        return
        new Query(SysOperationHelper::base64Decode(packedQuery));
    }

    /// <summary>
    ///     Set the query
    /// </summary>
    /// <param name = "_query">query</param>
    public void setQuery(Query _query)
    {
        packedQuery = SysOperationHelper::base64Encode(_query.pack());
    }

    // <summary>
    /// Gets or sets the value of the datacontract parameter company.
    /// </summary>
    /// <param name="_company">
    /// The new value of the datacontract parameter company; optional.
    /// </param>
    /// <returns>
    ///  The current value of datacontract parameter company
    /// </returns>
    [
        DataMemberAttribute,
        SysOperationLabelAttribute(literalStr("@_CustomtITServices:Company")),
        SysOperation_CustomplayOrderAttribute("1")
    ]
    public Str parmCompany(Str _company = company)
    {
        company = _company;
        return company;
    }

}

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;
    }

Tuesday, April 13, 2021

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