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.
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
Post a Comment