Scenario
During -1/+1 hour of store closing time. Before "Tender declaration" or "Close shift", check whether or not there is opened customer order which is requested to pick up at that store on current date.This relates to Real-time Service because POS needs to check opened customer order from Retail HQ.
Store shipping warehouse and closing hour
Shipping warehouse and closing hour are configured in Retail stores detail form; Retail > Common > Retail channels > Retail storesRetail HQ: Method for checking opened customer order
We needs to create a method to return a set of orders with status is opened, delivery date is current date and delivery warehouse is same as the store.Add the following method in the RetailTransactionServiceEX class. The method will return a set of sales orders in container array.
public static container pkaSearchSalesOrderOpenOrderList(str _storeId)
{
SalesTable salesTable;
container salesOrder = [true,''];
RetailStoreId retailStoreId = _storeId;
RetailStoreTable retailStoreTable = RetailStoreTable::find(retailStoreId);
SalesShippingDateRequested requestedDeliveryDate = systemDateGet();
if(retailStoreTable.RecId)
{
while select SalesId
from salesTable
order by salesTable.CreatedDateTime desc
where (
//Result must not contain SalesStatus::Canceled && SalesStatus::Delivered && SalesStatus::Invoiced
(salesTable.SalesStatus == SalesStatus::None ||
salesTable.SalesStatus == SalesStatus::Backorder)
//Check delivery date as current date
&& (salesTable.DeliveryDate == requestedDeliveryDate)
//Check warehouse same as retail store
&& (salesTable.InventLocationId == retailStoreTable.inventLocation)
)
{
salesOrder = conins(salesOrder, conlen(salesOrder) + 1, RetailTransactionService::getSalesOrder(salesTable.SalesId));
}
}
return salesOrder;
}
Retail POS: Calling extension methods
Create a Blank Operation button with: -- operation number: CHECKSALESORDER
- param: TENDERDECLARATION or CLOSESHIFT --> this will be process after checking order
I will simply create functions in BlankOperations.cs of Retail SDK for processing above operation number and its param.
/// <summary>
/// Displays an alert message according operation id passed.
/// </summary>
/// <param name="operationInfo"></param>
/// <param name="posTransaction"></param>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "0", Justification = "Grandfather")]
public void BlankOperation(IBlankOperationInfo operationInfo, IPosTransaction posTransaction)
{
switch ((operationInfo.OperationId).ToUpperInvariant().Replace(" ", string.Empty))
{
#region Check Sales Order
case "CHECKSALESORDER": //Check Sales Order
if (this.CheckNullOperationParam(operationInfo))
{
this.CheckSalesOrder(operationInfo);
}
break;
#endregion
default:
//default, just echo the operation number and parameter value
break;
}
}
For this Blank Operation button, parameter is mandatory. Make sure that param is defined.
private bool CheckNullOperationParam(IBlankOperationInfo operationInfo)
{
StringBuilder comment = new StringBuilder(128);
bool ret = true;
if (operationInfo.Parameter == "")
{
//throw error if operation parameter is empty
comment.Append("Operation parameter not found.");
SerializationHelper.ShowMessage(comment.ToString());
// Set this property to true when your operation is handled
operationInfo.OperationHandled = true;
ret = false;
}
return ret;
}
As the scenario "During -1/+1 hour of store closing time", we have to compare current time with closing hour configuration from Store table.
Getting StoreId from LSRetailPosis.Settings.ApplicationSettings.Terminal.StoreId and get closing time from RetailStoreTable in Store DB.
If no opened order, user is able to "Tender declaration" or "Close shift" by calling Application.RunOperation command.
{
string storeId = LSRetailPosis.Settings.ApplicationSettings.Terminal.StoreId;
bool isStoreClosingHour = DataCollection.IsStoreClosingHour(Application, storeId);
bool chkSalesOrder = false;
if (isStoreClosingHour)
{
chkSalesOrder = this.CheckSalesOrderExists(operationInfo);
}
else
{
chkSalesOrder = true;
}
if (chkSalesOrder)
{
switch ((operationInfo.Parameter).ToUpperInvariant().Replace(" ", string.Empty))
{
case "TENDERDECLARATION": //Tender Declaration
Application.RunOperation(PosisOperations.TenderDeclaration, null);
break;
case "CLOSESHIFT": //Tender Declaration
Application.RunOperation(PosisOperations.CloseShift, null);
break;
default:
StringBuilder comment = new StringBuilder(128);
comment.AppendFormat("Specified action for operation {0} not found", operationInfo.Parameter);
SerializationHelper.ShowMessage(comment.ToString());
break;
}
}
}
/// <summary>
/// Check whether or not system will check opened Sales Order at the moment
/// </summary>
/// <param name="Application"></param>
/// <param name="StoreId"></param>
/// <returns>Return True status for checking opened Sales Order at the moment</returns>
internal static bool IsStoreClosingHour(IApplication Application, string StoreId)
{
bool ret = false;
DataTable store = new DataTable();
string queryString = "SELECT DATEDIFF(HOUR, CONVERT(TIME, SYSDATETIME()), CONVERT(TIME, DATEADD(SECOND, [OPENTO], 0), 114)) AS TIMEDIFF " +
"FROM RETAILSTORETABLE AS STORE " +
"WHERE STORE.STORENUMBER = '" + StoreId + "' ";
store = DataCollection.GetData(Application, queryString);
if (store.Rows.Count > 0)
{
DataRow row = store.Rows[0];
// if current time is different form 1 / -1 hour of "Opening To" hour of store
// Return True status for checking opened Sales Order at the moment
if ((int)row["TIMEDIFF"] >= -1 && (int)row["TIMEDIFF"] <= 1)
{
ret = true;
}
}
return ret;
}
private bool CheckSalesOrderExists(IBlankOperationInfo operationInfo)
{
StringBuilder comment = new StringBuilder(128);
bool ret = true;
// Begin by checking if there is a connection to the Transaction Service
this.Application.TransactionServices.CheckConnection();
string storeId = LSRetailPosis.Settings.ApplicationSettings.Terminal.StoreId;
ReadOnlyCollection<object> containerArray;
DataTable salesOrders = new DataTable();
bool retValue;
string retComment;
containerArray = this.Application.TransactionServices.InvokeExtension("pkaSearchSalesOrderOpenOrderList", storeId);
retValue = SerializationHelper.ConvertToBooleanAtIndex(containerArray, 1);
retComment = containerArray[2].ToString();
salesOrders.Columns.Add("SALESID", typeof(string));
for (int i = 3; i < containerArray.Count; i++)
{
IList salesRecord = (IList)containerArray[i];
bool recordRetVal = SerializationHelper.ConvertToBooleanAtIndex(salesRecord, 0);
string recordComment = SerializationHelper.ConvertToStringAtIndex(salesRecord, 1);
// The particular sales order at this position in the container is blank so we need
// to jump over it process the next one...
if (!recordRetVal)
continue;
DataRow row = salesOrders.NewRow();
// some of these fields may not be properly initialized even if recordRetVal is true
row["SALESID"] = SerializationHelper.ConvertToStringAtIndex(salesRecord, 2);
salesOrders.Rows.Add(row);
}
if (salesOrders.Rows.Count > 0)
{
if (salesOrders.Rows.Count == 1)
{
DataRow row = salesOrders.Rows[0];
comment.AppendFormat("Outstanding sales order {0} is found.", row["SALESID"]);
}
else
{
comment.AppendFormat("There are outstanding sales orders found.");
}
SerializationHelper.ShowMessage(comment.ToString());
// Set this property to true when your operation is handled
operationInfo.OperationHandled = true;
ret = false;
}
return ret;
}
Tip: I also create another utility class for converting values and showing message by calling frmMessage dialog form.
internal static bool ConvertToBooleanAtIndex(IList list, int index)
{
try
{
return Convert.ToBoolean(list[index]);
}
catch
{
return false;
}
}
internal static string ConvertToStringAtIndex(IList list, int index)
{
try
{
return Convert.ToString(list[index]);
}
catch
{
return string.Empty;
}
}
internal static void ShowMessage(string message, MessageBoxIcon icon = MessageBoxIcon.Error)
{
using (LSRetailPosis.POSProcesses.frmMessage dialog = new LSRetailPosis.POSProcesses.frmMessage(message, MessageBoxButtons.OK, icon))
{
LSRetailPosis.POSProcesses.POSFormsManager.ShowPOSForm(dialog);
}
}
No comments:
Post a Comment