| | | 1 | | using OzonDomains; |
| | | 2 | | using OzonDomains.Models; |
| | | 3 | | |
| | | 4 | | namespace Services.AiAssistant; |
| | | 5 | | |
| | | 6 | | /// <summary> |
| | | 7 | | /// Форматирование записей orders_history для LLM. |
| | | 8 | | /// </summary> |
| | | 9 | | public static class OrderHistoryFormatter |
| | | 10 | | { |
| | | 11 | | public static string FormatFieldGlossary() => |
| | 17 | 12 | | """ |
| | 17 | 13 | | Таблица orders_history (журнал изменений заказа): |
| | 17 | 14 | | • OrderId — ID заказа |
| | 17 | 15 | | • ColumnName / ColumnDisplayName — изменённое поле (русское имя в ColumnDisplayName) |
| | 17 | 16 | | • OldValue / NewValue — было → стало |
| | 17 | 17 | | • ChangedAt — дата и время изменения (UTC в БД) |
| | 17 | 18 | | • ChangedBy — логин/имя пользователя, внёсшего изменение |
| | 17 | 19 | | Типичные поля: AppStatus (статус в отчёте), ClientStatus (статус Ozon), Supplier, ShipmentWarehouse, |
| | 17 | 20 | | Price, PurchasePrice, Comment, TransactionId (привязка к транзакции). |
| | 17 | 21 | | """; |
| | | 22 | | |
| | | 23 | | public static string FormatHistoryList( |
| | | 24 | | IReadOnlyList<OrderHistory> rows, |
| | | 25 | | IReadOnlyDictionary<int, string?> shipmentByOrderId, |
| | | 26 | | string title) |
| | | 27 | | { |
| | 15 | 28 | | if (rows.Count == 0) |
| | 1 | 29 | | return $"{title}: записей не найдено."; |
| | | 30 | | |
| | 14 | 31 | | var lines = rows.Select(h => |
| | 14 | 32 | | { |
| | 16 | 33 | | var field = !string.IsNullOrWhiteSpace(h.ColumnDisplayName) |
| | 16 | 34 | | ? h.ColumnDisplayName |
| | 16 | 35 | | : h.ColumnName ?? "поле"; |
| | 16 | 36 | | shipmentByOrderId.TryGetValue(h.OrderId, out var shipment); |
| | 16 | 37 | | var shipPart = !string.IsNullOrWhiteSpace(shipment) ? $" {shipment}" : ""; |
| | 16 | 38 | | return $" {h.ChangedAt:dd.MM.yyyy HH:mm} | {h.ChangedBy ?? "—"} | " + |
| | 16 | 39 | | $"заказ #{h.OrderId}{shipPart} | {field}: «{h.FormattedOldValue}» → «{h.FormattedNewValue}»"; |
| | 14 | 40 | | }); |
| | | 41 | | |
| | 14 | 42 | | return $"{title} ({rows.Count} записей):\n" + string.Join("\n", lines); |
| | | 43 | | } |
| | | 44 | | |
| | | 45 | | public static string FormatUserActivitySummary( |
| | | 46 | | IEnumerable<(string User, int Count, IReadOnlyList<string> Samples)> groups, |
| | | 47 | | string title) |
| | | 48 | | { |
| | 7 | 49 | | var list = groups.ToList(); |
| | 7 | 50 | | if (list.Count == 0) |
| | 1 | 51 | | return $"{title}: действий не найдено."; |
| | | 52 | | |
| | 6 | 53 | | var sb = new System.Text.StringBuilder(); |
| | 14 | 54 | | sb.AppendLine($"{title} ({list.Sum(g => g.Count)} изменений, {list.Count} пользователей):"); |
| | 36 | 55 | | foreach (var (user, count, samples) in list.OrderByDescending(g => g.Count)) |
| | | 56 | | { |
| | 8 | 57 | | sb.AppendLine($" • {user}: {count} изменений"); |
| | 34 | 58 | | foreach (var sample in samples.Take(3)) |
| | 9 | 59 | | sb.AppendLine($" {sample}"); |
| | | 60 | | } |
| | 6 | 61 | | return sb.ToString().TrimEnd(); |
| | | 62 | | } |
| | | 63 | | } |