x++ code to create custom service to reverse the work which is closed (work status)

Request Class:


 [DataContractAttribute("BASMSReverseWorkRequestContract")]

class BASMSReverseWorkRequestContract

{

    str       workId;

    str       dataAreaId;


    [DataMemberAttribute("WorkId")]

    public str parmWHSWorkId(str _workId = workId)

    {

        workId = _workId;

        return workId;

    }


    [DataMemberAttribute("dataAreaId")]

    public str parmdataAreaId(str _dataAreaId = dataAreaId)

    {

        dataAreaId = _dataAreaId;

        return dataAreaId;

    }


}


Response Class:


[DataContractAttribute("BASMSReverseWorkResponseContract")]

class BASMSReverseWorkResponseContract

{

    str  workStatus;

    List errorList;

   

    [DataMember('WorkStatus')]

    public str parmWorkStatus(str _workStatus = workStatus)

    {

        workStatus = _workStatus;

        return workStatus;

    }


    [DataMember('ErrorList')]

    public List parmErrorList(List _errorList = errorList)

    {

        errorList = _errorList;

        return errorList;

    }


    private static BASMSReverseWorkResponseContract construct()

    {

        return new BASMSReverseWorkResponseContract();

    }


    public static BASMSReverseWorkResponseContract newFromTableRecord(str _workstatus,List _errorList)

    {

        BASMSReverseWorkResponseContract  contract = BASMSReverseWorkResponseContract::construct();

        contract.parmWorkStatus(_workstatus);

        contract.parmErrorList(_errorList);

        return contract;

    }


}


Helper Class:


class BASMSReverseWorkHelper

{

    Common common;

    WHSReverseWorkMode          mode;

    WMSLocationId               location;

    WHSLoadTable                loadTable;

    WHSWaveTable                waveTable;

    str                         specifiedLocation;

    str                         message,workStatus;

    SysInfoLogEnumerator        infoLogEnum;

    SysInfologMessageStruct     infoMessageStruct;

    public void ok_clicked(

        Common              _common,

        WHSReverseWorkMode  _createPutaway,

        InventLocationId    _location)

    {

        WHSReverseSalesWork     reverseSalesWork;


        reverseSalesWork = WHSReverseSalesWork::newStandard(_common);

        reverseSalesWork.reverseWork(_createPutaway, _location);

    }


    private static BASReverseWorkHelper construct()

    {

        return new BASReverseWorkHelper();

    }


    private void checkWorkHeaders()

    {

        WHSWorkLine             workLine;

        str                     loadIdList;

        WHSWorkId               prevWorkId;

        WHSLoadTable            tmpLoadTable;

        WHSWorkLine             tmpWHSWorkLine;


        // Check for work headers associated with multiple loads if reversing by load

        if (loadTable)

        {

            while select workLine

                group by workLine.WorkId, workLine.LoadId

                join LoadId from tmpLoadTable

                where workLine.LoadId == tmpLoadTable.LoadId &&

                      workLine.LoadId != loadTable.LoadId    &&

                      workLine.LoadId != ''

                    exists join tmpWHSWorkLine

                    where tmpWHSWorkLine.WorkId == workLine.WorkId &&

                          tmpWHSWorkLine.LoadId == loadTable.LoadId

            {

                if (prevWorkId == workLine.WorkId)

                {

                    continue;

                }


                loadIdList += workLine.LoadId + ", ";

                prevWorkId = workLine.WorkId;

            }


            if (loadIdList)

            {

                loadIdList = subStr(loadIdList, 1, strLen(loadIdList) - 2);

                throw error(strFmt("@WAX2236", prevWorkId, loadTable.LoadId, loadIdList));

            }

        }

    }


    private void checkWorkLines()

