| | | 1 | | using OzonDomains.Models; |
| | | 2 | | using OzonOrdersWeb.Areas.Studio2.Models.Transactions; |
| | | 3 | | using OzonOrdersWeb.TransactionServices; |
| | | 4 | | using OzonOrdersWeb.WebServices.Transactions.Grid.Contracts; |
| | | 5 | | using OzonOrdersWeb.WebServices.Transactions; |
| | | 6 | | using OzonOrdersWeb.WebServices.Transactions.Grid.Definitions; |
| | | 7 | | using Services.ApiServices._1CApi.Models; |
| | | 8 | | using Services.ApiServices._1CApi.Stock; |
| | | 9 | | using Services.SupplierStatusServices; |
| | | 10 | | |
| | | 11 | | namespace OzonOrdersWeb.WebServices.Transactions.Grid.Commit; |
| | | 12 | | |
| | | 13 | | /// <summary>Пользователь, проводящий транзакцию (без ClaimsPrincipal — шаги не зависят от HTTP).</summary> |
| | 91 | 14 | | public sealed record TransactionCommitUser(string Id, string Name, bool IsAdmin, int? AccessProfileId); |
| | | 15 | | |
| | | 16 | | /// <summary> |
| | | 17 | | /// Состояние одного проведения, передаваемое между шагами. Шаги дописывают результаты |
| | | 18 | | /// (заказы после правок, ответы 1С, HTML-блоки итога) и могут остановить конвейер через <see cref="Fail"/>. |
| | | 19 | | /// </summary> |
| | | 20 | | public sealed class TransactionCommitContext |
| | | 21 | | { |
| | | 22 | | public required TransactionDefinition Definition { get; init; } |
| | | 23 | | public required TransactionCommitRequest Request { get; init; } |
| | | 24 | | public required TransactionCommitUser User { get; init; } |
| | | 25 | | public required IServiceProvider Services { get; init; } |
| | | 26 | | public CancellationToken CancellationToken { get; init; } |
| | | 27 | | |
| | | 28 | | /// <summary>Правки по Id заказа (из запроса, минус вычеркнутые).</summary> |
| | | 29 | | public Dictionary<int, TransactionGridRowEdit> Edits { get; } = new(); |
| | | 30 | | |
| | | 31 | | /// <summary>Заказы из БД (без трекинга), доступные пользователю и не вычеркнутые.</summary> |
| | | 32 | | public List<Order> Orders { get; set; } = new(); |
| | | 33 | | |
| | | 34 | | /// <summary>Заказы после <c>TransactOrder</c> (для разбитых — часть /2).</summary> |
| | | 35 | | public List<Order> UpdatedOrders { get; set; } = new(); |
| | | 36 | | |
| | | 37 | | /// <summary>Заказы, попавшие в документ (в целевом статусе).</summary> |
| | | 38 | | public List<Order> OrdersToTransaction { get; set; } = new(); |
| | | 39 | | |
| | | 40 | | /// <summary>Заказы, получающие только смену статуса (без 1С).</summary> |
| | | 41 | | public HashSet<int> StatusOnlyOrderIds { get; } = new(); |
| | | 42 | | |
| | | 43 | | /// <summary>Заказы, которые ApplyEdits пропустил — их проводит ZeroQuantityPolicyStep (транзит утерь).</summary> |
| | | 44 | | public HashSet<int> DeferredOrderIds { get; } = new(); |
| | | 45 | | |
| | | 46 | | /// <summary>Документ 1С уже создан другим шагом (транзит утерь) — OneCDocumentStep пропускается.</summary> |
| | | 47 | | public bool OneCHandledExternally { get; set; } |
| | | 48 | | |
| | | 49 | | public Dictionary<int, int> FromStatusByOrderId { get; set; } = new(); |
| | | 50 | | public List<StatusTransition> Transitions { get; set; } = new(); |
| | | 51 | | public AppStatus? TargetStatus { get; set; } |
| | | 52 | | |
| | | 53 | | /// <summary>Эффективный флаг 1С после проверок остатков и режима «из файла».</summary> |
| | | 54 | | public bool ProcessIn1C { get; set; } |
| | | 55 | | |
| | | 56 | | public StockCheckResult? StockCheck { get; set; } |
| | | 57 | | public HashSet<int> StockBlockedOrderIds { get; } = new(); |
| | | 58 | | |
| | | 59 | | public List<OneCResponse> OneCResponses { get; } = new(); |
| | | 60 | | public List<(string Sender, string Recipient, List<Order> Orders, List<OneCResponse> Result)> OneCGroups { get; } = |
| | | 61 | | public string? OneCSender { get; set; } |
| | | 62 | | public string? OneCRecipient { get; set; } |
| | | 63 | | |
| | | 64 | | /// <summary>Техническая часть комментария (детали 1С), дописывается к пользовательскому.</summary> |
| | | 65 | | public string TechnicalComment { get; set; } = string.Empty; |
| | | 66 | | |
| | | 67 | | /// <summary>HTML-блоки для карточки результата (1С, корзины, Ozon).</summary> |
| | | 68 | | public List<string> SummaryBlocks { get; } = new(); |
| | | 69 | | |
| | | 70 | | /// <summary>Блоки из <see cref="SummaryBlocks"/>, у которых уже есть структурированные строки в <see cref="Report"/ |
| | | 71 | | public HashSet<string> StructuredBlocks { get; } = new(StringComparer.Ordinal); |
| | | 72 | | |
| | | 73 | | /// <summary>Структурированный результат проведения для таблицы в модалке результата.</summary> |
| | | 74 | | public TransactionReportBuilder Report { get; } = new(); |
| | | 75 | | |
| | | 76 | | public List<string> Warnings { get; } = new(); |
| | | 77 | | public Dictionary<int, string> RowErrors { get; } = new(); |
| | | 78 | | |
| | | 79 | | /// <summary>Конфликты «уже заказано у поставщика», остановившие проведение; клиент показывает их в диалоге подтверж |
| | | 80 | | public List<SupplierOrderConflict> SupplierOrderConflicts { get; } = new(); |
| | | 81 | | |
| | | 82 | | public DateTime CreatedAt { get; } = DateTime.Now; |
| | | 83 | | public DateTime HistoryWindowStart { get; set; } = DateTime.Now; |
| | | 84 | | public int TransactionId { get; set; } |
| | | 85 | | public int ChangedCount { get; set; } |
| | | 86 | | public string TransactionDateTime { get; set; } = string.Empty; |
| | | 87 | | |
| | | 88 | | /// <summary>Результаты корзин поставщиков (providerKey → объект результата адаптера).</summary> |
| | | 89 | | public Dictionary<string, object> CartResults { get; } = new(StringComparer.OrdinalIgnoreCase); |
| | | 90 | | |
| | | 91 | | /// <summary>Итог проверки заказов у поставщиков после проведения (null — проверка не выполнялась).</summary> |
| | | 92 | | public SupplierVerificationSummary? SupplierVerification { get; set; } |
| | | 93 | | |
| | | 94 | | /// <summary>Итог сборки отправления Ozon (OrderToSupplier).</summary> |
| | | 95 | | public object? OzonShipResult { get; set; } |
| | | 96 | | |
| | | 97 | | /// <summary>Причина остановки конвейера; после установки шаги не выполняются.</summary> |
| | | 98 | | public (TransactionErrorCode Code, string Message)? Failure { get; private set; } |
| | | 99 | | |
| | | 100 | | public bool IsFailed => Failure != null; |
| | | 101 | | |
| | | 102 | | public void Fail(TransactionErrorCode code, string message) => Failure = (code, message); |
| | | 103 | | |
| | | 104 | | /// <summary>Пользовательский комментарий и состояние AI-комментария (см. <c>TransactionCommentAiSchedulingHelper.Be |
| | | 105 | | public TransactionCommentAiFlowState CommentFlow { get; set; } |
| | | 106 | | |
| | | 107 | | public string UserComment => CommentFlow.UserCommentOnly ?? string.Empty; |
| | | 108 | | |
| | | 109 | | public T Resolve<T>() where T : notnull => Services.GetRequiredService<T>(); |
| | | 110 | | |
| | | 111 | | /// <summary>Этап проведения для оверлея прогресса (SignalR, группа <c>Request.ProgressKey</c>).</summary> |
| | | 112 | | public Task StageAsync(string code, string title, string? detail = null) |
| | | 113 | | => Services.GetRequiredService<TransactionProgressReporter>().StageAsync(Request.ProgressKey, code, title, detai |
| | | 114 | | |
| | | 115 | | public T? TryResolve<T>() where T : class => Services.GetService<T>(); |
| | | 116 | | } |