using System.ComponentModel.DataAnnotations;
namespace Domain.Entities.Stocks;
///
/// SEIBro 시장별 단축코드 ↔ 발행회사번호 매핑 (getShotnByMart) — (Market, ShortCode) UNIQUE.
/// ISSUCO_CUSTNO 는 SEIBro 기업정보 API 전체의 조인키라 Wave 0 에서 가장 먼저 구축한다.
/// K-OTC(13)·기타(50) 등 KRX Stock 이 커버하지 않는 시장의 유일한 종목 마스터이기도 하다
/// (KOSPI/KOSDAQ/KONEX 는 Stock.IssucoCustno 로도 스탬핑되지만 이 테이블이 원본 스냅샷).
///
public class SeibroIssuerCode
{
[Key]
public int ID { get; private set; }
/// 시장구분 (MART_TPCD, char 2) — [11]유가 [12]코스닥 [13]K-OTC [14]코넥스 [50]기타
public string Market { get; private set; } = default!;
/// 단축코드 (SHOTN_ISIN)
public string ShortCode { get; private set; } = default!;
/// 종목명 (KOR_SECN_NM)
public string Name { get; private set; } = default!;
/// 발행회사 고객번호 (ISSUCO_CUSTNO) — 예탁결제원 부여
public int IssucoCustno { get; private set; }
/// 마지막 동기화 시각 (UTC)
public DateTime UpdatedAt { get; private set; } = DateTime.UtcNow;
private SeibroIssuerCode() { }
public static SeibroIssuerCode Create(string market, string shortCode, string name, int issucoCustno)
{
if (market is not { Length: 2 } || market.Any(c => !char.IsAsciiDigit(c)))
{
throw new ArgumentException("market must be 2 digits (MART_TPCD)", nameof(market));
}
if (string.IsNullOrWhiteSpace(shortCode) || shortCode.Trim().Length > 12)
{
throw new ArgumentException("shortCode required (max 12)", nameof(shortCode));
}
if (string.IsNullOrWhiteSpace(name))
{
throw new ArgumentException("name required", nameof(name));
}
return new SeibroIssuerCode
{
Market = market,
ShortCode = shortCode.Trim(),
Name = name.Trim(),
IssucoCustno = issucoCustno
};
}
/// 재동기화 반영 — 이름/회사번호 변경 시에만 UpdatedAt 갱신 (무변경 upsert 는 no-op)
public void Update(string name, int issucoCustno)
{
var changed = false;
if (!string.IsNullOrWhiteSpace(name) && Name != name.Trim())
{
Name = name.Trim();
changed = true;
}
if (IssucoCustno != issucoCustno)
{
IssucoCustno = issucoCustno;
changed = true;
}
if (changed)
{
UpdatedAt = DateTime.UtcNow;
}
}
}