    {

        //MoveToLocation and MoveUsingLocDirectives for a closed work creates a new open work. Order-committed reservation can't be set back in this case since reservation is on the work line.

        if (mode == WHSReverseWorkMode::MoveToLocation ||

                mode == WHSReverseWorkMode::MoveUsingLocDirectives)

        {

            WHSWorkLine workLine;

            WHSWorkTable workTable;

            select firstonly TableId from workTable

                where  (loadTable.LoadId && workTable.LoadId  == loadTable.LoadId)

                    || (waveTable.WaveId && workTable.WaveId  == waveTable.WaveId)

                    && (workTable.WorkStatus == WHSWorkStatus::InProcess

                    ||  workTable.WorkStatus == WHSWorkStatus::Closed)

                exists join workLine

                where  workLine.WorkId == workTable.WorkId

                    && workLine.WorkStatus  == WHSWorkStatus::Closed

                    && workLine.WorkType == WHSWorkType::Pick

                    && workLine.OrderCommittedInventDimId;

            if (workTable)

            {

                throw error("@WAX:ReverseWorkOrderCommittedError");

            }

        }

        

    }


    private WHSWorkLine getWorkLineWithOnHandForWork(WHSWorkTable _workTable)

    {

        WHSWorkLine lastPutLine = WHSWorkTable::getLastClosedPutWorkLine(_workTable.WorkId);

        WHSWorkLine nextPickLine = WHSWorkLine::getNextOppositeWorkLineFromWorkLine(lastPutLine);

        WHSWorkLine workLineWithOnHand = nextPickLine ? nextPickLine : lastPutLine;

        return workLineWithOnHand;

    }


    private boolean canCreateWorkToMoveItemsBack(WHSWorkTable  _workTable)

    {

        return !this.isSerialNumberCaptured(_workTable);

    }


    private boolean isSerialNumberCaptured(WHSWorkTable  _workTable)

    {

        InventTrans             inventTrans;

        InventTransOrigin       inventTransOrigin;

        InventDim               inventDim;

        while select itemId from inventTrans

            exists join inventDim

                where inventTrans.inventDimId == inventDim.inventDimId

                   && inventDim.inventSerialId != ''

            exists join inventTransOrigin

                where inventTransOrigin.RecId              == inventTrans.InventTransOrigin

                   && inventTransOrigin.ItemId             == inventTrans.itemId

                   && inventTransOrigin.ReferenceCategory  == InventTransType::WHSWork

                   && inventTransOrigin.ReferenceId        == _workTable.WorkId

        {

            switch (whsInventTable::captureSerial(inventTrans.ItemId))

            {

                case WHSRFWhenToCapture::Picking:

                case WHSRFWhenToCapture::Packing:

                    info(strFmt("@SYP4881557", inventTrans.ItemId));

                    return true;

            }

        }

        return false;

    }


    protected WHSWorkId createWorkToMoveItemsBack(WHSWorkTable  _workTable, WHSWorkLine _workLineWithOnHand)

    {

        WHSWorkId workId;

        InventDim inventDim = _workLineWithOnHand.inventDim();

        inventDim.InventSiteId = _workTable.InventSiteId;

        inventDim.InventLocationId = _workTable.InventLocationId;

        inventDim.wMSLocationId = _workLineWithOnHand.WMSLocationId;

        if (inventDim.wmsLocation().whsLocationIsLPControlled())

        {

            inventDim.LicensePlateId = _workTable.TargetLicensePlateId;

        }

        inventDim = InventDim::findOrCreate(inventDim);


        switch (mode)

        {

            case WHSReverseWorkMode::MoveToLocation:

            case WHSReverseWorkMode::MoveUsingLocDirectives:

                WHSTmpMovementWork tmpMovementWork;

                tmpMovementWork.InventDimId = inventDim.InventDimId;

                tmpMovementWork.Qty         = _workLineWithOnHand.InventQtyWork;

                tmpMovementWork.UnitID      = WHSCatchWeightHelper::inventHandlingUnitId(_workLineWithOnHand.ItemId);


                WHSWorkCreateMovement workCreate = WHSWorkCreate::construct(tmpMovementWork);

                workCreate.parmStartLocationId(_workLineWithOnHand.WMSLocationId);

                workCreate.parmTargetLicensePlateId(_workTable.TargetLicensePlateId);

                workId = workCreate.createWork();

                break;

        }


        if (workId)

        {

            info(strFmt("@WAX3849", workId));

        }


        return workId;

    }


