From 15d84485dd809abe8e76c32dd8d60470ce14f5ba Mon Sep 17 00:00:00 2001 From: Mikhail Trubnikov Date: Thu, 16 Nov 2023 14:24:22 +1000 Subject: [PATCH] =?UTF-8?q?feat(master):=20=D0=BE=D0=B1=D0=BD=D0=BE=D0=B2?= =?UTF-8?q?=D0=BB=D0=B5=D0=BD=D0=B0=20=D0=BB=D0=BE=D0=B3=D0=B8=D0=BA=D0=B0?= =?UTF-8?q?=20=D1=81=D1=82=D0=B0=D1=82=D1=83=D1=81=D0=BE=D0=B2=20=D0=BD?= =?UTF-8?q?=D0=B0=D1=80=D1=8F=D0=B4=D0=BE=D0=B2,=20=D0=BF=D1=80=D0=B8?= =?UTF-8?q?=D1=81=D0=B2=D0=BE=D1=8F=D0=B5=D0=BD=D0=B8=D1=8F=20=D0=B7=D0=BD?= =?UTF-8?q?=D0=B0=D1=87=D0=B5=D0=BD=D0=B8=D0=B9=20=D0=B6=D1=83=D1=80=D0=BD?= =?UTF-8?q?=D0=B0=D0=BB=D0=B0=20=D0=B0=D0=B3=D0=B5=D0=BD=D1=82=D0=B0.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- PARR.DAL/Models/ApplicationsInWork.cs | 25 ++++++- .../Services/OrderItemService.cs | 32 +++++---- PARR.Master/Services/OrderMasterService.cs | 71 ++++++++++++++----- 3 files changed, 96 insertions(+), 32 deletions(-) diff --git a/PARR.DAL/Models/ApplicationsInWork.cs b/PARR.DAL/Models/ApplicationsInWork.cs index 0ccbc4d2..2796cd7d 100644 --- a/PARR.DAL/Models/ApplicationsInWork.cs +++ b/PARR.DAL/Models/ApplicationsInWork.cs @@ -1,5 +1,4 @@ using Microsoft.EntityFrameworkCore; -using PARR.DAL.Contracts; using PARR.DAL.Models.Base; using PARR.DAL.Settings; using System.ComponentModel.DataAnnotations; @@ -22,8 +21,32 @@ namespace PARR.DAL.Models public Guid ApplicationId { get; set; } + /// + /// TemplateDuration в формате ЕСПП + /// public required string TemplateDuration { get; set; } + /// + /// TemplateDuration в формате TimeSpan + /// + public TimeSpan? TemplateDurationTimeSpan + { + get + { + try + { + //ЕСПП кривоногие, они почему-то таймспан пишут так "7 00:00:00", а правильно так: "7:00:00:00" + var durationWithTimeSpanFormat = TemplateDuration.Replace(" ", ":"); + + return TimeSpan.Parse(durationWithTimeSpanFormat); + } + catch + { + return null; + } + } + } + public required string ShortDescription { get; set; } //public required string FullDescription { get; set; } diff --git a/PARR.EsppOrderLoader/Services/OrderItemService.cs b/PARR.EsppOrderLoader/Services/OrderItemService.cs index dd9adb9b..85a4d9aa 100644 --- a/PARR.EsppOrderLoader/Services/OrderItemService.cs +++ b/PARR.EsppOrderLoader/Services/OrderItemService.cs @@ -53,7 +53,7 @@ namespace PARR.EsppOrderLoader.Services StatusCode = (int)orderStatusService.GetOrderStatusByName(esppOrder.Status), GenerateDate = template == null ? null - : CalcGenerationDate(esppOrder.ExpirationDateUTC, template.ApplicationsInWork!.TemplateDuration) + : CalcGenerationDate(esppOrder.ExpirationDateUTC, template.ApplicationsInWork!.TemplateDurationTimeSpan) }; if (!await orderService.CreateAsync(newOrder) || !await orderService.CommitAsync()) @@ -63,23 +63,29 @@ namespace PARR.EsppOrderLoader.Services } - private DateTimeOffset? CalcGenerationDate(DateTimeOffset expirationDateUTC, string templateDuration) + private DateTimeOffset? CalcGenerationDate(DateTimeOffset expirationDateUTC, TimeSpan? templateDuration) { - TimeSpan duration; + //TimeSpan duration; - try + //try + //{ + // //ЕСПП кривоногие, они почему-то таймспан пишут так "7 00:00:00", а правильно так: "7:00:00:00" + // var durationWithTimeSpanFormat = templateDuration.Replace(" ", ":"); + // duration = TimeSpan.Parse(durationWithTimeSpanFormat); + //} + //catch (Exception e) + //{ + // logger.LogError(e, $"Ошибка при конвертации templateDuration в TimeSpan, исходное значение: {templateDuration}"); + // return null; + //} + + if (templateDuration.HasValue) + return expirationDateUTC.Add(-templateDuration.Value); + else { - //ЕСПП кривоногие, они почему-то таймспан пишут так "7 00:00:00", а правильно так: "7:00:00:00" - var durationWithTimeSpanFormat = templateDuration.Replace(" ", ":"); - duration = TimeSpan.Parse(durationWithTimeSpanFormat); - } - catch (Exception e) - { - logger.LogError(e, $"Ошибка при конвертации templateDuration в TimeSpan, исходное значение: {templateDuration}"); + logger.LogError($"templateDuration = null."); return null; } - - return expirationDateUTC.Add(-duration); } } diff --git a/PARR.Master/Services/OrderMasterService.cs b/PARR.Master/Services/OrderMasterService.cs index db6991bf..94f78d48 100644 --- a/PARR.Master/Services/OrderMasterService.cs +++ b/PARR.Master/Services/OrderMasterService.cs @@ -40,15 +40,18 @@ namespace PARR.Master.Services public async Task ManageOrdersAsync() { + // логика работы описана в документации проекта + logger.LogInformation($"--- Начало поиска нарядов ---"); - //ищем наряды в статусе 1 и 2, присваиваем им историю работы агента, меняем стаус наряда + //ищем наряды в статусе 1 и 2 var ordersToManage = await GetOrdersNewOrWorkStatusesAsync(); logger.LogInformation($"Ищу наряды со статусом 1 и 2. Найдено нарядов: {ordersToManage.Count()} шт."); foreach (var order in ordersToManage) { + //присваиваем им историю работы агента, меняем стаус наряда logger.LogInformation($"Найден наряд id: {order.Id}, {order.Number}"); await SetHistoryAndUpdateOrderStatus(order); } @@ -84,56 +87,87 @@ namespace PARR.Master.Services /// private async Task SetHistoryAndUpdateOrderStatus(Order order) { - //TODO: тут тот таймаут? или надо TemplateDuration var agentHistory = await agentHistoryService.Get() .Where(t => t.TemplateId == order.TemplateId && t.DateCreated > order.GenerateDate!.Value.Add(-orderManageSettings.FindAgentHistoryStartOffset) - && t.DateCreated <= order.GenerateDate!.Value.AddSeconds(order.Template!.ApplicationsInWork!.AgentTimeOutSec!.Value) + //&& t.DateCreated <= order.GenerateDate!.Value.AddSeconds(order.Template!.ApplicationsInWork!.AgentTimeOutSec!.Value) + && t.DateCreated <= order.GenerateDate!.Value.Add(order.Template!.ApplicationsInWork!.TemplateDurationTimeSpan!.Value) && t.OrderId == null ) + .OrderBy(t => t.DateCreated) .ToListAsync(); - logger.LogInformation($"Для наряда {order.Id}, {order.Number} надено новых историй агентов: {agentHistory.Count()} шт. Присваиваю истории ИД наряда."); + logger.LogInformation($"Для наряда {order.Id}, {order.Number} найдено новых историй агентов: {agentHistory.Count()} шт."); foreach (var historyItem in agentHistory) + { historyItem.OrderId = order.Id; + logger.LogDebug($"Для наряда {order.Id}, {order.Number} добавил истрию агента {historyItem.Id}, {historyItem.HistoryLevelId}"); + + // если статус агента = завершил работу. то историю после завешения, не записываем, это возможно относится к другому наряду, или нам уже пофиг на неё + if (historyItem.HistoryLevelId == (int)AgentHistoryLevelEnum.End) + { + logger.LogDebug($"Для наряда {order.Id}, {order.Number} прекращаю добавлять историю агента, так как добавлена запись со статусом Стоп"); + continue; + } + } + + //отбрасываем все записи которые не добавлены этому наряду + agentHistory = agentHistory.Where(t => t.OrderId.HasValue).ToList(); + + // совмещенный список истории агента по этому наряду + var allHistory = agentHistory; + order.AgentHistories.ToList().ForEach(item => allHistory.Add(item)); + allHistory = allHistory.OrderBy(t => t.DateCreated).ToList(); + // смотрим историю агента, и тут же меняем статус наряда //1 Ищем статус "Агент начал выполнять задание" - var isAgentStarted = agentHistory.Any(t => t.HistoryLevelId == (int)AgentHistoryLevelEnum.Start) || order.AgentHistories.Any(t => t.HistoryLevelId == (int)AgentHistoryLevelEnum.Start); + var isAgentStarted = allHistory.Any(t => t.HistoryLevelId == (int)AgentHistoryLevelEnum.Start); //2 Ищем статус "Агент завершил выполнение задания" - var isAgentEnded = agentHistory.Any(t => t.HistoryLevelId == (int)AgentHistoryLevelEnum.End) || order.AgentHistories.Any(t => t.HistoryLevelId == (int)AgentHistoryLevelEnum.End); + var isAgentEnded = allHistory.Any(t => t.HistoryLevelId == (int)AgentHistoryLevelEnum.End); if (isAgentEnded) { order.NextStatusCode = (int)OrderStatusEnum.Complete; - logger.LogInformation($"Для наряда {order.Id}, {order.Number} меню статус на {OrderStatusEnum.Complete}"); + logger.LogInformation($"Для наряда {order.Id}, {order.Number} меняю статус на {OrderStatusEnum.Complete}"); } if (isAgentStarted && !isAgentEnded && order.StatusCode == (int)OrderStatusEnum.New) { order.NextStatusCode = (int)OrderStatusEnum.InWork; - logger.LogInformation($"Для наряда {order.Id}, {order.Number} меню статус на {OrderStatusEnum.InWork}"); + logger.LogInformation($"Для наряда {order.Id}, {order.Number} меняю статус на {OrderStatusEnum.InWork}"); } - //TODO: тут подумать про таймаут, по какому таймауту закрывтаь наряд? по таймауту агента, или по TemplateDuration? - //timeout - //if(isAgentStarted==false && isAgentEnded == false && ) - //{ - // // ставим Выполнен, так как превысил таймаут - // order.NextStatusCode = (int)OrderStatusEnum.Complete; - // logger.LogInformation($"Для наряда {order.Id}, {order.Number} меню статус на {OrderStatusEnum.Complete}"); - //} + //закрываем по таймауту. Если есть начало, и нет завершения по АгентТаймаут, то закрываем наряд. + if (isAgentStarted == true && isAgentEnded == false) + { + var lastStrartDate = allHistory.Last(t => t.HistoryLevelId == (int)AgentHistoryLevelEnum.Start).DateCreated; + var timeout = (double)order.Template!.ApplicationsInWork!.AgentTimeOutSec!; + + if (lastStrartDate.AddSeconds(timeout) <= DateTimeOffset.UtcNow) + { + order.NextStatusCode = (int)OrderStatusEnum.Complete; + logger.LogInformation($"Для наряда {order.Id}, {order.Number} меняю статус на {OrderStatusEnum.Complete}, закрываю наряд по таймауту ожидания агента. Время старта агента: {lastStrartDate}, допустимый timeOut: {timeout} сек."); + } + else + { + logger.LogDebug($"Для наряда {order.Id}, {order.Number} оставляю статус прежним, ожидаю завершение работы агента. Время старта агента: {lastStrartDate}, допустимый timeOut: {timeout} сек."); + } + + } + + //TODO: тут можно подумать, и закрывать наряды, у которых нет истории агента. сейчас мы такие наряды пропускаем, их будет закрывать руками админ. if (!await orderService.CommitAsync()) { logger.LogError($"Ошибка при сохранении НАРЯДА, id: {order.Id}"); } - logger.LogInformation($"Закончил работу с нарядом {order.Id}, {order.Number}"); + logger.LogInformation($"Закончил работу с нарядом {order.Id}, {order.Number}"); } @@ -173,7 +207,8 @@ namespace PARR.Master.Services && t.Template!.ApplicationsInWork!.IsAgent == true && t.GenerateDate.HasValue && t.Template!.ApplicationsInWork!.AgentTimeOutSec.HasValue - ); + && string.IsNullOrEmpty(t.Template!.ApplicationsInWork!.TemplateDuration) == false + ).OrderBy(t => t.DateCreated); } } }