SeibroIssuerImport.cs 2.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071
  1. using Application.Abstractions.Data;
  2. using Domain.Entities.Stocks;
  3. using Microsoft.EntityFrameworkCore;
  4. namespace Infrastructure.StockData;
  5. /// <summary>
  6. /// SeibroIssuerSyncService 의 DB 반영 로직 분리 (테스트 가능) — HTTP 없이 파서 출력(fixture)으로 검증한다
  7. /// (KRX 테스트들이 파서/로직을 분리 검증하는 방식 미러링).
  8. /// </summary>
  9. public static class SeibroIssuerImport
  10. {
  11. /// <summary>
  12. /// getShotnByMart 결과를 SeibroIssuerCode 로 upsert — UQ (Market, ShortCode) 기준.
  13. /// 동일 단축코드 중복 행은 마지막 행 우선. 무변경 행은 no-op (UpdatedAt 미갱신).
  14. /// </summary>
  15. public static async Task<(int Inserted, int Updated)> UpsertIssuerCodesAsync(IAppDbContext db, string market, IReadOnlyList<SeibroShotnByMartParser.Row> rows, CancellationToken ct)
  16. {
  17. var existing = await db.SeibroIssuerCode.Where(c => c.Market == market).ToListAsync(ct);
  18. var byShortCode = existing.ToDictionary(c => c.ShortCode);
  19. var inserted = 0;
  20. var updated = 0;
  21. foreach (var row in rows)
  22. {
  23. if (byShortCode.TryGetValue(row.ShortCode, out var code))
  24. {
  25. var was = code.UpdatedAt;
  26. code.Update(row.Name, row.IssucoCustno);
  27. if (code.UpdatedAt != was)
  28. {
  29. updated++;
  30. }
  31. }
  32. else
  33. {
  34. var created = SeibroIssuerCode.Create(market, row.ShortCode, row.Name, row.IssucoCustno);
  35. await db.SeibroIssuerCode.AddAsync(created, ct);
  36. byShortCode[row.ShortCode] = created;
  37. inserted++;
  38. }
  39. }
  40. await db.SaveChangesAsync(ct);
  41. return (inserted, updated);
  42. }
  43. /// <summary>
  44. /// Stock.IssucoCustno 스탬핑 — Stock.Code = 단축코드 조인. 이미 같은 값이면 무변경. 반환 = 실제 스탬핑된 종목 수.
  45. /// KRX Stock 은 KOSPI/KOSDAQ/KONEX 만 커버하므로 K-OTC(13) 등 미커버 시장 코드는 자연히 매칭되지 않는다.
  46. /// </summary>
  47. public static async Task<int> StampStockIssucoCustnoAsync(IAppDbContext db, IReadOnlyDictionary<string, int> custnoByShortCode, CancellationToken ct)
  48. {
  49. var stocks = await db.Stock.ToListAsync(ct);
  50. var stamped = 0;
  51. foreach (var stock in stocks)
  52. {
  53. if (!custnoByShortCode.TryGetValue(stock.Code, out var custno) || stock.IssucoCustno == custno)
  54. {
  55. continue;
  56. }
  57. stock.SetIssucoCustno(custno);
  58. stamped++;
  59. }
  60. await db.SaveChangesAsync(ct);
  61. return stamped;
  62. }
  63. }