    private void unPick(SalesLine _salesLine, WHSInventQtyWork _inventQtyWork)

    {

        InventTrans             inventTrans;

        InventTransOrigin       inventTransOrigin;

        Qty                     quantityUnpicked;

        ttsbegin;

        while select InventDimId, Qty, PdsCWQty from inventTrans

            exists join inventTransOrigin

                where inventTrans.InventTransOrigin     == inventTransOrigin.RecId

                    && inventTransOrigin.InventTransId  == _salesLine.InventTransId

                    && inventTrans.StatusIssue          == StatusIssue::Picked

                    && inventTrans.StatusReceipt        == StatusReceipt::None

        {

            WHSInvent::pickQuantities(_salesLine, inventTrans.InventDimId, inventTrans.Qty, inventTrans.PdsCWQty, null, UnknownNoYes::No /*No reserve*/);

            // Subtract since inventTrans.Qty is negative for sales issues.

            quantityUnpicked -= PdsGlobal::pdsIsCWItem(_salesLine.ItemId) ? inventTrans.PdsCWQty : inventTrans.Qty;

        }

        if (quantityUnpicked != _inventQtyWork)

        {

            throw error(strFmt("@SYP4881563", "@WAX2738"));

        }

        ttscommit;

    }


    private void reReserve(WHSLoadLine _loadLine, SalesLine _salesLine, Qty _handlingQty, WHSTransWeight _weight)

    {

        Qty qty;

        PdsCWQty cwQty;

        if (PdsGlobal::pdsIsCWItem(_salesLine.ItemId))

        {

            cwQty = _handlingQty;

            qty = _weight;

            // Reservation may attempt to update the movement buffer so this must be selected for update

            _salesLine.selectForUpdate(true);

        }

        else

        {

            cwQty = 0;

            qty = _handlingQty;

        }

        var movement = InventMovement::construct(_salesLine, InventMovSubType::None);

        var reservation = InventUpd_Reservation::newMovement(movement, -qty, false, false, false, -cwQty);

        reservation.updateNow();

    }


    private void unpickSalesLine(WHSLoadLine _loadLine, WHSInventQtyWork _inventQtyWork, WHSTransWeight _weight)

    {

        WHSLoadLine loadLine;

        WHSWorkLine workLine;

        SalesQty    pickedInTotalHandlingUnit;

        boolean     pickedInTotal = false;


        ttsbegin;


        // Get the sales line

        var salesLine = _loadLine.getOrderCommonFromLoadLine() as SalesLine;


        // When reversing a wave prevent reversal if work is ship confirmed.

        if (waveTable.WaveId && salesLine.deliveredInTotal() > 0)

        {

            // Do not undeliver qty.

            throw error("@WAX:ReverseWorkForDeliveredSalesLineError");

        }


        select count(RecId) from loadLine

            where loadLine.LoadId == _loadLine.LoadId

                && loadLine.InventTransId == _loadLine.InventTransId

                && loadLine.InventTransType == InventTransType::Sales;


        pickedInTotalHandlingUnit = PdsGlobal::pdsIsCWItem(salesLine.ItemId) ? salesLine.pdsCWPickedInTotal() : salesLine.pickedInTotalInventUnit();


        // Look at sales order details picked field and unpick

        if (pickedInTotalHandlingUnit > 0)

        {

            if (loadLine.RecId > 1)

            {

                select sum(InventQtyWork) from workLine

                    group by InventTransId

                        where workLine.InventTransId == _loadLine.InventTransId

                            && workLine.WorkStatus != WHSWorkStatus::Cancelled

                            && workLine.WorkType == WHSWorkType::Pick;


                this.unPick(salesLine, min(workLine.InventQtyWork, pickedInTotalHandlingUnit));

            }

            else

            {

                this.unPick(salesLine, _inventQtyWork);

            }


            pickedInTotal = true;

        }

            

        if (pickedInTotal || loadLine.RecId > 1)

        {

            _loadLine.PickedQty = max(0, _loadLine.PickedQty - _inventQtyWork);

            _loadLine.PickedWeight = max(0, _loadLine.PickedWeight - _weight);

            _loadLine.update();


            this.reReserve(_loadLine, salesLine, _inventQtyWork, _weight);

        }

  

        // Inform the user if the serial number is associated with load's sales line

        if (InventTable::find(salesLine.ItemId).isSalesProcessSerialActive()

            && WHSInventTable::captureSerial(salesLine.ItemId) != WHSRFWhenToCapture::None)

        {

            warning("@WAX:SerialNumbersExistOnSalesLine");

        }

        ttscommit;

    }


