Custom service to create and close a container in Advanced warehouse management (AWM) D365FO

 Description :- In Advanced Warehousing within Dynamics 365 the term "Container Closer" refers to the process of finalizing and completing various warehouse tasks and operations. This is a crucial step in the warehouse management process, this service performs this task, as it signifies that the specific tasks have been executed and the related transactions have been processed in the system.

Custom service to be developed to Container closure in D365.
Input: Shipment ID, Quantity, Item, Container ID
Expected Output: Container Closure in D365 (Validation has to be done along with Container  closure)

Create below mentioned objects :- 

Request contract :- To get user inputs to create and close container.

Response contract :- To give response (Task Confirmation message).

Helper class :- To write the business logic.

Service class :- To call the API out side of environment.

Request class :- 

/// <summary>

/// Request contract for BASMSAdvanceWarehouseManagementService

/// </summary>

[DataContractAttribute("BASMSContainerCloserRequest")]

class BASMSContainerCloserRequest

{

    str      dataAreaId;

    str      workerId;

    str      shipmentId;

    List     containerLineList;


    [DataMemberAttribute("DataAreaId")]

    public str parmDataAreaId(str _dataAreaId = dataAreaId)

    {

        dataAreaId = _dataAreaId;

        return dataAreaId;

    }


    [DataMemberAttribute("WorkerId")]

    public str parmWorkerId(str _workerId = workerId)

    {

        workerId = _workerId;

        return workerId;

    }


    [DataMemberAttribute("ShipmentId")]

    public str parmShipmentId(str _shipmentId = shipmentId)

    {

        shipmentId = _shipmentId;

        return shipmentId;

    }


    [DataMemberAttribute("ContainerDetailesList"),

        DataCollectionAttribute(Types::Class, classStr(BASMSCantainerCloserLinesRequest)),

         AifCollectionTypeAttribute('ContainerDetailesList', Types::Class, classStr(BASMSCantainerCloserLinesRequest)),

    AifCollectionTypeAttribute('return', Types::Class, classStr(BASMSCantainerCloserLinesRequest))]

    public List parmContainerLineList(List _containerLineList = containerLineList)

    {

        if(!prmIsDefault(_containerLineList))

        {

            containerLineList = _containerLineList;

        }

        return containerLineList;

    }


}

Request (Sub request) :- 

/// <summary>

/// sets the params for item list objects

/// </summary>

[DataContractAttribute("BASMSCantainerCloserLinesRequest")]

class BASMSCantainerCloserLinesRequest

{

    str itemId;

    int quantity;


    [DataMemberAttribute('ItemId')]

    public str parmItemId(str _itemId = itemId)

    {

        itemId = _itemId;

        return itemId;

    }


    [DataMemberAttribute('Quantity')]

    public int parmQuantity(int _quantity = quantity)

    {

        quantity = _quantity;

        return quantity;

    }


}

Response class :- 

/// <summary>

/// contract to set the values to be sent as a response to the service contract

/// </summary>

[DataContractAttribute("BASMSContainerCloserResponse")]

class BASMSContainerCloserResponse

{

    boolean       containerCreated;

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

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


    [DataMember('Containerclosed')]

    public boolean parmContainerCreated(boolean _containerCreated = containerCreated)

    {

        containerCreated = _containerCreated;

        return containerCreated;

    }


    [DataMember('ContainerDetails')]

    public List parmContainerDetails(List _containerDetailsList = containerDetailsList)

    {

        containerDetailsList = _containerDetailsList;

        return containerDetailsList;

    }


    [DataMember('ErrorsList')]

    public List parmErrorList(List _errorList = errorList)

    {

        errorList = _errorList;

        return errorList;

    }


    private static BASMSContainerCloserResponse construct()

    {

        return new BASMSContainerCloserResponse();

    }


    /// <summary>

    /// sets the values of the objects in the contract class

    /// </summary>

    /// <param name = "_salesTable">

    /// Record used to set the values

    /// </param>

    /// <param name = "salesOrderLineDetailsList">

    /// List of the line details for the sales order

    /// </param>

    /// <returns>

    /// set of objects for the <c>BASMSSalesOrderDetailsResponseContract</c> contract

    ///</returns>

    public static BASMSContainerCloserResponse newContainerCloser(boolean _containerCreated, List _containerDetails, List _errorList)

    {

        BASMSContainerCloserResponse  contract = BASMSContainerCloserResponse::construct();


        contract.parmContainerCreated(_containerCreated);

        contract.parmContainerDetails(_containerDetails);

        contract.parmErrorList(_errorList);


        return contract;

    }


}

