< Summary

Information
Class: Services.ApiServices.ArmtekApi.ArmtekDataManager
Assembly: Services
File(s): /home/runner/work/Studio2Prod/Studio2Prod/AppRepository/ApiServices/ArmtekApi/ArmtekDataManager.cs
Line coverage
89%
Covered lines: 128
Uncovered lines: 15
Coverable lines: 143
Total lines: 387
Line coverage: 89.5%
Branch coverage
70%
Covered branches: 68
Total branches: 96
Branch coverage: 70.8%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

File(s)

/home/runner/work/Studio2Prod/Studio2Prod/AppRepository/ApiServices/ArmtekApi/ArmtekDataManager.cs

#LineLine coverage
 1using Microsoft.Extensions.Logging;
 2using Services.ApiServices.ArmtekApi.Models.Envelope;
 3using Services.ApiServices.ArmtekApi.Models.Response;
 4
 5namespace Services.ApiServices.ArmtekApi;
 6
 7/// <summary>
 8/// Бизнес-уровень интеграции с Armtek Web-Services — read-методы, createOrder и editOrder (см. docs/api/armtek.md).
 9/// Никогда не бросает исключение из-за бизнес-MESSAGES внутри валидного конверта (например,
 10/// "заказ типа Возврат не обрабатывается этим методом" на getOrder) — всегда возвращает
 11/// ArmtekResponse&lt;T&gt; целиком, вызывающий код сам решает, что делать с HasErrors/частичным Resp.
 12/// ArmtekApiException прокидывается наружу только из ArmtekHttpClient (транспортные сбои).
 13/// </summary>
 14public class ArmtekDataManager
 15{
 16    private readonly ArmtekHttpClient _client;
 17    private readonly ArmtekConfig _config;
 18    private readonly ILogger<ArmtekDataManager> _logger;
 19    private readonly ArmtekBrandResolver? _brandResolver;
 20
 13721    public ArmtekDataManager(ArmtekHttpClient client, ArmtekConfig config, ILogger<ArmtekDataManager> logger,
 13722        ArmtekBrandResolver? brandResolver = null)
 23    {
 13724        _client = client;
 13725        _config = config;
 13726        _logger = logger;
 13727        _brandResolver = brandResolver;
 13728    }
 29
 10630    private string ResolveVkorg(string? vkorg) => string.IsNullOrWhiteSpace(vkorg) ? _config.DefaultVkorg : vkorg;
 31
 32    // ---- ws_ping ----
 33
 34    /// <summary>Проверка доступности сервиса. GET ws_ping/index.</summary>
 35    public Task<ArmtekResponse<ArmtekPingResponse>> PingAsync(CancellationToken ct = default)
 036        => _client.GetAsync<ArmtekPingResponse>("ws_ping/index", ct: ct);
 37
 38    // ---- ws_user ----
 39
 40    /// <summary>Список сбытовых организаций клиента. GET ws_user/getUserVkorgList.</summary>
 41    public Task<ArmtekResponse<List<ArmtekVkorgItem>>> GetUserVkorgListAsync(CancellationToken ct = default)
 142        => _client.GetAsync<List<ArmtekVkorgItem>>("ws_user/getUserVkorgList", ct: ct);
 43
 44    /// <summary>Структура клиента (покупатели/грузополучатели/адреса/договоры/контакты). POST ws_user/getUserInfo.</sum
 45    public Task<ArmtekResponse<ArmtekUserInfoResponse>> GetUserInfoAsync(string? vkorg = null, bool structure = true, Ca
 46    {
 1447        var form = new Dictionary<string, string>
 1448        {
 1449            ["VKORG"] = ResolveVkorg(vkorg),
 1450            ["STRUCTURE"] = structure ? "1" : "0"
 1451        };
 1452        return _client.PostFormAsync<ArmtekUserInfoResponse>("ws_user/getUserInfo", form, ct);
 53    }
 54
 55    /// <summary>Справочник брендов. GET ws_user/getBrandList.</summary>
 56    public Task<ArmtekResponse<List<string>>> GetBrandListAsync(CancellationToken ct = default)
 157        => _client.GetAsync<List<string>>("ws_user/getBrandList", ct: ct);
 58
 59    /// <summary>Список доступных складов. POST ws_user/getStoreList.</summary>
 60    public Task<ArmtekResponse<List<ArmtekStoreItem>>> GetStoreListAsync(string? vkorg = null, CancellationToken ct = de
 61    {
 462        var form = new Dictionary<string, string> { ["VKORG"] = ResolveVkorg(vkorg) };
 463        return _client.PostFormAsync<List<ArmtekStoreItem>>("ws_user/getStoreList", form, ct);
 64    }
 65
 66    // ---- ws_search ----
 67
 68    /// <summary>Проценка товара (цена и наличие) — включая аналоги при queryType=2. POST ws_search/search.</summary>
 69    public Task<ArmtekResponse<List<ArmtekSearchItem>>> SearchAsync(
 70        string kunnrRg,
 71        string pin,
 72        string? brand = null,
 73        string? vkorg = null,
 74        int? queryType = null,
 75        string? program = null,
 76        string? kunnrZa = null,
 77        bool? incotermsSelfPickup = null,
 78        string? vbeln = null,
 79        CancellationToken ct = default)
 80    {
 581        return SearchCoreAsync(kunnrRg, pin, brand, vkorg, queryType, program, kunnrZa, incotermsSelfPickup, vbeln, ct);
 82    }
 83
 84    private async Task<ArmtekResponse<List<ArmtekSearchItem>>> SearchCoreAsync(
 85        string kunnrRg, string pin, string? brand, string? vkorg, int? queryType, string? program,
 86        string? kunnrZa, bool? incotermsSelfPickup, string? vbeln, CancellationToken ct)
 87    {
 588        var resolvedBrand = await ResolveBrandAsync(brand, ct);
 589        var form = new Dictionary<string, string>
 590        {
 591            ["VKORG"] = ResolveVkorg(vkorg),
 592            ["KUNNR_RG"] = kunnrRg,
 593            ["PIN"] = pin
 594        };
 895        if (!string.IsNullOrWhiteSpace(resolvedBrand)) form["BRAND"] = resolvedBrand;
 696        if (queryType is not null) form["QUERY_TYPE"] = queryType.Value.ToString();
 597        if (!string.IsNullOrWhiteSpace(program)) form["PROGRAM"] = program;
 698        if (!string.IsNullOrWhiteSpace(kunnrZa)) form["KUNNR_ZA"] = kunnrZa;
 799        if (incotermsSelfPickup is not null) form["INCOTERMS"] = incotermsSelfPickup.Value ? "1" : "0";
 5100        if (!string.IsNullOrWhiteSpace(vbeln)) form["VBELN"] = vbeln;
 101
 5102        return await _client.PostFormAsync<List<ArmtekSearchItem>>("ws_search/search", form, ct);
 5103    }
 104
 105    /// <summary>Возвращает точное написание бренда из справочника Armtek для входного бренда Studio2.</summary>
 106    public async Task<string?> ResolveBrandAsync(string? brand, CancellationToken ct = default)
 107    {
 6108        if (string.IsNullOrWhiteSpace(brand) || _brandResolver is null)
 5109            return brand;
 110
 111        try
 112        {
 1113            return await _brandResolver.ResolveAsync(brand, ct);
 114        }
 1115        catch (Exception ex)
 116        {
 1117            _logger.LogInformation("Armtek: не удалось сопоставить бренд {Brand} со справочником API ({Message}); исполь
 1118            return brand;
 119        }
 6120    }
 121
 122    /// <summary>Безопасная проверка заказа: Армтек рассчитывает распределение, но не создаёт заказ.</summary>
 123    public Task<ArmtekResponse<ArmtekCreateOrderResponse>> CreateTestOrderAsync(
 124        string kunrg, IReadOnlyCollection<ArmtekOrderRequestItem> items, string? vkorg = null,
 125        string? kunza = null, bool? incotermsSelfPickup = null, CancellationToken ct = default, string? orderComment = n
 17126        => CreateOrderCoreAsync("ws_order/createTestOrder", kunrg, items, vkorg, kunza, incotermsSelfPickup, ct, orderCo
 127
 128    /// <summary>
 129    /// Создаёт реальный заказ Армтек. Вызывать только после явного подтверждения пользователя.
 130    /// <paramref name="orderComment"/> уходит в <c>TEXT_ORD</c> (до 100 символов) — метка Studio2 для сверки заказа
 131    /// перед повтором; комментарий позиции — <see cref="ArmtekOrderRequestItem.Comment"/> (<c>COMMENT</c>).
 132    /// </summary>
 133    public Task<ArmtekResponse<ArmtekCreateOrderResponse>> CreateOrderAsync(
 134        string kunrg, IReadOnlyCollection<ArmtekOrderRequestItem> items, string? vkorg = null,
 135        string? kunza = null, bool? incotermsSelfPickup = null, CancellationToken ct = default, string? orderComment = n
 16136        => CreateOrderCoreAsync("ws_order/createOrder", kunrg, items, vkorg, kunza, incotermsSelfPickup, ct, orderCommen
 137
 138    private Task<ArmtekResponse<ArmtekCreateOrderResponse>> CreateOrderCoreAsync(
 139        string endpoint, string kunrg, IReadOnlyCollection<ArmtekOrderRequestItem> items, string? vkorg,
 140        string? kunza, bool? incotermsSelfPickup, CancellationToken ct, string? orderComment = null)
 141    {
 33142        var form = new Dictionary<string, string>
 33143        {
 33144            ["VKORG"] = ResolveVkorg(vkorg),
 33145            ["KUNRG"] = kunrg,
 33146            // KEYZAK проценки может относиться к партнёрскому складу. Без DBTYP=3 Armtek проверяет
 33147            // только основной склад и возвращает «ничего не найдено» для реально доступной позиции.
 33148            ["DBTYP"] = "3"
 33149        };
 150        // KUNZA/INCOTERMS должны совпадать с параметрами проценки: иначе Армтек считает цену и склад по другому адресу.
 64151        if (!string.IsNullOrWhiteSpace(kunza)) form["KUNZA"] = kunza;
 64152        if (incotermsSelfPickup is not null) form["INCOTERMS"] = incotermsSelfPickup.Value ? "1" : "0";
 153        // TEXT_ORD — комментарий к заказу, до 100 символов (docs/api/armtek.md).
 47154        if (!string.IsNullOrWhiteSpace(orderComment)) form["TEXT_ORD"] = orderComment.Length <= 100 ? orderComment : ord
 33155        var index = 0;
 132156        foreach (var item in items)
 157        {
 33158            form[$"ITEMS[{index}][PIN]"] = item.Pin;
 33159            form[$"ITEMS[{index}][BRAND]"] = item.Brand;
 160            // Armtek принимает "2", но отвергает decimal-формат с незначащими нулями "2.000".
 33161            form[$"ITEMS[{index}][KWMENG]"] = item.Quantity.ToString("0.####", System.Globalization.CultureInfo.Invarian
 64162            if (!string.IsNullOrWhiteSpace(item.Keyzak)) form[$"ITEMS[{index}][KEYZAK]"] = item.Keyzak;
 163            // Armtek отклоняет "489.0000" как некорректный параметр, хотя "489" и "18.06" допустимы.
 64164            if (item.PriceMax is decimal priceMax) form[$"ITEMS[{index}][PRICEMAX]"] = priceMax.ToString("0.####", Syste
 35165            if (!string.IsNullOrWhiteSpace(item.DateMax)) form[$"ITEMS[{index}][DATEMAX]"] = item.DateMax;
 62166            if (!string.IsNullOrWhiteSpace(item.Comment)) form[$"ITEMS[{index}][COMMENT]"] = item.Comment.Length <= 100 
 33167            index++;
 168        }
 33169        return _client.PostFormAsync<ArmtekCreateOrderResponse>(endpoint, form, ct);
 170    }
 171
 172    /// <summary>Поиск по ассортименту без цен/остатков/привязки к покупателю. POST ws_search/assortment_search.</summar
 173    public Task<ArmtekResponse<List<ArmtekAssortmentItem>>> AssortmentSearchAsync(
 174        string pin, string? vkorg = null, string? program = null, CancellationToken ct = default)
 175    {
 2176        var form = new Dictionary<string, string>
 2177        {
 2178            ["VKORG"] = ResolveVkorg(vkorg),
 2179            ["PIN"] = pin
 2180        };
 2181        if (!string.IsNullOrWhiteSpace(program)) form["PROGRAM"] = program;
 182
 2183        return _client.PostFormAsync<List<ArmtekAssortmentItem>>("ws_search/assortment_search", form, ct);
 184    }
 185
 186    // ---- ws_order ----
 187
 188    /// <summary>
 189    /// Данные по заказу. GET ws_order/getOrder. Обрабатывает только "прямые" заказы
 190    /// (отгрузка/доставка со складов АРМТЕК/ЦЗ) — для заказов типа "Возврат" сервис
 191    /// отвечает MESSAGES[E] и RESP:null (см. ArmtekResponse&lt;T&gt;.HasErrors), не исключением;
 192    /// в этом случае вызывающий код должен использовать GetRefundAsync.
 193    /// </summary>
 194    public Task<ArmtekResponse<ArmtekGetOrderResponse>> GetOrderAsync(
 195        string kunrg, string order, string? vkorg = null, bool? edit = null, CancellationToken ct = default)
 196    {
 3197        var query = new Dictionary<string, string>
 3198        {
 3199            ["VKORG"] = ResolveVkorg(vkorg),
 3200            ["KUNRG"] = kunrg,
 3201            ["ORDER"] = order
 3202        };
 3203        if (edit is not null) query["EDIT"] = edit.Value ? "1" : "0";
 204
 3205        return _client.GetAsync<ArmtekGetOrderResponse>("ws_order/getOrder", query, ct);
 206    }
 207
 208    /// <summary>
 209    /// Меняет количество или отклоняет позиции заказа. POST ws_order/editOrder; <paramref name="abgru"/> — код причины
 210    /// из <c>getOrder.ABGRU_ITEMS</c> (запрашивать с <c>EDIT=1</c>). Ответ — пустой RESP, результат в MESSAGES.
 211    /// Меняет реальный заказ у Армтек: dry-run у метода нет.
 212    /// </summary>
 213    public Task<ArmtekResponse<Newtonsoft.Json.Linq.JToken>> EditOrderAsync(
 214        string kunrg, string order, IReadOnlyCollection<(string Posnr, decimal Quantity)> positions, string abgru,
 215        string? vkorg = null, string? note = null, CancellationToken ct = default)
 216    {
 0217        var form = new Dictionary<string, string>
 0218        {
 0219            ["VKORG"] = ResolveVkorg(vkorg),
 0220            ["KUNRG"] = kunrg,
 0221            ["ORDER"] = order
 0222        };
 0223        var index = 0;
 0224        foreach (var (posnr, quantity) in positions)
 225        {
 0226            form[$"POSITION_INPUT[{index}][POSNR]"] = posnr;
 0227            form[$"POSITION_INPUT[{index}][KWMENG]"] = quantity.ToString("0.####", System.Globalization.CultureInfo.Inva
 0228            form[$"POSITION_INPUT[{index}][ABGRU]"] = abgru;
 0229            if (!string.IsNullOrWhiteSpace(note)) form[$"POSITION_INPUT[{index}][NOTE]"] = note.Length <= 100 ? note : n
 0230            index++;
 231        }
 0232        return _client.PostFormAsync<Newtonsoft.Json.Linq.JToken>("ws_order/editOrder", form, ct);
 233    }
 234
 235    /// <summary>
 236    /// Данные по заказу v2, с детальной расшифровкой статусов при detailedStatus=true.
 237    /// GET ws_order/getOrder2. При таймауте API (STATUS-запрос требует больше расчётов на
 238    /// стороне Армтек) MESSAGES содержит ошибку, но HEADER/ITEMS в Resp приходят частично —
 239    /// не бросает исключение, вызывающий код читает HasErrors и частичный Resp по отдельности.
 240    /// </summary>
 241    public Task<ArmtekResponse<ArmtekGetOrder2Response>> GetOrder2Async(
 242        string kunrg, string order, string? vkorg = null, bool detailedStatus = true, CancellationToken ct = default)
 243    {
 6244        var query = new Dictionary<string, string>
 6245        {
 6246            ["VKORG"] = ResolveVkorg(vkorg),
 6247            ["KUNRG"] = kunrg,
 6248            ["ORDER"] = order,
 6249            ["STATUS"] = detailedStatus ? "1" : "0"
 6250        };
 251
 6252        return _client.GetAsync<ArmtekGetOrder2Response>("ws_order/getOrder2", query, ct);
 253    }
 254
 255    /// <summary>Данные по возврату (заказ с ORDER_TYPE="Возврат"). GET ws_order/getRefund.</summary>
 256    public Task<ArmtekResponse<ArmtekGetRefundResponse>> GetRefundAsync(
 257        string kunrg, string returnNumber, string? vkorg = null, CancellationToken ct = default)
 258    {
 2259        var query = new Dictionary<string, string>
 2260        {
 2261            ["VKORG"] = ResolveVkorg(vkorg),
 2262            ["KUNRG"] = kunrg,
 2263            ["RETURN"] = returnNumber
 2264        };
 265
 2266        return _client.GetAsync<ArmtekGetRefundResponse>("ws_order/getRefund", query, ct);
 267    }
 268
 269    // ---- ws_invoice ----
 270
 271    /// <summary>
 272    /// Данные по фактуре. GET ws_invoice/getInvoice. Один из invoice/zzsf обязателен —
 273    /// в отличие от MESSAGES[E] от самого API, это программерская ошибка вызова, а не
 274    /// бизнес-сценарий, поэтому кидается ArgumentException до похода в сеть.
 275    /// </summary>
 276    public Task<ArmtekResponse<ArmtekGetInvoiceResponse>> GetInvoiceAsync(
 277        string kunrg,
 278        string? invoice = null,
 279        string? zzsf = null,
 280        string? vkorg = null,
 281        bool refundFlag = false,
 282        bool? noCollapse = null,
 283        CancellationToken ct = default)
 284    {
 19285        if (string.IsNullOrWhiteSpace(invoice) && string.IsNullOrWhiteSpace(zzsf))
 1286            throw new ArgumentException("Нужно указать либо invoice, либо zzsf.", nameof(invoice));
 287
 18288        var query = new Dictionary<string, string>
 18289        {
 18290            ["VKORG"] = ResolveVkorg(vkorg),
 18291            ["KUNRG"] = kunrg
 18292        };
 35293        if (!string.IsNullOrWhiteSpace(invoice)) query["INVOICE"] = invoice;
 19294        if (!string.IsNullOrWhiteSpace(zzsf)) query["ZZSF"] = zzsf;
 20295        if (refundFlag) query["REFLAG"] = "1";
 18296        if (noCollapse is not null) query["NOCOLLAPS"] = noCollapse.Value ? "1" : "0";
 297
 18298        return _client.GetAsync<ArmtekGetInvoiceResponse>("ws_invoice/getInvoice", query, ct);
 299    }
 300
 301    // ---- ws_reports ----
 302
 303    /// <summary>
 304    /// Отчёт по заказам за период. POST ws_reports/getOrderReportByDate. Если заказов за период
 305    /// нет, RESP приходит null (в MESSAGES информационное "Список пуст") — не бросает исключение.
 306    /// </summary>
 307    public Task<ArmtekResponse<ArmtekGetOrderReportByDateResponse>> GetOrderReportByDateAsync(
 308        string kunnrRg,
 309        string? vkorg = null,
 310        DateTime? createdFrom = null,
 311        DateTime? createdTo = null,
 312        DateTime? deliveryFrom = null,
 313        DateTime? deliveryTo = null,
 314        bool? includeSales = null,
 315        bool? includeReturns = null,
 316        bool? currentLoginOnly = null,
 317        CancellationToken ct = default)
 318    {
 15319        var form = BuildReportForm(kunnrRg, vkorg, createdFrom, createdTo, deliveryFrom, deliveryTo, includeSales, inclu
 15320        return _client.PostFormAsync<ArmtekGetOrderReportByDateResponse>("ws_reports/getOrderReportByDate", form, ct);
 321    }
 322
 323    /// <summary>Отчёт по заказам в разрезе позиций за период. POST ws_reports/getOrderPositionsReportByDate.</summary>
 324    public Task<ArmtekResponse<ArmtekGetOrderPositionsReportByDateResponse>> GetOrderPositionsReportByDateAsync(
 325        string kunnrRg,
 326        string? vkorg = null,
 327        DateTime? createdFrom = null,
 328        DateTime? createdTo = null,
 329        DateTime? deliveryFrom = null,
 330        DateTime? deliveryTo = null,
 331        bool? includeSales = null,
 332        bool? includeReturns = null,
 333        bool? currentLoginOnly = null,
 334        CancellationToken ct = default)
 335    {
 1336        var form = BuildReportForm(kunnrRg, vkorg, createdFrom, createdTo, deliveryFrom, deliveryTo, includeSales, inclu
 1337        return _client.PostFormAsync<ArmtekGetOrderPositionsReportByDateResponse>("ws_reports/getOrderPositionsReportByD
 338    }
 339
 340    /// <summary>Отчёт по заказам в разрезе позиций (v2, с детализацией процессинга). POST ws_reports/getOrderPositionsR
 341    public Task<ArmtekResponse<ArmtekGetOrderPositionsReportByDate2Response>> GetOrderPositionsReportByDate2Async(
 342        string kunnrRg,
 343        string? vkorg = null,
 344        DateTime? createdFrom = null,
 345        DateTime? createdTo = null,
 346        DateTime? deliveryFrom = null,
 347        DateTime? deliveryTo = null,
 348        bool? includeSales = null,
 349        bool? includeReturns = null,
 350        bool? currentLoginOnly = null,
 351        bool? rejectedOnly = null,
 352        CancellationToken ct = default)
 353    {
 3354        var form = BuildReportForm(kunnrRg, vkorg, createdFrom, createdTo, deliveryFrom, deliveryTo, includeSales, inclu
 4355        if (rejectedOnly is not null) form["Rejected"] = rejectedOnly.Value ? "1" : "0";
 356
 3357        return _client.PostFormAsync<ArmtekGetOrderPositionsReportByDate2Response>("ws_reports/getOrderPositionsReportBy
 358    }
 359
 360    private Dictionary<string, string> BuildReportForm(
 361        string kunnrRg,
 362        string? vkorg,
 363        DateTime? createdFrom,
 364        DateTime? createdTo,
 365        DateTime? deliveryFrom,
 366        DateTime? deliveryTo,
 367        bool? includeSales,
 368        bool? includeReturns,
 369        bool? currentLoginOnly)
 370    {
 19371        var form = new Dictionary<string, string>
 19372        {
 19373            ["VKORG"] = ResolveVkorg(vkorg),
 19374            ["KUNNR_RG"] = kunnrRg
 19375        };
 32376        if (createdFrom is not null) form["SCRDATE"] = FormatDate(createdFrom.Value);
 32377        if (createdTo is not null) form["ECRDATE"] = FormatDate(createdTo.Value);
 19378        if (deliveryFrom is not null) form["SDLDATE"] = FormatDate(deliveryFrom.Value);
 19379        if (deliveryTo is not null) form["EDLDATE"] = FormatDate(deliveryTo.Value);
 23380        if (includeSales is not null) form["TYPEZK_SALE"] = includeSales.Value ? "1" : "0";
 19381        if (includeReturns is not null) form["TYPEZK_RETN"] = includeReturns.Value ? "1" : "0";
 23382        if (currentLoginOnly is not null) form["KURR_LOGIN"] = currentLoginOnly.Value ? "1" : "0";
 19383        return form;
 384    }
 385
 26386    private static string FormatDate(DateTime date) => date.ToString("yyyyMMdd");
 387}

Methods/Properties

.ctor(Services.ApiServices.ArmtekApi.ArmtekHttpClient,Services.ApiServices.ArmtekApi.ArmtekConfig,Microsoft.Extensions.Logging.ILogger`1<Services.ApiServices.ArmtekApi.ArmtekDataManager>,Services.ApiServices.ArmtekApi.ArmtekBrandResolver)
ResolveVkorg(System.String)
PingAsync(System.Threading.CancellationToken)
GetUserVkorgListAsync(System.Threading.CancellationToken)
GetUserInfoAsync(System.String,System.Boolean,System.Threading.CancellationToken)
GetBrandListAsync(System.Threading.CancellationToken)
GetStoreListAsync(System.String,System.Threading.CancellationToken)
SearchAsync(System.String,System.String,System.String,System.String,System.Nullable`1<System.Int32>,System.String,System.String,System.Nullable`1<System.Boolean>,System.String,System.Threading.CancellationToken)
SearchCoreAsync()
ResolveBrandAsync()
CreateTestOrderAsync(System.String,System.Collections.Generic.IReadOnlyCollection`1<Services.ApiServices.ArmtekApi.ArmtekOrderRequestItem>,System.String,System.String,System.Nullable`1<System.Boolean>,System.Threading.CancellationToken,System.String)
CreateOrderAsync(System.String,System.Collections.Generic.IReadOnlyCollection`1<Services.ApiServices.ArmtekApi.ArmtekOrderRequestItem>,System.String,System.String,System.Nullable`1<System.Boolean>,System.Threading.CancellationToken,System.String)
CreateOrderCoreAsync(System.String,System.String,System.Collections.Generic.IReadOnlyCollection`1<Services.ApiServices.ArmtekApi.ArmtekOrderRequestItem>,System.String,System.String,System.Nullable`1<System.Boolean>,System.Threading.CancellationToken,System.String)
AssortmentSearchAsync(System.String,System.String,System.String,System.Threading.CancellationToken)
GetOrderAsync(System.String,System.String,System.String,System.Nullable`1<System.Boolean>,System.Threading.CancellationToken)
EditOrderAsync(System.String,System.String,System.Collections.Generic.IReadOnlyCollection`1<System.ValueTuple`2<System.String,System.Decimal>>,System.String,System.String,System.String,System.Threading.CancellationToken)
GetOrder2Async(System.String,System.String,System.String,System.Boolean,System.Threading.CancellationToken)
GetRefundAsync(System.String,System.String,System.String,System.Threading.CancellationToken)
GetInvoiceAsync(System.String,System.String,System.String,System.String,System.Boolean,System.Nullable`1<System.Boolean>,System.Threading.CancellationToken)
GetOrderReportByDateAsync(System.String,System.String,System.Nullable`1<System.DateTime>,System.Nullable`1<System.DateTime>,System.Nullable`1<System.DateTime>,System.Nullable`1<System.DateTime>,System.Nullable`1<System.Boolean>,System.Nullable`1<System.Boolean>,System.Nullable`1<System.Boolean>,System.Threading.CancellationToken)
GetOrderPositionsReportByDateAsync(System.String,System.String,System.Nullable`1<System.DateTime>,System.Nullable`1<System.DateTime>,System.Nullable`1<System.DateTime>,System.Nullable`1<System.DateTime>,System.Nullable`1<System.Boolean>,System.Nullable`1<System.Boolean>,System.Nullable`1<System.Boolean>,System.Threading.CancellationToken)
GetOrderPositionsReportByDate2Async(System.String,System.String,System.Nullable`1<System.DateTime>,System.Nullable`1<System.DateTime>,System.Nullable`1<System.DateTime>,System.Nullable`1<System.DateTime>,System.Nullable`1<System.Boolean>,System.Nullable`1<System.Boolean>,System.Nullable`1<System.Boolean>,System.Nullable`1<System.Boolean>,System.Threading.CancellationToken)
BuildReportForm(System.String,System.String,System.Nullable`1<System.DateTime>,System.Nullable`1<System.DateTime>,System.Nullable`1<System.DateTime>,System.Nullable`1<System.DateTime>,System.Nullable`1<System.Boolean>,System.Nullable`1<System.Boolean>,System.Nullable`1<System.Boolean>)
FormatDate(System.DateTime)