    public WHSCapturedWeight currentCapturedWeight()

    {

        return 0;

    }


    private void reverseWorkLines(WHSWorkTable  _workTable)

    {

        WHSWorkLineLoadLineDetailsEnumerator enumerator = _workTable.getEnumerator();

        while (enumerator.moveNext())

        {

            WHSLoadLine loadLine = enumerator.currentLoadLine();

            if (loadLine)

            {

                this.unpickSalesLine(loadLine, enumerator.currentInventQtyWork(), 1);


                loadLine.reread(); // Reread because we update the loadLine in above method

                loadLine.WorkCreatedQty -= enumerator.currentInventQtyWork();

                loadLine.update();

            }

        }

    }


    public void setCancelWorkStatus(WHSWorkId _workId)

    {

        WHSWorkTable    workTable;

        ttsbegin;

        workTable = WHSWorkTable::find(_workId, true);

        if (workTable)

        {

            workTable.WorkStatus = WHSWorkStatus::Cancelled;

            workTable.WorkCancelledByUser      = curUserId();

            workTable.WorkCancelledUTCDateTime = DateTimeUtil::utcNow();

            workTable.update();

        }

        ttscommit;

    }


    public void reverseWork(WHSReverseWorkMode _mode, str _location,str _loadid, str _waveid)

    {

        WHSWorkTable            workTable;

        WHSLoadLine loadLine;


        if ((_mode == WHSReverseWorkMode::AutoMoveToLocation ||

             _mode == WHSReverseWorkMode::MoveToLocation)

            && !_location)

        {

            throw error("@WAX2237");

        }


        // Set global values.

        mode = WHSReverseWorkMode::MoveUsingLocDirectives;

        ttsbegin;

        this.checkWorkHeaders();

        this.checkWorkLines();

        // Go to the whs work load link table to find the work table records associated with the load

        while select workTable

            where workTable.LoadId  == _loadid    ||

                   workTable.WaveId  == _waveid  &&

                  workTable.WorkStatus   != WHSWorkStatus::Cancelled

        {

            WHSWorkLine workLineWithOnHand;

            switch (workTable.WorkStatus)

            {

                case WHSWorkStatus::Closed:

                    if (!workTable.isOriginForConsolidatedWork()) // We do not want to unpick lines from origin work - that's done through consolidated work

                    {

                        workLineWithOnHand = this.getWorkLineWithOnHandForWork(workTable);


                        this.reverseWorkLines(workTable);

                        if (this.canCreateWorkToMoveItemsBack(workTable))

                        {

                            this.createWorkToMoveItemsBack(workTable, workLineWithOnHand);

                        }

                        else

                        {

                            // Throw here if validation failed so that we roll back the reversal of work lines above.

                            throw error("@SYS18447");

                        }

                    }

                    this.setCancelWorkStatus(workTable.WorkId);

                    delete_from loadLine where loadLine.ShipmentId == workTable.ShipmentId;

                    break;

            }

        }


        ttscommit;

    }


    public void completeReverseWork(str _loadid, str _waveid)

    {

        mode = WHSReverseWorkMode::MoveUsingLocDirectives;

        location = '';

        this.reverseWork(mode,location,_loadid,_waveid);

    }


