using System.Globalization;
namespace Infrastructure.StockData;
///
/// SEIBro getStkStatInfo(주식 종목 정보) 응답 파서 — 순수 C#. "SEIBro 종목 보강" (Wave 0, Stock.EnrichFromSeibro 입력).
/// 행 필드(사용분): ISSUCO_CUSTNO / ISIN / SHOTN_ISIN / PVAL(액면가) / VOTRNO(1주당 의결권수) /
/// TOTAL_STK_CNT(총발행주식수) / ELTSC_YN([Y]전자 [N]예탁 → bool, 그 외 null).
/// 숫자 필드는 생략/빈 값/비숫자 시 null (0 과 구분). TOTAL_STK_CNT 는 스펙상 NUMBER(15,4) 라 decimal 로 읽어 long 절사.
///
public static class SeibroStkStatParser
{
/// 주식 종목 정보 1행 — 전 필드 nullable (SEIBro 는 필드 생략 가능)
public sealed record Row(
int? IssucoCustno,
string? Isin,
string? ShortCode,
decimal? FaceValue,
decimal? VotingRights,
long? TotalIssuedShares,
bool? IsElectronicSecurity
);
public static IReadOnlyList Parse(SeibroXml.Envelope envelope)
{
var rows = new List();
foreach (var fields in envelope.Rows)
{
rows.Add(new Row(
ParseNullableInt(SeibroXml.GetOrNull(fields, "ISSUCO_CUSTNO")),
SeibroXml.GetOrNull(fields, "ISIN")?.Trim(),
SeibroXml.GetOrNull(fields, "SHOTN_ISIN")?.Trim(),
ParseNullableDecimal(SeibroXml.GetOrNull(fields, "PVAL")),
ParseNullableDecimal(SeibroXml.GetOrNull(fields, "VOTRNO")),
ParseNullableLong(SeibroXml.GetOrNull(fields, "TOTAL_STK_CNT")),
ParseYn(SeibroXml.GetOrNull(fields, "ELTSC_YN"))
));
}
return rows;
}
private static int? ParseNullableInt(string? raw)
{
return int.TryParse(raw, NumberStyles.Integer, CultureInfo.InvariantCulture, out var value) ? value : null;
}
private static decimal? ParseNullableDecimal(string? raw)
{
return decimal.TryParse(raw, NumberStyles.Float, CultureInfo.InvariantCulture, out var value) ? value : null;
}
/// 총발행주식수 — 스펙 NUMBER(15,4) 대비 decimal 로 읽고 정수 절사
private static long? ParseNullableLong(string? raw)
{
return decimal.TryParse(raw, NumberStyles.Float, CultureInfo.InvariantCulture, out var value) ? (long)value : null;
}
private static bool? ParseYn(string? raw)
{
return raw?.Trim().ToUpperInvariant() switch
{
"Y" => true,
"N" => false,
_ => null
};
}
}