using Application.Abstractions.Data;
using Domain.Entities.Stocks;
using Microsoft.EntityFrameworkCore;
namespace Infrastructure.StockData;
///
/// SeibroDividendSyncService 의 DB 반영 로직 분리 (테스트 가능) — HTTP 없이 파서 출력(fixture)으로 검증한다
/// (SeibroIssuerImport 패턴 미러링). 세 엔티티(DividendSchedule/Dividend/RightsBaseDate) upsert 를 담당한다.
///
public static class SeibroDividendImport
{
///
/// getDivSchedulInfo 결과를 DividendSchedule 로 upsert — UQ (IssucoCustno, RgtStdDt, RgtRsnDetailSortCd).
/// 한 번의 호출로 들어온 rows 를 한 트랜잭션으로 반영한다 (날짜 스윕: 그날 여러 회사·유형).
///
public static async Task<(int Inserted, int Updated)> UpsertSchedulesAsync(IAppDbContext db, IReadOnlyList 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);
}
///
/// getDivInfo 결과를 Dividend 로 upsert — UQ (Isin, RgtStdDt). rows 는 한 회사(회사번호) 3년치 배당 이력.
///
public static async Task<(int Inserted, int Updated)> UpsertDividendsAsync(IAppDbContext db, IReadOnlyList 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);
}
///
/// getStddtInfo 결과를 RightsBaseDate 로 upsert — UQ (IssucoCustno, RgtStdDt, RgtRacd, RgtRsnDetailSortCd).
/// rows 는 한 회사 3년치 권리기준일.
///
public static async Task<(int Inserted, int Updated)> UpsertRightsBaseDatesAsync(IAppDbContext db, IReadOnlyList 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);
}
}