< Summary

Information
Class: OzonOrdersWeb.WebServices.ArmtekEtp.SettlementSupplierTile
Assembly: OzonOrdersWeb
File(s): /home/runner/work/Studio2Prod/Studio2Prod/OzonOrdersWeb/WebServices/ArmtekEtp/SettlementSuppliersOverview.cs
Line coverage
0%
Covered lines: 0
Uncovered lines: 9
Coverable lines: 9
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_Key()100%210%
get_Name()100%210%
get_LogoUrl()100%210%
get_LogoMark()100%210%
get_Description()100%210%
get_Url()100%210%
get_Summary()100%210%
get_Links()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
 7public sealed record SettlementSupplierSummary(
 8    int SettlementsCount,
 9    int InvoicesCount,
 10    int ItemsCount,
 11    DateTime? LastUpdatedAtUtc,
 12    string? LastError,
 13    DateTime? LastErrorAtUtc,
 14    decimal? Balance,
 15    string? BalanceCurrency,
 16    DateTime? BalanceDate);
 17
 18/// <summary>Плашка поставщика на странице /Settlements.</summary>
 019public sealed record SettlementSupplierTile(
 020    string Key,
 021    string Name,
 022    string LogoUrl,
 023    string? LogoMark,
 024    string Description,
 025    string Url,
 026    SettlementSupplierSummary Summary,
 027    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}