Helper class :- (I have created a helper class and created this method)

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

    public List createAndCloseContainer(str _dataAreaId, str _workerId, str _shipmentId, List _containerLineList)

    {

        boolean isContainerClosed;

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

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

       

        changecompany(_dataAreaId)

        {

            WHSWorkTable             workTable;

            WhsPackForm              whsPackForm;

            WHSTmpPackingLine        tmpPackingLine;

            WHSContainerTable        containerTable;

            InventDim                inventDim;

            WHSWorker                whsWorker;

            HcmWorker                hcmWorker;

            WHSPackProfile           whsPackProfile;

            WHSCloseContainerProfile whsCloseContainerProfile;


            WHSShipmentTable whsShipmentTable = WHSShipmentTable::find(_shipmentId);

        

            select firstonly whsWorker

                join inventDim

                where inventDim.inventDimId == whsWorker.DefaultPackingStationLocation

                join hcmWorker

                where hcmWorker.RecId == whsWorker.Worker

                && hcmWorker.PersonnelNumber == _workerId;


            if(!hcmWorker.PersonnelNumber)

            {

                errorList.addEnd(strFmt("Worker %1 does not exist.",_workerId));

            }

            else if(!whsShipmentTable)

            {

                errorList.addEnd(strFmt("SipmentId cannot be empty/The entry is not valid"));

            }

            else if(whsShipmentTable)

            {

                select firstonly workTable

                    where workTable.ShipmentId == _shipmentId;


                if(whsShipmentTable.ShipmentStatus == WHSShipmentStatus::Shipped

                        || whsShipmentTable.ShipmentStatus == WHSShipmentStatus::Loaded)

                {

                    errorList.addEnd(strFmt("Shipment %1 is shipper or loaded",_shipmentId));

                }

                else if(workTable.WorkStatus == WHSWorkStatus::Open || workTable.WorkStatus == WHSWorkStatus::InProcess )

                {

                    errorList.addEnd(strFmt("Cannot create/close container because shipmetId %1 not yet closed",_shipmentId));

                }

                else

                {

                    select firstonly whsPackProfile

                    where whsPackProfile.CloseContainerProfileId == whsWorker.CloseContainerProfileId;


                    WMSLocation   packStationLocation     = WMSLocation::find(inventDim.wMSLocationId,inventDim.InventLocationId);

                    str           containerId             = WHSContainerTable::generateContainerId();

                    str           newContainerTypeCode    = whsPackProfile.DefaultContainerType;

                    str           closeContainerProfileId = whsWorker.CloseContainerProfileId;

          

                    try

                    {

                        WHSContainerTable::createContainer(_shipmentId, containerId, newContainerTypeCode, closeContainerProfileId, '', packStationLocation);

                      

                        tmpPackingLine = WHSTmpPackingLine::populatePackingLines(_shipmentId,packStationLocation);


                        ListIterator    listEnum = new ListIterator(_containerLineList);


                        while(listEnum.more())

                        {

                            BASMSCantainerCloserLinesRequest itemsData = listEnum.value();


                            ItemId  itemId  = itemsData.parmItemId();

                            Qty     qty     = itemsData.parmQuantity();


                            select firstonly tmpPackingLine

                                   where tmpPackingLine.ItemId == itemId

                                   && tmpPackingLine.ShipmentId == _shipmentId;


                            if(!tmpPackingLine.RecId)

                            {

                                errorList.addEnd(strFmt("Item %1 can't be picked because it is not in the packing list", itemId));

                            }

                            else if(tmpPackingLine)

                            {

                                if(tmpPackingLine.Qty >= qty)

                                {

                                    whsPackForm = new WHSPackForm();

                                    whsPackForm.buttonPack_clicked(containerId,itemId,qty,tmpPackingLine,'');

                                }

                                else

                                {

                                    errorList.addEnd(strFmt("The container's maximum weight limit cannot be exceeded"));

                                }

                            }

                            listEnum.next();

                        }


                          select firstonly whsCloseContainerProfile

                                 where whsCloseContainerProfile.CloseContainerProfileId == whsWorker.CloseContainerProfileId;


                          Weight    calculatedContainerWeight   = WHSContainerTable::find(_shipmentId, containerId).calculateWeightInUOM(whsCloseContainerProfile.WeightUOM);


                          WHSContainerTable::closeContainer(_shipmentId,containerId, calculatedContainerWeight, whsCloseContainerProfile.WeightUOM,whsCloseContainerProfile.DefaultFinalShipLoc, false,'','');


                          containerTable = WHSContainerTable::find(_shipmentId, containerId);


                          if(containerTable.ContainerStatus == WHSContainerStatus::Closed)

                          {

                              isContainerClosed = boolean::true;

                              BASMSContainerDetailsResponse containerDetails = new BASMSContainerDetailsResponse();

                              containerDetails =  BASMSContainerDetailsResponse::newContainerDetails(_shipmentId, containerId, containerTable.ContainerStatus);

                              containerDetailsList.addEnd(containerDetails);


                          }


                    }

                    catch(Exception::Error)

                    {

                        isContainerClosed = boolean::false;

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


                        while(infoLogEnum.moveNext())

                        {

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

                            str integrationMessage = infoMessageStruct.message();

                            errorList.addEnd(integrationMessage);

                 

                        }

                    }

                }

            }

        }

       

        BASMSContainerCloserResponse containerCloser = new BASMSContainerCloserResponse();

        containerCloser =  BASMSContainerCloserResponse::newContainerCloser(isContainerClosed, containerDetailsList, errorList);

        containerCloserList.addEnd(containerCloser);


        return  containerCloserList;

    }

Service class :- (Create a service class and add this method)

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


    public List closeContainer(BASMSContainerCloserRequest _contract)

    {

    

        str     dataAreaId        = _contract.parmDataAreaId();

        str     workerId          = _contract.parmWorkerId();

        str     shipmentId        = _contract.parmShipmentId();

        List    containerLineList = _contract.parmContainerLineList();

       


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


        BASMSAdvanceWarehouseManagementHelper containerCloserHelper = new BASMSAdvanceWarehouseManagementHelper();

        containerCloserList = containerCloserHelper.createAndCloseContainer(dataAreaId,workerId,shipmentId,containerLineList);


        return containerCloserList;


    }

Create a service and service group in D365FO and map the service class in Services.
By using Postman we can test the services.


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