< Summary

Information
Class: Services.AiAssistant.OrderHistoryPageContextLoader
Assembly: Services
File(s): /home/runner/work/Studio2Prod/Studio2Prod/AppRepository/AiAssistant/OrderHistoryPageContextLoader.cs
Line coverage
0%
Covered lines: 0
Uncovered lines: 67
Coverable lines: 67
Total lines: 126
Line coverage: 0%
Branch coverage
0%
Covered branches: 0
Total branches: 32
Branch coverage: 0%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%210%
IsOrderAccessibleAsync()0%620%
LoadFormattedContextAsync()0%210140%
FormatPageContext(...)0%272160%

File(s)

/home/runner/work/Studio2Prod/Studio2Prod/AppRepository/AiAssistant/OrderHistoryPageContextLoader.cs

#LineLine coverage
 1using System.Text;
 2using Microsoft.EntityFrameworkCore;
 3using OzonDomains;
 4using OzonDomains.Models;
 5using OzonRepositories.Data;
 6using Services.BitrixStockServices;
 7using Services.DataServices;
 8
 9namespace Services.AiAssistant;
 10
 11/// <summary>
 12/// Те же данные, что на странице OrderHistory/GetOrderHistory — для AI-контекста.
 13/// </summary>
 14public sealed class OrderHistoryPageContextLoader
 15{
 16    private readonly IOrderHistoryDataService _historyService;
 17    private readonly OrdersDataServices _ordersData;
 18    private readonly TransactionDataServices _transactionData;
 19    private readonly OrderRepository _orderRepository;
 20    private readonly AiOrderScopeApplier _scopeApplier;
 21    private readonly IBitrixStockSyncArticleHistoryService _bitrixArticleHistory;
 22
 023    public OrderHistoryPageContextLoader(
 024        IOrderHistoryDataService historyService,
 025        OrdersDataServices ordersData,
 026        TransactionDataServices transactionData,
 027        OrderRepository orderRepository,
 028        AiOrderScopeApplier scopeApplier,
 029        IBitrixStockSyncArticleHistoryService bitrixArticleHistory)
 30    {
 031        _historyService       = historyService;
 032        _ordersData           = ordersData;
 033        _transactionData      = transactionData;
 034        _orderRepository      = orderRepository;
 035        _scopeApplier         = scopeApplier;
 036        _bitrixArticleHistory = bitrixArticleHistory;
 037    }
 38
 39    public async Task<bool> IsOrderAccessibleAsync(int orderId, string? userId, CancellationToken ct = default)
 40    {
 041        if (orderId <= 0) return false;
 042        var query = _orderRepository.GetQueryable(includeArchived: true).Where(o => o.Id == orderId);
 043        query = await _scopeApplier.ApplyAsync(query, userId, ct);
 044        return await query.AnyAsync(ct);
 045    }
 46
 47    public async Task<string?> LoadFormattedContextAsync(int orderId, string? userId, CancellationToken ct = default)
 48    {
 049        if (!await IsOrderAccessibleAsync(orderId, userId, ct))
 050            return null;
 51
 052        var histories = await _historyService.GetByOrderIdAsync(orderId) ?? [];
 53
 054        var order = histories.FirstOrDefault()?.Order;
 055        if (order == null)
 56        {
 057            order = await _ordersData.GetAsyncNoTracking(orderId).ConfigureAwait(false);
 058            if (order == null)
 059                return null;
 60        }
 61
 062        var transactionIds = AiOrderTransactionIdCollector.Collect(order, histories).ToList();
 063        var transactions = await _transactionData.GetTransactionsByIdsAsync(transactionIds);
 64
 065        var sb = new StringBuilder(FormatPageContext(order, histories, transactions ?? []));
 66
 067        if (!string.IsNullOrWhiteSpace(order.Article))
 68        {
 069            var bitrixPage = await _bitrixArticleHistory.GetAllAsync(
 070                order.Article.Trim(), maxReports: 15, ct);
 071            sb.AppendLine();
 072            sb.AppendLine(BitrixStockArticleHistoryAiFormatter.FormatForAiAnalysis(bitrixPage));
 73        }
 74
 075        return sb.ToString().TrimEnd();
 076    }
 77
 78    private static string FormatPageContext(
 79        Order order,
 80        List<OrderHistory> histories,
 81        List<Transaction> transactions)
 82    {
 083        var sb = new StringBuilder();
 084        sb.AppendLine($"=== OrderHistory/GetOrderHistory — заказ #{order.Id} ===");
 085        OrderRussianFieldFormatter.AppendKeyPartiesBlock(sb, order);
 086        sb.AppendLine($"Номер отправления: {order.ShipmentNumber}");
 087        sb.AppendLine($"Товар: {order.ProductName}");
 088        sb.AppendLine($"Артикул: {order.Article}");
 89
 090        var txSummaries = transactions.Select(t => new TransactionSummary
 091        {
 092            Id        = t.Id,
 093            TypeName  = t.Type?.GetDisplayName() ?? "—",
 094            CreatedAt = t.CreatedDateTime,
 095            CreatedBy = t.CreateBy,
 096            Comment   = t.Comment
 097        }).ToList();
 098        OrderRussianFieldFormatter.AppendTransactionsBlock(sb, txSummaries);
 99
 0100        if (histories.Count == 0)
 101        {
 0102            sb.AppendLine("История изменений (orders_history): записей нет.");
 103        }
 104        else
 105        {
 0106            sb.AppendLine($"История изменений ({histories.Count} записей), по дням:");
 0107            foreach (var dayGroup in histories
 0108                         .GroupBy(h => h.ChangedAt.Date)
 0109                         .OrderByDescending(g => g.Key))
 110            {
 0111                sb.AppendLine($"--- {dayGroup.Key:dd.MM.yyyy} ---");
 0112                foreach (var h in dayGroup.OrderByDescending(x => x.ChangedAt))
 113                {
 0114                    var field = !string.IsNullOrWhiteSpace(h.ColumnDisplayName)
 0115                        ? h.ColumnDisplayName
 0116                        : h.ColumnName ?? "поле";
 0117                    sb.AppendLine(
 0118                        $"  {h.ChangedAt:HH:mm:ss} | {h.ChangedBy ?? "—"} | {field}: " +
 0119                        $"«{h.FormattedOldValue}» → «{h.FormattedNewValue}»");
 120                }
 121            }
 122        }
 123
 0124        return sb.ToString().TrimEnd();
 125    }
 126}