< Summary

Information
Class: OzonOrdersWeb.WebServices.ArmtekEtp.SettlementSupplierSummary
Assembly: OzonOrdersWeb
File(s): /home/runner/work/Studio2Prod/Studio2Prod/OzonOrdersWeb/WebServices/ArmtekEtp/SettlementSuppliersOverview.cs
Line coverage
0%
Covered lines: 0
Uncovered lines: 10
Coverable lines: 10
Total lines: 104
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
.ctor(...)100%210%
get_SettlementsCount()100%210%
get_InvoicesCount()100%210%
get_ItemsCount()100%210%
get_LastUpdatedAtUtc()100%210%
get_LastError()100%210%
get_LastErrorAtUtc()100%210%
get_Balance()100%210%
get_BalanceCurrency()100%210%
get_BalanceDate()100%210%

File(s)

/home/runner/work/Studio2Prod/Studio2Prod/OzonOrdersWeb/WebServices/ArmtekEtp/SettlementSuppliersOverview.cs

#LineLine coverage
 1using Microsoft.EntityFrameworkCore;
 2using OzonRepositories.Context;
 3
 4namespace OzonOrdersWeb.WebServices.ArmtekEtp;
 5
 6/// <summary>Сводка взаиморасчётов одного поставщика: сальдо по последнему документу, объёмы и время обновления.</summar
 07public sealed record SettlementSupplierSummary(
 08    int SettlementsCount,
 09    int InvoicesCount,
 010    int ItemsCount,
 011    DateTime? LastUpdatedAtUtc,
 012    string? LastError,
 013    DateTime? LastErrorAtUtc,
 014    decimal? Balance,
 015    string? BalanceCurrency,
 016    DateTime? BalanceDate);
 17
 18/// <summary>Плашка поставщика на странице /Settlements.</summary>
 19public sealed record SettlementSupplierTile(
 20    string Key,
 21    string Name,
 22    string LogoUrl,
 23    string? LogoMark,
 24    string Description,
 25    string Url,
 26    SettlementSupplierSummary Summary,
 27    IReadOnlyList<(string Title, string Icon, string Url)> Links);
 28
 29/// <summary>
 30/// Поставщики раздела «Взаиморасчёты». Сейчас только Armtek (кабинет etp.armtek.ru); следующий поставщик добавляется
 31/// своей плашкой в <see cref="GetTilesAsync"/>.
 32/// </summary>
 33public sealed class SettlementSuppliersOverview(ApplicationDbContext db, IConfiguration configuration)
 34{
 35    /// <summary>Расписание автозагрузки для подписи на страницах: «каждый день в 07:00 (МСК)» или выражение cron как ес
 36    public string ScheduleText
 37    {
 38        get
 39        {
 40            if (!configuration.GetValue("ArmtekEtp:Enabled", false))
 41                return "автозагрузка выключена";
 42            var cron = configuration["ArmtekEtp:Cron"] is { Length: > 0 } c ? c : Services.ArmtekEtpServices.ArmtekEtpSy
 43            var parts = cron.Split(' ', StringSplitOptions.RemoveEmptyEntries);
 44            return parts.Length == 5 && parts[2] == "*" && parts[3] == "*" && parts[4] == "*"
 45                && int.TryParse(parts[0], out var minute) && int.TryParse(parts[1], out var hour)
 46                ? $"каждый день в {hour:00}:{minute:00} (МСК)"
 47                : $"по расписанию {cron} (МСК)";
 48        }
 49    }
 50
 51    public async Task<SettlementSupplierSummary> GetArmtekSummaryAsync(CancellationToken ct = default)
 52    {
 53        var last = await db.ArmtekSettlements.AsNoTracking()
 54            .Where(x => x.Balance != null)
 55            .OrderByDescending(x => x.DocDate).ThenByDescending(x => x.Id)
 56            .Select(x => new { x.Balance, x.Currency, x.DocDate })
 57            .FirstOrDefaultAsync(ct);
 58
 59        // «Обновлено» — время последней успешной загрузки, даже если новых документов не было.
 60        var lastSuccess = await db.ArmtekEtpSyncRuns.AsNoTracking()
 61            .Where(x => x.Success == true)
 62            .MaxAsync(x => x.FinishedAtUtc, ct);
 63        // Предупреждение — по последнему завершённому запуску: его ошибка или то, что взаиморасчёты из кабинета
 64        // не обновились (фактуры по API при этом загружены).
 65        var lastRun = await db.ArmtekEtpSyncRuns.AsNoTracking()
 66            .Where(x => x.FinishedAtUtc != null)
 67            .OrderByDescending(x => x.FinishedAtUtc)
 68            .Select(x => new { x.Success, x.Message, x.SettlementsError, x.FinishedAtUtc })
 69            .FirstOrDefaultAsync(ct);
 70        var lastFailure = lastRun == null ? null
 71            : lastRun.Success == false ? new { lastRun.Message, lastRun.FinishedAtUtc }
 72            : lastRun.SettlementsError != null ? new { Message = (string?)("Взаиморасчёты из кабинета не обновлены: " + 
 73            : null;
 74
 75        return new SettlementSupplierSummary(
 76            await db.ArmtekSettlements.CountAsync(ct),
 77            await db.ArmtekInvoices.CountAsync(ct),
 78            await db.ArmtekInvoiceItems.CountAsync(ct),
 79            lastSuccess ?? await db.ArmtekSettlements.MaxAsync(x => (DateTime?)x.UpdatedAtUtc, ct),
 80            lastFailure?.Message,
 81            lastFailure?.FinishedAtUtc,
 82            last?.Balance,
 83            last?.Currency,
 84            last?.DocDate);
 85    }
 86
 87    public async Task<IReadOnlyList<SettlementSupplierTile>> GetTilesAsync(CancellationToken ct = default)
 88    {
 89        const string armtek = "/Settlements/Armtek";
 90        return
 91        [
 92            new SettlementSupplierTile(
 93                "Armtek", "Армтек", "/images/armtek-logo.svg", "BY",
 94                "Взаиморасчёты, фактуры и позиции из личного кабинета etp.armtek.ru, автозагрузка " + ScheduleText,
 95                armtek,
 96                await GetArmtekSummaryAsync(ct),
 97                [
 98                    ("Взаиморасчёты", "fa-scale-balanced", armtek + "?tab=settlements"),
 99                    ("Фактуры", "fa-file-invoice", armtek + "?tab=invoices"),
 100                    ("Позиции фактур", "fa-list", armtek + "?tab=items")
 101                ])
 102        ];
 103    }
 104}