Three key layers contribute to the overall functionality and user experience of an application. These layers play crucial roles in extending the capabilities of an application, adapting it to specific user requirements, and enhancing the overall user experience.
Related to subflows, they are complex structures with complex objects, functions, relations and interdependency with other part of the codes. Understanding and responsibly modify the workflows could be a difficult and time costly activity, therefore from the product department we do not support modifications on subflows.
Helpful Tips and Resources
Click the link below to visit our Article site, where you will find examples and useful information. We are continuously adding new articles featuring the most common customizations.
Produmex WMS Articles: Customization examples (more subsections are available)
The following content is NOT only to developers but to consultants with strong coding knowledge, for more information check the link below:
Customization examples (more subsections are available)
For advanced scripting in Produmex WMS you will need a strong knowledge about the following programing languages.
Programing languages as required skills:
It is important to lay down general basics about scripting. Generally speaking scripting is a powerful tool for developers and IT professionals, enabling them to automate tasks, enhance functionality, and create dynamic applications.
Definition: Scripting refers to writing a series of commands that are executed by a certain runtime environment. These commands are typically used to automate tasks that would otherwise be performed manually. Here are some key points about scripting:
The benefits of scripting:
There are input and output parameters defined in the Hookflow class.
The value from the parameter can be loaded by the Get() method.
Set value in the parameter can be done by the Set() methd: BackRequested.Set(true);
It is not possible to define additional input or output parameters.
Customization Articles for WMS scripting:
How to make custom bin location list in Put Away
How to make custom bin location list in AdHoc move
There are two classes in every HookFlow script that are pre defined in the Execute() method.
It is the Session and the ISboProviderService classes.
References:
using Produmex.Foundation.SlimScreen; using Produmex.Foundation.Wwf.Sbo.LocalServices;
Remove the comment before the variables in case you would like to use them!
Session session = GetScopeParameter("Session") as Session; ISboProviderService sboProviderService = GetScopeParameter(" <WwfService>ISboService") as ISboProviderService;
Necessary classes:
Class | Reference |
---|---|
PmxDbConnection | Produmex.Foundation.Data.Sbo; |
You can get the connection from sboProviderService.
Example - creating a Picklist provider with connection
sboProviderService.InvokeMethodWithDbConnection<object>(false, false, null, null, delegate (PmxDbConnection conn, object[] parameters) { PmxPickListProvider plProv = new PmxPickListProvider(conn); PmxPickList pickList = plProv.GetBO( WaveKey.Get() ); return null; });
Customization Articles for WMS scripting:
How to display product image after selecting the item in Picking and Ad-Hoc picking
Screen can be generated by the ShowScreen method of the session object.
There are different types that we can use.
Necessary classes:
Class | Message |
---|---|
Reference | using Produmex.Foundation.Messages; using Produmex.Foundation.Wwf.Sbo.LocalServices; using Produmex.Foundation.SlimScreen; |
Parameters
Name | Type | Description |
---|---|---|
MessageKey | String | Set your message |
ShowButton | Bool | - |
Parameters collection
Name | Type | Description |
---|---|---|
TitleKey | String | Title of the screen |
ImagePath | String | Full path of the picture |
MessageKey | String | Message under the screen |
ShowButton | Bool | - |
Example:
Message msg = null; session.ShowScreen(typeof(Produmex.Foundation.SlimScreen.Interfaces.IShowImageScreen), this.DefaultCultureInfo, BuildParamCollection( "TitleKey", "Picture of the product", "MessageKey", "message under the picture", "ImagePath", "<PATH OF THE IMAGE>", "ShowButton", true )); msg = WaitForMessage();
You can capture additional text information on this screen. The captured data can be get from the message object.
The value can be used in the Hookflow for further processing, or if the Hookflow script has an output parameter, then we can put the captured value into the output parameter.
Parameters
Name | Type | Description |
---|---|---|
InitialErrorKey | String | n.a. in custom usage |
TitleKey | String | Title of the screen |
Information | String | Additional information on the screen |
Parameters | Object of sting | n.a. in custom usage |
AllowToGoBack | Bool | - |
ForceDataEntry | Bool | - |
AllowMultiLine | Bool | - |
MinimumNumberOfCharacters | Int | Minimum number of characters that must be typed |
Example:
The entered text will be used on a message screen.
string initialErrorKey = null; string FreeText = ""; Message msg = null; session.ShowCustomizedScreen(typeof(Produmex.Foundation.SlimScreen.Interfaces.IEnterStringValueScreen), DefaultCultureInfo.Get(), BuildParamCollection( "InitialErrorKey", initialErrorKey, "TitleKey", "Title of the screen", "Information", "Information text", "Parameters", new object[] { "" }, "AllowToGoBack", true, "ForceDataEntry", true, "AllowMultiLine", true, "MinimumNumberOfCharacters", 5 ), WorkflowId, nameof(PickingScript_Screens.EnterStringValueScreen1)); msg = WaitForMessage(); if (msg.Name.EndsWith(".StringEntered")) { FreeText = ExtractParameter<string>(msg.Parameters, "stringValue"); } msg = null; session.ShowScreen(typeof(Produmex.Foundation.SlimScreen.Interfaces.IShowMessageScreen), this.DefaultCultureInfo, BuildParamCollection( "MessageKey", "Entered text: " + FreeText, "ShowButton", true )); msg = WaitForMessage();
You can create an item list in a DataSet object to select an item from a list. The captured data can be get from the message object.
The value can be used in the Hookflow for further processing, or if the Hookflow script has an output parameter, then we can put the captured value into the output parameter.
Parameters
Name | Type | Description |
---|---|---|
InitialErrorKey | String | n.a. in custom usage |
TitleKey | String | Title of the screen |
Information | String | Additional information on the screen |
Parameters | Object of sting | n.a. in custom usage |
AllowToGoBack | Bool | - |
ForceDataEntry | Bool | - |
AllowMultiLine | Bool | - |
MinimumNumberOfCharacters | Int | Minimum number of characters that must be typed |
Example:
The selected item will be used on a message screen.
string initialErrorKey = null; string FreeText = ""; Message msg = null; DataSet dsItems = null; string query = "SELECT DISTINCT PMX_OITMANAGED_BY_PMX.ItemCode AS ProductCode, PMX_OITMANAGED_BY_PMX.U_PMX_CUDE AS ProductDescription, PMX_OITMANAGED_BY_PMX.CodeBars AS GTIN, PMX_OITMANAGED_BY_PMX.U_PMX_HBBD, PMX_OITMANAGED_BY_PMX.U_PMX_PILR, PMX_OITMANAGED_BY_PMX.ManBtchNum, PMX_OITMANAGED_BY_PMX.U_PMX_LOUN, PMX_OITMANAGED_BY_PMX.NumInBuy, PMX_OITMANAGED_BY_PMX.BuyUnitMsr, PMX_OITMANAGED_BY_PMX.InvntryUom, PMX_OITMANAGED_BY_PMX.CodeBars AS CodeBars, PMX_OITMANAGED_BY_PMX.ItemName FROM PMX_OITMANAGED_BY_PMX WITH (NOLOCK) WHERE PMX_OITMANAGED_BY_PMX.InvntItem = 'Y' AND PMX_OITMANAGED_BY_PMX.InvntItem = 'Y' AND NOT ( PMX_OITMANAGED_BY_PMX.frozenFor = 'Y' AND ( ( PMX_OITMANAGED_BY_PMX.frozenFrom IS NULL OR CURRENT_TIMESTAMP >= PMX_OITMANAGED_BY_PMX.frozenFrom ) AND ( PMX_OITMANAGED_BY_PMX.frozenTo IS NULL OR CURRENT_TIMESTAMP < DATEADD( day, 1, PMX_OITMANAGED_BY_PMX.frozenTo ) ) ) ) ORDER BY ProductDescription"; dsItems = sboProviderService.RunView(false, null, null, query); session.ShowCustomizedScreen(typeof(Produmex.Foundation.SlimScreen.Interfaces.ISelectProductScreen), DefaultCultureInfo.Get(), BuildParamCollection( "InitialErrorKey", initialErrorKey, "TitleKey", "Title of the screen", "ProductDS", dsItems ), WorkflowId, nameof(ChecksScript_Screens.SelectProductScreen1)); msg = WaitForMessage(); if (msg.Name.EndsWith(".ProductSelected")) { FreeText = ExtractParameter<string>( msg.Parameters, "itemCode" ); } msg = null; session.ShowScreen(typeof(Produmex.Foundation.SlimScreen.Interfaces.IShowMessageScreen), this.DefaultCultureInfo, BuildParamCollection( "MessageKey", "Entered text: " + FreeText, "ShowButton", true )); msg = WaitForMessage();
Parameters
Name,Type,Description TitleKey,String,Name of the screen MessageKey,String,question string
Example:
Message msg = null; session.ShowCustomizedScreen(typeof(Produmex.Foundation.SlimScreen.Interfaces.IDecisionScreen), DefaultCultureInfo.Get(), BuildParamCollection( "TitleKey", "Title of the screen", "MessageKey", "Do you want to continue?"), WorkflowId, nameof(ReceptionScript_Screens.DecisionScreen22)); msg = WaitForMessage(); if (msg.Name.EndsWith(".Yes")) { // goto Step_ClearDataBeforeNextItem; } if (msg.Name.EndsWith(".No")) { BackRequested.Set(true); }
Necessary classes:
Class | Reference |
---|---|
PmxDbConnection | Produmex.Foundation.Data.Sbo; |
You can get the connection from sboProviderService.
Example - creating a Picklist provider with connection
sboProviderService.InvokeMethodWithDbConnection<object>(false, false, null, null, delegate (PmxDbConnection conn, object[] parameters) { PmxPickListProvider plProv = new PmxPickListProvider(conn); PmxPickList pickList = plProv.GetBO( WaveKey.Get() ); return null; });
Customization Articles for WMS scripting:
How to display product image after selecting the item in Picking and Ad-Hoc picking
Screen can be generated by the ShowScreen method of the session object.
There are different types that we can use.
Necessary classes:
Class | Message |
---|---|
Reference | using Produmex.Foundation.Messages; using Produmex.Foundation.Wwf.Sbo.LocalServices; using Produmex.Foundation.SlimScreen; |
Parameters
Name | Type | Description |
---|---|---|
MessageKey | String | Set your message |
ShowButton | Bool | - |
Parameters collection
Name | Type | Description |
---|---|---|
TitleKey | String | Title of the screen |
ImagePath | String | Full path of the picture |
MessageKey | String | Message under the screen |
ShowButton | Bool | - |
Example:
Message msg = null; session.ShowScreen(typeof(Produmex.Foundation.SlimScreen.Interfaces.IShowImageScreen), this.DefaultCultureInfo, BuildParamCollection( "TitleKey", "Picture of the product", "MessageKey", "message under the picture", "ImagePath", "<PATH OF THE IMAGE>", "ShowButton", true )); msg = WaitForMessage();
You can capture additional text information on this screen. The captured data can be get from the message object.
The value can be used in the Hookflow for further processing, or if the Hookflow script has an output parameter, then we can put the captured value into the output parameter.
Parameters
Name | Type | Description |
---|---|---|
InitialErrorKey | String | n.a. in custom usage |
TitleKey | String | Title of the screen |
Information | String | Additional information on the screen |
Parameters | Object of sting | n.a. in custom usage |
AllowToGoBack | Bool | - |
ForceDataEntry | Bool | - |
AllowMultiLine | Bool | - |
MinimumNumberOfCharacters | Int | Minimum number of characters that must be typed |
Example:
The entered text will be used on a message screen.
string initialErrorKey = null; string FreeText = ""; Message msg = null; session.ShowCustomizedScreen(typeof(Produmex.Foundation.SlimScreen.Interfaces.IEnterStringValueScreen), DefaultCultureInfo.Get(), BuildParamCollection( "InitialErrorKey", initialErrorKey, "TitleKey", "Title of the screen", "Information", "Information text", "Parameters", new object[] { "" }, "AllowToGoBack", true, "ForceDataEntry", true, "AllowMultiLine", true, "MinimumNumberOfCharacters", 5 ), WorkflowId, nameof(PickingScript_Screens.EnterStringValueScreen1)); msg = WaitForMessage(); if (msg.Name.EndsWith(".StringEntered")) { FreeText = ExtractParameter<string>(msg.Parameters, "stringValue"); } msg = null; session.ShowScreen(typeof(Produmex.Foundation.SlimScreen.Interfaces.IShowMessageScreen), this.DefaultCultureInfo, BuildParamCollection( "MessageKey", "Entered text: " + FreeText, "ShowButton", true )); msg = WaitForMessage();
You can create an item list in a DataSet object to select an item from a list. The captured data can be get from the message object.
The value can be used in the Hookflow for further processing, or if the Hookflow script has an output parameter, then we can put the captured value into the output parameter.
Parameters
Name | Type | Description |
---|---|---|
InitialErrorKey | String | n.a. in custom usage |
TitleKey | String | Title of the screen |
Information | String | Additional information on the screen |
Parameters | Object of sting | n.a. in custom usage |
AllowToGoBack | Bool | - |
ForceDataEntry | Bool | - |
AllowMultiLine | Bool | - |
MinimumNumberOfCharacters | Int | Minimum number of characters that must be typed |
Example:
The selected item will be used on a message screen.
string initialErrorKey = null; string FreeText = ""; Message msg = null; DataSet dsItems = null; string query = "SELECT DISTINCT PMX_OITMANAGED_BY_PMX.ItemCode AS ProductCode, PMX_OITMANAGED_BY_PMX.U_PMX_CUDE AS ProductDescription, PMX_OITMANAGED_BY_PMX.CodeBars AS GTIN, PMX_OITMANAGED_BY_PMX.U_PMX_HBBD, PMX_OITMANAGED_BY_PMX.U_PMX_PILR, PMX_OITMANAGED_BY_PMX.ManBtchNum, PMX_OITMANAGED_BY_PMX.U_PMX_LOUN, PMX_OITMANAGED_BY_PMX.NumInBuy, PMX_OITMANAGED_BY_PMX.BuyUnitMsr, PMX_OITMANAGED_BY_PMX.InvntryUom, PMX_OITMANAGED_BY_PMX.CodeBars AS CodeBars, PMX_OITMANAGED_BY_PMX.ItemName FROM PMX_OITMANAGED_BY_PMX WITH (NOLOCK) WHERE PMX_OITMANAGED_BY_PMX.InvntItem = 'Y' AND PMX_OITMANAGED_BY_PMX.InvntItem = 'Y' AND NOT ( PMX_OITMANAGED_BY_PMX.frozenFor = 'Y' AND ( ( PMX_OITMANAGED_BY_PMX.frozenFrom IS NULL OR CURRENT_TIMESTAMP >= PMX_OITMANAGED_BY_PMX.frozenFrom ) AND ( PMX_OITMANAGED_BY_PMX.frozenTo IS NULL OR CURRENT_TIMESTAMP < DATEADD( day, 1, PMX_OITMANAGED_BY_PMX.frozenTo ) ) ) ) ORDER BY ProductDescription"; dsItems = sboProviderService.RunView(false, null, null, query); session.ShowCustomizedScreen(typeof(Produmex.Foundation.SlimScreen.Interfaces.ISelectProductScreen), DefaultCultureInfo.Get(), BuildParamCollection( "InitialErrorKey", initialErrorKey, "TitleKey", "Title of the screen", "ProductDS", dsItems ), WorkflowId, nameof(ChecksScript_Screens.SelectProductScreen1)); msg = WaitForMessage(); if (msg.Name.EndsWith(".ProductSelected")) { FreeText = ExtractParameter<string>( msg.Parameters, "itemCode" ); } msg = null; session.ShowScreen(typeof(Produmex.Foundation.SlimScreen.Interfaces.IShowMessageScreen), this.DefaultCultureInfo, BuildParamCollection( "MessageKey", "Entered text: " + FreeText, "ShowButton", true )); msg = WaitForMessage();
Parameters
Name,Type,Description TitleKey,String,Name of the screen MessageKey,String,question string
Example:
Message msg = null; session.ShowCustomizedScreen(typeof(Produmex.Foundation.SlimScreen.Interfaces.IDecisionScreen), DefaultCultureInfo.Get(), BuildParamCollection( "TitleKey", "Title of the screen", "MessageKey", "Do you want to continue?"), WorkflowId, nameof(ReceptionScript_Screens.DecisionScreen22)); msg = WaitForMessage(); if (msg.Name.EndsWith(".Yes")) { // goto Step_ClearDataBeforeNextItem; } if (msg.Name.EndsWith(".No")) { BackRequested.Set(true); }
Use the Get() method to read the parameter:
LogisticUnits.Get()
Example:
protected override void Execute() { // Parameters in scope Session session = GetScopeParameter("Session") as Session; ISboProviderService sboProviderService = GetScopeParameter("<WwfService>ISboService") as ISboProviderService; foreach(LogisticUnitGoodsReceipt LUGR in LogisticUnits.Get()) { s_log.Error("CHECK DATA IN LOG - SSCC: " + LUGR.SSCC); foreach (LogisticUnitItemGoodReceipt LIGR in LUGR.ItemsOnLogisticUnit) { s_log.Error("CHECK DATA IN LOG - ItemCode: " + LIGR.ItemCode); s_log.Error("CHECK DATA IN LOG - Quantity: " + LIGR.Quantity.ToString()); foreach (PackagingTypeInfo P in LIGR.FullListOfPackagingTypes){ s_log.Error("CHECK DATA IN LOG - Uom: " + P.PackagingTypeName); s_log.Error("CHECK DATA IN LOG - Quantity: " + P.Quantity.ToString()); } } } }
Standalone Script is used for starting a logic individually from Produmex WMS by the WMS robot tool. It can be scheduled in the Windows Scheduler. This can be for example a very complex replenishment order generation.
Necessary classes:
Class | Reference |
---|---|
TransactionScope | using System.Transactions; |
PmxDbConnection | using Produmex.Foundation.Data.Sbo; |
Steps:
Copy your connection string text from any config file of the Produmex WMS tools or Fat Client application.
private static string CONNECTION_STRING = “”;
using (TransactionScope scope = PmxDbConnection.GetNewTransactionScope())
using (PmxDbConnectionDirect conn = PmxDbConnectionMgr.GetDirectConnection(SboConnectionString.ParseStringToObject(CONNECTION_STRING)))
Example:
using ( TransactionScope scope = PmxDbConnection.GetNewTransactionScope()) { using (PmxDbConnectionDirect conn = PmxDbConnectionMgr.GetDirectConnection(SboConnectionString.ParseStringToObject(CONNECTION_STRING))) { conn.Open(); Console.WriteLine("Connection is open"); string query = @"SELECT TOP 1 DocEntry FROM PMX_PLHE WHERE DocStatus = 'O' ORDER BY DocEntry "; using (ISboRecordset rs1 = SboRecordsetHelper.RunQuery(s_log, query, conn)) { while (!rs1.EoF) { … Do Something … rs1.MoveNext(); } } } scope.Complete(); //Complete transaction }
You can find the list of methods and fields of the Produmex WMS classes in this section.
Fields | - | - |
---|---|---|
Methods | ISboRecordset RunQuery(ILog log, string query, PmxDbConnection dbConn) | Provide the result of the query into ISboRecordset class |
Fields | EoF | Bool |
---|---|---|
Methods | void MoveFirst() | - |
void MoveLast() | - | |
void MoveNext() | - | |
void MovePrevious() | - | |
void RedoOriginalQuery() | - | |
GetTypedValue<string> ("<Col_Name>") GetTypedValue<int>("Col_Name") GetTypedValue<double>("Col_Name") | Read data from the recordset |
Initialization | new PmxItemAllConnectionsProvider (conn); |
---|---|
Methods | PmxItemInfo GetCachedItemInfo (string itemCode) |
PmxItemInfo GetItemInfo (string itemCode) |
Fields | private string ItemCode; private bool IsLogisticCarrier; private bool IsLogisticUnit; private bool IsReturnableItem; private string Description; private bool HasBestBeforeDate; private bool IsInventoryItem; private bool HasBatchnumber; private string CodeBars; private int? ItemLabelReportKey; private int NumberOfCopiesItemLabel; private bool NeedsReasonForPurchaseReturn; private bool NeedsReasonForSalesReturn; private string QualityStatusCodeProduction; private string QuarantinedQualityStatusCodeReception; private string ReleasedQualityStatusCodeReception; private string QualityStatusCodeReceptionController; private string QualityStatusCodeSalesReturn; private bool ScanBaseComponent; private PmxItemInfo m_baseItemInfo; private int ShelfLifeInDays; private string ExpiryDefinitionCodeForProduction; private string ExpiryDefinitionCodeForReception; private string InventoryUom; private string m_purchaseUom; private string SalesUom; private double NumberOfItemsPerPurchaseUnit; private double NumberOfItemsPerSalesUnit; private string SalesBarcode; private string PurchaseBarcode; private bool PrintItemLabel; private string Uom2; private double DefaultQuantityUom2; private bool CorrectStockUom; private bool CorrectStockUom2; private bool UseUom2; private PmxUomToUse UomToUseForPurchase; private PmxUomToUse UomToUseForInventoryTransitions; private PmxUomToUse UomToUseForSales; private int UomDecimals; private int Uom2Decimals; private bool HasSecondBatchNumber; private string PictureName; private string PackingImage; private string PackingRemarks; private string VendorItemDescription; private string CustomItemDescription; private bool HasNoValue; private string LowestSellablePackagingType; private int ShelfLifeInDaysReception; private string SerialNumberFormat; private bool CreateSsccOnReception; private Collection<PmxItemPackagingTypeInfo> ListOfPackagingTypes = new Collection<PmxItemPackagingTypeInfo>(); private PmxDictionary<string, double> BarcodesAndUomQuantities = new PmxDictionary<string, double>(); private PmxDictionary<string, double> PurchaseBarcodesAndUomQuantities = new PmxDictionary<string, double>(); private PmxDictionary<string, double> SalesBarcodesAndUomQuantities = new PmxDictionary<string, double>(); private PmxDictionary<string, string> DefaultWarehouseLocationOrZone = new PmxDictionary<string, string>(); |
---|---|
Methods | - |
Initialization | new PmxItemTransactionalInfoProvider (conn); | - |
---|---|---|
Methods | void ChangeBBDOnBatch (int itriKey, DateTime newBBD, bool changeExpDate = false) | Change BBD of a batch number itriKey = PMX_ITRI.InternalKey |
void ChangeInternalBatchNumber (int itriKey, string newBatchNumber2) | Change 2nd Batch number of a batch number itriKey = PMX_ITRI.InternalKey |
Initialization | new PmxLogisticUnitIDProvider(conn); | - |
---|---|---|
Methods | int GenerateNewLogisticUnit (string supplierPalletNumber) | Generates a new SSCC, the result of the method is PMX_LUID.InternalKey |
bool CheckIsLuidsInInventory (Collection<int> luids) | - | |
bool CheckIsSSCCMasterLogisticUnit (string sscc) | - | |
int GetLUIDBySSCC (string sscc) | PMX_LUID.InternalKey |
Fields | private string Code public string Name public bool IsActive public bool IsPickLocation public int Sequence public bool CanBeLinedUp public double? MaximumQuantity public int? MaximumLogisticUnits public bool AllowCountDuringCycleCount public bool AllowCountDuringOtherOperation public bool NeedsToBeCounted public int? LockedBy public int CountAfterNumberOfDays public int CountAfterNumberOfOperations |
---|---|
Methods | - |
Initialization | new PmxOseBinProvider (conn); |
---|---|
Methods | PmxOseBin GetBO(string key) |
public class LogisticUnitGoodsReceipt { AllowReceptionWithoutLUID = logisticUnitGoodsReceipt.AllowReceptionWithoutLUID, IsMoveToLockedStockLocation = logisticUnitGoodsReceipt.IsMoveToLockedStockLocation, ItemsOnLogisticUnit = Mapper.LocalCollectionOfLogisticUnitItemGoodReceipts(logisticUnitGoodsReceipt.ItemsOnLogisticUnit), LogisticUnitId = logisticUnitGoodsReceipt.LogisticUnitId, MasterLUID = logisticUnitGoodsReceipt.MasterLUID, Reason = logisticUnitGoodsReceipt.Reason, SpecificLocationCode = logisticUnitGoodsReceipt.SpecificLocationCode, SSCC = logisticUnitGoodsReceipt.SSCC, SupplierPalletNumber = logisticUnitGoodsReceipt.SupplierPalletNumber, UnitPrice = logisticUnitGoodsReceipt.UnitPrice, }
public class LogisticUnitItemGoodReceipt { AutoSelectPO = logisticUnitItemGoodReceipt.AutoSelectPO, BatchNumber1 = logisticUnitItemGoodReceipt.BatchNumber1, BatchNumber2 = logisticUnitItemGoodReceipt.BatchNumber2, BeasItemVersion = logisticUnitItemGoodReceipt.BeasItemVersion, BestBeforeDate = logisticUnitItemGoodReceipt.BestBeforeDate, FullListOfPackagingTypes = Mapper.LocalCollectionOfPackagingTypeInfos(logisticUnitItemGoodReceipt.FullListOfPackagingTypes), IsLogisticCarrier = logisticUnitItemGoodReceipt.IsLogisticCarrier, IsLogisticCarrierForLogisticUnit = logisticUnitItemGoodReceipt.IsLogisticCarrierForLogisticUnit, ItemCode = logisticUnitItemGoodReceipt.ItemCode, ListOfBatchAttributes = Mapper.LocalCollectionOfItemTransactionalBatchAttributeInfos(logisticUnitItemGoodReceipt.ListOfBatchAttributes), ListOfPackagingTypes = Mapper.LocalCollectionOfItemTransactionalPackagingTypeInfos(logisticUnitItemGoodReceipt.ListOfPackagingTypes), ListOfReasonsByZoneType = Mapper.LocalDictionaryOfReasonInfos(logisticUnitItemGoodReceipt.ListOfReasonsByZoneType), ListOfSerialNumbers = logisticUnitItemGoodReceipt.ListOfSerialNumbers, OverrideLocationCode = logisticUnitItemGoodReceipt.OverrideLocationCode, PurchaseDocRef = Mapper.LocalDocumentRef(logisticUnitItemGoodReceipt.PurchaseDocRef), PurchaseDocumentLineNum = logisticUnitItemGoodReceipt.PurchaseDocumentLineNum, QuantitiesForUom2 = logisticUnitItemGoodReceipt.QuantitiesForUom2, Quantity = logisticUnitItemGoodReceipt.Quantity, QuantityPerUom = logisticUnitItemGoodReceipt.QuantityPerUom, QuantityUom2 = logisticUnitItemGoodReceipt.QuantityUom2, ReasonInfo = logisticUnitItemGoodReceipt.ReasonInfo, UnitPrice = logisticUnitItemGoodReceipt.UnitPrice, Uom2 = logisticUnitItemGoodReceipt.Uom2, Usage = logisticUnitItemGoodReceipt.Usage, }
public class PackagingTypeInfo { private string m_packagingTypeCode; private string m_packagingTypeName; // Uom private double m_quantity; private double? m_initialQuantity; private double m_quantityPerPack = 1; private Collection<string> m_barcode; private bool m_showOnScreen; private int m_numberOfDecimals = 0; private bool m_hideDuringEnteringQuantity; }
Customization Articles for WMS scripting:
How to change the Quality Status by scripting
How to remove the SSCC for certain items, and put them on the location directly
Initialization | NEW PmxMoveProvider(conn); | - |
---|---|---|
Methods | PmxMoveProvider GetNewBO() | Generate a new Business Object into memory |
string AddBO (PmxMove bo) | Create the object in database | |
PmxMoveLine GetNewAddedLine (PmxMove document) | Add a new line for the item |
No need to do any configuration on this object.
Example usage:
PmxMoveProvider moveProv = new PmxMoveProvider(conn); PmxMove move = moveProv.GetNewBO(); PmxMoveLine moveLine = moveProv.GetNewAddedLine( move ); moveLine.ItemCode = ...; moveLine.Quantity = ...; ...; moveProv.AddBO( move , true);
Fields |
---|
private string SourceStorageLocationCode; private int? SourceLogisticUnitIdentificationKey; private string DestinationStorageLocationCode; private int? DestinationLogisticUnitIdentificationKey; private string SourceQualityStatusCode; private string DestinationQualityStatusCode; private bool isLogisticCarrier; private int? ItemTransactionalInfoKey; private string ReasonCode; private string ReasonFreeText; private string ReasonLocationCode; |
public enum PmxMoveOrderType { Move = 1, PutAway = 2, Replenish = 4, WarehouseTransfer = 8, PutAwayProduction = 12 }
public enum PmxMoveOrderStatus { NothingMoved = 1, Closed = 2, PartiallyMoved = 4 }
public enum PmxMoveInOneTime { Invalid = 0, CannotBeMovedInOneTime = 1, CanBeInOneTime = 2, MustBeMovedInOneTime = 4 }
public enum PmxMoveOrderStockLevel { Detail = 1, Item = 2, MasterLuid = 4 }
Initialization | new PmxMoveOrderProvider(conn); | - |
---|---|---|
Methods | PmxMoveOrder GetNewBO() | Generate a new Business Object into memory |
string AddBO (PmxMoveOrder bo) | Create the object in database | |
void UpdateBO (PmxMoveOrder bo, bool onlyUpdateHeader, bool baseDocumentIsClosing) | Updates the Business object in database | |
void CloseDocument (PmxMoveOrder document) | Closing Move Order document | |
PmxMoveOrderLine GetNewAddedLine (PmxMoveOrder document) | Add a new line to the document |
Fields | private PmxMoveOrderStatus MoveOrderStatus; private DateTime DueDate; private int Priority; private PmxMoveOrderType MoveOrderType; private PmxMoveInOneTime MoveLogUnitIn1Time; private int? LockedBy; private string FromPmxWhsCode; private string ToPmxWhsCode; private string Remarks; |
---|---|
Methods | - |
Fields | private PmxMoveOrderStatus MoveOrderLineStatus; private string SourceStorageLocationCode; private int? SourceLogisticUnitIdentificationKey; private string DestinationStorageLocationCode; private int? DestinationLogisticUnitIdentificationKey; private string QualityStatusCode; private int? ItemTransactionalInfoKey; private PmxMoveOrderStockLevel StockLevel; private string WaBoxCode; |
---|---|
Methods | - |
Customization Articles for WMS scripting:
How to generate Move Order by scripting
public enum PmxPickListProposalStockStatus { None, Partially, All }
public enum PmxPickObjectType { Sales, WhsTransfer, Production, WhsTransferProd }
public enum PmxInventoryLockingLevel { ItemNoLocking = 0, ItemQuality = 1, ItemBatchNumberBestBeforeDate = 2, ItemLUID = 4, ItemDetail = 8 }
Initialization | new PmxPickListProposalProvider (conn); | - |
---|---|---|
Methods | PmxPickListProposal GetNewBO() | Generate a new Business Object into memory |
PmxPickListProposal GetBO(int key) | - | |
string AddBO (PmxPickListProposal bo) | Create the object in database | |
void UpdateBO (PmxPickListProposal bo, bool onlyUpdateHeader, bool baseDocumentIsClosing) | Updates the Business object in database | |
void CloseDocument (PmxPickListProposal document) | Closing Move Order document | |
PmxMoveOrderLine GetNewAddedLine (PmxPickListProposal document) | Add a new line to the document |
Fields | private string CardCode; private string CardName; private string ShipToCode; private string ShipToaddress; private string DestinationStorageLocation; private PmxPickListProposalStockStatus FullStockStatus; private PmxPickListProposalStockStatus NotExpiredStockStatus; private DateTime DueDate; private string PickPackRemarks; private string Remarks; private int? RouteLineDocEntry; private int? RouteLineLineNum; private bool IsCustomerCollect; private string PickListType; private BusinessObjectProperty<int?> ShippingID; private string MoveToWarehouse; private string MoveToLocationCode; private PmxPickObjectType PickObjType; |
---|---|
Methods | - |
Fields | private int? ItemTransactionalInfoKey; private int? LogisticUnitIdentificationKey; private string QualityStatusCode; private PmxPickListProposalStockStatus FullStockStatus; private PmxPickListProposalStockStatus NotExpiredStockStatus; private double PickListQuantity; private PmxInventoryLockingLevel InvLockLevel; private bool ForceBatch; private bool IsSampleOrder; public double? QuantityForTempLock; |
---|---|
Methods | - |
public enum PmxPickListStatus { NotReady = 1, Closed = 2, PartiallyReady = 4, Ready = 8, PartiallyPicked = 0x10, Picked = 0x20, PartiallyDelivered = 0x40, PartiallyPacked = 0x80, Packed = 0x100, ForcedClosed = 0x200, PartiallyShipped = 0x400, Shipped = 0x800 }
public enum PmxPickObjectType { Sales, WhsTransfer, Production, WhsTransferProd }
public enum PmxInventoryLockingLevel { ItemNoLocking = 0, ItemQuality = 1, ItemBatchNumberBestBeforeDate = 2, ItemLUID = 4, ItemDetail = 8 }
Initialization | new PmxPickListProposalProvider (conn); | - |
---|---|---|
Methods | PmxPickListProposal GetNewBO() | Generate a new Business Object into memory |
PmxPickListProposal GetBO(int key) | - | |
string AddBO (PmxPickListProposal bo) | Create the object in database | |
void UpdateBO (PmxPickListProposal bo, bool onlyUpdateHeader, bool baseDocumentIsClosing) | Updates the Business object in database | |
void CloseDocument (PmxPickListProposal document) | Closing Move Order document | |
PmxMoveOrderLine GetNewAddedLine (PmxPickListProposal document) | Add a new line to the document |
Fields | private PmxPickListStatus PickListStatus; private string CardCode; private string ShipToAddress; private string ShipToCode; private string DestStorLocCode; private int? PickListProposalEntry; private BusinessObjectProperty<int> Priority; private DateTime DueDate; private int? LockBy; private string CardName; private int? RouteKey; private string ReasonCodeNotFullShipping; private string ReasonFreeTextNotFullShipping; private int? WaveKey; private string PickPackRemarks; private bool IsCustomerCollect; private bool IsPrinted; private string PickListType; private DateTime? LastPrintDateTime; private int? PackLockBy; private string MoveToWarehouse; private string MoveToLocationCode; private PmxPickObjectType PickObjType; |
---|---|
Methods | - |
Fields | private PmxPickListStatus PickListLineStatus; private int? ItemTransactionalInfoKey; private string StorageLocationCode; private int? LogisticUnitIdentificationKey; private string QualityStatusCode; private int Sequence; private double QuantityPicked; private double QuantityPacked; private double OriginalQuantity; private double? QuantityPickedUom2; private double? QuantityPackedUom2; private string ReasonCodeNotFullPicking; private PmxInventoryLockingLevel InvLockLevel; private bool ForceBatch; private bool IsSampleOrder; |
---|---|
Methods | - |
Customization Articles for WMS scripting:
How to trigger a print event from a script
Initialization | new PmxReportProvider (conn); | - |
---|---|---|
Methods | PmxReport GetBO(int key) | The code of the report from the OSE |
Initialization | new PmxOsePrinterProvider (conn); | - |
---|---|---|
Methods | PmxOsePrinter GetNewBO() | Not supported |
PmxOsePrinter GetBO(string key) | The code of the printer from the OSE |
The method provides the closest printer to a location.
Page size of the printer must be configured in the call.
DeviceID can be null.
PmxOsePrinter GetPrinterForLocation( string CurrentLocationCode, string DeviceID, string PageSizeCode)
Initialization | new ReportPrinterDevice (conn); | - |
---|---|---|
Methods | void PrintReport ( PmxReport report, PmxOsePrinter printer, CultureInfo cultureInfo, int numberOfCopies, DataSet ds, Collection<ReportParameter> reportParameters) --- CR parameters from PMX layouts | Create a new object for the printing |
PmxReportProvider reportProvider = new PmxReportProvider(conn); PmxReport report = reportProvider.GetBO(6); // report code FROM OSE PmxOsePrinterProvider printerProvider = new PmxOsePrinterProvider(conn); PmxOsePrinter printer = printerProvider.GetNewBO(); printer = printerProvider.GetBO("PRINTER"); // printer code from OSE // create the report parameter structure Collection<ReportParameter> reportParameters = new Collection<ReportParameter>(); reportParameters.Add(new ReportParameter("@luid", Luids[i])); ReportPrinterDevice device = new ReportPrinterDevice(conn); device.PrintReport(report, printer, null, 1, null, reportParameters);
From product version 2023.06, users can start the scanner application of the Mobile Client in customization mode and you can customize all the workflows available. From product version 2024.06, users can now create more complex customized workflows in the customization mode by creating user queries and adjusting & filtering the options in the Customization Manager.
Users have the possibility to customize the buttons and the screens of the flow while different customization for user groups and users can be defined in a way that is optimal for the warehouse.
Videos on the customization mode are available here and here.
Overview about the customization UIs:
The name of the parameter is /cust. When you start the Mobile Client in customization mode, a customization icon (a cog sign) is displayed on the top-right corner of the screen. If you click the icon, it becomes red and the customization mode is active.
To customize the flow, proceed as follows:
Note: In order to see the changes the user needs to restart the Mobile Client with disabled/switched off customization mode.
User Group: If you select a specific user group, the customization applies to the users in the given user group.
User: By default, no user is selected. Instead of user groups, you can define a specific user to whom the customization applies. Enable the User option and use the drop-down menu to select a user.
Default Button: The Default Button section is active if you customize a button.
Visible: By default, the visible option is enabled.
Note: Hiding buttons overrides customizations. 'User' settings override 'User Group' settings and specific 'User Group' settings override 'All Users' settings.
Example: The customization applies to the Inventory user group. The Order button is set as the default button on the Select a Filter screen. The screen is displayed for the user for two seconds and if the user doesn't tap another button, the system proceeds with the Order button.
Load Event: In this field you can customize an existing event, write the preferable name in the field than push the save button. What we do here is selecting any of the events that are already in use and modifying it's action.
Load Event Name: In this field you can modify an existing event by giving a unique name for your new customized event, after saving the unique name open the Query Manager in B1 where you can add your query to the name. For example create a “sales_return” name in the Load Event field and open it up in the Query Manager for furthermore customization.
Load Event List: Under the Load Event field there are a list of the previous events and actions that you have already been through.
Manage: Pushing the manage button will show the customization manager screen.
The Customization Manager screen is a helpful UI to manage your customizations in a visual way. On this screen you can find all of your user queries in a simple table. In the Customization Manager you can not change the database informations, you only have the option to filter/activate/inactivate/delete your added queries.
In the All Components part you can find a tree structure, the purpose of this navigation tree is to easily manage the rows where you added a new queries. The “golden arrow” shows the selected row in the tree structure. If you select the All components row than in the table on the right side will show every grid, every lines that are found below it in the system.
The main components in the tree structure:
The Filter section contain all the filter options to search for a specific query.
Screen: By default, no screen is selected. In the screen from dropdown menu you can select the preferred screen.
User Group:If you select a specific user group, the customization applies to the users in the given user group.
Options:
User:By default, no user is selected. Instead of user groups, you can define a specific user to whom the customization applies. Enable the User option and use the drop-down menu to select a user.
Show: This options is a dropdown menu where you can choose between several options to search a specific group of queries e.g. if you would like to check on the all of your inactive queries.
Options:
Customization: By clicking the options inside of the Customization aggregation you can easily set a quick filter and search for a group of queries.
Options:
Full Workflow: Clicking on the Full Workflow will extend the Workflow column with extra information about the path of the flows.
Reset Filters: With this button you can clear the filters that you previously set.
1. Limitation: On the Events tab you can see your previous steps/actions listed under the Load Event field. In that list you can clearly follow all your steps since you opened the mobile client in customization mode. Be aware you will not find those kind of actions listed when you selected a value from a list by a manual click, for example you chose a product by clicking it's name from the list instead of scanning the item barcode.
The selected values will only appear in the action list when you manually entered the value (customercode, location etc.) into the field or scanned that value.
2. Limitation: If a user query are no longer used there is a specific procedure to remove the query from the system. First you have to delete the query from the Customization Manager, after that action open the Query Manager in SBO and remove the unused query from that table.
Insert the <customercode> to the input field, and after you added the query to the Query Manager, the query automatically will select the predefined customer then waits 1 second and clicks the forward button.
Load Event Name: sales_return
MSSQL:
SELECT '<customercode>' as "txtCustomerCode", 'btnForward' as "DefaultButton", 1 as "DefaultButtonClickTimeout"
HANA:
SELECT '<customercode>' as "txtCustomerCode", 'btnForward' as "DefaultButton", 1 as "DefaultButtonClickTimeout" FROM DUMMY
Implementation: Add the query in the Query Manager in SBO.
Validation of the input quantity value on the reception flow, in this example we are showing as default quantity the minor between still to receive and default quantity logistic unit.
Load Event Name: default_quantity
Implementation: Add the query in the Query Manager in SBO.
MSSQL:
SELECT CASE WHEN CAST(LEFT('$[lblQuantity]', CHARINDEX(' ', '$[lblQuantity]')-1) AS INT) < U_PMX_DQLU THEN LEFT('$[lblQuantity]', CHARINDEX(' ', '$[lblQuantity]')-1) ELSE U_PMX_DQLU END AS "edtCounter0" FROM "OITM" WHERE U_PMX_CUDE = '$[lblItem]'
HANA:
SELECT CASE WHEN CAST(LEFT('$[lblQuantity]', LOCATE( '$[lblQuantity]',' ')-1) AS INTEGER) < "U_PMX_DQLU" THEN LEFT('$[lblQuantity]', LOCATE( '$[lblQuantity]',' ')-1) ELSE "U_PMX_DQLU" END AS "edtCounter0" FROM "OITM" WHERE "U_PMX_CUDE" = '$[lblItem]'
In this example if the query finds a Pick List that is connected to the <customercode> then the query will select the first Pick List then clicking on the forward button, if the query will not find a Pick List then nothing will happen.
Load Event Name: finding_picklist_connected_default_customer
Implementation: Add the query in the Query Manager in SBO.
MSSQL & HANA:
SELECT TOP 1 "DocEntry" AS "txtPickList", CASE WHEN "PMX_PLHE"."DocEntry" IS NOT NULL THEN 'btnForward' ELSE '' END AS "DefaultButton", CASE WHEN "PMX_PLHE"."DocEntry" IS NOT NULL THEN '1' ELSE '' END AS "DefaultButtonClickTimeout" FROM "PMX_PLHE" WHERE "CardCode" = '<customercode>' ORDER BY "DocEntry" ASC
Scripting is not supported by our standard support tickets!
Support on scripting requires the purchase of Premium service.
Premium Service - If you wish to receive assistance on scripting cases, you inquiry will be then classified as Premium Service and will require the involvement of our delivery team in at least one remote session.
Modifying workflows can cause serious disruption of processes and even data corruption. Extreme Caution is advised!
It is recommended that only experienced WMS Consultants attempt to modify these workflows.
Boyum IT cannot be held responsible for issues resulting from externally modified workflows.