using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.DependencyInjection; 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.EsppOrderManager.Services; using PARR.EsppOrderManager.Settings; namespace PARR.EsppOrderManager { internal class EsppOrderManager : IEsppOrderManager { private readonly MqSettings mqSettings; private readonly IMqService mqService; private readonly ILogger logger; private readonly ITransformService transformService; private readonly IEsppOrderService esppOrderService; private readonly IServiceProvider serviceProvider; public EsppOrderManager( MqSettings mqSettings, IMqService mqService, ILogger logger, ITransformService transformService, IEsppOrderService esppOrderService, IServiceProvider serviceProvider ) { this.mqSettings = mqSettings; this.mqService = mqService; this.logger = logger; this.transformService = transformService; this.esppOrderService = esppOrderService; this.serviceProvider = serviceProvider; } public async void Start() { // логика работы описана в документации //var isConnected = mqService.InitConsumer(mqSettings, ManageOrderAsync); //if (!isConnected) // throw new Exception("Ошибка при подключении к RabbitMq"); //test, and remove async in method name await ManageOrderAsync("{\"OrderId\":\"77eeccfb-4ca0-443e-8cc7-f6aa9dc774b7\"}"); } public void Stop() { mqService.Dispose(); } private async Task ManageOrderAsync(string msg) { logger.LogDebug($"Получили сообщение: {msg}"); var objFromQuery = transformService.GetModelFromJson(msg); if (objFromQuery == null) return; using (var scope = serviceProvider.CreateScope()) { var orderService = scope.ServiceProvider.GetService(); if (orderService == null) throw new Exception("Не смог получить серивс IOrderService, scope.ServiceProvider.GetService()"); await ManageOrderToScopeAsync(orderService, objFromQuery); } logger.LogDebug($"Закончил работу с сообщением: {msg}"); } private async Task ManageOrderToScopeAsync(IOrderService orderService, OrderManageMq objFromQuery) { var order = await orderService.Get() .Include(t => t.AgentHistories).ThenInclude(t => t.AgentHistoryLevel) .Include(t => t.OrderStatus) .Include(t => t.NextStatus) .Include(t => t.Template).ThenInclude(t => t!.ApplicationsInWork).ThenInclude(t => t!.Work).ThenInclude(t => t!.Tnk) .FirstOrDefaultAsync(t => t.Id == objFromQuery.OrderId); if (!IsValidOrder(ref order, ref objFromQuery)) return; logger.LogDebug($"Найден наряд в БД: {order!.Number}"); var resultMsg = GenerateResultMsg(order!); var workDuration = CalcWorkDuration(order!); // Изменям статус наряда в ЕСПП var result = await esppOrderService.ChangeOrderToEsppAsync(order!, resultMsg, workDuration); if (result) { logger.LogInformation($"Статусы наряда {order!.Number} в ЕСПП обновлены. Установлен статус: {order.NextStatus!.Description}"); //обновляем статусы в БД order.StatusCode = order.NextStatusCode!.Value; if (!await orderService.CommitAsync()) { logger.LogError($"Ошибка при обновлении статуса в БД у наряда: {order.Number}. Не установлен статус {order.NextStatus!.Description}"); } } else logger.LogError($"Ошибка при обновлении статуса наряда {order!.Number}. Статус не изменен."); } private bool IsValidOrder(ref Order? order, ref OrderManageMq query) { if (order == null) { logger.LogError($"Не найден наряд с OrderId: {query.OrderId}"); return false; } if (order.StatusCode == order.NextStatusCode) { logger.LogInformation($"У наряда {order.Id}, {order.Number} статусы равны, ничего не делаем. Статус: {order.OrderStatus!.Description}"); return false; } if (!order.NextStatusCode.HasValue) { logger.LogWarning($"У наряда {order.Id}, {order.Number} не установлено поле {nameof(order.NextStatusCode)}"); return false; } return true; } /// /// Генерирует текст поля Решение, в зависимости от статуса наряда и от истории Агента /// /// /// private string GenerateResultMsg(Order order) { var agentHistory = order.AgentHistories .OrderBy(t => t.DateCreated) .Select(t => $"{t.DateCreated} :: {t.AgentHistoryLevel?.Name} :: {t.Message}"); var baseMsg = order.Template!.ApplicationsInWork!.Solution + "\r\n"; var msgAgent = "Работы выполнены средствами автоматизации. \r\n" + "Журнал работы: \r\n" + $"{string.Join("\r\n", agentHistory)}"; var msgAgentEmpty = "Работы должны были выполняться средствами автоматизации. " + "От средств автоматизации не поступило сообщений. " + "Работы не выполнены."; return baseMsg + (agentHistory.Any() ? msgAgent : msgAgentEmpty); } /// /// Рассчиать трудозатраты /// /// /// private TimeSpan CalcWorkDuration(Order order) { var agentHistory = order.AgentHistories .OrderBy(t => t.DateCreated); if (!agentHistory.Any()) return GetTnkDurationByScriptDuration(TimeSpan.Zero); var dateStart = agentHistory.LastOrDefault(t => t.HistoryLevelId == (int)AgentHistoryLevelEnum.Start)?.DateCreated; var dateEnd = agentHistory.LastOrDefault(t => t.HistoryLevelId == (int)AgentHistoryLevelEnum.End)?.DateCreated; if (dateStart.HasValue && dateEnd.HasValue) { var duration = dateEnd.Value - dateStart.Value; logger.LogDebug($"Продолжительность работы скрипта: {duration}"); return GetTnkDurationByScriptDuration(duration); } return GetTnkDurationByScriptDuration(TimeSpan.Zero); } /// /// Получить время для списания ТНК по времени работы скрипта /// /// /// private TimeSpan GetTnkDurationByScriptDuration(TimeSpan scriptDuration) { // минимальное значение 1 минута var minDuration = new TimeSpan(0, 1, 0); if (scriptDuration < minDuration) { logger.LogDebug($"Продолжительность меньше минимального, беру минимальное: {minDuration}. {scriptDuration}<{minDuration}"); return minDuration; } else return scriptDuration; } } }