X++ code to create transfer journals in d365 fo

 /// <summary>

/// Service class for move inventory

/// </summary>

class MovementTransferService extends sysoperationservicebase

{

    QueryRun queryRun;

    /// <summary>

    /// method to call Initquery

    /// </summary>

    public void new()

    {

        this.initQuery();

        

    }


    /// <summary>

    /// descrption of the service class

    /// </summary>

    /// <returns>test</returns>

    static ClassDescription description()

    {

        return 'Movement transfer journals';

    }


    /// <summary>

    /// initilaize query for the process

    /// </summary>

    public void initQuery()

    {

        Query                   query = new Query();

        query.addDataSource(tablenum(TransactionBase));

        

        queryRun = new QueryRun(query);

    }


    /// <summary>

    /// Returns query run for the query

    /// </summary>

    /// <returns>QR</returns>

    public QueryRun queryRun()

    {

        return queryRun;

    }


    /// <summary>

    /// to call the process method

    /// </summary>

    public void run()

    {

        //2. Query Processing

        this.initQuery();

        QueryBuildDataSource  qBDS = queryRun.query().dataSourceTable(tablenum(TransactionBase));

        qBDS.addRange(Fieldnum(TransactionBase , TransactionType)).value('OTransferMaterial');

        qBDS.addRange(Fieldnum(TransactionBase , Task)).value('ProcessOTransferMaterial');

        qBDS.addRange(fieldNum(TransactionBase, IsProcessed)).value(SysQuery::value(Isprocessed::NotProcessed));

        while (queryRun.next())

        {

           TransactionBase   TransactionBase = queryRun.get(tablenum(MV2TransactionBase));

            this.processRecord(TransactionBase);

        }

    }


    /// <summary>

    /// Proceesed records

    /// </summary>

    /// <param name = "_TransactionBase">TransactionBase</param>

    public void processRecord(TransactionBase _TransactionBase)

    {

        TransactionBase          TransactionBaseUPD;

        InventTable                 inventTable;

        InventJournalTrans          inventJournalTrans;

        InventJournalTable          inventJournalTable;

        InventDim                   frominventDim,ToinventDim, inventdimfnd;

        InventDimCombination        inventdimcombo;

        WMSLocation                 fromwMSLocation, toWmslocation;

        InventoryTransactions    inventoryTrans;

        tolocation               mv2tolocation;

       

        int                         lineNum;

        ;

        try

        {

            ttsbegin;

            InventParameters       inventParameters = InventParameters::find();

            inventoryTrans   = InventoryTransactions::findbyId(_TransactionBase.ID);

            if(!inventoryTrans)

            {

                throw Global::error('Inventory transactions are empty');

            }

            mv2tolocation = mv2tolocation::findbyId(_MV2TransactionBase.ID);

            if(!mv2tolocation)

            {

                throw Global::error('ToLocations are does not exists');

            }

            inventJournalTable.clear();

            inventJournalTable.initValue();

            inventJournalTable.initFromInventJournalName(InventJournalName::find(inventParameters.TransferJournalNameId));

            if (inventJournalTable.validateField(fieldNum(InventJournalTable, JournalNameId)))

            {

                inventJournalTable.modifiedField(fieldNum(InventJournalTable, JournalNameId));

                inventJournalTable.JournalType      = InventJournalType::Transfer;

                inventJournalTable.Description = 'Inventory Transfer Journal';

                inventJournalTable.insert();

            }


            inventJournalTrans.clear();

            inventJournalTrans.initFromInventJournalTable(inventJournalTable);

            inventJournalTrans.TransDate      = DateTimeUtil::date(_MV2TransactionBase.TransactionDate);

            //get item details

            inventdimcombo                    = InventDimCombination::findVariantId(inventoryTrans.ItemNumber);

            if(inventdimcombo)

            {

                inventTable = inventdimcombo.inventTable();

            }

            else

            {

                inventTable = InventTable::find(inventoryTrans.ItemNumber);

            }

            inventJournalTrans.initFromInventTable(inventTable);

            inventJournalTrans.LineNum          = lineNum;

            inventJournalTrans.modifiedField(fieldNum(InventJournalTrans, ItemId));


            frominventDim.clear();

            frominventDim.initValue();

            frominventDim.InventSiteId          = InventSite::findRecId(str2Int64(inventoryTrans.SiteKey)).SiteId;

            frominventDim.InventLocationId      = InventLocation::findRecId(str2Int64(inventoryTrans.WarehouseKey)).InventLocationId;

            select firstonly fromwMSLocation

                where fromwMSLocation.RecId == str2Int64(inventoryTrans.InventoryLocationKey);

            frominventDim.wMSLocationId = fromwMSLocation.wMSLocationId;

            //get product dimensions from Varaint

            inventdimfnd                        = InventDim::findInLegalEntity(inventdimcombo.InventDimId, curExt());

            //from Inventory details

            frominventDim.InventColorId         = inventdimfnd.InventColorId;

            frominventDim.InventSizeId          = inventdimfnd.InventSizeId;

            frominventDim.configId              = inventdimfnd.configId;

            frominventDim.InventStyleId         = inventdimfnd.InventStyleId;

            frominventDim.InventVersionId       = inventdimfnd.InventVersionId;

            //batch lot number

            if(EcoResTrackingDimensionGroup::find(inventTable.trackingDimensionGroup()).Name=='Batch-Phy')

            {

                InventBatch inventbatch = InventBatch::findOrCreateWithProdDate(inventoryTrans.BatchLotNumber,

                                                                                inventTable.ItemId,

                                                                                DateTimeUtil::getToday(DateTimeUtil::getUserPreferredTimeZone()));

                if(inventbatch)

                {

                    frominventDim.inventBatchId         = inventbatch.inventBatchId;

                }

            }

          

            frominventDim = InventDim::findOrCreate(frominventDim);


            //to inventory details

            ToinventDim.clear();

            ToinventDim.initValue();

            ToinventDim.InventSiteId          = InventSite::findRecId(str2Int64(mv2tolocation.ToSiteKey)).SiteId;

            ToinventDim.InventLocationId      = InventLocation::findRecId(str2Int64(mv2tolocation.ToWarehouseKey)).InventLocationId;

            select firstonly toWmslocation

                where toWmslocation.RecId == str2Int64(mv2tolocation.ToInventoryLocationKey);

            ToinventDim.wMSLocationId = toWmslocation.wMSLocationId;


            ToinventDim.InventColorId         = inventdimfnd.InventColorId;

            ToinventDim.InventSizeId          = inventdimfnd.InventSizeId;

            ToinventDim.configId              = inventdimfnd.configId;

            ToinventDim.InventStyleId         = inventdimfnd.InventStyleId;

            ToinventDim.InventVersionId       = inventdimfnd.InventVersionId;

            if(frominventDim.inventBatchId)

            {

                ToinventDim.inventBatchId         = frominventDim.inventBatchId;

            }

            ToinventDim = InventDim::findOrCreate(ToinventDim);

            inventJournalTrans.InventDimId = frominventDim.inventDimId;

            inventJournalTrans.ToInventDimId = ToinventDim.inventDimId;

            inventJournalTrans.modifiedField(fieldNum(InventJournalTrans, inventDimId));

            inventJournalTrans.Qty              = inventoryTrans.Quantity;

            inventJournalTrans.modifiedField(fieldNum(inventJournalTrans, Qty));

            inventJournalTrans.JournalType      = InventJournalType::Transfer;

            inventJournalTrans.insert();

            if(MV2Parameters::find().PostMoveInventory == Noyes::Yes)

            {

                this.postInventTransferJouranl(inventJournalTrans.JournalId);

            }

            // update in log form

            mV2TransactionBaseUPD                                = mV2TransactionBase::findbyId(_MV2TransactionBase.ID, true);

            mV2TransactionBaseUPD.IsProcessed                    = MV2Isprocessed::Processed;

            mV2TransactionBaseUPD.MV2JournalId                   = inventJournalTable.JournalId;

            mV2TransactionBaseUPD.ErrorDescription               = ' ';

            mV2TransactionBaseUPD.update();

            ttscommit;

        }

        catch (Exception::Error)

        {

            str errormessage = infolog.text(infolog.line());

            ttsbegin;

            mV2TransactionBaseUPD                                = mV2TransactionBase::findbyId(_MV2TransactionBase.ID, true);

            mV2TransactionBaseUPD.IsProcessed                    = MV2Isprocessed::Error;

            mV2TransactionBaseUPD.MV2JournalId                   = nullValueFromType(Types::String);

            mV2TransactionBaseUPD.ErrorDescription               = errormessage;

            mV2TransactionBaseUPD.update();

            ttscommit;

        }

           

    }


