< Summary

Information
Class: Services.ApiServices._1CApi.OData.OneCDocumentDetails
Assembly: Services
File(s): /home/runner/work/Studio2Prod/Studio2Prod/AppRepository/ApiServices/1CApi/OData/OneCDocumentViewService.cs
Line coverage
0%
Covered lines: 0
Uncovered lines: 16
Coverable lines: 16
Total lines: 248
Line coverage: 0%
Branch coverage
N/A
Covered branches: 0
Total branches: 0
Branch coverage: N/A
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
get_RefKey()100%210%
get_DocTypeLabel()100%210%
get_Number()100%210%
get_Date()100%210%
get_Posted()100%210%
get_DeletionMark()100%210%
get_CounterpartyName()100%210%
get_ContractName()100%210%
get_OrganizationName()100%210%
get_WarehouseName()100%210%
get_WarehouseRecipientName()100%210%
get_OperationKind()100%210%
get_Comment()100%210%
get_TotalAmount()100%210%
get_VatAmount()100%210%
get_Lines()100%210%

File(s)

/home/runner/work/Studio2Prod/Studio2Prod/AppRepository/ApiServices/1CApi/OData/OneCDocumentViewService.cs

#LineLine coverage
 1using Services.ApiServices._1CApi.OData.Models;
 2
 3namespace Services.ApiServices._1CApi.OData;
 4
 5public class OneCDocumentViewService
 6{
 7    private readonly IOneCODataClient _client;
 8    private readonly IOneCODataReferenceService _refs;
 9
 10    // Порядок попытки: сначала расходная, потом перемещение
 11    private static readonly (string header, string lines, string label)[] KnownDocTypes =
 12    [
 13        ("Document_РасходнаяНакладная",   "Document_РасходнаяНакладная_Запасы",   "Расходная накладная"),
 14        ("Document_ПеремещениеЗапасов",    "Document_ПеремещениеЗапасов_Запасы",    "Перемещение запасов"),
 15        ("Document_ПриходнаяНакладная",   "Document_ПриходнаяНакладная_Запасы",   "Приходная накладная"),
 16    ];
 17
 18    public OneCDocumentViewService(IOneCODataClient client, IOneCODataReferenceService refs)
 19    {
 20        _client = client;
 21        _refs = refs;
 22    }
 23
 24    public async Task<OneCDocumentDetails?> GetDocumentAsync(Guid refKey)
 25    {
 26        foreach (var (headerEndpoint, linesEndpoint, docLabel) in KnownDocTypes)
 27        {
 28            var result = await TryFetchDocumentAsync(refKey, headerEndpoint, linesEndpoint, docLabel);
 29            if (result != null) return result;
 30        }
 31        return null;
 32    }
 33
 34    public async Task<(Guid RefKey, OneCDocumentDetails Doc)?> FindByNumberAsync(string number)
 35    {
 36        var escaped = number.Replace("'", "''");
 37        foreach (var (headerEndpoint, _, _) in KnownDocTypes)
 38        {
 39            try
 40            {
 41                var rows = await _client.GetSinglePageAsync<ODataDocHeader>(
 42                    headerEndpoint, top: 1,
 43                    queryParams: new Dictionary<string, string>
 44                    {
 45                        ["$filter"] = $"Number eq '{escaped}'",
 46                        ["$select"] = "Ref_Key,Number"
 47                    });
 48                if (rows.Count == 0 || rows[0].RefKey == Guid.Empty) continue;
 49                var doc = await GetDocumentAsync(rows[0].RefKey);
 50                if (doc != null) return (rows[0].RefKey, doc);
 51            }
 52            catch { /* следующий тип */ }
 53        }
 54        return null;
 55    }
 56
 57    private async Task<OneCDocumentDetails?> TryFetchDocumentAsync(
 58        Guid refKey, string headerEndpoint, string linesEndpoint, string docLabel)
 59    {
 60        // Универсальная шапка — поля есть во всех типах документов
 61        var header = await _client.GetByGuidAsync<ODataGenericDocument>(
 62            headerEndpoint, refKey,
 63            "Ref_Key,Number,Date,Posted,DeletionMark,Организация_Key,СтруктурнаяЕдиница_Key,ВидОперации,СуммаДокумента,К
 64
 65        if (header == null || header.RefKey == Guid.Empty) return null;
 66
 67        // Дополнительные поля специфичные для расходной накладной
 68        ODataExpenseDocumentExtra? extra = null;
 69        if (headerEndpoint is "Document_РасходнаяНакладная" or "Document_ПриходнаяНакладная")
 70        {
 71            extra = await _client.GetByGuidAsync<ODataExpenseDocumentExtra>(
 72                headerEndpoint, refKey,
 73                "Ref_Key,Контрагент_Key,Договор_Key,СуммаНДС");
 74        }
 75
 76        // Для перемещения — получатель
 77        Guid warehouseRecipientKey = Guid.Empty;
 78        if (headerEndpoint == "Document_ПеремещениеЗапасов")
 79        {
 80            var transfer = await _client.GetByGuidAsync<ODataTransferDocument>(
 81                headerEndpoint, refKey,
 82                "Ref_Key,СтруктурнаяЕдиницаПолучатель_Key");
 83            warehouseRecipientKey = transfer?.WarehouseRecipientKey ?? Guid.Empty;
 84        }
 85
 86        var orgName = await ResolveNameAsync("Catalog_Организации", header.OrganizationKey);
 87        var warehouseName = await ResolveNameAsync("Catalog_СтруктурныеЕдиницы", header.WarehouseKey);
 88        var warehouseRecipientName = warehouseRecipientKey != Guid.Empty
 89            ? await ResolveNameAsync("Catalog_СтруктурныеЕдиницы", warehouseRecipientKey)
 90            : string.Empty;
 91        var counterpartyName = extra != null ? await ResolveNameAsync("Catalog_Контрагенты", extra.CounterpartyKey) : st
 92        var contractName = extra != null ? await ResolveNameAsync("Catalog_ДоговорыКонтрагентов", extra.ContractKey) : s
 93
 94        var lines = await _client.GetSinglePageAsync<ODataExpenseDocumentLine>(
 95            linesEndpoint,
 96            top: 200,
 97            queryParams: new Dictionary<string, string>
 98            {
 99                ["$filter"] = $"Ref_Key eq guid'{refKey}'",
 100                ["$orderby"] = "LineNumber"
 101            });
 102
 103        var resolvedLines = new List<OneCDocumentLineDetails>();
 104        foreach (var line in lines)
 105        {
 106            var nomName = string.Empty;
 107            var nomArticle = string.Empty;
 108            if (line.NomenclatureKey != Guid.Empty)
 109            {
 110                var nom = await _client.GetByGuidAsync<ODataNomenclatureFull>(
 111                    "Catalog_Номенклатура", line.NomenclatureKey, "Ref_Key,Description,Артикул");
 112                nomName = nom?.Description ?? string.Empty;
 113                nomArticle = nom?.Article ?? string.Empty;
 114            }
 115
 116            var charName = string.Empty;
 117            if (line.CharacteristicKey.HasValue && line.CharacteristicKey.Value != Guid.Empty)
 118                charName = await ResolveNameAsync("Catalog_ХарактеристикиНоменклатуры", line.CharacteristicKey.Value);
 119
 120            var batchName = string.Empty;
 121            if (line.BatchKey.HasValue && line.BatchKey.Value != Guid.Empty)
 122                batchName = await ResolveNameAsync("Catalog_ПартииНоменклатуры", line.BatchKey.Value);
 123
 124            var lineWhName = string.Empty;
 125            if (line.WarehouseKey != header.WarehouseKey && line.WarehouseKey != Guid.Empty)
 126                lineWhName = await ResolveNameAsync("Catalog_СтруктурныеЕдиницы", line.WarehouseKey);
 127
 128            resolvedLines.Add(new OneCDocumentLineDetails
 129            {
 130                LineNumber = line.LineNumber,
 131                NomenclatureName = nomName,
 132                NomenclatureArticle = nomArticle,
 133                CharacteristicName = charName,
 134                BatchName = batchName,
 135                WarehouseName = lineWhName,
 136                Quantity = line.Quantity,
 137                Price = line.Price,
 138                Amount = line.Amount,
 139                VatAmount = line.VatAmount,
 140            });
 141        }
 142
 143        return new OneCDocumentDetails
 144        {
 145            RefKey = refKey,
 146            DocTypeLabel = docLabel,
 147            Number = header.Number,
 148            Date = ParseDate(header.Date),
 149            Posted = header.Posted,
 150            DeletionMark = header.DeletionMark,
 151            CounterpartyName = counterpartyName,
 152            ContractName = contractName,
 153            OrganizationName = orgName,
 154            WarehouseName = warehouseName,
 155            WarehouseRecipientName = warehouseRecipientName,
 156            OperationKind = header.OperationKind,
 157            Comment = header.Comment,
 158            TotalAmount = header.TotalAmount,
 159            VatAmount = extra?.VatAmount ?? 0,
 160            Lines = resolvedLines,
 161        };
 162    }
 163
 164    private async Task<string> ResolveNameAsync(string catalog, Guid guid)
 165    {
 166        if (guid == Guid.Empty) return string.Empty;
 167        try
 168        {
 169            var item = await _client.GetByGuidAsync<ODataNamedItem>(catalog, guid, "Ref_Key,Description");
 170            return item?.Description ?? string.Empty;
 171        }
 172        catch
 173        {
 174            return string.Empty;
 175        }
 176    }
 177
 178    private static DateTime? ParseDate(string raw)
 179    {
 180        if (string.IsNullOrWhiteSpace(raw)) return null;
 181        if (DateTime.TryParse(raw, out var dt)) return dt;
 182        return null;
 183    }
 184}
 185
 186// Общие поля есть в любом типе документа
 187file class ODataGenericDocument
 188{
 189    [Newtonsoft.Json.JsonProperty("Ref_Key")] public Guid RefKey { get; set; }
 190    [Newtonsoft.Json.JsonProperty("Number")] public string Number { get; set; } = string.Empty;
 191    [Newtonsoft.Json.JsonProperty("Date")] public string Date { get; set; } = string.Empty;
 192    [Newtonsoft.Json.JsonProperty("Posted")] public bool Posted { get; set; }
 193    [Newtonsoft.Json.JsonProperty("DeletionMark")] public bool DeletionMark { get; set; }
 194    [Newtonsoft.Json.JsonProperty("Организация_Key")] public Guid OrganizationKey { get; set; }
 195    [Newtonsoft.Json.JsonProperty("СтруктурнаяЕдиница_Key")] public Guid WarehouseKey { get; set; }
 196    [Newtonsoft.Json.JsonProperty("ВидОперации")] public string OperationKind { get; set; } = string.Empty;
 197    [Newtonsoft.Json.JsonProperty("СуммаДокумента")] public decimal TotalAmount { get; set; }
 198    [Newtonsoft.Json.JsonProperty("Комментарий")] public string? Comment { get; set; }
 199}
 200
 201// Дополнительные поля только расходной накладной
 202file class ODataExpenseDocumentExtra
 203{
 204    [Newtonsoft.Json.JsonProperty("Ref_Key")] public Guid RefKey { get; set; }
 205    [Newtonsoft.Json.JsonProperty("Контрагент_Key")] public Guid CounterpartyKey { get; set; }
 206    [Newtonsoft.Json.JsonProperty("Договор_Key")] public Guid ContractKey { get; set; }
 207    [Newtonsoft.Json.JsonProperty("СуммаНДС")] public decimal VatAmount { get; set; }
 208}
 209
 210file class ODataNamedItem
 211{
 212    [Newtonsoft.Json.JsonProperty("Description")]
 213    public string Description { get; set; } = string.Empty;
 214}
 215
 216public class OneCDocumentDetails
 217{
 0218    public Guid RefKey { get; set; }
 0219    public string DocTypeLabel { get; set; } = string.Empty;
 0220    public string Number { get; set; } = string.Empty;
 0221    public DateTime? Date { get; set; }
 0222    public bool Posted { get; set; }
 0223    public bool DeletionMark { get; set; }
 0224    public string CounterpartyName { get; set; } = string.Empty;
 0225    public string ContractName { get; set; } = string.Empty;
 0226    public string OrganizationName { get; set; } = string.Empty;
 0227    public string WarehouseName { get; set; } = string.Empty;
 0228    public string WarehouseRecipientName { get; set; } = string.Empty;
 0229    public string OperationKind { get; set; } = string.Empty;
 0230    public string? Comment { get; set; }
 0231    public decimal TotalAmount { get; set; }
 0232    public decimal VatAmount { get; set; }
 0233    public List<OneCDocumentLineDetails> Lines { get; set; } = new();
 234}
 235
 236public class OneCDocumentLineDetails
 237{
 238    public int LineNumber { get; set; }
 239    public string NomenclatureName { get; set; } = string.Empty;
 240    public string NomenclatureArticle { get; set; } = string.Empty;
 241    public string CharacteristicName { get; set; } = string.Empty;
 242    public string BatchName { get; set; } = string.Empty;
 243    public string WarehouseName { get; set; } = string.Empty;
 244    public decimal Quantity { get; set; }
 245    public decimal Price { get; set; }
 246    public decimal Amount { get; set; }
 247    public decimal VatAmount { get; set; }
 248}