// метод, который возвращает значения полей даты/времени состояния private StatusDTS getStatusRunTimeDTS(OrderStatusEnum status) { StatusDTS retVal = new StatusDTS(); switch (status) { case OrderStatusEnum.None: break; case OrderStatusEnum.WaitingCook: retVal.DateEntered = Convert.ToDateTime(_dbRunTimeRecord.InitDate); retVal.TimeStanding = Convert.ToInt32(_dbRunTimeRecord.WaitingCookTS); break; case OrderStatusEnum.Cooking: retVal.DateEntered = Convert.ToDateTime(_dbRunTimeRecord.CookingStartDate); retVal.TimeStanding = Convert.ToInt32(_dbRunTimeRecord.CookingTS); break; case OrderStatusEnum.Ready: retVal.DateEntered = Convert.ToDateTime(_dbRunTimeRecord.ReadyDate); if (_isUseReadyConfirmed) { retVal.TimeStanding = Convert.ToInt32(_dbRunTimeRecord.ReadyTS); } else { retVal.TimeStanding = Convert.ToInt32(_dbRunTimeRecord.WaitingTakeTS); } break; case OrderStatusEnum.ReadyConfirmed: retVal.DateEntered = Convert.ToDateTime(_dbRunTimeRecord.ReadyConfirmedDate); retVal.TimeStanding = Convert.ToInt32(_dbRunTimeRecord.WaitingTakeTS); break; case OrderStatusEnum.Took: retVal.DateEntered = Convert.ToDateTime(_dbRunTimeRecord.TakeDate); retVal.TimeStanding = Convert.ToInt32(_dbRunTimeRecord.WaitingCommitTS); break; case OrderStatusEnum.Cancelled: retVal.DateEntered = Convert.ToDateTime(_dbRunTimeRecord.CancelDate); break; case OrderStatusEnum.Commit: retVal.DateEntered = Convert.ToDateTime(_dbRunTimeRecord.CommitDate); break; case OrderStatusEnum.CancelConfirmed: retVal.DateEntered = Convert.ToDateTime(_dbRunTimeRecord.CancelConfirmedDate); break; default: break; } return(retVal); }
private void startStatusTimer(StatusDTS statusDTS) { DateTime dtEnterToStatus = statusDTS.DateEntered; if (_tsTimersDict.ContainsKey(this.Status) && ((_curTimer == null) || (_curTimer.Enabled == false) || (_curTimer != _tsTimersDict[this.Status]) || (_curTimer.StartDT != _tsTimersDict[this.Status].StartDT)) ) { _curTimer = _tsTimersDict[this.Status]; _curTimer.Start(dtEnterToStatus); } }
// запуск таймера для обновленного состояния private void startStatusTimer(StatusDTS statusDTS) { DateTime dtEnterToStatus = statusDTS.DateEntered; // сохранить дату входа в состояние во внутреннем словаре _dtEnterStatusDict[this.Status] = dtEnterToStatus; if (_tsTimersDict.ContainsKey(this.Status) && ((_curTimer == null) || (_curTimer.Enabled == false) || (_curTimer != _tsTimersDict[this.Status]) || (_curTimer.StartDT != _tsTimersDict[this.Status].StartDT)) ) { _curTimer = _tsTimersDict[this.Status]; _curTimer.Start(dtEnterToStatus); } }
// первый (инициализирующий) старт таймера private void startStatusTimerAtFirst() { StatusDTS statusDTS = getStatusRunTimeDTS(this.Status); // установить дату входа в состояние DateTime dtEnterState = statusDTS.DateEntered; if (dtEnterState.IsZero()) { dtEnterState = DateTime.Now; setStatusRunTimeDTS(this.Status, dtEnterState, -1); saveRunTimeRecord(); statusDTS = getStatusRunTimeDTS(this.Status); } startStatusTimer(statusDTS); }
// обновить добавленный к списку зависимый ингредиент по родительскому блюду // т.е. для нового объекта в заказе private void updateIngredientByParentDish() { // найти уже существующее блюдо для данного ингредиента _parentDish = getParentDish(); if (_parentDish != null) { StatusDTS dtsBase = _parentDish.getStatusRunTimeDTS(_parentDish.Status); // и если оно поменялось, то обновляем статус ингредиента if (this.DishStatusId != _parentDish.DishStatusId) { StatusDTS preDtsBase = _parentDish.getStatusRunTimeDTS(this.Status); UpdateStatus(_parentDish.Status, dtsBase.DateEntered, preDtsBase.TimeStanding); } else { setStatusRunTimeDTS(this.Status, dtsBase.DateEntered, -1); saveRunTimeRecord(); startStatusTimer(dtsBase); } } }
} // method UpdateFromDBEntity // внешнее обновление СОСТОЯНИЯ заказа // параметр isUpdateDishStatus = true, если заказ БЫЛ обновлен ИЗВНЕ (из БД/КДС), то в этом случае дату входа в новое состояние для блюд берем из заказа // isUpdateDishStatus = false, если заказ БУДЕТ обновлен по общему состоянию всех блюд public bool UpdateStatus(OrderStatusEnum newStatus, bool isUpdateDishStatus, string machineName = null) { // если статус не поменялся, то попытаться обновить только статус блюд if (this.Status == newStatus) { return(false); } bool retVal = false; string sLogMsg = string.Format(" - ORDER.UpdateStatus() Id/Num {0}/{1}, from {2} to {3}", this.Id, this.Number, this.Status.ToString(), newStatus.ToString()); DateTime dtTmr = DateTime.Now; if (machineName == null) { AppLib.WriteLogOrderDetails(sLogMsg + " - START"); } else { AppLib.WriteLogClientAction(machineName, sLogMsg + " - START"); } // время нахождения в ПРЕДЫДУЩЕМ состоянии, в секундах int secondsInPrevState = 0; if (_curTimer != null) // если есть таймер предыдущего состояния { _curTimer.Stop(); // остановить таймер состояния // получить время нахождения в состоянии с момента последнего входа secondsInPrevState = _curTimer.IncrementTS; } // дата входа в новое состояние DateTime dtEnterToNewStatus = DateTime.Now; // обновление заказа по ПОСЛЕДНЕМУ состоянию блюд, если они есть if ((isUpdateDishStatus == false) && (_dishesDict.Values.Count > 0)) { dtEnterToNewStatus = getMaxDishEnterStateDate(newStatus); } // сохранить новый статус ОБЪЕКТА в БД if (saveStatusToDB(newStatus, machineName)) { // изменить статус в ОБЪЕКТЕ OrderStatusEnum preStatus = this.Status; this.Status = newStatus; OrderStatusId = (int)Status; // сохраняем в записи RunTimeRecord дату входа в новое состояние setStatusRunTimeDTS(this.Status, dtEnterToNewStatus, -1); // и время нахождения в предыдущем состоянии setStatusRunTimeDTS(preStatus, DateTime.MinValue, secondsInPrevState); // и в БД saveRunTimeRecord(); // запуск таймера для нового состояния StatusDTS statusDTS = getStatusRunTimeDTS(this.Status); startStatusTimer(statusDTS); // обновить уже существующие блюда при внешнем изменении статуса заказа if (isUpdateDishStatus) { bool dishUpdSuccess = true; // для получения результата обновления через AND try { foreach (OrderDishModel modelDish in _dishesDict.Values) { // только для блюд if (modelDish.ParentUid.IsNull()) { // дату входа в состояние берем из заказа, а время нахожд.в предыд.состоянии из самого блюда dishUpdSuccess &= modelDish.UpdateStatus(newStatus, statusDTS.DateEntered); } } } catch (Exception ex) { AppLib.WriteLogErrorMessage("Ошибка обновления статуса блюд при обновлении статуса заказа {0}/{1} с {2} на {3}: {4}", this.Id, this.Number, this.Status, newStatus, ex.ToString()); dishUpdSuccess = false; } } retVal = true; } sLogMsg += " - FINISH - " + (DateTime.Now - dtTmr).ToString(); if (machineName == null) { AppLib.WriteLogOrderDetails(sLogMsg); } else { AppLib.WriteLogClientAction(machineName, sLogMsg); } // различные действия после успешного изменения статуса заказа if (retVal) { // создание файла для Одермана (feature enable, ready status is terminal) if (OrdermanNotifier.IsEnable && IsReadyStatusFinal()) { OrdermanNotifier omanNotifier = new OrdermanNotifier(this); bool result = omanNotifier.CreateNoticeFileForOrder(); } } return(retVal); } // method
// *** CONSTRUCTOR *** public OrderModel(Order dbOrder) { Id = dbOrder.Id; Uid = dbOrder.UID; Number = dbOrder.Number; TableName = dbOrder.TableNumber; CreateDate = dbOrder.CreateDate; HallName = dbOrder.RoomNumber; Waiter = dbOrder.Waiter; DivisionColorRGB = dbOrder.DivisionColorRGB; OrderStatusId = dbOrder.OrderStatusId; Status = (OrderStatusEnum)dbOrder.OrderStatusId; //AppLib.GetStatusEnumFromNullableInt(dbOrder.OrderStatusId); _isUseReadyConfirmed = AppProperties.GetBoolProperty("UseReadyConfirmedState"); _dishesDict = new Dictionary <int, OrderDishModel>(); // получить отсоединенную RunTime запись из таблицы состояний _dbRunTimeRecord = getOrderRunTimeRecord(dbOrder.Id); // создать словарь накопительных счетчиков _tsTimersDict = new Dictionary <OrderStatusEnum, TimeCounter>(); // таймер времени приготовления _tsTimersDict.Add(OrderStatusEnum.Cooking, new TimeCounter() { Name = OrderStatusEnum.Cooking.ToString() }); // таймер времени ожидания выдачи, нахождение в состоянии Готов _tsTimersDict.Add(OrderStatusEnum.Ready, new TimeCounter() { Name = OrderStatusEnum.Ready.ToString() }); if (_isUseReadyConfirmed) { _tsTimersDict.Add(OrderStatusEnum.ReadyConfirmed, new TimeCounter() { Name = OrderStatusEnum.ReadyConfirmed.ToString() }); } // таймер времени ожидания фиксации заказа, нахождение в состоянии Выдано _tsTimersDict.Add(OrderStatusEnum.Took, new TimeCounter() { Name = OrderStatusEnum.Took.ToString() }); // таймер нахождения в состоянии отмены _tsTimersDict.Add(OrderStatusEnum.Cancelled, new TimeCounter() { Name = OrderStatusEnum.Cancelled.ToString() }); // для нового объекта статус по умолчанию - В ПРОЦЕССЕ ГОТОВКИ if (this.OrderStatusId < 1) { OrderStatusEnum newStatus = OrderStatusEnum.Cooking; UpdateStatus(newStatus, false); } else { // обновить статус заказа по статусам всех блюд OrderStatusEnum eStatusAllDishes = AppLib.GetStatusAllDishes(dbOrder.Dishes); if ((eStatusAllDishes != OrderStatusEnum.None) && (this.Status != eStatusAllDishes) && ((int)this.Status < (int)eStatusAllDishes)) { UpdateStatus(eStatusAllDishes, false); } } StatusDTS statusDTS = getStatusRunTimeDTS(this.Status); DateTime dtEnterState = statusDTS.DateEntered; if (dtEnterState.IsZero()) { dtEnterState = DateTime.Now; setStatusRunTimeDTS(this.Status, dtEnterState, -1); saveRunTimeRecord(); statusDTS = getStatusRunTimeDTS(this.Status); } startStatusTimer(statusDTS); // добавить блюда к заказу // расставить сначала блюдо, потом его ингредиенты, т.к. ингр.могут идти ПЕРЕД блюдом List <OrderDish> dishParentList = dbOrder.Dishes.Where(d => d.ParentUid.IsNull()).ToList(); Dictionary <int, OrderDish> dAll = new Dictionary <int, OrderDish>(); foreach (OrderDish dishParent in dishParentList) { if (dAll.ContainsKey(dishParent.Id) == false) { dAll.Add(dishParent.Id, dishParent); // отобрать ингредиенты List <OrderDish> ingrList = dbOrder.Dishes.Where(ingr => (ingr.ParentUid == dishParent.UID) && (ingr.Id != dishParent.Id)).ToList(); foreach (OrderDish ingr in ingrList) { if (dAll.ContainsKey(ingr.Id) == false) { dAll.Add(ingr.Id, ingr); } } } } foreach (OrderDish dbDish in dAll.Values) // dbOrder.OrderDish { if (this._dishesDict.ContainsKey(dbDish.Id) == false) { OrderDishModel newDish = new OrderDishModel(dbDish, this); this._dishesDict.Add(newDish.Id, newDish); } } } // ctor
public override bool Equals(object obj) { StatusDTS obj2 = (StatusDTS)obj; return(DateEntered.Equals(obj2.DateEntered) && TimeStanding.Equals(obj2.TimeStanding)); }
} // method // ****************************************** // ОСНОВНАЯ ПРОЦЕДУРА БИЗНЕС-ЛОГИКИ // ПРИ ИЗМЕНЕНИИ СТАТУСА БЛЮДА или НЕЗАВИСИМОГО ИНГРЕДИЕНТА // ****************************************** // команды на изменение статуса блюда могут приходить как от КДС, так и из FrontOffice (при чтении из БД) // состояния и даты сохраняются в БД при каждом изменении // isUpdateParentOrder = true, если запрос на изменение состояния пришел от КДС, иначе запрос из внутренней логики, напр. автоматическое изменение статуса из ожидания в готовку public bool UpdateStatus(OrderStatusEnum newStatus, DateTime dtEnterState = default(DateTime), int preStateTS = 0, string machineName = null) { // если статус не поменялся для существующей записи, то ничего не делать if (this.Status == newStatus) { return(false); } // автоматический переход из Готово в ПодтвГотово: вход в режим отслеживания нахождения в состоянии Готов if ((_isUseReadyConfirmed == true) && (_autoGotoReadyConfirmPeriod > 0) && (newStatus == OrderStatusEnum.Ready) && (this.Status != OrderStatusEnum.Ready)) { _dtReadyStatusInput = DateTime.Now; } string sLogMsg = string.Format(" - DISH.UpdateStatus() Id {0}/{1}, from {2} to {3}", this.Id, this.Name, this.Status.ToString(), newStatus.ToString()); DateTime dtTmr = DateTime.Now; if (machineName == null) { AppLib.WriteLogOrderDetails(sLogMsg + " - START"); } else { AppLib.WriteLogClientAction(machineName, sLogMsg + " - START"); } bool isUpdSuccess = false; // здесь тоже лочить, т.к. вызовы могут быть как циклческие (ингр.для блюд), так и из заказа / КДС-а lock (this) { // время нахождения в ПРЕДЫДУЩЕМ состоянии, в секундах int secondsInPrevState = 0; if (_curTimer != null) // если есть таймер предыдущего состояния { _curTimer.Stop(); // остановить таймер состояния // получить время нахождения в состоянии с момента последнего входа secondsInPrevState = _curTimer.IncrementTS; // Debug.Print("secondsInPrevState {0}", secondsInPrevState); } if (preStateTS != 0) { secondsInPrevState = preStateTS; } // дата входа в новое состояние: или то, что передано, или текущую DateTime dtEnterToNewStatus = DateTime.Now; // если переданы данные из родительского объекта (заказ или блюдо для ингредиентов) if (!dtEnterState.IsZero()) { dtEnterToNewStatus = dtEnterState; } // сохранить новый статус ОБЪЕКТА в БД if (saveStatusToDB(newStatus, machineName)) { // изменить статус в ОБЪЕКТЕ OrderStatusEnum preStatus = this.Status; this.Status = newStatus; this.DishStatusId = (int)newStatus; // **** запись или в RunTimeRecord или в ReturnTable StatusDTS statusDTS = getStatusRunTimeDTS(this.Status); if (statusDTS.DateEntered.IsZero()) { // сохраняем дату входа в новое состояние setStatusRunTimeDTS(this.Status, dtEnterToNewStatus, -1); // сохраняем в записи RunTimeRecord время нахождения в предыдущем состоянии setStatusRunTimeDTS(preStatus, DateTime.MinValue, secondsInPrevState); saveRunTimeRecord(); } // возврат в предыдущие состояния, создать новую запись в Return table else { saveReturnTimeRecord(preStatus, newStatus, dtEnterToNewStatus, secondsInPrevState); // при возврате из Ready в Cooking обнулять в RunTime-record дату входа в состояние Ready // чтобы при следующем входе в Ready таймер ожидания выноса начал считаться с периода ExpectedTake if (!_isUseReadyConfirmed && (preStatus == OrderStatusEnum.Ready) && (newStatus == OrderStatusEnum.Cooking)) { _dbRunTimeRecord.ReadyDate = DateTime.MinValue; } if (_isUseReadyConfirmed && (preStatus == OrderStatusEnum.ReadyConfirmed) && ((newStatus == OrderStatusEnum.Cooking) || (newStatus == OrderStatusEnum.Ready))) { _dbRunTimeRecord.ReadyConfirmedDate = DateTime.MinValue; } } // запуск таймера для нового состояния statusDTS = getStatusRunTimeDTS(this.Status); startStatusTimer(statusDTS); // попытка обновить статус ЗАКАЗА проверкой состояний всех блюд/ингредиентов _modelOrder.UpdateStatusByVerificationDishes(); isUpdSuccess = true; } } sLogMsg += " - FINISH - " + (DateTime.Now - dtTmr).ToString(); if (machineName == null) { AppLib.WriteLogOrderDetails(sLogMsg); } else { AppLib.WriteLogClientAction(machineName, sLogMsg); } return(isUpdSuccess); } // method UpdateStatus