| | | 1 | | using OzonDomains; |
| | | 2 | | using OzonDomains.Models; |
| | | 3 | | using OzonRepositories.Context; |
| | | 4 | | using OzonRepositories.Data; |
| | | 5 | | |
| | | 6 | | namespace Services.DataServices |
| | | 7 | | { |
| | | 8 | | /// <summary> |
| | | 9 | | /// Единый сервис записи истории переходов между статусами для всех транзакций по заказам. |
| | | 10 | | /// Заполняет все поля модели StatusTransitionHistory. Запись выполняется только для заказов, |
| | | 11 | | /// у которых найден соответствующий переход в справочнике StatusTransition. |
| | | 12 | | /// </summary> |
| | | 13 | | public class StatusTransitionHistoryService : IStatusTransitionHistoryService |
| | | 14 | | { |
| | | 15 | | private readonly IStatusTransitionHistoryRepository _repository; |
| | | 16 | | private readonly ApplicationDbContext _context; |
| | | 17 | | |
| | 15 | 18 | | public StatusTransitionHistoryService( |
| | 15 | 19 | | IStatusTransitionHistoryRepository repository, |
| | 15 | 20 | | ApplicationDbContext context) |
| | | 21 | | { |
| | 15 | 22 | | _repository = repository; |
| | 15 | 23 | | _context = context; |
| | 15 | 24 | | } |
| | | 25 | | |
| | | 26 | | /// <inheritdoc /> |
| | | 27 | | public async Task RecordStatusTransitionHistoryAsync( |
| | | 28 | | TransactionType transactionType, |
| | | 29 | | IReadOnlyList<Order> ordersWithNewStatus, |
| | | 30 | | IReadOnlyDictionary<int, int> orderIdToFromStatusId, |
| | | 31 | | IReadOnlyList<StatusTransition> transitions, |
| | | 32 | | string? comment, |
| | | 33 | | int? performedByUserId, |
| | | 34 | | DateTime performedAt, |
| | | 35 | | string? metadata = null) |
| | | 36 | | { |
| | 12 | 37 | | if (ordersWithNewStatus == null || ordersWithNewStatus.Count == 0) |
| | 2 | 38 | | return; |
| | 10 | 39 | | if (transitions == null || transitions.Count == 0) |
| | 2 | 40 | | return; |
| | | 41 | | |
| | 8 | 42 | | var list = new List<StatusTransitionHistory>(); |
| | 36 | 43 | | foreach (var order in ordersWithNewStatus) |
| | | 44 | | { |
| | 10 | 45 | | if (!orderIdToFromStatusId.TryGetValue(order.Id, out var fromStatusId)) |
| | | 46 | | continue; |
| | | 47 | | |
| | | 48 | | // Целевой статус: из заказа (Id или навигация) или из перехода по типу транзакции и исходному статусу |
| | 8 | 49 | | var toStatusIdFromOrder = order.AppStatusId ?? order.AppStatus?.Id ?? 0; |
| | 8 | 50 | | var transition = transitions.FirstOrDefault(t => |
| | 16 | 51 | | t.FromStatusId == fromStatusId && |
| | 16 | 52 | | t.TransactionType == transactionType && |
| | 16 | 53 | | (toStatusIdFromOrder == 0 || t.ToStatusId == toStatusIdFromOrder)); |
| | | 54 | | |
| | 8 | 55 | | if (transition == null) |
| | 3 | 56 | | transition = transitions.FirstOrDefault(t => |
| | 6 | 57 | | t.FromStatusId == fromStatusId && |
| | 6 | 58 | | t.TransactionType == transactionType); |
| | | 59 | | |
| | 8 | 60 | | if (transition == null) |
| | | 61 | | continue; |
| | | 62 | | |
| | 6 | 63 | | var toStatusId = toStatusIdFromOrder != 0 ? toStatusIdFromOrder : transition.ToStatusId; |
| | | 64 | | |
| | 6 | 65 | | list.Add(new StatusTransitionHistory |
| | 6 | 66 | | { |
| | 6 | 67 | | EntityId = order.Id, |
| | 6 | 68 | | EntityType = "Order", |
| | 6 | 69 | | StatusTransitionId = transition.Id, |
| | 6 | 70 | | FromStatusId = fromStatusId, |
| | 6 | 71 | | ToStatusId = toStatusId, |
| | 6 | 72 | | TransactionType = transactionType, |
| | 6 | 73 | | Comment = comment != null && comment.Length > 500 ? comment.Substring(0, 500) : comment, |
| | 6 | 74 | | PerformedByUserId = performedByUserId, |
| | 6 | 75 | | PerformedAt = performedAt, |
| | 6 | 76 | | Metadata = metadata |
| | 6 | 77 | | }); |
| | | 78 | | } |
| | | 79 | | |
| | 8 | 80 | | if (list.Count == 0) |
| | 2 | 81 | | return; |
| | | 82 | | |
| | 6 | 83 | | _repository.AddRange(list); |
| | 6 | 84 | | await _context.SaveChangesAsync(); |
| | 12 | 85 | | } |
| | | 86 | | |
| | | 87 | | /// <inheritdoc /> |
| | | 88 | | public async Task RecordManualStatusChangeAsync( |
| | | 89 | | IReadOnlyList<Order> ordersWithNewStatus, |
| | | 90 | | IReadOnlyDictionary<int, int> orderIdToFromStatusId, |
| | | 91 | | int? performedByUserId, |
| | | 92 | | DateTime performedAt) |
| | | 93 | | { |
| | 5 | 94 | | if (ordersWithNewStatus == null || ordersWithNewStatus.Count == 0) |
| | 2 | 95 | | return; |
| | | 96 | | |
| | | 97 | | const string manualComment = "Изменено вручную"; |
| | 3 | 98 | | var list = new List<StatusTransitionHistory>(); |
| | 20 | 99 | | foreach (var order in ordersWithNewStatus) |
| | | 100 | | { |
| | 7 | 101 | | if (!orderIdToFromStatusId.TryGetValue(order.Id, out var fromStatusId)) |
| | | 102 | | continue; |
| | | 103 | | |
| | 6 | 104 | | var toStatusId = order.AppStatusId ?? order.AppStatus?.Id ?? 0; |
| | 6 | 105 | | if (toStatusId == 0 || toStatusId == fromStatusId) |
| | | 106 | | continue; |
| | | 107 | | |
| | 3 | 108 | | list.Add(new StatusTransitionHistory |
| | 3 | 109 | | { |
| | 3 | 110 | | EntityId = order.Id, |
| | 3 | 111 | | EntityType = "Order", |
| | 3 | 112 | | StatusTransitionId = null, |
| | 3 | 113 | | FromStatusId = fromStatusId, |
| | 3 | 114 | | ToStatusId = toStatusId, |
| | 3 | 115 | | TransactionType = null, |
| | 3 | 116 | | Comment = manualComment, |
| | 3 | 117 | | PerformedByUserId = performedByUserId, |
| | 3 | 118 | | PerformedAt = performedAt, |
| | 3 | 119 | | Metadata = null |
| | 3 | 120 | | }); |
| | | 121 | | } |
| | | 122 | | |
| | 3 | 123 | | if (list.Count == 0) |
| | 1 | 124 | | return; |
| | | 125 | | |
| | 2 | 126 | | _repository.AddRange(list); |
| | 2 | 127 | | await _context.SaveChangesAsync(); |
| | 5 | 128 | | } |
| | | 129 | | } |
| | | 130 | | } |