using System.ComponentModel.DataAnnotations;
namespace Domain.Entities.Stocks;
///
/// SEIBro 배당분배금내역 (getDivInfo) — 종목별 배정비율·금액·시가배당율·차등배당 (Wave 1 ★P0).
/// 자연키 UNIQUE (Isin, RgtStdDt) — 한 종목·권리기준일당 1행.
/// ⚠️ getDivInfo 응답엔 ISSUCO_CUSTNO 가 없다(샘플 확인) — 종목 조인은 Isin 으로 Stock.ISIN 을 맞춘다.
/// 소수 precision 은 스펙(NUMBER(30,20)/(23,18)) 을 SQL Server decimal 최대(38,x) 안에서 decimal(28,10) 로 안전 설정.
///
public class Dividend
{
[Key]
public int ID { get; private set; }
/// 종목번호 (ISIN)
public string Isin { get; private set; } = default!;
/// 한글종목명 (KOR_SECN_NM)
public string KorSecnNm { get; private set; } = default!;
/// 종목종류 (SECN_KACD_NM) — 보통주/우선주/2우선주… 문자열
public string? SecnKacdNm { get; private set; }
/// 권리기준일자 (RGT_STD_DT)
public DateOnly RgtStdDt { get; private set; }
/// 액면가 (PVAL)
public decimal? Pval { get; private set; }
/// 주식배정비율 (STK_ALOC_RATIO)
public decimal? StkAllocRatio { get; private set; }
/// 현금배정비율 (CASH_ALOC_RATIO)
public decimal? CashAllocRatio { get; private set; }
/// 현금배정금액 (CASH_ALOC_AMT) — 1주당 현금배당(원)
public decimal? CashAllocAmt { get; private set; }
/// 시가배당율 (MARTP_DIV_RATE)
public decimal? MartpDivRate { get; private set; }
/// 배당지급일(현금 1차지급시작일, TH1_PAY_TERM_BEGIN_DT)
public DateOnly? Th1PayTermBeginDt { get; private set; }
/// 교부일자(주식, DELI_DT)
public DateOnly? DeliDt { get; private set; }
/// 대주주기타차등배정여부 (MAJSHR_ETC_DIFF_ALOC_YN, Y/N) — 미제공 null
public bool? MajshrEtcDiffAllocYn { get; private set; }
/// 자사주무배정여부 (TSTK_NOAGN_YN, Y/N) — 미제공 null
public bool? TstkNoagnYn { get; private set; }
/// 현금차등배당금액 (CASH_DIFF_DIVIAMT_VAL)
public decimal? CashDiffDiviAmt { get; private set; }
/// 현금차등배당율 (CASH_DIFF_DIVI_RATE)
public decimal? CashDiffDiviRate { get; private set; }
/// 주식차등배당율 (STK_DIFF_DIVI_RATE)
public decimal? StkDiffDiviRate { get; private set; }
/// 시가차등배당율 (MARTP_DIFF_DIVI_RATE)
public decimal? MartpDiffDiviRate { get; private set; }
public DateTime UpdatedAt { get; private set; } = DateTime.UtcNow;
private Dividend() { }
public static Dividend Create(
string isin,
string korSecnNm,
string? secnKacdNm,
DateOnly rgtStdDt,
decimal? pval,
decimal? stkAllocRatio,
decimal? cashAllocRatio,
decimal? cashAllocAmt,
decimal? martpDivRate,
DateOnly? th1PayTermBeginDt,
DateOnly? deliDt,
bool? majshrEtcDiffAllocYn,
bool? tstkNoagnYn,
decimal? cashDiffDiviAmt,
decimal? cashDiffDiviRate,
decimal? stkDiffDiviRate,
decimal? martpDiffDiviRate)
{
if (string.IsNullOrWhiteSpace(isin))
{
throw new ArgumentException("isin required", nameof(isin));
}
if (string.IsNullOrWhiteSpace(korSecnNm))
{
throw new ArgumentException("korSecnNm required", nameof(korSecnNm));
}
return new Dividend
{
Isin = isin.Trim(),
KorSecnNm = korSecnNm.Trim(),
SecnKacdNm = string.IsNullOrWhiteSpace(secnKacdNm) ? null : secnKacdNm.Trim(),
RgtStdDt = rgtStdDt,
Pval = pval,
StkAllocRatio = stkAllocRatio,
CashAllocRatio = cashAllocRatio,
CashAllocAmt = cashAllocAmt,
MartpDivRate = martpDivRate,
Th1PayTermBeginDt = th1PayTermBeginDt,
DeliDt = deliDt,
MajshrEtcDiffAllocYn = majshrEtcDiffAllocYn,
TstkNoagnYn = tstkNoagnYn,
CashDiffDiviAmt = cashDiffDiviAmt,
CashDiffDiviRate = cashDiffDiviRate,
StkDiffDiviRate = stkDiffDiviRate,
MartpDiffDiviRate = martpDiffDiviRate
};
}
/// 재수집 반영 — 변경 필드가 있을 때만 UpdatedAt 갱신 (무변경 upsert 는 no-op)
public void Update(
string korSecnNm,
string? secnKacdNm,
decimal? pval,
decimal? stkAllocRatio,
decimal? cashAllocRatio,
decimal? cashAllocAmt,
decimal? martpDivRate,
DateOnly? th1PayTermBeginDt,
DateOnly? deliDt,
bool? majshrEtcDiffAllocYn,
bool? tstkNoagnYn,
decimal? cashDiffDiviAmt,
decimal? cashDiffDiviRate,
decimal? stkDiffDiviRate,
decimal? martpDiffDiviRate)
{
var changed = false;
if (!string.IsNullOrWhiteSpace(korSecnNm) && KorSecnNm != korSecnNm.Trim())
{
KorSecnNm = korSecnNm.Trim();
changed = true;
}
var normalizedSecnKacdNm = string.IsNullOrWhiteSpace(secnKacdNm) ? null : secnKacdNm.Trim();
if (SecnKacdNm != normalizedSecnKacdNm)
{
SecnKacdNm = normalizedSecnKacdNm;
changed = true;
}
if (Pval != pval)
{
Pval = pval;
changed = true;
}
if (StkAllocRatio != stkAllocRatio)
{
StkAllocRatio = stkAllocRatio;
changed = true;
}
if (CashAllocRatio != cashAllocRatio)
{
CashAllocRatio = cashAllocRatio;
changed = true;
}
if (CashAllocAmt != cashAllocAmt)
{
CashAllocAmt = cashAllocAmt;
changed = true;
}
if (MartpDivRate != martpDivRate)
{
MartpDivRate = martpDivRate;
changed = true;
}
if (Th1PayTermBeginDt != th1PayTermBeginDt)
{
Th1PayTermBeginDt = th1PayTermBeginDt;
changed = true;
}
if (DeliDt != deliDt)
{
DeliDt = deliDt;
changed = true;
}
if (MajshrEtcDiffAllocYn != majshrEtcDiffAllocYn)
{
MajshrEtcDiffAllocYn = majshrEtcDiffAllocYn;
changed = true;
}
if (TstkNoagnYn != tstkNoagnYn)
{
TstkNoagnYn = tstkNoagnYn;
changed = true;
}
if (CashDiffDiviAmt != cashDiffDiviAmt)
{
CashDiffDiviAmt = cashDiffDiviAmt;
changed = true;
}
if (CashDiffDiviRate != cashDiffDiviRate)
{
CashDiffDiviRate = cashDiffDiviRate;
changed = true;
}
if (StkDiffDiviRate != stkDiffDiviRate)
{
StkDiffDiviRate = stkDiffDiviRate;
changed = true;
}
if (MartpDiffDiviRate != martpDiffDiviRate)
{
MartpDiffDiviRate = martpDiffDiviRate;
changed = true;
}
if (changed)
{
UpdatedAt = DateTime.UtcNow;
}
}
}