using System.ComponentModel.DataAnnotations; namespace Domain.Entities.Stocks; /// /// SEIBro 배당일정 (getDivSchedulInfo) — 현금/주식/동시/무배당 일정·명부폐쇄·권리락일 (Wave 1 ★P0). /// 자연키 UNIQUE (IssucoCustno, RgtStdDt, RgtRsnDetailSortCd) — 한 회사·기준일에 배당 세부유형이 여럿(주식+현금 동시 등) 존재할 수 있다. /// 날짜 스윕(getDivSchedulInfo, custno 미지정 → 그날 전체 회사)으로 수집한다. /// public class DividendSchedule { [Key] public int ID { get; private set; } /// 발행회사 고객번호 (ISSUCO_CUSTNO) public int IssucoCustno { get; private set; } /// 대표종목명 (REP_SECN_NM) public string RepSecnNm { get; private set; } = default!; /// 권리사유코드 (RGT_RACD) — 103 배당/분배 public string? RgtRacd { get; private set; } /// 권리사유세부유형코드 (RGT_RSN_DTAIL_SORT_CD) — 01주식 02현금 03동시 04무배당 public string RgtRsnDetailSortCd { get; private set; } = default!; /// 권리기준일자 (RGT_STD_DT) public DateOnly RgtStdDt { get; private set; } /// 배정방법코드 (ALOC_WHCD) — 1정율 2정액 3정율+정액 public string? AllocWhcd { get; private set; } /// 결산구분코드 (SETACC_TPCD) — 1결산 2반기 3분기 public string? SetaccTpcd { get; private set; } /// 확정구분코드 (FIX_TPCD) — 1확정 2예고 3미정 public string? FixTpcd { get; private set; } /// 명부폐쇄시작일자 (ROST_CLOSE_BEGIN_DT) public DateOnly? RostCloseBeginDt { get; private set; } /// 명부폐쇄종료일자 (ROST_CLOSE_EXPRY_DT) public DateOnly? RostCloseExpryDt { get; private set; } /// 권리락일자 (XRGT_DT) public DateOnly? XrgtDt { get; private set; } /// 전자증권 여부 (ELTSC_YN, Y=전자/N=예탁) — 미제공 null public bool? IsElectronicSecurity { get; private set; } public DateTime UpdatedAt { get; private set; } = DateTime.UtcNow; private DividendSchedule() { } public static DividendSchedule Create( int issucoCustno, string repSecnNm, string? rgtRacd, string rgtRsnDetailSortCd, DateOnly rgtStdDt, string? allocWhcd, string? setaccTpcd, string? fixTpcd, DateOnly? rostCloseBeginDt, DateOnly? rostCloseExpryDt, DateOnly? xrgtDt, bool? isElectronicSecurity) { if (string.IsNullOrWhiteSpace(repSecnNm)) { throw new ArgumentException("repSecnNm required", nameof(repSecnNm)); } if (string.IsNullOrWhiteSpace(rgtRsnDetailSortCd)) { throw new ArgumentException("rgtRsnDetailSortCd required", nameof(rgtRsnDetailSortCd)); } return new DividendSchedule { IssucoCustno = issucoCustno, RepSecnNm = repSecnNm.Trim(), RgtRacd = string.IsNullOrWhiteSpace(rgtRacd) ? null : rgtRacd.Trim(), RgtRsnDetailSortCd = rgtRsnDetailSortCd.Trim(), RgtStdDt = rgtStdDt, AllocWhcd = string.IsNullOrWhiteSpace(allocWhcd) ? null : allocWhcd.Trim(), SetaccTpcd = string.IsNullOrWhiteSpace(setaccTpcd) ? null : setaccTpcd.Trim(), FixTpcd = string.IsNullOrWhiteSpace(fixTpcd) ? null : fixTpcd.Trim(), RostCloseBeginDt = rostCloseBeginDt, RostCloseExpryDt = rostCloseExpryDt, XrgtDt = xrgtDt, IsElectronicSecurity = isElectronicSecurity }; } /// 재수집 반영 — 변경 필드가 있을 때만 UpdatedAt 갱신 (무변경 upsert 는 no-op) public void Update( string repSecnNm, string? rgtRacd, string? allocWhcd, string? setaccTpcd, string? fixTpcd, DateOnly? rostCloseBeginDt, DateOnly? rostCloseExpryDt, DateOnly? xrgtDt, bool? isElectronicSecurity) { var changed = false; if (!string.IsNullOrWhiteSpace(repSecnNm) && RepSecnNm != repSecnNm.Trim()) { RepSecnNm = repSecnNm.Trim(); changed = true; } var normalizedRacd = string.IsNullOrWhiteSpace(rgtRacd) ? null : rgtRacd.Trim(); if (RgtRacd != normalizedRacd) { RgtRacd = normalizedRacd; changed = true; } var normalizedAllocWhcd = string.IsNullOrWhiteSpace(allocWhcd) ? null : allocWhcd.Trim(); if (AllocWhcd != normalizedAllocWhcd) { AllocWhcd = normalizedAllocWhcd; changed = true; } var normalizedSetaccTpcd = string.IsNullOrWhiteSpace(setaccTpcd) ? null : setaccTpcd.Trim(); if (SetaccTpcd != normalizedSetaccTpcd) { SetaccTpcd = normalizedSetaccTpcd; changed = true; } var normalizedFixTpcd = string.IsNullOrWhiteSpace(fixTpcd) ? null : fixTpcd.Trim(); if (FixTpcd != normalizedFixTpcd) { FixTpcd = normalizedFixTpcd; changed = true; } if (RostCloseBeginDt != rostCloseBeginDt) { RostCloseBeginDt = rostCloseBeginDt; changed = true; } if (RostCloseExpryDt != rostCloseExpryDt) { RostCloseExpryDt = rostCloseExpryDt; changed = true; } if (XrgtDt != xrgtDt) { XrgtDt = xrgtDt; changed = true; } if (IsElectronicSecurity != isElectronicSecurity) { IsElectronicSecurity = isElectronicSecurity; changed = true; } if (changed) { UpdatedAt = DateTime.UtcNow; } } }