    /// <summary>

    /// method is used for posting the journal

    /// </summary>

    /// <param name = "_journalId">journalnum</param>

    public void postInventTransferJouranl(JournalId _journalId)

    {

        InventJournalTable      inventJournalTable;

        InventJournalTrans      inventJournalTrans;

        JournalCheckPost        journalCheckPost;

        boolean throwserror=true;

        boolean showinforesult=true;

 

 

        inventJournalTable = InventJournalTable::find(_journalId,true);

        try

        {

            ttsbegin;

            inventJournalTable.SystemBlocked = NoYes::Yes;

            inventJournalTable.update();

            journalCheckPost =

            InventJournalCheckPost::newJournalCheckPost(JournalCheckpostType::Check,inventJournalTable);

            journalCheckPost.parmThrowCheckFailed(throwserror);

            journalCheckPost.parmShowInfoResult(showinforesult);

            journalCheckPost.run();

 

            inventJournalTable.SystemBlocked = NoYes::No;

            inventJournalTable.Posted = NoYes::Yes;

            select count(RecId) from inventJournalTrans where inventJournalTrans.JournalId == inventJournalTable.JournalId;

            inventJournalTable.NumOfLines = inventJournalTrans.recid;

            inventJournalTable.update();

            ttscommit;

        }

        catch

        {

            throw exception::UpdateConflict;

        }


    }


}

