DividendSchedule.cs 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. using System.ComponentModel.DataAnnotations;
  2. namespace Domain.Entities.Stocks;
  3. /// <summary>
  4. /// SEIBro 배당일정 (getDivSchedulInfo) — 현금/주식/동시/무배당 일정·명부폐쇄·권리락일 (Wave 1 ★P0).
  5. /// 자연키 UNIQUE (IssucoCustno, RgtStdDt, RgtRsnDetailSortCd) — 한 회사·기준일에 배당 세부유형이 여럿(주식+현금 동시 등) 존재할 수 있다.
  6. /// 날짜 스윕(getDivSchedulInfo, custno 미지정 → 그날 전체 회사)으로 수집한다.
  7. /// </summary>
  8. public class DividendSchedule
  9. {
  10. [Key]
  11. public int ID { get; private set; }
  12. /// <summary>발행회사 고객번호 (ISSUCO_CUSTNO)</summary>
  13. public int IssucoCustno { get; private set; }
  14. /// <summary>대표종목명 (REP_SECN_NM)</summary>
  15. public string RepSecnNm { get; private set; } = default!;
  16. /// <summary>권리사유코드 (RGT_RACD) — 103 배당/분배</summary>
  17. public string? RgtRacd { get; private set; }
  18. /// <summary>권리사유세부유형코드 (RGT_RSN_DTAIL_SORT_CD) — 01주식 02현금 03동시 04무배당</summary>
  19. public string RgtRsnDetailSortCd { get; private set; } = default!;
  20. /// <summary>권리기준일자 (RGT_STD_DT)</summary>
  21. public DateOnly RgtStdDt { get; private set; }
  22. /// <summary>배정방법코드 (ALOC_WHCD) — 1정율 2정액 3정율+정액</summary>
  23. public string? AllocWhcd { get; private set; }
  24. /// <summary>결산구분코드 (SETACC_TPCD) — 1결산 2반기 3분기</summary>
  25. public string? SetaccTpcd { get; private set; }
  26. /// <summary>확정구분코드 (FIX_TPCD) — 1확정 2예고 3미정</summary>
  27. public string? FixTpcd { get; private set; }
  28. /// <summary>명부폐쇄시작일자 (ROST_CLOSE_BEGIN_DT)</summary>
  29. public DateOnly? RostCloseBeginDt { get; private set; }
  30. /// <summary>명부폐쇄종료일자 (ROST_CLOSE_EXPRY_DT)</summary>
  31. public DateOnly? RostCloseExpryDt { get; private set; }
  32. /// <summary>권리락일자 (XRGT_DT)</summary>
  33. public DateOnly? XrgtDt { get; private set; }
  34. /// <summary>전자증권 여부 (ELTSC_YN, Y=전자/N=예탁) — 미제공 null</summary>
  35. public bool? IsElectronicSecurity { get; private set; }
  36. public DateTime UpdatedAt { get; private set; } = DateTime.UtcNow;
  37. private DividendSchedule() { }
  38. public static DividendSchedule Create(
  39. int issucoCustno,
  40. string repSecnNm,
  41. string? rgtRacd,
  42. string rgtRsnDetailSortCd,
  43. DateOnly rgtStdDt,
  44. string? allocWhcd,
  45. string? setaccTpcd,
  46. string? fixTpcd,
  47. DateOnly? rostCloseBeginDt,
  48. DateOnly? rostCloseExpryDt,
  49. DateOnly? xrgtDt,
  50. bool? isElectronicSecurity)
  51. {
  52. if (string.IsNullOrWhiteSpace(repSecnNm))
  53. {
  54. throw new ArgumentException("repSecnNm required", nameof(repSecnNm));
  55. }
  56. if (string.IsNullOrWhiteSpace(rgtRsnDetailSortCd))
  57. {
  58. throw new ArgumentException("rgtRsnDetailSortCd required", nameof(rgtRsnDetailSortCd));
  59. }
  60. return new DividendSchedule
  61. {
  62. IssucoCustno = issucoCustno,
  63. RepSecnNm = repSecnNm.Trim(),
  64. RgtRacd = string.IsNullOrWhiteSpace(rgtRacd) ? null : rgtRacd.Trim(),
  65. RgtRsnDetailSortCd = rgtRsnDetailSortCd.Trim(),
  66. RgtStdDt = rgtStdDt,
  67. AllocWhcd = string.IsNullOrWhiteSpace(allocWhcd) ? null : allocWhcd.Trim(),
  68. SetaccTpcd = string.IsNullOrWhiteSpace(setaccTpcd) ? null : setaccTpcd.Trim(),
  69. FixTpcd = string.IsNullOrWhiteSpace(fixTpcd) ? null : fixTpcd.Trim(),
  70. RostCloseBeginDt = rostCloseBeginDt,
  71. RostCloseExpryDt = rostCloseExpryDt,
  72. XrgtDt = xrgtDt,
  73. IsElectronicSecurity = isElectronicSecurity
  74. };
  75. }
  76. /// <summary>재수집 반영 — 변경 필드가 있을 때만 UpdatedAt 갱신 (무변경 upsert 는 no-op)</summary>
  77. public void Update(
  78. string repSecnNm,
  79. string? rgtRacd,
  80. string? allocWhcd,
  81. string? setaccTpcd,
  82. string? fixTpcd,
  83. DateOnly? rostCloseBeginDt,
  84. DateOnly? rostCloseExpryDt,
  85. DateOnly? xrgtDt,
  86. bool? isElectronicSecurity)
  87. {
  88. var changed = false;
  89. if (!string.IsNullOrWhiteSpace(repSecnNm) && RepSecnNm != repSecnNm.Trim())
  90. {
  91. RepSecnNm = repSecnNm.Trim();
  92. changed = true;
  93. }
  94. var normalizedRacd = string.IsNullOrWhiteSpace(rgtRacd) ? null : rgtRacd.Trim();
  95. if (RgtRacd != normalizedRacd)
  96. {
  97. RgtRacd = normalizedRacd;
  98. changed = true;
  99. }
  100. var normalizedAllocWhcd = string.IsNullOrWhiteSpace(allocWhcd) ? null : allocWhcd.Trim();
  101. if (AllocWhcd != normalizedAllocWhcd)
  102. {
  103. AllocWhcd = normalizedAllocWhcd;
  104. changed = true;
  105. }
  106. var normalizedSetaccTpcd = string.IsNullOrWhiteSpace(setaccTpcd) ? null : setaccTpcd.Trim();
  107. if (SetaccTpcd != normalizedSetaccTpcd)
  108. {
  109. SetaccTpcd = normalizedSetaccTpcd;
  110. changed = true;
  111. }
  112. var normalizedFixTpcd = string.IsNullOrWhiteSpace(fixTpcd) ? null : fixTpcd.Trim();
  113. if (FixTpcd != normalizedFixTpcd)
  114. {
  115. FixTpcd = normalizedFixTpcd;
  116. changed = true;
  117. }
  118. if (RostCloseBeginDt != rostCloseBeginDt)
  119. {
  120. RostCloseBeginDt = rostCloseBeginDt;
  121. changed = true;
  122. }
  123. if (RostCloseExpryDt != rostCloseExpryDt)
  124. {
  125. RostCloseExpryDt = rostCloseExpryDt;
  126. changed = true;
  127. }
  128. if (XrgtDt != xrgtDt)
  129. {
  130. XrgtDt = xrgtDt;
  131. changed = true;
  132. }
  133. if (IsElectronicSecurity != isElectronicSecurity)
  134. {
  135. IsElectronicSecurity = isElectronicSecurity;
  136. changed = true;
  137. }
  138. if (changed)
  139. {
  140. UpdatedAt = DateTime.UtcNow;
  141. }
  142. }
  143. }