| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140 |
- using Application.Abstractions.Data;
- using Domain.Entities.Stocks;
- using Microsoft.EntityFrameworkCore;
- namespace Infrastructure.StockData;
- /// <summary>
- /// SeibroDividendSyncService 의 DB 반영 로직 분리 (테스트 가능) — HTTP 없이 파서 출력(fixture)으로 검증한다
- /// (SeibroIssuerImport 패턴 미러링). 세 엔티티(DividendSchedule/Dividend/RightsBaseDate) upsert 를 담당한다.
- /// </summary>
- public static class SeibroDividendImport
- {
- /// <summary>
- /// getDivSchedulInfo 결과를 DividendSchedule 로 upsert — UQ (IssucoCustno, RgtStdDt, RgtRsnDetailSortCd).
- /// 한 번의 호출로 들어온 rows 를 한 트랜잭션으로 반영한다 (날짜 스윕: 그날 여러 회사·유형).
- /// </summary>
- public static async Task<(int Inserted, int Updated)> UpsertSchedulesAsync(IAppDbContext db, IReadOnlyList<SeibroDivSchedulParser.Row> rows, CancellationToken ct)
- {
- if (rows.Count == 0)
- {
- return (0, 0);
- }
- var custnos = rows.Select(c => c.IssucoCustno).Distinct().ToList();
- var existing = await db.DividendSchedule.Where(c => custnos.Contains(c.IssucoCustno)).ToListAsync(ct);
- var byKey = existing.ToDictionary(c => (c.IssucoCustno, c.RgtStdDt, c.RgtRsnDetailSortCd));
- var inserted = 0;
- var updated = 0;
- foreach (var row in rows)
- {
- var key = (row.IssucoCustno, row.RgtStdDt, row.RgtRsnDetailSortCd);
- if (byKey.TryGetValue(key, out var entity))
- {
- var was = entity.UpdatedAt;
- entity.Update(row.RepSecnNm, row.RgtRacd, row.AllocWhcd, row.SetaccTpcd, row.FixTpcd, row.RostCloseBeginDt, row.RostCloseExpryDt, row.XrgtDt, row.IsElectronicSecurity);
- if (entity.UpdatedAt != was)
- {
- updated++;
- }
- }
- else
- {
- var created = DividendSchedule.Create(row.IssucoCustno, row.RepSecnNm, row.RgtRacd, row.RgtRsnDetailSortCd, row.RgtStdDt, row.AllocWhcd, row.SetaccTpcd, row.FixTpcd, row.RostCloseBeginDt, row.RostCloseExpryDt, row.XrgtDt, row.IsElectronicSecurity);
- await db.DividendSchedule.AddAsync(created, ct);
- byKey[key] = created;
- inserted++;
- }
- }
- await db.SaveChangesAsync(ct);
- return (inserted, updated);
- }
- /// <summary>
- /// getDivInfo 결과를 Dividend 로 upsert — UQ (Isin, RgtStdDt). rows 는 한 회사(회사번호) 3년치 배당 이력.
- /// </summary>
- public static async Task<(int Inserted, int Updated)> UpsertDividendsAsync(IAppDbContext db, IReadOnlyList<SeibroDivInfoParser.Row> rows, CancellationToken ct)
- {
- if (rows.Count == 0)
- {
- return (0, 0);
- }
- var isins = rows.Select(c => c.Isin).Distinct().ToList();
- var existing = await db.Dividend.Where(c => isins.Contains(c.Isin)).ToListAsync(ct);
- var byKey = existing.ToDictionary(c => (c.Isin, c.RgtStdDt));
- var inserted = 0;
- var updated = 0;
- foreach (var row in rows)
- {
- var key = (row.Isin, row.RgtStdDt);
- if (byKey.TryGetValue(key, out var entity))
- {
- var was = entity.UpdatedAt;
- entity.Update(row.KorSecnNm, row.SecnKacdNm, row.Pval, row.StkAllocRatio, row.CashAllocRatio, row.CashAllocAmt, row.MartpDivRate, row.Th1PayTermBeginDt, row.DeliDt, row.MajshrEtcDiffAllocYn, row.TstkNoagnYn, row.CashDiffDiviAmt, row.CashDiffDiviRate, row.StkDiffDiviRate, row.MartpDiffDiviRate);
- if (entity.UpdatedAt != was)
- {
- updated++;
- }
- }
- else
- {
- var created = Dividend.Create(row.Isin, row.KorSecnNm, row.SecnKacdNm, row.RgtStdDt, row.Pval, row.StkAllocRatio, row.CashAllocRatio, row.CashAllocAmt, row.MartpDivRate, row.Th1PayTermBeginDt, row.DeliDt, row.MajshrEtcDiffAllocYn, row.TstkNoagnYn, row.CashDiffDiviAmt, row.CashDiffDiviRate, row.StkDiffDiviRate, row.MartpDiffDiviRate);
- await db.Dividend.AddAsync(created, ct);
- byKey[key] = created;
- inserted++;
- }
- }
- await db.SaveChangesAsync(ct);
- return (inserted, updated);
- }
- /// <summary>
- /// getStddtInfo 결과를 RightsBaseDate 로 upsert — UQ (IssucoCustno, RgtStdDt, RgtRacd, RgtRsnDetailSortCd).
- /// rows 는 한 회사 3년치 권리기준일.
- /// </summary>
- public static async Task<(int Inserted, int Updated)> UpsertRightsBaseDatesAsync(IAppDbContext db, IReadOnlyList<SeibroStddtParser.Row> rows, CancellationToken ct)
- {
- if (rows.Count == 0)
- {
- return (0, 0);
- }
- var custnos = rows.Select(c => c.IssucoCustno).Distinct().ToList();
- var existing = await db.RightsBaseDate.Where(c => custnos.Contains(c.IssucoCustno)).ToListAsync(ct);
- var byKey = existing.ToDictionary(c => (c.IssucoCustno, c.RgtStdDt, c.RgtRacd, c.RgtRsnDetailSortCd));
- var inserted = 0;
- var updated = 0;
- foreach (var row in rows)
- {
- var key = (row.IssucoCustno, row.RgtStdDt, row.RgtRacd, row.RgtRsnDetailSortCd);
- if (byKey.TryGetValue(key, out var entity))
- {
- var was = entity.UpdatedAt;
- entity.Update(row.RepSecnNm, row.RgtRacdNm);
- if (entity.UpdatedAt != was)
- {
- updated++;
- }
- }
- else
- {
- var created = RightsBaseDate.Create(row.IssucoCustno, row.RepSecnNm, row.RgtStdDt, row.RgtRacd, row.RgtRacdNm, row.RgtRsnDetailSortCd);
- await db.RightsBaseDate.AddAsync(created, ct);
- byKey[key] = created;
- inserted++;
- }
- }
- await db.SaveChangesAsync(ct);
- return (inserted, updated);
- }
- }
|