using System.ComponentModel.DataAnnotations;
namespace Domain.Entities.Stocks;
///
/// SEIBro 파생결합증권 상환종목 (getRedIsinInfo) — 상환일별 상환종목·수량 (Wave 5). 자연키 UNIQUE (Isin, RedDt, DerisecExerTpcd).
/// 상환일(RED_DT) × 종류(SECN_KACD{4101/4102/4301/4302}) 날짜 스윕으로 수집. 응답 필드는 Isin·DerisecExerTpcd·RedQty 3종.
/// 응답에 없는 RedDt·SecnKacd 는 요청 파라미터를 배치가 스탬핑한다. 같은 상환일에 만기·조기(2/3) 두 건 가능하여 (Isin, RedDt, DerisecExerTpcd) 로 구분.
///
public class DerivRedemption
{
[Key]
public int ID { get; private set; }
/// 종목코드 (ISIN)
public string Isin { get; private set; } = default!;
/// 파생증권권리행사구분코드 (DERISEC_EXER_TPCD) — 2만기상환 3조기상환
public string DerisecExerTpcd { get; private set; } = default!;
/// 상환수량 (RED_QTY)
public decimal? RedQty { get; private set; }
/// 상환일자 (RED_DT, 요청값 스탬핑)
public DateOnly RedDt { get; private set; }
/// 종목종류코드 (SECN_KACD, 요청값 스탬핑) — 4101ELS 4102ELB 4301DLS 4302DLB
public string SecnKacd { get; private set; } = default!;
public DateTime UpdatedAt { get; private set; } = DateTime.UtcNow;
private DerivRedemption() { }
public static DerivRedemption Create(string isin, string derisecExerTpcd, decimal? redQty, DateOnly redDt, string secnKacd)
{
if (string.IsNullOrWhiteSpace(isin))
{
throw new ArgumentException("isin required", nameof(isin));
}
return new DerivRedemption
{
Isin = isin.Trim(),
DerisecExerTpcd = derisecExerTpcd.Trim(),
RedQty = redQty,
RedDt = redDt,
SecnKacd = secnKacd.Trim()
};
}
/// 재수집 반영 — 변경 필드가 있을 때만 UpdatedAt 갱신 (자연키 Isin/RedDt/DerisecExerTpcd 은 불변)
public void Update(decimal? redQty, string secnKacd)
{
var changed = false;
changed |= Set(redQty, RedQty, v => RedQty = v);
changed |= Set(secnKacd.Trim(), SecnKacd, v => SecnKacd = v);
if (changed)
{
UpdatedAt = DateTime.UtcNow;
}
}
private static bool Set(T incoming, T current, Action assign)
{
if (EqualityComparer.Default.Equals(incoming, current))
{
return false;
}
assign(incoming);
return true;
}
}