public static OrderStatusEnum GetStatusAllDishes(IEnumerable <OrderDish> dishes) { if ((dishes == null) || (dishes.Count() == 0)) { return(OrderStatusEnum.None); } int statId = -1, curStat; HashSet <int> unUsedDeps = (HashSet <int>)AppProperties.GetProperty("UnusedDepartments"); foreach (OrderDish dish in dishes) { if ((unUsedDeps != null) && (unUsedDeps.Contains(dish.DepartmentId))) { } else { curStat = dish.DishStatusId; if (statId == -1) { statId = curStat; } else if (statId != dish.DishStatusId) { return(OrderStatusEnum.None); } } } return((OrderStatusEnum)statId); }
public static bool UpdateModelDictsFromDB(out string errMsg) { errMsg = ""; // список статусов -> в словарь List <OrderStatusModel> list1 = DBOrderHelper.GetOrderStatusesList(); if (list1 == null) { errMsg = DBOrderHelper.ErrorMessage; return(false); } list1.ForEach(item => _statuses.Add(item.Id, item)); // список отделов -> в словарь // а также обновить словарь кол-ва блюд по цехам Dictionary <int, decimal> depQty = (Dictionary <int, decimal>)AppProperties.GetProperty("dishesQty"); depQty.Clear(); List <DepartmentModel> list2 = DBOrderHelper.GetDepartmentsList(); if (list2 == null) { errMsg = DBOrderHelper.ErrorMessage; return(false); } list2.ForEach(item => { _departments.Add(item.Id, item); depQty.Add(item.Id, 0m); }); return(true); }
// проверка возможности АВТОМАТИЧЕСКОГО перехода в состояние Cooking private void checkAutoStartCooking(Dictionary <int, OrderModel> orders) { OrderStatusEnum eStatus; decimal depDepth, dishQnt; bool isStart; Dictionary <int, decimal> dishesQty = (Dictionary <int, decimal>)AppProperties.GetProperty("dishesQty"); foreach (OrderModel order in orders.Values) // orders loop { foreach (OrderDishModel dish in order.Dishes.Values) // dishes loop { eStatus = (OrderStatusEnum)dish.DishStatusId; if (eStatus <= OrderStatusEnum.WaitingCook) { // 1. для отдела установлен автоматический старт приготовления и текущая дата больше даты ожидаемого времени начала приготовления DateTime n = DateTime.Now; isStart = (ModelDicts.GetDepAutoStart(dish.DepartmentId) && (n >= dish.CreateDate.AddSeconds(dish.DelayedStartTime))); // 2. проверяем общее кол-во такого блюда в заказах, если установлено кол-во одновременно готовящихся блюд if (isStart == true) { depDepth = ModelDicts.GetDepDepthCount(dish.DepartmentId); if ((dishesQty != null) && (dishesQty.ContainsKey(dish.DepartmentId)) && (depDepth > 0)) { dishQnt = Math.Ceiling(dish.Quantity); if (dishesQty[dish.DepartmentId] < depDepth) { isStart = true; // обновить кол-во готовящихся блюд в словаре dishesQty[dish.DepartmentId] += dishQnt; } else { isStart = false; } } } // автостарт приготовления блюда if (isStart) { DateTime dtTmr = DateTime.Now; string sLogMsg = string.Format(" - AutoStart Cooking Id {0}/{1}", dish.Id, dish.Name); AppLib.WriteLogOrderDetails(sLogMsg + " - start"); dish.UpdateStatus(OrderStatusEnum.Cooking); sLogMsg += " - finish - " + (DateTime.Now - dtTmr).ToString(); AppLib.WriteLogOrderDetails(sLogMsg); } } } // loop } // loop }
// обновление состояния заказа проверкой состояний всех блюд // установить сост.заказа в 0,2,3,4,5 если ВСЕ блюда наход.в этом состоянии // установить сост.заказа в 1, если ХОТЬ одно блюдо наход.в сост. 1 public void UpdateStatusByVerificationDishes() { int iStat = -1; HashSet <int> unUsedDeps = (HashSet <int>)AppProperties.GetProperty("UnusedDepartments"); foreach (OrderDishModel dish in _dishesDict.Values) { // пропуск блюд, входящих в неотображаемые цеха // или имеющие отрицательное количество - отмененные if ((unUsedDeps != null) && (unUsedDeps.Contains(dish.DepartmentId))) { continue; } if (dish.Quantity < 0) { continue; } // первое доступное блюдо if (iStat == -1) { iStat = dish.DishStatusId; } // если хотя бы одно блюдо в состояние Готовится, то и заказ переводим в это состояние, если он был не в этом состоянии if ((dish.DishStatusId == (int)OrderStatusEnum.Cooking) && (this.OrderStatusId != (int)OrderStatusEnum.Cooking)) { AppLib.WriteLogOrderDetails(string.Format(" изменение статуса заказа {0}/{1} с {2} на 'Готовится', т.к. есть блюдо в состоянии 'Готовится'" , this.Id, this.Number , ((OrderStatusEnum)this.OrderStatusId).ToString())); UpdateStatus(OrderStatusEnum.Cooking, false); _isUpdStatusFromDishes = true; return; } // есть неодинаковый статус - выйти if (iStat != dish.DishStatusId) { return; } } if ((iStat != -1) && (this.OrderStatusId != iStat)) { string sLog = string.Format(" изменение статуса заказа {0}/{1} на {2} согласно общему статусу всех блюд ПРИ ОБНОВЛЕНИИ БЛЮДА...", this.Id, this.Number, iStat); AppLib.WriteLogOrderDetails(sLog); OrderStatusEnum statDishes = AppLib.GetStatusEnumFromNullableInt(iStat); UpdateStatus(statDishes, false); _isUpdStatusFromDishes = true; } } // method
} // method private string getDishesQtyString() { // получить словарь по отделам (направлениям печати) Dictionary <int, decimal> dishesQty = (Dictionary <int, decimal>)AppProperties.GetProperty("dishesQty"); StringBuilder sb = new StringBuilder(); foreach (KeyValuePair <int, decimal> item in dishesQty) { if (sb.Length > 0) { sb.Append("; "); } sb.Append(string.Format("{0}/{1}", item.Key, item.Value)); } return(sb.ToString()); }
// узнать, в каком состоянии находятся ВСЕ БЛЮДА заказа public static OrderStatusEnum oldGetStatusAllDishes(IEnumerable <OrderDish> dishes) { if ((dishes == null) || (dishes.Count() == 0)) { return(OrderStatusEnum.None); } OrderStatusEnum retVal = OrderStatusEnum.None; int iLen = Enum.GetValues(typeof(OrderStatusEnum)).Length; int dishCount = dishes.Count(); int[] statArray = new int[iLen]; HashSet <int> unUsedDeps = (HashSet <int>)AppProperties.GetProperty("UnusedDepartments"); int iStatus; foreach (OrderDish dish in dishes) { if ((unUsedDeps != null) && (unUsedDeps.Contains(dish.DepartmentId))) { dishCount--; } else { iStatus = dish.DishStatusId; statArray[iStatus]++; } } for (int i = 0; i < iLen; i++) { if (statArray[i] == dishCount) { retVal = (OrderStatusEnum)i; break; } } return(retVal); }
// CONSTRUCTOR public OrdersModel() { // статусы заказов, которые выбираются из БД для отображения на КДС _allowedKDSStatuses = new HashSet <int>(); _allowedKDSStatuses.Add((int)OrderStatusEnum.WaitingCook); _allowedKDSStatuses.Add((int)OrderStatusEnum.Cooking); _allowedKDSStatuses.Add((int)OrderStatusEnum.Ready); if (AppProperties.GetBoolProperty("IsReadTakenDishes")) { _allowedKDSStatuses.Add((int)OrderStatusEnum.Took); } _allowedKDSStatuses.Add((int)OrderStatusEnum.Cancelled); _allowedKDSStatuses.Add((int)OrderStatusEnum.Transferred); _allowedKDSStatuses.Add((int)OrderStatusEnum.ReadyConfirmed); DBOrderHelper.AllowedKDSStatuses = _allowedKDSStatuses; // неиспользуемые отделы, отфильтровываются на службе _unUsedDeps = (HashSet <int>)AppProperties.GetProperty("UnusedDepartments"); DBOrderHelper.UnusedDeps = _unUsedDeps; // буферы для хранения коллекций заказов _dbOrders = DBOrderHelper.DBOrders; _orders = new Dictionary <int, OrderModel>(); // учитывать ли отмененные блюда при подсчете одновременно готовящихся блюд для автостарта готовки _takeCancelledInAutostartCooking = AppProperties.GetBoolProperty("TakeCancelledInAutostartCooking"); // используется, если для детального лога нужно еще чего-то сделать _isLogOrderDetails = (AppProperties.GetBoolProperty("IsWriteTraceMessages") && AppProperties.GetBoolProperty("TraceOrdersDetails")); _changeStatusYesterdayOrdersCfg = (AppLib.TimeOfAutoCloseYesterdayOrders != TimeSpan.Zero); _changeStatusYesterdayOrdersCurrent = _changeStatusYesterdayOrdersCfg; _currentDate = DateTime.Now.Date; //_currentDate = _currentDate.AddDays(-1); _delOrders = new List <Order>(); }
// обновить коллекцию private void updateDishesQuantityDict(Dictionary <int, OrderModel> orders) { // получить словарь по отделам (направлениям печати) Dictionary <int, decimal> dishesQty = (Dictionary <int, decimal>)AppProperties.GetProperty("dishesQty"); // очистить кол-во List <int> keys = dishesQty.Keys.ToList(); foreach (int key in keys) { dishesQty[key] = 0m; } decimal qnt; OrderStatusEnum eStatus; bool isTakeQuantity, isTakeCancelled; foreach (OrderModel order in orders.Values) // orders loop { foreach (OrderDishModel dish in order.Dishes.Values) // dishes loop { eStatus = (OrderStatusEnum)dish.DishStatusId; isTakeCancelled = (_takeCancelledInAutostartCooking && (eStatus == OrderStatusEnum.Cancelled)); isTakeQuantity = dish.ParentUid.IsNull() && ((eStatus == OrderStatusEnum.Cooking) || isTakeCancelled); // кол-во блюд для подсчета округляем до верхнего целого qnt = Math.Ceiling(dish.Quantity); qnt = isTakeQuantity ? (isTakeCancelled ? -qnt : qnt) : 0m; if ((dishesQty.ContainsKey(dish.DepartmentId)) && (qnt != 0m)) { dishesQty[dish.DepartmentId] += qnt; } } // loop } // loop } // method
// сложить настройки из config-файла в словарь настроек приложения private static void putAppConfigParamsToAppProperties() { NameValueCollection cfg = ConfigurationManager.AppSettings; string value; // наименование службы MS SQL Server, как в services.msc setGlobalValueFromCfg("MSSQLServiceName", MSSQLService.Controller.ServiceName); // флаг перезапуска sql-службы, по умолчанию - false setGlobalValueFromCfg("MSSQLServiceRestartEnable", false); // уровень совместимости БД (120 - это MS SQL Server 2014) setGlobalValueFromCfg("MSSQLServerCompatibleLevel", 0); // таймаут выполнения команд в MS SQL, в СЕКУНДАХ setGlobalValueFromCfg("MSSQLCommandTimeout", 2); // уведомление Одерманов о готовом заказе setGlobalValueFromCfg("NoticeOrdermanFeature", false); setGlobalValueFromCfg <string>("NoticeOrdermanFolder", null); // проверка настроек ф-и уведомления if (AppProperties.GetBoolProperty("NoticeOrdermanFeature")) { string folder = (string)AppProperties.GetProperty("NoticeOrdermanFolder"); if (folder == null) { AppLib.WriteLogInfoMessage("Функция NoticeOrdermanFeature включена, но не указана папка для сохранения файлов-уведомлений NoticeOrdermanFolder"); } else { if (!folder.EndsWith(@"\")) { AppProperties.SetProperty("NoticeOrdermanFolder", folder + @"\"); } if (!System.IO.Directory.Exists(folder)) { AppLib.WriteLogInfoMessage("Функция NoticeOrdermanFeature включена, указана папка для сохранения файлов-уведомлений NoticeOrdermanFolder, но в системе эта папка не существует!"); } } } // режим сортировки заказов string ordersSortMode = "Desc"; value = cfg["SortOrdersByCreateDate"]; if ((value != null) && (value.Equals("Asc", StringComparison.OrdinalIgnoreCase))) { ordersSortMode = "Asc"; } AppProperties.SetProperty("SortOrdersByCreateDate", ordersSortMode); // время ожидания в состоянии ГОТОВ (время, в течение которого официант должен забрать блюдо), в секундах setGlobalValueFromCfg("ExpectedTake", 0); // читать ли из БД выданные блюда setGlobalValueFromCfg("IsReadTakenDishes", false); // использовать ли двухэтапный переход в состояние ГОТОВ/ подтверждение состояния ГОТОВ (повар переводит, шеф-повар подтверждает) setGlobalValueFromCfg("UseReadyConfirmedState", false); // Время, в СЕКУНДАХ, автоматического перехода из Готово в ПодтвГотово, при включенном ПодтвГотово (UseReadyConfirmedState = true). Если отсутствует или равно 0, то автоматического перехода не будет. setGlobalValueFromCfg("AutoGotoReadyConfirmPeriod", 0); // учитывать ли отмененные блюда при подсчете одновременно готовящихся блюд для автостарта готовки setGlobalValueFromCfg("TakeCancelledInAutostartCooking", false); value = cfg["TimeOfAutoCloseYesterdayOrders"]; TimeSpan ts = TimeSpan.Zero; if (value != null) { if (!TimeSpan.TryParse(value, CultureInfo.InvariantCulture, out ts)) { ts = TimeSpan.Zero; } } AppProperties.SetProperty("TimeOfAutoCloseYesterdayOrders", ts); setGlobalValueFromCfg("MidnightShiftShowYesterdayOrders", 0d); // неиспользуемые цеха value = cfg["UnusedDepartments"]; if (!value.IsNull()) // не Null и не пусто { HashSet <int> unUsed = new HashSet <int>(); if (value.Contains(',')) { value = value.Replace(',', ';'); } int[] ids = value.Split(';').Select(s => s.Trim().ToInt()).ToArray(); foreach (int item in ids) { if ((item != 0) && !unUsed.Contains(item)) { unUsed.Add(item); } } if (unUsed.Count == 0) { AppProperties.SetProperty("UnusedDepartments", null); } else { AppProperties.SetProperty("UnusedDepartments", unUsed); } } else { AppProperties.SetProperty("UnusedDepartments", null); } // Максимальное количество архивных файлов журнала. По умолчанию, равно 0 (нет ограничения). value = cfg["MaxLogFiles"]; AppProperties.SetProperty("MaxLogFiles", ((value == null) ? 0 : value.ToInt())); // отладочные сообщения setGlobalValueFromCfg("IsWriteTraceMessages", false); setGlobalValueFromCfg("TraceOrdersDetails", false); setGlobalValueFromCfg("IsLogClientAction", false); setGlobalValueFromCfg("TraceQueryToMSSQL", false); // ВНУТРЕННИЕ КОЛЛЕКЦИИ // коллекция для хранения готовящегося количества блюд по цехам (направлениям печати) AppProperties.SetProperty("dishesQty", new Dictionary <int, decimal>()); }
public bool CreateNoticeFileForOrder() { OrderStatusEnum status = (OrderStatusEnum)_order.OrderStatusId; string logMsg = $"Создание файла-уведомления для заказа № {_order.Number} (id {_order.Id}, status {status.ToString()})..."; writeLogMsg(logMsg); // check notice folder string sResult = null; string folder = (string)AppProperties.GetProperty("NoticeOrdermanFolder"); bool bResult = IntegraLib.AppEnvironment.CheckFolder(folder, out sResult); if (bResult == false) { writeLogMsg(" - " + sResult); return(false); } folder = sResult; bool retVal = false; string fileName = null, fileText = null; OrderStatusEnum toFileStatus = (OrderStatusEnum)_order.OrderStatusId; if (toFileStatus == OrderStatusEnum.ReadyConfirmed) { toFileStatus = OrderStatusEnum.Ready; } fileText = string.Format("Order UID: {1}{0}Order Id: {2}{0}Order Number: {3}{0}Order Status: {4} ({5}){0}Write Time: {7}{0}Waiter Name: {6}{0}Table Name: {8}", Environment.NewLine, _order.Uid, _order.Id, _order.Number, ((int)toFileStatus).ToString(), toFileStatus.ToString(), _order.Waiter, DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), _order.TableName); // для терминального состояния Готов ЗАКАЗА if (_order.IsReadyStatusFinal() == true) { fileName = $"{folder}ordNumber_{_order.Number}" + ".txt"; } // иначе вывести в файл-уведомление БЛЮДА в состоянии Готово else { List <OrderDishModel> readyDishes = _order.GetDishesReadyStatFin(); int cnt = readyDishes.Count; if (cnt > 0) { IntegraLib.StringHelper.SBufClear(); foreach (OrderDishModel dish in readyDishes) { logMsg = $" - блюдо '{dish.Name}' id {dish.Id}, status {((OrderStatusEnum)dish.DishStatusId).ToString()}"; writeLogMsg(logMsg); IntegraLib.StringHelper.SBufAppendText(Environment.NewLine + getDishStrForNoticeFile(dish)); } fileText += IntegraLib.StringHelper.SBufGetString(); fileName = $"{folder}ordNumber_{_order.Number} ({cnt.ToString()} dishes)" + ".txt"; } else { writeLogMsg(" - нет блюд в состоянии ГОТОВ"); } } if ((fileName != null) && (fileText != null)) { try { System.IO.File.WriteAllText(fileName, fileText); writeLogMsg($" - файл '{fileName}' создан успешно"); retVal = true; } catch (Exception ex) { writeLogMsg(" - Error: " + ex.Message); } } return(retVal); }
// создание файла уведомления о состоянии БЛЮДА // для заказа создается файл [номер заказа].txt, для блюда - [номер заказа]([id блюда]).txt // для блюда, не ингредиента, только, если сам заказ еще не готов и NoticeOrdermanDishNotice = 1 (создавать файл-уведомления для блюда) public bool CreateNoticeFileForDishes(string orderDishIds) { string logMsg = $"Создание файла состояния для блюд/id {orderDishIds} заказа № {_order.Number} (id {_order.Id})..."; writeLogMsg(logMsg); if (orderDishIds.IsNull()) { writeLogMsg(" - перечень id блюд - пустой!"); return(false); } // check notice folder string sResult = null; string folder = (string)AppProperties.GetProperty("NoticeOrdermanFolder"); bool bResult = IntegraLib.AppEnvironment.CheckFolder(folder, out sResult); if (bResult == false) { writeLogMsg(" - " + sResult); return(false); } folder = sResult; bool retVal = false; string fileName = null, fileText = null; OrderStatusEnum toFileStatus = (OrderStatusEnum)_order.OrderStatusId; if (toFileStatus == OrderStatusEnum.ReadyConfirmed) { toFileStatus = OrderStatusEnum.Ready; } fileText = string.Format("Order UID: {1}{0}Order Id: {2}{0}Order Number: {3}{0}Order Status: {4} ({5}){0}Waiter Name: {6}", Environment.NewLine, _order.Uid, _order.Id, _order.Number, ((int)toFileStatus).ToString(), toFileStatus.ToString(), _order.Waiter); int[] ids = orderDishIds.Split(';').Select(s => s.ToInt()).ToArray(); if (ids.Length > 0) { IntegraLib.StringHelper.SBufClear(); OrderDishModel dish; foreach (int dishId in ids) { if (_order.Dishes.ContainsKey(dishId)) { dish = _order.Dishes[dishId]; IntegraLib.StringHelper.SBufAppendText(Environment.NewLine + getDishStrForNoticeFile(dish)); } } fileText += IntegraLib.StringHelper.SBufGetString(); fileName = $"{folder}ordNumber_{_order.Number} (dishes {orderDishIds})" + ".txt"; try { System.IO.File.WriteAllText(fileName, fileText); writeLogMsg($" - файл '{fileName}' создан успешно"); retVal = true; } catch (Exception ex) { writeLogMsg(" - Error: " + ex.Message); } } return(retVal); }