using Application.Abstractions.Data; using Domain.Entities.Stocks; using Microsoft.EntityFrameworkCore; namespace Infrastructure.StockData; /// /// SeibroIssuerSyncService 의 DB 반영 로직 분리 (테스트 가능) — HTTP 없이 파서 출력(fixture)으로 검증한다 /// (KRX 테스트들이 파서/로직을 분리 검증하는 방식 미러링). /// public static class SeibroIssuerImport { /// /// getShotnByMart 결과를 SeibroIssuerCode 로 upsert — UQ (Market, ShortCode) 기준. /// 동일 단축코드 중복 행은 마지막 행 우선. 무변경 행은 no-op (UpdatedAt 미갱신). /// public static async Task<(int Inserted, int Updated)> UpsertIssuerCodesAsync(IAppDbContext db, string market, IReadOnlyList rows, CancellationToken ct) { var existing = await db.SeibroIssuerCode.Where(c => c.Market == market).ToListAsync(ct); var byShortCode = existing.ToDictionary(c => c.ShortCode); var inserted = 0; var updated = 0; foreach (var row in rows) { if (byShortCode.TryGetValue(row.ShortCode, out var code)) { var was = code.UpdatedAt; code.Update(row.Name, row.IssucoCustno); if (code.UpdatedAt != was) { updated++; } } else { var created = SeibroIssuerCode.Create(market, row.ShortCode, row.Name, row.IssucoCustno); await db.SeibroIssuerCode.AddAsync(created, ct); byShortCode[row.ShortCode] = created; inserted++; } } await db.SaveChangesAsync(ct); return (inserted, updated); } /// /// Stock.IssucoCustno 스탬핑 — Stock.Code = 단축코드 조인. 이미 같은 값이면 무변경. 반환 = 실제 스탬핑된 종목 수. /// KRX Stock 은 KOSPI/KOSDAQ/KONEX 만 커버하므로 K-OTC(13) 등 미커버 시장 코드는 자연히 매칭되지 않는다. /// public static async Task StampStockIssucoCustnoAsync(IAppDbContext db, IReadOnlyDictionary custnoByShortCode, CancellationToken ct) { var stocks = await db.Stock.ToListAsync(ct); var stamped = 0; foreach (var stock in stocks) { if (!custnoByShortCode.TryGetValue(stock.Code, out var custno) || stock.IssucoCustno == custno) { continue; } stock.SetIssucoCustno(custno); stamped++; } await db.SaveChangesAsync(ct); return stamped; } }