< Summary

Information
Class: OzonOrdersWeb.WebServices.Transactions.ReceiptOriginRow
Assembly: OzonOrdersWeb
File(s): /home/runner/work/Studio2Prod/Studio2Prod/OzonOrdersWeb/WebServices/Transactions/ArmtekReceiptOriginService.cs
Line coverage
0%
Covered lines: 0
Uncovered lines: 2
Coverable lines: 2
Total lines: 91
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_OrderId()100%210%
get_Country()100%210%

File(s)

/home/runner/work/Studio2Prod/Studio2Prod/OzonOrdersWeb/WebServices/Transactions/ArmtekReceiptOriginService.cs

#LineLine coverage
 1using Microsoft.EntityFrameworkCore;
 2using OzonDomains.Models;
 3using OzonDomains.Models.ArmtekEtp;
 4using OzonRepositories.Context;
 5using Services.ApiServices._1CApi.OData;
 6
 7namespace OzonOrdersWeb.WebServices.Transactions;
 8
 09public sealed record ReceiptOriginRow(int OrderId, string Article, string? SourceCountry,
 010    string? Country, string? SourceGtd, string? Gtd, string? Error);
 11public sealed record ReceiptOriginPreview(bool Applicable, string? Error, IReadOnlyList<ReceiptOriginRow> Rows)
 12{
 13    public bool Ready => Applicable && Error == null && Rows.Count > 0 && Rows.All(r => r.Error == null);
 14}
 15
 16public sealed class ArmtekReceiptOriginService(ApplicationDbContext db, IOneCODataReferenceService references)
 17{
 18    /// <summary>Номер ГТД для товара без декларации (страна ЕАЭС, внутренние поставки): в фактуре «- -».</summary>
 19    public const string DefaultGtd = OneCODataConstants.DefaultGtdNumber;
 20
 21    /// <param name="manualDefaultGtd">
 22    /// Заказы, где пользователь сам вписал номер по умолчанию: он важнее фактуры и проверки справочника не требует.
 23    /// </param>
 24    public async Task<ReceiptOriginPreview> PreviewAsync(string? number, int[] ids, CancellationToken ct,
 25        IReadOnlySet<int>? manualDefaultGtd = null)
 26    {
 27        var links = await db.ArmtekOrderItems.AsNoTracking().Include(x => x.ArmtekOrder)
 28            .Where(x => ids.Contains(x.StudioOrderId)).ToListAsync(ct);
 29        if (links.Count == 0) return new(false, null, []);
 30        if (string.IsNullOrWhiteSpace(number)) return new(true, "Введите номер фактуры, УПД или ТТН Армтека.", []);
 31        var key = number.Trim();
 32        var invoices = await db.ArmtekInvoices.AsNoTracking().Include(x => x.Items)
 33            .Where(x => x.Vbeln == key || x.UpdNumber == key || x.TtnNumber == key).ToListAsync(ct);
 34        var rows = new List<ReceiptOriginRow>();
 35        foreach (var id in ids.Distinct())
 36        {
 37            var orderLinks = links.Where(x => x.StudioOrderId == id).ToList();
 38            var matches = invoices.SelectMany(invoice => invoice.Items.Where(item =>
 39                orderLinks.Any(link => Matches(link, invoice, item)))).ToList();
 40            if (matches.Count != 1)
 41            {
 42                rows.Add(new(id, orderLinks.FirstOrDefault()?.Pin ?? id.ToString(), null, null, null, null,
 43                    matches.Count == 0 ? "Позиция заказа не найдена в фактуре. Проверьте номер и загрузку фактуры."
 44                        : "В фактуре несколько подходящих позиций. Требуется уточнить партию."));
 45                continue;
 46            }
 47            var item = matches[0];
 48            var country = CountryName(item.Country);
 49            var declaredGtd = manualDefaultGtd?.Contains(id) == true ? null : DeclarationNumber(item.Gtd);
 50            var gtd = declaredGtd ?? DefaultGtd;
 51            var countryKey = await references.GetCountryGuidByNameAsync(country);
 52            var gtdKey = await references.GetGtdGuidByNumberAsync(gtd);
 53            // «Без ГТД» не требует записи в справочнике: приходная получит пустую ссылку.
 54            var gtdResolved = gtdKey is { } found && found != Guid.Empty || declaredGtd == null;
 55            var errors = new List<string>();
 56            if (countryKey == null || countryKey == Guid.Empty)
 57                errors.Add($"Страна «{item.Country}» не найдена в справочнике 1С");
 58            if (!gtdResolved)
 59                errors.Add($"ГТД «{gtd}» не найдена в справочнике 1С");
 60            rows.Add(new(id, item.Article ?? string.Empty, item.Country,
 61                countryKey.HasValue && countryKey != Guid.Empty ? country : null, item.Gtd,
 62                gtdResolved ? gtd : null,
 63                errors.Count == 0 ? null : string.Join(". ", errors)));
 64        }
 65        return new(true, null, rows);
 66    }
 67
 68    public static bool Matches(ArmtekOrderItem link, ArmtekInvoice invoice, ArmtekInvoiceItem item)
 69        => link.ArmtekOrder != null
 70           && Digits(link.ArmtekOrder.Kunrg) == Digits(invoice.Kunnr)
 71           && Digits(link.ArmtekOrder.Vbeln).Length > 0
 72           && Digits(link.ArmtekOrder.Vbeln) == Digits(item.OrderNumber)
 73           && Normalize(link.Pin).Length > 0 && Normalize(link.Pin) == Normalize(item.Article)
 74           && Normalize(link.Brand).Length > 0 && Normalize(link.Brand) == Normalize(item.Brand)
 75           && (string.IsNullOrWhiteSpace(link.Posnr) || string.IsNullOrWhiteSpace(item.OrderPosition)
 76               || Digits(link.Posnr) == Digits(item.OrderPosition));
 77
 78    public static string CountryName(string? value)
 79    {
 80        var text = value?.Trim() ?? string.Empty;
 81        // Формат Армтека: (CN, 156) Китай. Без названия код страны не угадываем.
 82        return text.StartsWith('(') && text.IndexOf(')') is var end && end >= 0
 83            ? text[(end + 1)..].Trim() : text;
 84    }
 85
 86    public static string? DeclarationNumber(string? value)
 87        => string.IsNullOrWhiteSpace(value) || !value.Any(char.IsDigit) ? null : value.Trim();
 88    private static string Digits(string? value) => (value ?? string.Empty).Trim().TrimStart('0');
 89    private static string Normalize(string? value)
 90        => string.Concat((value ?? string.Empty).Where(char.IsLetterOrDigit)).ToUpperInvariant();
 91}

Methods/Properties

get_OrderId()
get_Country()