X++ code to get Ledger period start date / End date And calculate main account balance from trail balances

 public AmountMst openingbalance()

    {

        LedgerBalanceMainAccountAmounts ledgerBalance;

        GeneralJournalAccountEntry      generalJournalAccountEntry;

        GeneralJournalEntry              generaljournalentry;

        FiscalCalendarPeriod             fiscalCalendarPeriod;

        AmountMst  opSum;

        LedgerPeriodCode ledgerPeriodCode;

        InventPosting     inventposting;

// To get period start date

       periodstart periodStartDate = FiscalCalendarYear::findYearByCalendarDate(Ledger::fiscalCalendar(), fromDate).StartDate;

       

        select * from inventposting 

            where inventposting.InventAccountType == InventAccountType::PurchPackingSlipPurchaseOffsetAccount;

        /// select statement to get sum of Main account balances

        select sum(AccountingCurrencyAmount) from generalJournalAccountEntry 

            where generalJournalAccountEntry.MainAccount == MainAccount::findByMainAccountId(inventposting.ledgerAccountName()).RecId

                join generaljournalentry where generalJournalAccountEntry.GeneralJournalEntry == generaljournalentry.RecId

                    && generaljournalentry.AccountingDate >= periodStartDate 

                    && generaljournalentry.AccountingDate<= fromDate

                        join fiscalCalendarPeriod where fiscalCalendarPeriod.RecId == generaljournalentry.FiscalCalendarPeriod

                            && (fiscalCalendarPeriod.Type == FiscalPeriodType::Opening

                            || fiscalCalendarPeriod.Type == FiscalPeriodType::Operating);


        return generalJournalAccountEntry.AccountingCurrencyAmount;

Multithreading (Batch bundelling) Using sysoperation in D365 fo X++

 Here is my requirement is I have to create Job card journals that flowing from 3rd part application through a data entity.

For that, I have implemented a Multithreading sysopeartion which is a batch bundling process.

For that, I have created a base class and implementing it through required classes.


Read comments for a better understanding.

1.Create on contract class 

this contract class will hold the parameters for user that he need to specify the maximum number of records and sleep time betweeen each task based on his data.

/// <summary>

/// contract class to get and set the parameters

/// </summary>

[DataContractAttribute]

class WipTransactionsMultithreadContract

{

    TransDate       fromDate,toDate;

    PositiveNumber  taskSleepTimeMs;

    PositiveNumber  maxTaskCount;

    public Range           batchIdentifier;

test

    /// <summary>

    /// Parm method to intilize batch identifier ranges values

    /// </summary>

    /// <param name = "_batchIdentifier">Range</param>

    /// <returns>Range</returns>

    [DataMemberAttribute,SysOperationControlVisibilityAttribute(false)]

    public Range parmBatchIdentifier(Range _batchIdentifier = batchIdentifier)

    {

        batchIdentifier = _batchIdentifier;

        return batchIdentifier;

    }

    /// <summary>

    /// parm method to set the sleep time for batch

    /// </summary>

    /// <param name = "_taskSleepTimeMs">positive integer</param>

    /// <returns>Sleeptime</returns>

    [DataMemberAttribute,SysOperationLabelAttribute("Task Sleep Time"),SysOperationHelpTextAttribute("Task Sleep Time in ms"),SysOperationDisplayOrderAttribute('1')]

    public PositiveNumber parmTaskSleepTimeMs(PositiveNumber _taskSleepTimeMs = taskSleepTimeMs)

    {

        taskSleepTimeMs = _taskSleepTimeMs;

        return taskSleepTimeMs;

    }

    /// <summary>

    ///parm method to specify Max number of task count

    /// </summary>

    /// <param name = "_maxTaskCount">Positive integer</param>

    /// <returns>Maxtaskcount</returns>

    [DataMemberAttribute,SysOperationLabelAttribute("Max task Count"),SysOperationHelpTextAttribute("Enter Max Task count"),SysOperationDisplayOrderAttribute('2')]

    public PositiveNumber parmMaxTaskCount(PositiveNumber _maxTaskCount = maxTaskCount)

    {

        maxTaskCount = _maxTaskCount;

        return maxTaskCount;

    }

}

By this, we are given a user interface for the user

2. Now create one base class which will used to run thread tasks for operation

/// <summary>

/// base class to run opearions in parellel batch process

/// </summary>

class testWiptransactionsMultithreadBase extends SysOperationServiceBase

{

    Range                       batchIdentifier;

    BatchHeader                 batchHeader;

    Batchable                   finalTask;

    /// <summary>

    /// method used to run threads for our batch

    /// </summary>

    /// <param name = "_TestWipTransactionsMultithreadContract">TestWipTransactionsMultithreadContract</param>

    public void runSubTask(TestWipTransactionsMultithreadContract _TestWipTransactionsMultithreadContract)

    {

        container               batchIdentifierCon;

        int                     i;

        batchIdentifier =_TestWipTransactionsMultithreadContract.batchIdentifier;

        if (batchIdentifier) //child task

        {

            if (batchIdentifier == this.finalTaskIdentifier())

            {

                this.runFinalTask();

            }

            else

            {

                this.runThreadTask();

            }

        }

        else

        {

            this.runStartTask();

            batchIdentifier = this.finalTaskIdentifier();

            this.processThreadItem(true); //create the final task, we need a dependency, so create it in the beggining.

            batchIdentifierCon = this.getBatchIdentifiersRangeCon();

            for (i = 1; i <= conLen(batchIdentifierCon); i++)

            {

                batchIdentifier = conPeek(batchIdentifierCon, i);

                this.processThreadItem(false);

            }

            if (finalTask)

            {

                if (this.isExecutingInBatch())

                {

                    batchHeader.save();

                }

                else

                {

                    finalTask.run();

                }

            }

        }

    }

    /// <summary>

    /// Intial method for task run

    /// </summary>

    public void runStartTask()

    {

    }

    /// <summary>

    /// runs thread task for devided batches

    /// </summary>

    public void runThreadTask()

    {

    }

    /// <summary>

    /// runs final task for batch

    /// </summary>

    public void runFinalTask()

    {

    }

    /// <summary>

    /// Identifer method to recognize the end value

    /// </summary>

    /// <returns>Identifier string</returns>

    public Range  finalTaskIdentifier()

    {

        return '--TheLast--';

    }

    /// <summary>

    /// Container for holding the ranges

    /// </summary>

    /// <returns>Range container</returns>

    public container  getBatchIdentifiersRangeCon()

    {

        container  res;

        return res;

    }

    /// <summary>

    /// Process the thread based recrds in service class

    /// </summary>

    /// <param name = "_isLast">boolean</param>

    protected void processThreadItem(boolean _isLast)

    {

        //WiptransactionsMultithreadservice        childThread;

        SysOperationServiceController  controller;

        WipTransactionsMultithreadContract dataContract;

        ;

        if (!batchIdentifier)

        {

            return;

        }

        controller = new SysOperationServiceController(classStr(WiptransactionsMultithreadservice),methodStr(WiptransactionsMultithreadservice,runSubTask));

        dataContract = controller.getDataContractObject('_WipTransactionsMultithreadContract');

        // initialize variables for the data contract

        dataContract.parmBatchIdentifier(batchIdentifier);

        if(this.isExecutingInBatch() && !batchHeader)

        {

            // if no batchheader has been set yet, get it

            batchHeader = this.getCurrentBatchHeader();

        }

        if (_isLast)

        {

            finalTask = controller;

        }

        if (this.isExecutingInBatch())

        {

            batchHeader.addRuntimeTask(controller, this.getCurrentBatchTask().RecId);

            if (! _isLast && finalTask)

            {

                batchHeader.addDependency(finalTask, controller, BatchDependencyStatus::FinishedOrError);

            }

                }

        else

        {

            if (! _isLast)

            {

                controller.run();

                //childThread.run();

            }

        }

    }

}

3. Create one service class which implemnts from Multithreadbase

/// <summary>

/// Service class to create batches for job card operations

/// </summary>

class TestWiptransactionsMultithreadservice extends TestWiptransactionsMultithreadBase

{

    QueryRun       queryRun;

    TransDate       fromDate,toDate;

    PositiveNumber  taskSleepTimeMs;

    PositiveNumber  maxTaskCount;

    /// <summary>

    /// A new method intilzes query

    /// </summary>

    public void new()

    {

        this.initQuery();

    }

    /// <summary>

    /// description for the class

    /// </summary>

    /// <returns>string</returns>

    static ClassDescription description()

    {

        return 'Batch multiple threads';

    }

    /// <summary>

    /// Run method to intilze contract class parameters to base class

    /// </summary>

    /// <param name = "TestWipTransactionsMultithreadContract">contract</param>

    public void runSubTask(TestWipTransactionsMultithreadContract _TestWipTransactionsMultithreadContract)

    {

        super(_TestWipTransactionsMultithreadContract);

    }

    /// <summary>

    /// Start method

    /// </summary>

    public void runStartTask()

    {

        //1. data preparation

        info(strFmt('%1 - Start operation',AifUtil::applyUserPreferredTimeZoneOffset(DateTimeUtil::utcNow())));

    }

    /// <summary>

    /// Used to run the query class

    /// </summary>

    /// <returns>queryrun</returns>

    public QueryRun queryRun()

    {

        return queryRun;

    }

    /// <summary>

    /// Default value for parameter

    /// </summary>

    public void initParmDefault()

    {

        this.initQuery();

        taskSleepTimeMs = 100;

    }

    /// <summary>

    /// Method used for create custom query

    /// </summary>

    public void initQuery()

    {

        Query                   query = new Query();

        query.addDataSource(tablenum(WipTransactions));

        queryRun = new QueryRun(query);

    }

    /// <summary>

    /// Runs Threads and process query for batch job

    /// </summary>

    public void runThreadTask()

    {

        //2. Query Processing

        this.initQuery();

        QueryBuildDataSource  qBDS = queryRun.query().dataSourceTable(tablenum(TesWipTransactions));

        qBDS.addRange(fieldnum(TesWipTransactions, RecId)).value(batchIdentifier);

        qBDS.addRange(Fieldnum(Testwiptransactions ,RecordLaborStatusType)).value('Stop');

        qBDS.addRange(fieldNum(TestWipTransactions, Isprocessed)).value(SysQuery::value(TestIsprocessed::NotProcessed));

        while (queryRun.next())

        {

            TestWipTransactions   wiptrans = queryRun.get(tablenum(TestWipTransactions));

            this.processRecord(wiptrans);

        }

    }

    /// <summary>

    /// end of the runnable task 

    /// </summary>

    public void runFinalTask()

    {

        //3.final task

        info(strfmt('%2 - %1 record(s) processed', SysQuery::countTotal(queryRun),

                AifUtil::applyUserPreferredTimeZoneOffset(DateTimeUtil::utcNow())));

    }

    /// <summary>

    /// sets range values in container based on the given parameter

    /// </summary>

    /// <returns>container</returns>

    public container  getBatchIdentifiersRangeCon()

    {

        container  res;

        QueryRun   queryRunLocal = new QueryRun(queryRun.query());

        QueryBuildDataSource   qBDS = queryRunLocal.query().dataSourceTable(tablenum(TestWipTransactions));

        int                    totalRecords, curRecord, recordsPerBatch;

        RecId                  fromRecId, toRecId;

        qBDS.sortClear();

        qBDS.addSortField(fieldnum(TestWipTransactions, RecId));

        qBDS.addRange(fieldnum(TestWipTransactions, RecId)).value(batchIdentifier);

        qBDS.addRange(Fieldnum(Testwiptransactions ,RecordLaborStatusType)).value('Stop');

        qBDS.addRange(fieldNum(TestWipTransactions, Isprocessed)).value(SysQuery::value(TestIsprocessed::NotProcessed));

        totalRecords = SysQuery::countTotal(queryRunLocal);

        recordsPerBatch = maxTaskCount > 0 ? totalRecords div maxTaskCount : totalRecords;

        if (! recordsPerBatch)

        {

            recordsPerBatch = 1;

        }

        while (queryRunLocal.next())

        {

            TestWipTransactions   wiptransactions = queryRunLocal.get(tablenum(TestWipTransactions));

            if (!fromRecId)

            {

                fromRecId = wiptransactions.RecId;

            }

            curRecord++;

            toRecId = wiptransactions.RecId;

            if ((curRecord mod recordsPerBatch) == 0)

            {

                res += SysQuery::range(fromRecId, toRecId);

                fromRecId = 0;

                curRecord = 0;

            }

        }

        if (curRecord && fromRecId && toRecId)

        {

            res += SysQuery::range(fromRecId, toRecId);

        }

        return res;

    }

    /// <summary>

    /// process records for creating batch

    /// </summary>

    /// <param name = "_wiptransactions">TestWipTransactions</param>

    public void processRecord(TestWipTransactions  _wiptransactions)

    {

        try

        {

            //do some job using WIptransactions   add your service method

            TestWIPTransactionsJobcardsBatch testWIPTransactionsJobcardsBatch = new   TestWIPTransactionsJobcardsBatch();

            TestWIPTransactionsJobcardsBatch.Processoperation(_wiptransactions);

            _wiptransactions.reread();

            sleep(taskSleepTimeMs);

        }

        catch

        {

            error(strfmt('Error occured for RecordId %1 OrderNum %2 ',_wiptransactions.RecId,_wiptransactions.OrderNumber));

        }

    }

    /// <summary>

    /// Method to intiate operation 

    /// </summary>

    /// <param name = "_TestWipTransactionsMultithreadContract">Contract</param>

    public void createJobcards(TestWipTransactionsMultithreadContract _TestWipTransactionsMultithreadContract)

    {

        taskSleepTimeMs=_TestWipTransactionsMultithreadContract.parmTaskSleepTimeMs();

        maxTaskCount=_TestWipTransactionsMultithreadContract.parmMaxTaskCount();

        // this.PopulateGroupTable();

        this.runSubTask(_TestWipTransactionsMultithreadContract);

    }

}

4. Create one process class that is responsible to run our operations

Here I'm creating one class named  "WIPTransactionsJobcardsBatch" which is used to process the records and create job cards, you can create any of the classes that processed your requirement.

After creating this class you must have to call this class in multithread service class so that we can divide the records and process the divided records in this service class.

Let me give you one scenario, this will create and post job cards for incoming records.

TestWIPTransactionsJobcardsBatch:

/// <summary>

/// Clss to run the process for creating job cards

/// </summary>

class  testWIPTransactionsJobcardsBatch

{

    /// <summary>

    /// method used to create the Job cards

    /// </summary>

    /// <param name = "_wiptransactions">TestWipTransactions</param>

    public void Processoperation(TestWipTransactions _wiptransactions)

    {

        ProdJournalTable                        prodJournalTable;

        ProdJournalRoute                        prodJournalRoute;

        ProdRoute                               prodRoute;

        testwiptransactions                      wiptransactions,wiptransactionsUpd;

        TestTransactionBase                      transactionBase;

        try

        {

            ttsbegin;

            wiptransactions = _wiptransactions;

            select firstonly prodRoute where prodRoute.ProdId == wiptransactions.OrderNumber

                        && prodRoute.OprNum == str2Int(wiptransactions.OperationNumber);

            if(!prodRoute)

            {

                throw Global::error(strFmt('Route OprNum -%1 Does not exists for OrderNum - %2',wiptransactions.OperationNumber,wiptransactions.OrderNumber));

            }

            prodJournalTable.clear();

            prodJournalTable.initValue();

            prodJournalTable.JournalType             = prodjournaltype::JobCard;

            prodJournalTable.ProdId                  = prodRoute.ProdId;

            prodJournalTable.JournalNameId           = ProdParametersDim::findDefault().JobCardJournalNameId;

            prodJournalTable.Description             = ProdJournalName::find(prodJournalTable.JournalNameId).Description;

            prodJournalTable.VoucherSeqRecId         = ProdJournalName::find(prodJournalTable.JournalNameId).VoucherSeqRecId;

            prodJournalTable.VoucherDraw             = journalVoucherDraw::Post;

            prodJournalTable.NumOfLines              = 1;

            prodJournalTable.insert();

            //job card entry

            prodJournalRoute.clear();

            prodJournalRoute.JournalId               = prodJournalTable.journalId;

            prodJournalRoute.ProdId                  = prodRoute.ProdId;

            prodJournalRoute.initValue();

            prodJournalRoute.OprNum                  = prodRoute.OprNum;

            prodJournalRoute.JobId                   = ProdRouteJob::findJobOpr(prodRoute.ProdId,prodRoute.OprNum, prodRoute.OprPriority).JobId;

            prodJournalRoute.OprId                   = prodRoute.OprId;

            prodJournalRoute.DefaultDimension        = prodRoute.DefaultDimension;

            prodJournalRoute.JobType                 = RouteJobType::Process;

            // prodJournalRoute.CategoryHoursId         = prodRoute.SetUpCategoryId;

            //prodJournalRoute.CategoryQtyId           = prodRoute.ProcessCategoryId;

            prodJournalRoute.WrkCtrId                = wrkctrtable::findByRecId(str2Int64(wiptransactions.WorkCenterExternalKey)).WrkCtrId;

            //added for wrkctrCategoryhourse id

            WrkCtrTable wrkCtrTable                  = prodJournalRoute.wrkCtrTable();

            ProdJobType prodJobType                  = ProdJobType::construct(prodJournalRoute.JobType);

            prodJournalRoute.setCategoryHours(wrkCtrTable.SetUpCategoryId);

            prodJournalRoute.setCategoryQty(wrkCtrTable.QtyCategoryId);

            // for worker

            transactionBase                          = TestTransactionBase::findbyId(wiptransactions.ID);

            prodJournalRoute.Worker                  = str2Int64(transactionBase.PerformedByErpUserKey) ;

            // for deault dimensions

            //prodJournalRoute.DefaultDimension        = prodJournalRoute.copyDimension(prodJournalRoute.prodTable().DefaultDimension);

            //prodJournalRoute.DefaultDimension        = prodJournalRoute.mergeDimension(wrkCtrTable.DefaultDimension, prodJournalRoute.DefaultDimension);

            prodJournalRoute.QtyGood                 = wiptransactions.CompletedQuantity;

            prodJournalRoute.FromTime                = DateTimeUtil::time(wiptransactions.StartLabourDate);

            prodJournalRoute.ToTime                  = DateTimeUtil::time(wiptransactions.EndLaborDate);

            prodJournalRoute.Hours                   = (wiptransactions.DurationInMinutes)/60;

            if (wiptransactions.CompletedQuantity)

            {

                prodJournalRoute.ProdPickList            = NoYes::Yes;

            }

            prodJournalRoute.insert();

            if(TestParameters::find().PostJobCardJournal == NoYes::Yes)

            {

                ProdJournalCheckPostRoute ProdJournalCheckPostRoute;

                ProdJournalCheckPostRoute = ProdJournalCheckPostRoute::newPostJournal(prodJournalRoute.journalId,true);

                ProdJournalCheckPostRoute.runOperation();

            }

            wiptransactionsUpd                      = Testwiptransactions::findRecId(wiptransactions.RecId,true);

            wiptransactionsUpd.Isprocessed          = TestIsprocessed::Processed;

            wiptransactionsUpd.TestJobCardId         = prodJournalTable.journalId;

            wiptransactionsUpd.ErrorDescription     = ' ';

            wiptransactionsUpd.update();

            ttscommit;

        }

        catch(Exception::Error)

        {

            str errormessage = infolog.text(infologLine());

            ttsbegin;

            wiptransactionsUpd =   Testwiptransactions::findRecId(wiptransactions.RecId,true) ;

            wiptransactionsUpd.Isprocessed = TestIsprocessed::Error;

            wiptransactionsUpd.ErrorDescription = errormessage;

            wiptransactionsUpd.update();

            ttscommit;

        }

    }

}

Now all set to run the operation, one thing is pending that you have to create one controller class to execute this operation and give the scope of both service classes.

5. TestWIPTransactionsJobCardController :

Opeartion will be intiated from Multithread service class itself. Lets Go..!

/// <summary>

/// Controller class to run Batch for job Card creations

/// </summary>

class TestWIPTransactionsJobCardController Extends SysOperationServiceController

{

    /// <summary>

    /// Caption for batch job

    /// </summary>

    /// <returns>string caption</returns>

       public ClassDescription caption()

    {

        return 'Test Job Card Creation';

    }

    /// <summary>

    /// new method used for intilize service class in controller

    /// </summary>

    protected void new()

    {

        super(classStr(TestWiptransactionsMultithreadservice), methodStr(TestWiptransactionsMultithreadservice,createJobcards ), SysOperationExecutionMode::Synchronous);

    }

    /// <summary>

    /// method to create object for controller

    /// </summary>

    /// <param name = "_executionMode">synchronus</param>

    /// <returns>controller</returns>

    public static TestWIPTransactionsJobCardController construct(SysOperationExecutionMode _executionMode = SysOperationExecutionMode::Synchronous)

    {

        TestWIPTransactionsJobCardController controller;

        controller = new  TestWIPTransactionsJobCardController();

        controller.parmExecutionMode(_executionMode);

        return controller;

    }

    /// <summary>

    /// Main method intiate Opeartion for batch

    /// </summary>

    /// <param name = "_args">args</param>

    public static void main(Args _args)

    {

        TestWIPTransactionsJobCardController controller;

        controller =  TestWIPTransactionsJobCardController::construct();

        controller.parmArgs(_args);

        controller.startOperation();

    }

}

Now create one Action menu item and this controller class and run, Now your batch will run in the multithreading batch bundling process.

Thank you !!

Reference: Click here



Create Product Recipt and register inventory using X++(Sysoperation)

By using the below code we can create a product recipt for purchase order and register inventory aswell

points to remember:

in my requiremnet transaction base is the master table holds the data of transactions

inventory transactions will hold the data of  item number and quantity

Order entity will hold the data of PurchOrders.

Assume the data flowing from above tables and allow us to create product recipet and inventory registration.

 


class TestProductReceiptPostingService

{

    PurchFormLetterParmData          purchFormLetterParmData;

    PurchParmTable                   purchParmTable;

    PurchParmLine                    purchParmLine;

    purchParmUpdate                  purchParmUpdate;

    PurchTable                       purchTable;

    TransDate                        packingSlipDate;

    PackingSlipId                    packingSlipId;

    purchFormLetter                  purchFormLetter;

  testorderentity                   Orderentity,Orderentity1;

    

    


        /// <summary>

    /// Processer method to register the item

    /// </summary>

    /// <param name = "_Transbase">testtransactionbase</param>

    public void insertParmTableData(testInventoryTransactions _inventoryTrans, testtransactionbase _Transbase)

    {

        Orderentity     = testorderentity::findbyId(_Transbase.ID);

        if(!Orderentity)

        {

            throw Global::Error(strFmt('Manufacturing Order for inventroy transaction ID- %1 is not yet created',_Transbase.ID));

        }

        purchTable = PurchTable::find(Orderentity.OrderNumber,false);


        purchFormLetterParmData = PurchFormletterParmData::newData(DocumentStatus::PackingSlip,VersioningUpdateType::Initial);

        purchFormLetterParmData.parmOnlyCreateParmUpdate(true);

        purchFormLetterParmData.createData(false);

        purchParmUpdate = purchFormLetterParmData.parmParmUpdate();


        // Set PurchParmTable table

        purchParmTable.clear();

        purchParmTable.TransDate = DateTimeUtil::date(_Transbase.TransactionDate); // which can be changed

        purchParmTable.Ordering = DocumentStatus::PackingSlip;

        purchParmTable.ParmJobStatus = ParmJobStatus::Waiting;

        purchParmTable.Num = _Transbase.Reference; // product receipt no

        purchParmTable.PurchId = purchTable.PurchId;

        purchParmTable.PurchName = purchTable.PurchName;

        purchParmTable.DeliveryName = purchTable.DeliveryName;

        purchParmTable.DeliveryPostalAddress = purchTable.DeliveryPostalAddress;

        purchParmTable.OrderAccount = purchTable.OrderAccount;

        purchParmTable.CurrencyCode = purchTable.CurrencyCode;

        purchParmTable.InvoiceAccount = purchTable.InvoiceAccount;

        purchParmTable.ParmId = purchParmUpdate.ParmId;

        purchParmTable.insert();

    }


    public boolean insertParmLineData(testInventoryTransactions _inventoryTrans, testtransactionbase _Transbase)

    {

        InventDim inventDim;

        PurchLine purchLine;

        WMSLocation Location;

        int64       linenum;

        boolean ret = false;

        InventDimCombination    inventDimCombination;

        str itemid;


        select firstonly inventDimCombination where inventDimCombination.RetailVariantId == _inventoryTrans.ItemNumber;

        if (inventDimCombination.recid)

        {

            itemid  = inventDimCombination.ItemId;

        }

        else

        {

            itemid = _inventoryTrans.ItemNumber;

        }


        Orderentity1     = testorderentity::findbyId(_Transbase.ID);

        linenum          = str2Int64(Orderentity1.LineNumber);


        select firstonly Location where Location.RecId == str2Int64(_inventoryTrans.InventoryLocationKey);

        select firstonly purchLine 

            where purchLine.ItemId  == itemid

            && purchLine.PurchId    == purchTable.PurchId

            && purchLine.LineNumber == linenum

           ;

        purchParmLine.InitFromPurchLine(purchLine);

        inventDim = purchLine.inventDim(); 

        purchParmLine.ItemId = purchLine.ItemId;

        purchParmLine.ReceiveNow = decRound(_inventoryTrans.Quantity, 2);

        purchParmLine.InventDimId = inventDim.inventdimid;

        purchParmLine.ParmId = purchParmTable.ParmId;

        purchParmLine.TableRefId = purchParmTable.TableRefId;

        purchParmLine.setQty(DocumentStatus::PackingSlip, false, true);

        purchParmLine.setLineAmount();

        purchParmLine.insert();               

       // inventDim.inventBatchId = _inventoryTrans.BatchLotNumber;

        inventDim.wMSLocationId = Location.wMSLocationId;

        inventDim = inventDim::findOrCreate(inventDim); //Creating new invent dim for registration

        this.registerInventory(purchParmLine, inventDim);

        ret = true;

        return ret;

    }


    public void registerInventory(PurchParmLine _purchParmline,InventDim _inventDim)

    {

        InventTransWMS_Register inventTransWMS_register;

        InventTrans inventTranslocal = InventTrans::findTransId(_purchParmline.InventTransId, true);

        TmpInventTransWMS tmpInventTransWMS;

        InventDim inventDimlocal = inventTranslocal.inventDim();

        InventDim InventBatchCheck;

 

        inventDimlocal.inventBatchId = _inventDim.inventBatchId;

        inventDimlocal.InventLocationId = _inventDim.InventLocationId;

        inventDimlocal.InventSiteId = _inventDim.inventSiteId;

        inventDimlocal = InventDim::findOrCreate(inventDimlocal);

        inventTransWMS_register = inventTransWMS_register::newStandard(tmpInventTransWMS);


        inventTranslocal.inventDimId = inventDimlocal.inventDimId;

    

        tmpInventTransWMS.clear();

        tmpInventTransWMS.initFromInventTrans(inventTranslocal);

        tmpInventTransWMS.ItemId = inventTranslocal.ItemId;

        tmpInventTransWMS.InventQty = _purchParmline.ReceiveNow;

        tmpInventTransWMS.insert();


        inventTransWMS_register.writeTmpInventTransWMS(tmpInventTransWMS,

                                                    inventTranslocal,

                                                     inventDimlocal);

       

        inventTransWMS_register.updateInvent(inventTranslocal);

    }


    public boolean processProductReceipt()

    {

        boolean ret  = false;

        purchFormLetter = PurchFormLetter::construct(DocumentStatus::PackingSlip);

        purchFormLetter.transDate(systemDateGet());

        purchFormLetter.proforma(false);

        purchFormLetter.specQty(PurchUpdate::ReceiveNow);

        purchFormLetter.purchTable(purchTable);

        purchFormLetter.parmParmTableNum(purchParmTable.Num);

        purchFormLetter.parmId(purchParmTable.ParmId);

        purchFormLetter.purchParmUpdate(purchFormLetterParmData.parmParmUpdate());

        purchFormLetter.run();

        ret = true;

        return ret;

    }


    public void updateTransactionBase( testtransactionbase _Transbase)

    {

        testTransactionBase  testtransactionbase;


        test   transactionbase                  = testtransactionbase::findbyId(_Transbase.ID,true);

        testtransactionbase.IsProcessed      = testIsprocessed::Processed;

        testtransactionbase.testJournalId     = purchTable.PurchId;

        testtransactionbase.ErrorDescription = ' ';

        testtransactionbase.update();

    }


}




Lets implement it in Sysoperation:

class TestProductReceiptPostingHelper extends SysOperationServiceBase

{

    public void processOperation()

    {

        Log                         errorMessage;

        SysInfologEnumerator        sysInfologEnumerator;

        TestTransactionBase          Transbase,transactionbase;

        TestInventoryTransactions    inventoryTrans;

        boolean                     firstrecord = false,ret = false,post = false;

        testProductReceiptPostingService PostingService = new testProductReceiptPostingService();


        #OCCRetryCount

        try

        {

            while select * from inventoryTrans

            join Transbase

                where Transbase.ID == inventoryTrans.ID

                   && Transbase.TransactionType == 'OReceiveItem'

                   && (Transbase.Task == 'ProcessOReceiveItemPurchaseReceiptToStock'

                   ||  Transbase.Task == 'ProcessOReceiveItemPurchaseReceiptToInspection'

                   ||  Transbase.Task == 'ProcessOReceiveItemPurchaseReceiptToDock')

                   &&  Transbase.IsProcessed == testIsprocessed::NotProcessed

            {

                ttsbegin;

                if (firstrecord == false)

                {

                    PostingService.insertParmTableData(inventoryTrans,Transbase);

                    firstrecord = true;

                }

                ret = PostingService.insertParmLineData(inventoryTrans,Transbase);

                if (ret == true)

                {

                    PostingService.updateTransactionBase(Transbase);

                }

                ttscommit;

            }

            if(ret == true)

            {

                post = PostingService.processProductReceipt();

            }

        }

        catch(Exception::Error)

        {

            error('Error: Posting failed!');

               

            errormessage = infolog.text(infologLine());


            ttsbegin;

            testtransactionbase                  = testtransactionbase::findbyId(Transbase.ID,true);

            testtransactionbase.IsProcessed      = testIsprocessed::NotProcessed;

            testtransactionbase.errordescription = errormessage;

            testtransactionbase.update();

            ttscommit;

        }

        catch (Exception::Deadlock)

        {

            retry; // *** here the program stucked and not continue.

        }

        catch (Exception::UpdateConflict)

        {

            retry;

        }

        catch(Exception::DuplicateKeyException)

        {

            // retry in case of an duplicate key conflict

            if (appl.ttsLevel() == 0)

            {

                if (xSession::currentRetryCount() >= #RetryNum)

                {

                    throw Exception::DuplicateKeyExceptionNotRecovered;

                }

                else

                {

                    retry;

                }

            }

            else

            {

                throw Exception::DuplicateKeyException;

            }

        }

    }

}



Controller class for run operation:



class testProductReceiptPostingController extends SysOperationServiceController

{

    protected void new()

    {

        super();

        this.parmClassName(classStr(TestProductReceiptPostingHelper));

        this.parmMethodName(methodStr(TestProductReceiptPostingHelper, processOperation));


        this.parmDialogCaption('TestProduct Receipt Posting Batch');

    }


    public ClassDescription caption()

    {

        return 'Test Product Receipt Posting Batch';

    }


    public static void main(Args args)

    {

        TestProductReceiptPostingController controller;

    

        controller = new TestProductReceiptPostingController();

        controller.parmShowDialog(true);

        controller.startOperation();

    }


}


If we implement it in Multithreading using Sysoperation. Well !! will see it  in my next blog !!!

Thank you !


BYOD connection using X++ code

 //using System.Data.SqlClient;

class BYODConnection

{

    //    private DMFDataSource dmfDataSource

//    /// <summary>

//    /// Runs the class with the specified arguments.

//    /// </summary>

//    /// <param name = "_args">The specified arguments.</param>

    public static void main(Args _args)

    {

        boolean issuccess;

        str connectionstr;

        DMFDataSource dmfdb = DMFDataSource::find("BYOD10");

        if(dmfdb)

        {

            issuccess = DMFDataSource::validateEntityConnectionString(dmfdb);

        }

        else

        {

            CryptoBlob encryptedCryptoBlob;

            str value = "Data Source=serverName,1433; Initial Catalog=DB; Integrated Security=False; User ID=USer; Password=Passwrd";

// encrpyt the connection string

            encryptedCryptoBlob = WinAPIServer::cryptProtectData(str2cryptoblob(value));

            dmfdb.SourceName = "BYOd10";

            dmfdb.Type = DMFSourceType::EntityDB;

            dmfdb.Description = 'D365 to AZure Sql';

            dmfdb.EnableTargetTriggers = NoYes::Yes;

            dmfdb.insert();

            if(dmfdb)

            {

                Common common = dmfdb;

                connectionstr = appl.EncryptToStringForPurpose(value, common.encryptionPurpose(fieldNum(DMFDataSource, EntityStoreConnectionString)));

                info(strFmt("%1",connectionstr));

                ttsbegin;

                dmfdb.selectForUpdate(true);

                dmfdb.EntityStoreConnectionString = connectionstr;

                dmfdb.update();

                ttscommit;

                issuccess = DMFDataSource::validateEntityConnectionString(dmfdb);

            }

        }

        if(issuccess)

        {

            Info("Done");

        }

        else

        {

            Error("Failed");

        

        }

    

    }


}

Publish Entity using X++ code in D365 Fo

Using the below class we can publish entities to BYOD


 class Entitypublish

{

    /// <summary>

    /// Runs the class with the specified arguments.

    /// </summary>

    /// <param name = "_args">The specified arguments.</param>

    public static void main(Args _args)

    {

        DmfPublishedEntity dmfPublishedEntity;

        MV2EntityList    EntityList;

        DMFDataSource dmfDataSource;

        container listOfUnPublishedEntites,listOfPublishedEnties;


        boolean alreadyPublished;

        Entitypublish class1 = new Entitypublish();

        while select * from EntityList

        {

            DMFEntity entityloc = DMFEntity::find(EntityList.EntityName);

            dmfDataSource = dmfDataSource::find("BYOD10");


            select firstonly EntityName from dmfPublishedEntity

                    where dmfPublishedEntity.EntityName == entityloc.EntityName

                       && dmfPublishedEntity.SourceFormat == dmfDataSource.SourceName;

            

            if (dmfPublishedEntity.RecId)

            {

                alreadyPublished = true;

                listOfPublishedEnties =conIns(listOfPublishedEnties,1, dmfPublishedEntity.EntityName);

            }

            else

            {

                listOfUnPublishedEntites =conIns(listOfUnPublishedEntites,1,entityloc.EntityName);

            }

            class1.changetracking(entityloc);

        }

    

        if (alreadyPublished)

        {

            str  publishedEnties = con2Str(listOfPublishedEnties,',');

            DialogButton dialogBox = Box::yesNo(strFmt('@DMF:DMFEntityRePublishConfirm',publishedEnties,dmfDataSource.SourceName),DialogButton::No);


            if (dialogBox == DialogButton::Yes)

            {

                DMFEntityDbPublish::publishSchemaAsync(str2con(dmfDataSource.SourceName),listOfPublishedEnties,NoYes::Yes, '');

            }

        }

            

        if (conLen(listOfUnPublishedEntites))

        {

            DMFEntityDbPublish::publishSchemaAsync(str2con(dmfDataSource.SourceName),listOfUnPublishedEntites,NoYes::No, '');

        }

    }


    //Change tracking

        

           

    public void changetracking(DMFEntity _entityloc)

    {

        DictDataEntity dictEntity = new DictDataEntity(tableName2Id(_entityloc.TargetEntity));

        Query query = DMFEntityBase::defaultCTQuery(dictEntity);

        if(query == null)

        {

            if (DMFEntityBase::enableChangeTracking(_entityloc, true, true, false))

            {

                this.listOfTablesCTEnabled(_entityloc, DMFChangeTrackingType::ALL);


            }

        }

        else

        {

            if(DMFEntityBase::enableChangeTracking(_entityloc, true, true,true))

            {

                this.listOfTablesCTEnabled(_entityloc, DMFChangeTrackingType::CustomQuery);

            }

        

        }

        

    }


    public void listOfTablesCTEnabled(DMFEntity _entity,DMFChangeTrackingType __changeTrackingType)

    {

           

        AifSqlChangeTrackingEnabledTables   CTEnabledTablesloc;

        container   listOfEnabledTables;

        while select TableName from CTEnabledTablesloc

            where CTEnabledTablesloc.EntityName == _entity.TargetEntity

        {

            listOfEnabledTables = conIns(listOfEnabledTables,1,CTEnabledTablesloc.TableName);

        }

        if (conLen(listOfEnabledTables))

        {

            info(strFmt("@DMF:DMFCTEnableSuccess", _entity.EntityName));

            info(strFmt("@DMF:DMFCTEnabledList",con2Str(listOfEnabledTables)));

            info("@DMF:DMFCTIncrementalPush");

        }

    

    }


}

Create finacial dimenison Using X++

 //Change the arguments (variable) names and assign names as per your requirements

//Change in the function as well
public DimensionDefault createDefaultDimension(str department, str purpose, str costCenter)
{
    DimensionAttributeValueSetStorage   valueSetStorage = new DimensionAttributeValueSetStorage();
    DimensionDefault                    result;
    int                     i;
    DimensionAttribute      dimensionAttribute;
    DimensionAttributeValue dimensionAttributeValue;
    
    //Change the dimension names. Use the dimension name which are open and active in the system
    //I have given Region, Purpose and Costcentre just for an example
    
    container               conAttr = ["Region", "Purpose", "Costcentre"];
    
    //Change the values which you want to set in dimensions. Use values which are open and active in the system
    //I have given the arguments of function as values for dimensions.
    
    //Dimension name    ->      dimension value
    
    //Region            ->      department
    //Purpose           ->      purpose
    //Costcentre        ->      costCenter
    
    container               conValue = [department, purpose, costCenter];
    
    str                     dimValue;
    
    for (i = 1; i <= conLen(conAttr); i++)
    {
        dimensionAttribute = dimensionAttribute::findByName(conPeek(conAttr,i));
        if (dimensionAttribute.RecId == 0)
        {
            continue;
        }
        dimValue = conPeek(conValue,i);
        if (dimValue != "")
        {
            dimensionAttributeValue = dimensionAttributeValue::findByDimensionAttributeAndValue(dimensionAttribute,dimValue,false,true);
            valueSetStorage.addItem(dimensionAttributeValue);
        }
    }
    
    result = valueSetStorage.save();
    //It reutrns the value of type DimensionDefault
    return result;
}

CAR report in D365 f0


1.check metadata path

2.Navigate to specued path using cmd


C:\>cd K:

C:\>k:

 K:\>cd AosService\PackagesLocalDirectory

Note : Paste Xppbp cmd if mot found navigate to bin folder

K:\AosService\PackagesLocalDirectory>cd bin

K:\AosService\PackagesLocalDirectory\bin>xppbp.exe -metadata=K:\AosService\PackagesLocalDirectory -all -model="MV2" -xmlLog=C:\temp\BPCheckLogcd.xml -module="MV2" -car=c:\temp\CAReport.xlsx

To Get shipping carriers address and contact information in ax 2012

   while select  * from electronicAddress

                join logisticslocation where logisticslocation.ParentLocation ==TMSCarrierLogisticsLocationloc.Location

                && logisticslocation.RecId == electronicAddress.Location && electronicAddress.IsPrimary == true// NoYes::Yes;


            {

                ttsbegin;

                logisticsElectronicAddressloc = LogisticsElectronicAddress::findPrimary(electronicAddress.Location,electronicAddress.type);

                if(logisticsElectronicAddressloc.Locator)

                {

                   

                    if( logisticsElectronicAddressloc.type == LogisticsElectronicAddressMethodType::Phone)

                    {

                        tmscarrier.MV2TelephoneNumber = logisticsElectronicAddressloc.locator;

                    }


                    if(logisticsElectronicAddressloc.type == LogisticsElectronicAddressMethodType::Fax )

                    {

                        tmscarrier.MV2FaxNumber = logisticsElectronicAddressloc.locator;

                    }

                }

               

Create Product variants In ax 2012

 Creation of product Variants in Ax 2012 

Public void prodVariants(RefRecId _oldrecid, RefRecId _newRecid)

{


    select ProductDimensionGroup from ecoResProductDimensionGroupProductloc

         where ecoResProductDimensionGroupProductloc.Product == _oldrecid

            join ecoResProductDimensionGroup

                where ecoResProductDimensionGroup.RecId==ecoResProductDimensionGroupProductloc.ProductDimensionGroup;


    if (ecoResProductDimensionGroup.Name=="Config")

    {

        while select productMasterConfiguration

            where productMasterConfiguration.ConfigProductMaster== _oldrecid


        {

            productMasterConfigurationVariants = this.copyProdDimensionConfig(_newRecid , productMasterConfiguration);

            ecoResConfiguration = EcoResConfiguration::find(productMasterConfigurationVariants.Configuration);

            conVariants  = EcoResProductVariantDimValue::getDimensionValuesContainer(ecoResConfiguration.Name,ecoResSize.Name,

                                                                                                ecoResColor.Name);

            this.addVariantsToReleasedProduct(_newRecid,conVariants);

        }


    }

    if (ecoResProductDimensionGroup.Name=="Size")

    {

        while select ecoResProductMasterSize

              where ecoResProductMasterSize.SizeProductMaster == _oldrecid

        {

            ecoResProductMasterSizeVariants = this.copyProdDimensionsSIze(_newRecid , ecoResProductMasterSize);

            ecoResSize = EcoResSize::find(ecoResProductMasterSizeVariants.Size);

            conVariants  = EcoResProductVariantDimValue::getDimensionValuesContainer(ecoResConfiguration.Name,ecoResSize.Name,

                                                                                                ecoResColor.Name);

            this.addVariantsToReleasedProduct(_newRecid,conVariants);

        }

    }

    if (ecoResProductDimensionGroup.Name=="color")

    {

        while select ecoResProductMastercolor

            where ecoResProductMastercolor.ColorProductMaster == _oldrecid

        {

            ecoResProductMastercolorVariants = this.copyProdDimensionColur(_newRecid ,ecoResProductMastercolor);

            ecoResColor = EcoResColor::find(ecoResProductMastercolorVariants.Color);

            conVariants  = EcoResProductVariantDimValue::getDimensionValuesContainer(ecoResConfiguration.Name,ecoResSize.Name,

                                                                                                ecoResColor.Name);

            this.addVariantsToReleasedProduct(_newRecid,conVariants);

        }


    }

    if (ecoResProductDimensionGroup.Name=="Style")

    {

        while select ecoResProductMasterStyle

            where  ecoResProductMasterStyle.StyleProductMaster == _oldrecid

        {

            ecoResProductMasterStyleVariants = this.copyProdDimensionsStyle(_newRecid ,ecoResProductMasterStyle);

            ecoResStyle = EcoResStyle::find(ecoResProductMasterStyleVariants.Style);

            conVariants  = EcoResProductVariantDimValue::getDimensionValuesContainer(ecoResConfiguration.Name,ecoResSize.Name,

                                                                                             ecoResColor.Name,ecoResStyle.Name);

            this.addVariantsToReleasedProduct(_newRecid,conVariants);

        }


    }

    if (ecoResProductDimensionGroup.Name=="SizeCol")

    {

         while select ecoResProductMasterSize

             where ecoResProductMasterSize.SizeProductMaster == _oldrecid

                join ecoResProductMastercolor

                    where ecoResProductMastercolor.ColorProductMaster==ecoResProductMasterSize.SizeProductMaster

        {

            ecoResProductMasterSizeVariants = this.copyProdDimensionsSIze(_newRecid , ecoResProductMasterSize);

            ecoResSize = EcoResSize::find(ecoResProductMasterSizeVariants.Size);

            ecoResProductMastercolorVariants = this.copyProdDimensionColur(_newRecid ,ecoResProductMastercolor);

            ecoResColor = EcoResColor::find(ecoResProductMastercolorVariants.Color);

            conVariants  = EcoResProductVariantDimValue::getDimensionValuesContainer(ecoResConfiguration.Name,ecoResSize.Name,

                                                                                             ecoResColor.Name,ecoResStyle.Name);

            this.addVariantsToReleasedProduct(_newRecid,conVariants);

        }


    }

    if (ecoResProductDimensionGroup.Name=="ColorStyle")

    {

        while select ecoResProductMastercolor

            where ecoResProductMastercolor.ColorProductMaster == _oldrecid

                join ecoResProductMasterStyle

                    where ecoResProductMasterStyle.StyleProductMaster ==ecoResProductMastercolor.ColorProductMaster

        {


            ecoResProductMastercolorVariants = this.copyProdDimensionColur(_newRecid ,ecoResProductMastercolor);

            ecoResColor = EcoResColor::find(ecoResProductMastercolorVariants.Color);


            ecoResProductMasterStyleVariants = this.copyProdDimensionsStyle(_newRecid ,ecoResProductMasterStyle);

            ecoResStyle = EcoResStyle::find(ecoResProductMasterStyleVariants.Style);

            conVariants  = EcoResProductVariantDimValue::getDimensionValuesContainer(ecoResConfiguration.Name,ecoResSize.Name,

                                                                                             ecoResColor.Name,ecoResStyle.Name);

            this.addVariantsToReleasedProduct(_newRecid,conVariants);


        }

    }


}




private void addVariantsToReleasedProduct(RefRecId _productMasterRecId,

                                            container  _con)

{

    EcoResProductReleaseManagerBase     releaseManager;

    Name                                configId;


 //   i=1;

    if (_productMasterRecId)

    {

        ecoResDistinctProductVariant    = EcoResProductVariantManager::findDistinctProductVariant(_productMasterRecId,_con);


                if (!ecoresdistinctproductvariant)

                {

                    ecoresproductvariantmanager::createproductvariant(_productMasterRecId,

                                                                    ecoresproduct::find(_productMasterRecId).searchname + ecoresconfiguration.name,

                                                                    _con);

                    //info("product variants created");

        //con = _con;

        //while (i<=conLen(con))

        //{

            //configId = conPeek(con,i);

                   }


          while  select ecoResDistinctProductVariant

                where ecoResDistinctProductVariant.ProductMaster == _productMasterRecId //&&

                //ecoResDistinctProductVariant.DisplayProductNumber == EcoResProductNumberBuilderVariant::buildFromProductNumberAndDimensions(ecoResProductMaster.productNumber(),

           {                                                                                          //EcoResProductVariantDimValue::getDimensionValuesContainer(configId));

                if (ecoResDistinctProductVariant && !ecoResDistinctProductVariant.isReleased())

                {

                    releaseManager = EcoResProductReleaseManagerBase::newFromProduct(ecoResDistinctProductVariant);

                    releaseManager.release();

                }

           // i++;

           }

        //info('Product variants released');

    }

}