    [AifCollectionTypeAttribute('return', Types::Class, classStr(BASMSReverseWorkResponseContract))]

    public List getReverseWork(str _workId , str _dataAreaId)

    {

        str  workId          = _workId;

        str  dataAreaId      = _dataAreaId;

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

        WHSLoadLine          loadLine;

        boolean              workCompleted;

        WHSWorkTable workTable;

        changecompany(dataAreaId)

        {

            List errorList = new List(Types::String);

            try

            {

                ttsbegin;

            WHSWorkTable worktable1 = WHSWorkTable::find(workId);

            if (workId == '')

            {

                workStatus = '';

                message = strFmt("Please enter the workid");

                errorList.addEnd(message);

            }

            else if (!worktable1)

            {

                workStatus = '';

                message = strFmt("Workid %1 is invalid Please enter a valid workid",workId);

                errorList.addEnd(message);

            }

            else if (worktable1.WorkStatus == WHSWorkStatus::Closed)

            {

                select firstonly workTable

                where workTable.WorkId == workId;

                this.completeReverseWork(workTable.LoadId,workTable.WaveId);

                workStatus = 'Cancelled';

            }

            else if (worktable1.WorkStatus == WHSWorkStatus::Open)

            {

                workStatus = 'Open';

                message = strFmt("You cannot Reverse the work %1 because it has a status of Open.",worktable1.WorkId);

                errorList.addEnd(message);

            }

            else if (worktable1.WorkStatus == WHSWorkStatus::Cancelled)

            {

                workStatus = 'Cancelled';

                message = strFmt("You cannot Reverse the work %1 because it has a status of Canceled.",worktable1.WorkId);

                errorList.addEnd(message);

            }

            ttscommit;

            }


            catch(Exception::Error)

            {

                workCompleted = boolean::false;

                infoLogEnum   = SysInfoLogEnumerator::newData(infolog.infologData());

                while(infoLogEnum.moveNext())

                {

                    infoMessageStruct      = SysInfologMessageStruct::construct(infoLogEnum.currentMessage());

                    str integrationMessage = infoMessageStruct.message();

                    errorList.addEnd(integrationMessage);

                }

                ttsabort;

            }


            BASMSReverseWorkResponseContract workOrderData = new BASMSReverseWorkResponseContract();

            workOrderData = BASMSReverseWorkResponseContract::newFromTableRecord(workStatus,errorList);

            workOrderList.addEnd(workOrderData);

            return workOrderList;

        }


    }


}


Service Class :

class BASMSReverseWorkService

{

    [AifCollectionTypeAttribute('return', Types::Class, classStr(BASMSReverseWorkResponseContract))]  // name of the response contract class


    // service method


    public List completeReverseWork(BASMSReverseWorkRequestContract _contract) // name of the contract class

    {


        BASMSReverseWorkHelper workOrderData = new BASMSReverseWorkHelper();

     

        str             workId = _contract.parmWHSWorkId();

        

        str             dataAreaId  = _contract.parmdataAreaId();

        

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

     

        workOrderList = workOrderData.getReverseWork(workId,dataAreaId);


        return workOrderList;

     

    }


    [AifCollectionTypeAttribute('return', Types::Class, classStr(BASMSWorkHeaderCancellationResponseContract))]  // name of the response contract class


    // service method


    public List getWorkHeaderCancellation(BASMSWorkHeaderCancellationRequestContract _contract) // name of the contract class

    {


        BASMSWorkHeaderCancellationHelper workOrderData = new BASMSWorkHeaderCancellationHelper();

     

        str             workId = _contract.parmWHSWorkId();

        

        str             dataAreaId  = _contract.parmdataAreaId();

        

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

     

        workOrderList = workOrderData.getWorkHeaderCancellation(workId,dataAreaId);


        return workOrderList;

     

    }


}

Comments

Popular posts from this blog

how to post trade agreement journals automatically using x++ code

How to Create a wizard in x++ d365

x++ code to submit and approve and reject the invent movement workflow in d365 F&O