/
rezvich
/
Prik
Обзор
Документация
Войти
/
rezvich
/
Prik
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
Application/SmpAttachService.cs
152 строки
5 KB
waweda299
Прик
08 июн 2026, 15:52
08 июн 2026, 15:52
9ddc25e
Код
Авторство
О чём код?
// prik/Application/SmpAttachService.cs using Microsoft.Extensions.Logging; using prik.Domain; using prik.Infrastructure.Db; using prik.Infrastructure.Refs; using prik.Infrastructure.Settings; using prik.Infrastructure.Soap; namespace prik.Application { public interface ISmpAttachService { Task RunAsync(List<PrikRow> rows, CancellationToken ct); } public sealed class SmpAttachService : ISmpAttachService { private readonly ILogger<SmpAttachService> _log; private readonly AppSettings _cfg; private readonly IDbConnectionFactory _db; private readonly ILpuRefsRepository _repo; private readonly IRefFileResolver _refs; private readonly IExcelEnpListLoader _excel; private readonly ISoapClient _soap; private readonly FerzlParser _parser; public SmpAttachService( ILogger<SmpAttachService> log, AppSettings cfg, IDbConnectionFactory db, ILpuRefsRepository repo, IRefFileResolver refs, IExcelEnpListLoader excel, ISoapClient soap, FerzlParser parser) { _log = log; _cfg = cfg; _db = db; _repo = repo; _refs = refs; _excel = excel; _soap = soap; _parser = parser; } public async Task RunAsync(List<PrikRow> rows, CancellationToken ct) { var target = rows .Where(r => r.AreaType == 1 && r.Comment == "OK") .ToList(); if (target.Count == 0) { return; } // refs (один раз на пачку) var rr = _refs.Resolve(_cfg.Pipeline.RefDir); var enpNartan = _excel.LoadEnpSet(rr.NartanPath, "enp"); Dictionary<string, string> lpuStruct; Dictionary<string, OidSmpRow> oids; using (var conn = _db.Create()) { conn.Open(); lpuStruct = await _repo.LoadLpuStructAsync(conn, ct); oids = await _repo.LoadOidsSmpAsync(conn, ct); } var max = Math.Min(_cfg.Pipeline.MaxWorkers, 10); using var sem = new SemaphoreSlim(max, max); var tasks = target.Select(async row => { await sem.WaitAsync(ct); try { row.CommentSmp = await ProcessOneAsync(row, lpuStruct, oids, enpNartan, ct); } catch (Exception ex) { row.CommentSmp = "SMP: " + ex.Message; } finally { sem.Release(); } }); await Task.WhenAll(tasks); var ok = target.Count(r => r.CommentSmp == "OK"); var err = target.Count(r => r.CommentSmp is not null && r.CommentSmp != "OK"); _log.LogInformation("SMP attach done. total={Total} ok={Ok} err={Err}. refs: nartan={Nartan}", target.Count, ok, err, rr.NartanPath); } private async Task<string> ProcessOneAsync( PrikRow row, Dictionary<string, string> lpuStruct, Dictionary<string, OidSmpRow> oids, HashSet<string> enpNartan, CancellationToken ct) { if (string.IsNullOrWhiteSpace(row.Enp)) { return "СМП: нет ENP"; } var lpuT = (row.Lpu ?? "").Trim(); var enp = row.Enp.Trim(); var codeMo = CalcSmpMoCode(lpuT, enp, lpuStruct, enpNartan); if (string.IsNullOrWhiteSpace(codeMo)) { return $"СМП: не найден lpu_s/Code_MO для lpu_t={lpuT}"; } if (!oids.TryGetValue(codeMo, out var oidRow) || string.IsNullOrWhiteSpace(oidRow.OidSmp)) { return $"СМП: не найден OID_SMP для Code_MO={codeMo}"; } var moDepId = oidRow.OidSmp.Trim(); var moId = oidRow.MoId.Trim(); var (extId, xml) = SmpAttachXmlBuilder.BuildRegisterAttachSmp( row: row, moCode: codeMo, moId: moId, moDepId: moDepId); var resp = await _soap.PostAsync(_cfg.Soap.AttachUrl, xml, "registerAttachSMP", extId, ct); var err = _parser.ParseErrorMessage(resp); // "менее 1 года" — это не ошибка, запись фактически встала return SoapErrorRules.IsAttachLessThanYear(err) ? "OK" : err ?? "OK"; } private static string? CalcSmpMoCode( string lpuT, string enp, Dictionary<string, string> lpuTToLpuS, HashSet<string> enpNartan) { return lpuT == "070906" && enpNartan.Contains(enp) ? "070597" : lpuTToLpuS.TryGetValue(lpuT, out var v) ? v : null; } } }