using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Logging; using PARR.BLL.Domain.Mq; using PARR.BLL.Services.Interfaces; using PARR.DAL.Contracts; using PARR.DAL.Models; using PARR.DAL.Services.Interfaces; using PARR.Master.Settings; using System.Text.Json; namespace PARR.Master.Services { internal class OrderMasterService : IOrderMasterService { private readonly ILogger logger; private readonly IOrderService orderService; private readonly IAgentHistoryService agentHistoryService; private readonly OrderManageSettings orderManageSettings; private readonly MqSettings mqSettings; private readonly IMqService mqService; public OrderMasterService( ILogger logger, IOrderService orderService, IAgentHistoryService agentHistoryService, OrderManageSettings orderManageSettings, MqSettings mqSettings, IMqService mqService ) { this.logger = logger; this.orderService = orderService; this.agentHistoryService = agentHistoryService; this.orderManageSettings = orderManageSettings; this.mqSettings = mqSettings; this.mqService = mqService; } public async Task ManageOrdersAsync() { logger.LogInformation($"--- Начало поиска нарядов ---"); //ищем наряды в статусе 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); } //находим наряды где статусы не равны, добавляем их в Rabbit var ordersWithStatusNotEqual = await GetOrdresWithStatusCodeNotEqualAsync(); var objs = ordersWithStatusNotEqual.Select(t => JsonSerializer.Serialize(new OrderManageMq { OrderId = t.Id })); logger.LogInformation($"Ищу наряды где статусы не равны. Найдено нарядов: {ordersWithStatusNotEqual.Count()}. Добавляю их в RabbitMQ."); if (objs.Any()) { var sendResult = mqService.Send(mqSettings, objs.ToArray()); if (sendResult.IsSuccess) { logger.LogInformation($"Наряды переданы в RabbitMQ: {objs.Count()}"); logger.LogDebug($"Список нардов переданных в RabbitMQ: {string.Join(", ", objs)}"); } else logger.LogError($"Ошибка при передаче нарядов в Rabbit, неперадынные сообщения: {string.Join(", ", sendResult!.NotSendMessages)}"); } logger.LogInformation($"=== Конец работы с нарядами=== "); } /// /// Находит наряды в статусе 1 и 2, присваивает им историю работы агента, меняет стаус наряда /// /// /// 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.OrderId == null ) .ToListAsync(); logger.LogInformation($"Для наряда {order.Id}, {order.Number} надено новых историй агентов: {agentHistory.Count()} шт. Присваиваю истории ИД наряда."); foreach (var historyItem in agentHistory) historyItem.OrderId = order.Id; // смотрим историю агента, и тут же меняем статус наряда //1 Ищем статус "Агент начал выполнять задание" var isAgentStarted = agentHistory.Any(t => t.HistoryLevelId == (int)AgentHistoryLevelEnum.Start) || order.AgentHistories.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); if (isAgentEnded) { order.NextStatusCode = (int)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}"); } //TODO: тут подумать про таймаут, по какому таймауту закрывтаь наряд? по таймауту агента, или по TemplateDuration? //timeout //if(isAgentStarted==false && isAgentEnded == false && ) //{ // // ставим Выполнен, так как превысил таймаут // order.NextStatusCode = (int)OrderStatusEnum.Complete; // logger.LogInformation($"Для наряда {order.Id}, {order.Number} меню статус на {OrderStatusEnum.Complete}"); //} if (!await orderService.CommitAsync()) { logger.LogError($"Ошибка при сохранении НАРЯДА, id: {order.Id}"); } logger.LogInformation($"Закончил работу с нарядом {order.Id}, {order.Number}"); } /// /// Получить список нарядов, со статусами 1 или 2 /// private async Task> GetOrdersNewOrWorkStatusesAsync() { return await GetOrdres() .Where(t => t.StatusCode == (int)OrderStatusEnum.New || t.StatusCode == (int)OrderStatusEnum.InWork) .ToListAsync(); } /// /// Получить список нарядов, у которых StatusCode!=NextStatusCode /// private async Task> GetOrdresWithStatusCodeNotEqualAsync() { return await GetOrdres() .Where(t => t.NextStatusCode.HasValue && t.NextStatusCode.Value != t.StatusCode) .ToListAsync(); } /// /// Основной запрос на получения списка нарядов со связями, по базовому условию /// /// private IQueryable GetOrdres() { return orderService.Get() .Include(t => t.Template).ThenInclude(t => t!.ApplicationsInWork) .Include(t => t.AgentHistories) .Where(t => t.TemplateId.HasValue && t.Template!.ApplicationsInWork!.IsAgent == true && t.GenerateDate.HasValue && t.Template!.ApplicationsInWork!.AgentTimeOutSec.HasValue ); } } }