using System.ComponentModel.DataAnnotations; namespace Domain.Entities.Stocks; /// /// SEIBro 채권 이자지급 정보 (getIntPayInfo) — 이자지급 주기·방식·직전/차기 이표일 (Wave 4). PK Isin (스냅샷 갱신). /// ⚠️ 실샘플 fixture 가 result="0"(빈) 이라 필드 매핑은 채권.md 스펙 기준 — 운영 첫 수집 시 로그로 확인. /// 응답에 ISIN 필드가 없을 수 있어(getIntPayInfo 는 ISIN 을 요청 파라미터로만 받음) 배치가 요청 ISIN 을 스탬핑한다. /// public class BondInterestPayment { /// 종목코드 (ISIN, 요청값 스탬핑) — PK [Key] [MaxLength(12)] public string Isin { get; private set; } = default!; /// 표면이자율 (COUPON_RATE) public decimal? CouponRate { get; private set; } /// 이자지급방법구분코드 (INT_PAY_WAY_TPCD) — 1이표 2할인 3복리 4단리 public string? IntPayWayTpcd { get; private set; } /// 이자지급주기기간수 (INT_PAY_CYCLE_TERMS) public int? IntPayCycleTerms { get; private set; } /// 이자지급주기구분코드 (INT_PAY_CYCLE_TPCD) — 23개월 24분기 25반기 26년 99기타 public string? IntPayCycleTpcd { get; private set; } /// 절상절사구분코드 (RVLT_SEVER_TPCD) — 1올림 2버림 3반올림 9해당없음 public string? RvltSeverTpcd { get; private set; } /// 경과이자지급여부 (ACRINT_PAY_YN, Y/N) public bool? AcrintPayYn { get; private set; } /// 은행휴무일이자지급일구분코드 (BANK_HOLIDAY_INT_PAYDD_TPCD) — 1직전영업일 2직후영업일 3해당일 public string? BankHolidayIntPaydayTpcd { get; private set; } /// 이자지급시기구분코드 (INT_PAY_TIMS_TPCD) — 01후급 02선급 03상환시 04발행시 public string? IntPayTimsTpcd { get; private set; } /// 직전이표일 (BEFORE_DATE) public DateOnly? BeforeDate { get; private set; } /// 차기이표일 (AFTER_DATE) public DateOnly? AfterDate { get; private set; } public DateTime UpdatedAt { get; private set; } = DateTime.UtcNow; private BondInterestPayment() { } public static BondInterestPayment Create( string isin, decimal? couponRate, string? intPayWayTpcd, int? intPayCycleTerms, string? intPayCycleTpcd, string? rvltSeverTpcd, bool? acrintPayYn, string? bankHolidayIntPaydayTpcd, string? intPayTimsTpcd, DateOnly? beforeDate, DateOnly? afterDate) { if (string.IsNullOrWhiteSpace(isin)) { throw new ArgumentException("isin required", nameof(isin)); } return new BondInterestPayment { Isin = isin.Trim(), CouponRate = couponRate, IntPayWayTpcd = Trimmed(intPayWayTpcd), IntPayCycleTerms = intPayCycleTerms, IntPayCycleTpcd = Trimmed(intPayCycleTpcd), RvltSeverTpcd = Trimmed(rvltSeverTpcd), AcrintPayYn = acrintPayYn, BankHolidayIntPaydayTpcd = Trimmed(bankHolidayIntPaydayTpcd), IntPayTimsTpcd = Trimmed(intPayTimsTpcd), BeforeDate = beforeDate, AfterDate = afterDate }; } /// 재수집 반영 (PK Isin 은 불변) — 스냅샷 갱신, 변경 시에만 UpdatedAt public void Update( decimal? couponRate, string? intPayWayTpcd, int? intPayCycleTerms, string? intPayCycleTpcd, string? rvltSeverTpcd, bool? acrintPayYn, string? bankHolidayIntPaydayTpcd, string? intPayTimsTpcd, DateOnly? beforeDate, DateOnly? afterDate) { var changed = false; changed |= Set(couponRate, CouponRate, v => CouponRate = v); changed |= Set(Trimmed(intPayWayTpcd), IntPayWayTpcd, v => IntPayWayTpcd = v); changed |= Set(intPayCycleTerms, IntPayCycleTerms, v => IntPayCycleTerms = v); changed |= Set(Trimmed(intPayCycleTpcd), IntPayCycleTpcd, v => IntPayCycleTpcd = v); changed |= Set(Trimmed(rvltSeverTpcd), RvltSeverTpcd, v => RvltSeverTpcd = v); changed |= Set(acrintPayYn, AcrintPayYn, v => AcrintPayYn = v); changed |= Set(Trimmed(bankHolidayIntPaydayTpcd), BankHolidayIntPaydayTpcd, v => BankHolidayIntPaydayTpcd = v); changed |= Set(Trimmed(intPayTimsTpcd), IntPayTimsTpcd, v => IntPayTimsTpcd = v); changed |= Set(beforeDate, BeforeDate, v => BeforeDate = v); changed |= Set(afterDate, AfterDate, v => AfterDate = v); if (changed) { UpdatedAt = DateTime.UtcNow; } } private static string? Trimmed(string? value) { return string.IsNullOrWhiteSpace(value) ? null : value.Trim(); } private static bool Set(T incoming, T current, Action assign) { if (EqualityComparer.Default.Equals(incoming, current)) { return false; } assign(incoming); return true; } }