using System.ComponentModel.DataAnnotations;
namespace Domain.Entities.Stocks;
///
/// 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 한다.
///
public class StockIssuanceChange
{
[Key]
public int ID { get; private set; }
/// 발행회사 고객번호 (ISSUCO_CUSTNO)
public int? IssucoCustno { get; private set; }
/// 종목번호 (ISIN)
public string Isin { get; private set; } = default!;
/// 종목종류코드 (SECN_KACD) — 0101 보통주 0201 우선주…
public string? SecnKacd { get; private set; }
/// 종목발행횟수 (SECN_ISSU_NTIMES)
public int SecnIssuNtimes { get; private set; }
/// 발행일자 (ISSU_DT)
public DateOnly IssuDt { get; private set; }
/// 발행가 (ISSUPRC, 1주당)
public decimal? Issuprc { get; private set; }
/// 발행수량 (ISSU_QTY) — 감소는 음수
public long? IssuQty { get; private set; }
/// 종목발행사유코드 (SECN_ISSU_RACD)
public string SecnIssuRacd { get; private set; } = default!;
/// 종목발행사유명 (SECN_ISSU_NM) — 예 액면분할
public string? SecnIssuNm { get; private set; }
/// 상장일자 (LIST_DT)
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
};
}
/// 재수집 반영 — 변경 필드가 있을 때만 UpdatedAt 갱신 (자연키는 불변)
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;
}
}
}