2023-11-17 16:03:36 +10:00
|
|
|
|
using Microsoft.EntityFrameworkCore;
|
2023-11-20 16:59:58 +10:00
|
|
|
|
using Microsoft.Extensions.DependencyInjection;
|
2023-11-17 16:03:36 +10:00
|
|
|
|
using Microsoft.Extensions.Logging;
|
2026-04-14 16:27:27 +10:00
|
|
|
|
using PARR.Core.Common.Interfaces;
|
|
|
|
|
|
using PARR.Core.Common.Interfaces.RabbitServices;
|
2026-04-30 10:35:31 +10:00
|
|
|
|
using PARR.Core.Repositories.Interfaces;
|
2026-04-14 12:01:49 +10:00
|
|
|
|
using PARR.Domain.Common.Rabbit.Messages;
|
2026-04-30 10:35:31 +10:00
|
|
|
|
using PARR.Domain.Entities;
|
2026-04-13 16:58:30 +10:00
|
|
|
|
using PARR.Domain.Enums;
|
2023-11-20 12:26:33 +10:00
|
|
|
|
using PARR.EsppOrderManager.Services;
|
2023-10-24 11:29:55 +10:00
|
|
|
|
using PARR.EsppOrderManager.Settings;
|
|
|
|
|
|
|
|
|
|
|
|
namespace PARR.EsppOrderManager
|
|
|
|
|
|
{
|
|
|
|
|
|
internal class EsppOrderManager : IEsppOrderManager
|
|
|
|
|
|
{
|
|
|
|
|
|
private readonly MqSettings mqSettings;
|
2026-04-14 12:01:49 +10:00
|
|
|
|
private readonly IRabbitService mqService;
|
2023-10-24 11:29:55 +10:00
|
|
|
|
private readonly ILogger<EsppOrderManager> logger;
|
2023-11-17 16:03:36 +10:00
|
|
|
|
private readonly ITransformService transformService;
|
2023-11-20 12:26:33 +10:00
|
|
|
|
private readonly IEsppOrderService esppOrderService;
|
2023-11-20 16:59:58 +10:00
|
|
|
|
private readonly IServiceProvider serviceProvider;
|
2023-11-21 14:37:41 +10:00
|
|
|
|
private readonly ResultTemplateSettings resultTemplateSettings;
|
2023-10-24 11:29:55 +10:00
|
|
|
|
|
|
|
|
|
|
public EsppOrderManager(
|
|
|
|
|
|
MqSettings mqSettings,
|
2026-04-14 12:01:49 +10:00
|
|
|
|
IRabbitService mqService,
|
2023-11-17 16:03:36 +10:00
|
|
|
|
ILogger<EsppOrderManager> logger,
|
|
|
|
|
|
ITransformService transformService,
|
2023-11-20 16:59:58 +10:00
|
|
|
|
IEsppOrderService esppOrderService,
|
2023-11-21 14:37:41 +10:00
|
|
|
|
IServiceProvider serviceProvider,
|
|
|
|
|
|
ResultTemplateSettings resultTemplateSettings
|
2023-10-24 11:29:55 +10:00
|
|
|
|
)
|
|
|
|
|
|
{
|
|
|
|
|
|
this.mqSettings = mqSettings;
|
|
|
|
|
|
this.mqService = mqService;
|
|
|
|
|
|
this.logger = logger;
|
2023-11-17 16:03:36 +10:00
|
|
|
|
this.transformService = transformService;
|
2023-11-20 12:26:33 +10:00
|
|
|
|
this.esppOrderService = esppOrderService;
|
2023-11-20 16:59:58 +10:00
|
|
|
|
this.serviceProvider = serviceProvider;
|
2023-11-21 14:37:41 +10:00
|
|
|
|
this.resultTemplateSettings = resultTemplateSettings;
|
2023-10-24 11:29:55 +10:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-08-20 14:10:22 +10:00
|
|
|
|
public async Task StartAsync()
|
2023-10-24 11:29:55 +10:00
|
|
|
|
{
|
2023-11-17 16:03:36 +10:00
|
|
|
|
// логика работы описана в документации
|
2023-10-24 11:29:55 +10:00
|
|
|
|
|
2025-08-20 14:10:22 +10:00
|
|
|
|
var isConnected = await mqService.InitConsumerAsync(mqSettings, ManageOrderAsync);
|
2023-11-17 16:03:36 +10:00
|
|
|
|
|
2023-11-21 14:37:41 +10:00
|
|
|
|
if (!isConnected)
|
|
|
|
|
|
throw new Exception("Ошибка при подключении к RabbitMq");
|
2023-11-17 16:03:36 +10:00
|
|
|
|
|
|
|
|
|
|
//test, and remove async in method name
|
2023-11-21 14:37:41 +10:00
|
|
|
|
//await ManageOrderAsync("{\"OrderId\":\"49191af5-c313-4388-9720-a61fd13f15a8\"}");
|
2023-10-24 11:29:55 +10:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-08-20 14:10:22 +10:00
|
|
|
|
public async Task StopAsync()
|
2023-10-24 11:29:55 +10:00
|
|
|
|
{
|
2025-08-20 14:10:22 +10:00
|
|
|
|
await mqService.DisposeAsync();
|
2023-10-24 11:29:55 +10:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2023-11-20 16:59:58 +10:00
|
|
|
|
private async Task ManageOrderAsync(string msg)
|
2023-10-24 11:29:55 +10:00
|
|
|
|
{
|
2023-11-21 14:37:41 +10:00
|
|
|
|
//logger.LogDebug($"Получили сообщение: {msg}");
|
2023-10-24 11:29:55 +10:00
|
|
|
|
|
2023-11-20 16:59:58 +10:00
|
|
|
|
var objFromQuery = transformService.GetModelFromJson<OrderManageMq>(msg);
|
|
|
|
|
|
if (objFromQuery == null)
|
2023-11-17 16:03:36 +10:00
|
|
|
|
return;
|
|
|
|
|
|
|
2023-11-20 16:59:58 +10:00
|
|
|
|
using (var scope = serviceProvider.CreateScope())
|
2023-11-17 16:03:36 +10:00
|
|
|
|
{
|
2026-04-30 10:35:31 +10:00
|
|
|
|
var orderService = scope.ServiceProvider.GetService<IOrderRepository>();
|
2023-11-20 16:59:58 +10:00
|
|
|
|
if (orderService == null)
|
|
|
|
|
|
throw new Exception("Не смог получить серивс IOrderService, scope.ServiceProvider.GetService<IOrderService>()");
|
2023-11-17 16:03:36 +10:00
|
|
|
|
|
2023-11-20 16:59:58 +10:00
|
|
|
|
await ManageOrderToScopeAsync(orderService, objFromQuery);
|
2023-11-17 16:03:36 +10:00
|
|
|
|
}
|
|
|
|
|
|
|
2023-11-20 16:59:58 +10:00
|
|
|
|
logger.LogDebug($"Закончил работу с сообщением: {msg}");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2026-04-30 10:35:31 +10:00
|
|
|
|
private async Task ManageOrderToScopeAsync(IOrderRepository orderService, OrderManageMq objFromQuery)
|
2023-11-20 16:59:58 +10:00
|
|
|
|
{
|
|
|
|
|
|
var order = await orderService.Get()
|
|
|
|
|
|
.Include(t => t.AgentHistories).ThenInclude(t => t.AgentHistoryLevel)
|
|
|
|
|
|
.Include(t => t.OrderStatus)
|
|
|
|
|
|
.Include(t => t.NextStatus)
|
2025-06-25 14:17:34 +10:00
|
|
|
|
.Include(t => t.Template).ThenInclude(t => t!.Job).ThenInclude(t => t!.Tnk)
|
2023-11-20 16:59:58 +10:00
|
|
|
|
.FirstOrDefaultAsync(t => t.Id == objFromQuery.OrderId);
|
|
|
|
|
|
|
|
|
|
|
|
if (!IsValidOrder(ref order, ref objFromQuery))
|
2023-11-20 12:26:33 +10:00
|
|
|
|
return;
|
|
|
|
|
|
|
2023-11-20 16:59:58 +10:00
|
|
|
|
logger.LogDebug($"Найден наряд в БД: {order!.Number}");
|
|
|
|
|
|
|
|
|
|
|
|
var resultMsg = GenerateResultMsg(order!);
|
|
|
|
|
|
var workDuration = CalcWorkDuration(order!);
|
2023-11-17 16:03:36 +10:00
|
|
|
|
|
2023-11-20 12:26:33 +10:00
|
|
|
|
// Изменям статус наряда в ЕСПП
|
2023-11-20 16:59:58 +10:00
|
|
|
|
var result = await esppOrderService.ChangeOrderToEsppAsync(order!, resultMsg, workDuration);
|
2023-11-20 12:26:33 +10:00
|
|
|
|
|
|
|
|
|
|
if (result)
|
|
|
|
|
|
{
|
2023-11-20 16:59:58 +10:00
|
|
|
|
logger.LogInformation($"Статусы наряда {order!.Number} в ЕСПП обновлены. Установлен статус: {order.NextStatus!.Description}");
|
2023-11-20 12:26:33 +10:00
|
|
|
|
|
|
|
|
|
|
//обновляем статусы в БД
|
2023-11-20 16:59:58 +10:00
|
|
|
|
order.StatusCode = order.NextStatusCode!.Value;
|
2023-12-25 09:53:10 +10:00
|
|
|
|
order.DateModified = DateTimeOffset.UtcNow;
|
|
|
|
|
|
|
2023-11-20 12:26:33 +10:00
|
|
|
|
if (!await orderService.CommitAsync())
|
|
|
|
|
|
{
|
|
|
|
|
|
logger.LogError($"Ошибка при обновлении статуса в БД у наряда: {order.Number}. Не установлен статус {order.NextStatus!.Description}");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
2023-11-20 16:59:58 +10:00
|
|
|
|
logger.LogError($"Ошибка при обновлении статуса наряда {order!.Number}. Статус не изменен.");
|
|
|
|
|
|
}
|
2023-11-20 12:26:33 +10:00
|
|
|
|
|
2023-11-20 16:59:58 +10:00
|
|
|
|
|
|
|
|
|
|
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;
|
2023-11-17 16:03:36 +10:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2023-11-20 12:26:33 +10:00
|
|
|
|
/// Генерирует текст поля Решение, в зависимости от статуса наряда и от истории Агента
|
2023-11-17 16:03:36 +10:00
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="order"></param>
|
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
|
private string GenerateResultMsg(Order order)
|
|
|
|
|
|
{
|
|
|
|
|
|
var agentHistory = order.AgentHistories
|
|
|
|
|
|
.OrderBy(t => t.DateCreated)
|
|
|
|
|
|
.Select(t => $"{t.DateCreated} :: {t.AgentHistoryLevel?.Name} :: {t.Message}");
|
2023-10-24 11:29:55 +10:00
|
|
|
|
|
2023-11-21 14:37:41 +10:00
|
|
|
|
//"Template": "{base}\n{msgAgent}",
|
|
|
|
|
|
//"MsgAgent": "Работы выполнены средствами автоматизации.\nЖурнал работы:\n{agentHistory}",
|
|
|
|
|
|
//"MsgAgentEmpty": "Работы должны были выполняться средствами автоматизации. От средств автоматизации не поступило сообщений. Работы не выполнены."
|
2023-11-20 12:26:33 +10:00
|
|
|
|
|
2023-11-21 14:37:41 +10:00
|
|
|
|
//Шаблон поля Решение
|
|
|
|
|
|
var template = resultTemplateSettings.Template;
|
2023-11-17 16:03:36 +10:00
|
|
|
|
|
2023-11-21 14:37:41 +10:00
|
|
|
|
//Поле решение из ApplicationsInWork
|
2025-06-25 14:17:34 +10:00
|
|
|
|
var baseMsg = order.Template!.Job!.Group!.Solution;
|
2023-11-17 16:03:36 +10:00
|
|
|
|
|
2023-11-21 14:37:41 +10:00
|
|
|
|
//Формируем сообщения от Агента
|
|
|
|
|
|
var msgAgent = agentHistory.Any()
|
|
|
|
|
|
? resultTemplateSettings.MsgAgent.Replace("{agentHistory}", string.Join("\n", agentHistory))
|
|
|
|
|
|
: resultTemplateSettings.MsgAgentEmpty;
|
|
|
|
|
|
|
|
|
|
|
|
return template.Replace("{base}", baseMsg).Replace("{msgAgent}", msgAgent);
|
2023-10-24 11:29:55 +10:00
|
|
|
|
}
|
2023-11-17 16:03:36 +10:00
|
|
|
|
|
2023-11-17 16:25:12 +10:00
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Рассчиать трудозатраты
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="order"></param>
|
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
|
private TimeSpan CalcWorkDuration(Order order)
|
|
|
|
|
|
{
|
|
|
|
|
|
var agentHistory = order.AgentHistories
|
|
|
|
|
|
.OrderBy(t => t.DateCreated);
|
|
|
|
|
|
|
|
|
|
|
|
if (!agentHistory.Any())
|
2023-11-20 12:26:33 +10:00
|
|
|
|
return GetTnkDurationByScriptDuration(TimeSpan.Zero);
|
2023-11-17 16:25:12 +10:00
|
|
|
|
|
|
|
|
|
|
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)
|
2023-11-20 12:26:33 +10:00
|
|
|
|
{
|
|
|
|
|
|
var duration = dateEnd.Value - dateStart.Value;
|
|
|
|
|
|
logger.LogDebug($"Продолжительность работы скрипта: {duration}");
|
2023-11-17 16:25:12 +10:00
|
|
|
|
|
2023-11-20 12:26:33 +10:00
|
|
|
|
return GetTnkDurationByScriptDuration(duration);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return GetTnkDurationByScriptDuration(TimeSpan.Zero);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Получить время для списания ТНК по времени работы скрипта
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="scriptDuration"></param>
|
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
|
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;
|
2023-11-17 16:25:12 +10:00
|
|
|
|
}
|
|
|
|
|
|
|
2023-10-24 11:29:55 +10:00
|
|
|
|
}
|
|
|
|
|
|
}
|