SeibroCorpActionQueryHandlerTests.cs 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  1. using Domain.Entities.Stocks;
  2. using Domain.Entities.Stocks.ValueObject;
  3. using MeetingHandler = Application.Features.Api.Stocks.GetMeetingCalendar.Handler;
  4. using MeetingQuery = Application.Features.Api.Stocks.GetMeetingCalendar.Query;
  5. using CbHandler = Application.Features.Api.Stocks.GetCbExercises.Handler;
  6. using CbQuery = Application.Features.Api.Stocks.GetCbExercises.Query;
  7. namespace Application.Tests;
  8. [TestClass]
  9. public sealed class SeibroCorpActionQueryHandlerTests
  10. {
  11. [TestMethod]
  12. public async Task GetMeetingCalendar_FiltersByGmetDt_JoinsStockName_CountsAgendas()
  13. {
  14. // 기대 행위: 총회일 from~to 필터 + Stock(IssucoCustno) 조인 종목명 + 안건수 집계 + 최신순.
  15. var custno = 810000 + Random.Shared.Next(1, 99999);
  16. var code = $"74{Random.Shared.Next(1000, 9999)}";
  17. var stdDt = new DateOnly(2024, 12, 31);
  18. var gmetDt = new DateOnly(2025, 3, 20);
  19. using var db = TestDb.Create();
  20. var stock = Stock.Create(code, "총회종목", StockMarket.KOSPI, new DateOnly(2020, 1, 2), isin: $"KR7{code}003");
  21. stock.SetIssucoCustno(custno);
  22. await db.Stock.AddAsync(stock);
  23. await db.GeneralMeeting.AddAsync(GeneralMeeting.Create(custno, "00001", "001", "99", null, null, true, "1", null, "서울", false, stdDt, gmetDt, "0900", null, false, true, false));
  24. // 범위 밖 총회
  25. await db.GeneralMeeting.AddAsync(GeneralMeeting.Create(custno, "00001", "002", "99", null, null, true, "1", null, "부산", false, new DateOnly(2023, 6, 1), new DateOnly(2023, 6, 20), "1000", null, false, false, false));
  26. // 안건 2건 (in-range 총회)
  27. await db.MeetingAgenda.AddAsync(MeetingAgenda.Create(custno, "00001", stdDt, gmetDt, "001", 1, "1", "1", "001", null, "재무제표승인", null, null, null, "9", "1"));
  28. await db.MeetingAgenda.AddAsync(MeetingAgenda.Create(custno, "00001", stdDt, gmetDt, "001", 2, "2", "2", "101", null, "이사 선임", null, "홍길동", null, "9", "1"));
  29. await db.SaveChangesAsync(default);
  30. var handler = new MeetingHandler(db);
  31. var result = await handler.Handle(new MeetingQuery(new DateOnly(2025, 1, 1), new DateOnly(2025, 12, 31), 1, 50), default);
  32. Assert.IsTrue(result.IsSuccess);
  33. var mine = result.Value.List.Where(c => c.IssucoCustno == custno).ToList();
  34. Assert.AreEqual(1, mine.Count, "2025 총회 1건만 (2023 제외)");
  35. Assert.AreEqual("총회종목", mine[0].Name, "Stock 조인 종목명");
  36. Assert.AreEqual(code, mine[0].Code);
  37. Assert.AreEqual("001", mine[0].MeetingKind);
  38. Assert.IsTrue(mine[0].Evote);
  39. Assert.AreEqual(2, mine[0].AgendaCount, "안건 2건 집계");
  40. }
  41. [TestMethod]
  42. public async Task GetCbExercises_ByExerciseStock_Default_OrdersDesc()
  43. {
  44. // 기대 행위: 기본(byBond=false) 은 XRC_STK_ISIN(행사주식) 기준 조회, 최신 행사일 순.
  45. var code = $"75{Random.Shared.Next(1000, 9999)}";
  46. var stkIsin = $"KR7{code}003";
  47. var bondIsin1 = $"KR6{Guid.NewGuid().ToString("N")[..9]}";
  48. var bondIsin2 = $"KR6{Guid.NewGuid().ToString("N")[..9]}";
  49. using var db = TestDb.Create();
  50. var stock = Stock.Create(code, "행사주식", StockMarket.KOSDAQ, new DateOnly(2019, 5, 5), isin: stkIsin);
  51. await db.Stock.AddAsync(stock);
  52. await db.ConvertibleExercise.AddAsync(ConvertibleExercise.Create(bondIsin1, "씨비1", "CB", stkIsin, "행사주식", new DateOnly(2025, 2, 10), null, null, null, 1000m, 5000m, null));
  53. await db.ConvertibleExercise.AddAsync(ConvertibleExercise.Create(bondIsin2, "비더블유2", "BW", stkIsin, "행사주식", new DateOnly(2025, 4, 1), null, null, null, 2000m, 5200m, null));
  54. // 다른 행사주식 — 제외되어야
  55. await db.ConvertibleExercise.AddAsync(ConvertibleExercise.Create(bondIsin1, "씨비1", "CB", $"KR7{Guid.NewGuid().ToString("N")[..9]}", "다른주식", new DateOnly(2025, 3, 1), null, null, null, 500m, 5000m, null));
  56. await db.SaveChangesAsync(default);
  57. var handler = new CbHandler(db);
  58. var result = await handler.Handle(new CbQuery(code, false, 1, 50), default);
  59. Assert.IsTrue(result.IsSuccess);
  60. Assert.AreEqual(stkIsin, result.Value.Isin);
  61. Assert.AreEqual(2, result.Value.Total, "행사주식 = code 인 2건만");
  62. Assert.AreEqual(new DateOnly(2025, 4, 1), result.Value.List[0].RgtStdDt, "최신 행사일 순");
  63. Assert.AreEqual("BW", result.Value.List[0].BondKind);
  64. Assert.AreEqual(5200m, result.Value.List[0].ExercisePrice);
  65. }
  66. [TestMethod]
  67. public async Task GetCbExercises_ByBond_UsesIsinDirectly()
  68. {
  69. // 기대 행위: byBond=true 는 BOND_ISIN 기준 조회 (Stock 미조인, 입력을 ISIN 으로 간주).
  70. var bondIsin = $"KR6{Guid.NewGuid().ToString("N")[..9]}";
  71. var stkIsin = $"KR7{Guid.NewGuid().ToString("N")[..9]}";
  72. using var db = TestDb.Create();
  73. await db.ConvertibleExercise.AddAsync(ConvertibleExercise.Create(bondIsin, "씨비", "CB", stkIsin, "주식", new DateOnly(2025, 1, 15), null, null, null, 300m, 4800m, null));
  74. await db.SaveChangesAsync(default);
  75. var handler = new CbHandler(db);
  76. var result = await handler.Handle(new CbQuery(bondIsin, true, 1, 50), default);
  77. Assert.IsTrue(result.IsSuccess);
  78. Assert.AreEqual(bondIsin, result.Value.Isin);
  79. Assert.AreEqual(1, result.Value.Total);
  80. Assert.AreEqual(stkIsin, result.Value.List[0].ExerciseStockIsin, "행사주식 ISIN 링크");
  81. }
  82. }