| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142 |
- using System.ComponentModel.DataAnnotations;
- namespace Domain.Entities.Stocks;
- /// <summary>
- /// SEIBro 주식증감내역 (getStkIncdecDetails) — 발행횟수별 주식수 변동(액면분할·증자·이익소각 등) (Wave 2 ★P1).
- /// rolling per-회사번호(SHOTN_ISIN) 로 수집한다.
- /// ⚠️ 자연키: plan 은 (Isin, SecnIssuNtimes) 를 제시하나 실응답(삼성전자 fixture)에서 동일 발행횟수(75)가
- /// 서로 다른 발행일·사유(액면분할 20180503 / 이익소각 20181204)로 2행 존재한다 → (Isin, SecnIssuNtimes) 단독은 충돌.
- /// 따라서 UNIQUE (Isin, SecnIssuNtimes, IssuDt, SecnIssuRacd) 로 확장해 데이터 손실 없이 upsert 한다.
- /// </summary>
- public class StockIssuanceChange
- {
- [Key]
- public int ID { get; private set; }
- /// <summary>발행회사 고객번호 (ISSUCO_CUSTNO)</summary>
- public int? IssucoCustno { get; private set; }
- /// <summary>종목번호 (ISIN)</summary>
- public string Isin { get; private set; } = default!;
- /// <summary>종목종류코드 (SECN_KACD) — 0101 보통주 0201 우선주…</summary>
- public string? SecnKacd { get; private set; }
- /// <summary>종목발행횟수 (SECN_ISSU_NTIMES)</summary>
- public int SecnIssuNtimes { get; private set; }
- /// <summary>발행일자 (ISSU_DT)</summary>
- public DateOnly IssuDt { get; private set; }
- /// <summary>발행가 (ISSUPRC, 1주당)</summary>
- public decimal? Issuprc { get; private set; }
- /// <summary>발행수량 (ISSU_QTY) — 감소는 음수</summary>
- public long? IssuQty { get; private set; }
- /// <summary>종목발행사유코드 (SECN_ISSU_RACD)</summary>
- public string SecnIssuRacd { get; private set; } = default!;
- /// <summary>종목발행사유명 (SECN_ISSU_NM) — 예 액면분할</summary>
- public string? SecnIssuNm { get; private set; }
- /// <summary>상장일자 (LIST_DT)</summary>
- public DateOnly? ListDt { get; private set; }
- public DateTime UpdatedAt { get; private set; } = DateTime.UtcNow;
- private StockIssuanceChange() { }
- public static StockIssuanceChange Create(
- int? issucoCustno,
- string isin,
- string? secnKacd,
- int secnIssuNtimes,
- DateOnly issuDt,
- decimal? issuprc,
- long? issuQty,
- string secnIssuRacd,
- string? secnIssuNm,
- DateOnly? listDt)
- {
- if (string.IsNullOrWhiteSpace(isin))
- {
- throw new ArgumentException("isin required", nameof(isin));
- }
- if (string.IsNullOrWhiteSpace(secnIssuRacd))
- {
- throw new ArgumentException("secnIssuRacd required", nameof(secnIssuRacd));
- }
- return new StockIssuanceChange
- {
- IssucoCustno = issucoCustno,
- Isin = isin.Trim(),
- SecnKacd = string.IsNullOrWhiteSpace(secnKacd) ? null : secnKacd.Trim(),
- SecnIssuNtimes = secnIssuNtimes,
- IssuDt = issuDt,
- Issuprc = issuprc,
- IssuQty = issuQty,
- SecnIssuRacd = secnIssuRacd.Trim(),
- SecnIssuNm = string.IsNullOrWhiteSpace(secnIssuNm) ? null : secnIssuNm.Trim(),
- ListDt = listDt
- };
- }
- /// <summary>재수집 반영 — 변경 필드가 있을 때만 UpdatedAt 갱신 (자연키는 불변)</summary>
- public void Update(
- int? issucoCustno,
- string? secnKacd,
- decimal? issuprc,
- long? issuQty,
- string? secnIssuNm,
- DateOnly? listDt)
- {
- var changed = false;
- if (issucoCustno is not null && IssucoCustno != issucoCustno)
- {
- IssucoCustno = issucoCustno;
- changed = true;
- }
- var normalizedSecnKacd = string.IsNullOrWhiteSpace(secnKacd) ? null : secnKacd.Trim();
- if (SecnKacd != normalizedSecnKacd)
- {
- SecnKacd = normalizedSecnKacd;
- changed = true;
- }
- if (Issuprc != issuprc)
- {
- Issuprc = issuprc;
- changed = true;
- }
- if (IssuQty != issuQty)
- {
- IssuQty = issuQty;
- changed = true;
- }
- var normalizedSecnIssuNm = string.IsNullOrWhiteSpace(secnIssuNm) ? null : secnIssuNm.Trim();
- if (SecnIssuNm != normalizedSecnIssuNm)
- {
- SecnIssuNm = normalizedSecnIssuNm;
- changed = true;
- }
- if (ListDt != listDt)
- {
- ListDt = listDt;
- changed = true;
- }
- if (changed)
- {
- UpdatedAt = DateTime.UtcNow;
- }
- }
- }
|