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;
}
}