From 313dade65b5ead1b19b9243fd04a026b033780d8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E9=A9=AC=E5=86=B0=E5=86=B0?= <437394478@qq.com>
Date: Wed, 26 Aug 2026 21:21:55 +0800
Subject: [PATCH] =?UTF-8?q?fix:=20=E7=BB=93=E7=AE=97=E5=8D=95=E4=B8=AD?=
=?UTF-8?q?=E7=9A=84=E5=87=80=E9=A2=9D=E7=BB=93=E7=AE=97=E9=87=91=E9=A2=9D?=
=?UTF-8?q?=E7=9A=84=E4=BF=AE=E6=94=B9?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../TradeSettleBillGenerator.cs | 6 +++++
.../SwapSettlementBillRowBuilder.cs | 25 ++++++++++---------
2 files changed, 19 insertions(+), 12 deletions(-)
diff --git a/Plugins/YLErp.Plugins.GuoLian/DocumentGenerator/TradeSettleBillGenerator.cs b/Plugins/YLErp.Plugins.GuoLian/DocumentGenerator/TradeSettleBillGenerator.cs
index 7d851a7f..53d448db 100644
--- a/Plugins/YLErp.Plugins.GuoLian/DocumentGenerator/TradeSettleBillGenerator.cs
+++ b/Plugins/YLErp.Plugins.GuoLian/DocumentGenerator/TradeSettleBillGenerator.cs
@@ -74,6 +74,11 @@ namespace YLErp.Plugins.GuoLian.DocumentGenerator
var underlying = Context.GetTradeUnderlying(flowEventGroup.UnderlyingCode);
var closeNotionalValue = unwindData?.CloseNotionalValue
?? flowEventGroup.Quantity * flowEventGroup.ContractSize * posi.PosiGrossPrice;
+ var settlementDate = flowEventGroup.UnwindDate
+ ?? throw new ServiceException($"平仓事件{flowEventGroup.id}缺少结算日");
+ var currentDayFloatingDividend = Context.GetEodPositions(tradeId, settlementDate)
+ .FirstOrDefault(x => x.PositionId == flowEventGroup.PositionId)
+ ?.TdPosiDividend ?? 0m;
// 行构造器统一处理客户视角、结算公式、品种差异和模板展示精度。
var row = SwapSettlementBillRowBuilder.Build(new SwapSettlementBillRowInput
@@ -86,6 +91,7 @@ namespace YLErp.Plugins.GuoLian.DocumentGenerator
Positions = positions,
UnderlyingInstrumentType = underlying?.UnderlyingInstrumentType,
CloseNotionalValue = closeNotionalValue,
+ CurrentDayFloatingDividend = currentDayFloatingDividend,
ExitYtm = unwindData?.FlowEvents?
.FirstOrDefault(x => x.PositionType > 0)?.ExitYtm,
IncludePeriodPaymentInNetting = (tradeExtend?.ExtendObj?.DividendPayDate ?? 1) == 0
diff --git a/YLErpDAL/Modules/TradeModule/DocGenerateModule/SwapSettlementBillRowBuilder.cs b/YLErpDAL/Modules/TradeModule/DocGenerateModule/SwapSettlementBillRowBuilder.cs
index 45a8497e..36fe722e 100644
--- a/YLErpDAL/Modules/TradeModule/DocGenerateModule/SwapSettlementBillRowBuilder.cs
+++ b/YLErpDAL/Modules/TradeModule/DocGenerateModule/SwapSettlementBillRowBuilder.cs
@@ -9,7 +9,7 @@ namespace YLErp.Modules.TradeModule.DocGenerateModule;
///
/// 构造普通收益互换结算单单行数据所需的业务输入。
-/// 数据均来自平仓事件及其关联交易,避免依赖平仓后可能已不存在的日终持仓。
+/// 数据来自平仓事件、关联交易及结算日日终持仓。
///
public sealed class SwapSettlementBillRowInput
{
@@ -40,6 +40,9 @@ public sealed class SwapSettlementBillRowInput
/// 平仓事件浮动腿记录的期末结算收益率(展示态数值)。
public decimal? ExitYtm { get; set; }
+ /// 结算日日终持仓中的当日浮动端分红,保留原始收付方向。
+ public decimal CurrentDayFloatingDividend { get; set; }
+
/// 期间付息或分红是否计入本次净额结算。
public bool IncludePeriodPaymentInNetting { get; set; }
}
@@ -87,25 +90,19 @@ public static class SwapSettlementBillRowBuilder
var floatingAmount = -input.CloseFlow.MarkClosePnl;
var fee = -(input.CloseFlow.TradingFee + input.CloseFlow.TradingFeePending);
var marginInterest = -marginEvents.Sum(x => x.InterestClosePnL);
- var periodAmount = -input.CloseFlow.DividendIn;
var initialMargin = SumMargin(effectiveMargins, InterestModeEnum.初始预付金);
var additionalMargin = SumMargin(effectiveMargins, InterestModeEnum.追加预付金);
- var marginBackAmount = marginEvents.Sum(x => x.InterestPrincipal);
- // 沿用原结算单口径:全部事件利息、浮动盈亏和预付金返还本金参与净额结算。
+ // 净额结算仅包含全部事件利息和浮动盈亏,不包含预付金返还本金。
var netSettlementAmount = -eventFlows.Sum(x => x.InterestClosePnL)
- - input.CloseFlow.FloatPnlSum
- + marginBackAmount;
+ - input.CloseFlow.FloatPnlSum;
var maturitySettlementAmount = netSettlementAmount + initialMargin + additionalMargin;
var floatRateAbs = input.CloseNotionalValue == 0m
? 0m
: interestAmount / input.CloseNotionalValue;
- // 同一数据库字段在模板中按标的类型拆分:现券展示期间付息,ETF 展示期间分红。
+ // 日终持仓的当日浮动端分红按标的类型拆分:债券展示期间付息,非债券展示期间分红。
var isCashBond = ConsGlobal.InstrumentType.IsBond(input.UnderlyingInstrumentType);
- var isEtf = ConsGlobal.InstrumentType.Fund.Equals(
- input.UnderlyingInstrumentType,
- StringComparison.OrdinalIgnoreCase);
// 此处集中完成模板字段映射和展示精度处理,生成器只负责组装原始业务数据。
return new ExcelReportModel
@@ -120,8 +117,12 @@ public static class SwapSettlementBillRowBuilder
InterestRate = interestEvents.Sum(x => x.InterestRate).ToString("0.00%"),
PosiNotionalValue = input.CloseNotionalValue.ToString("0.00"),
Quantity = input.CloseFlow.Quantity.ToString("0.00"),
- DividendIn = periodAmount.ToString("0.00"),
- PeriodDividend = isEtf ? periodAmount.ToString("0.00") : string.Empty,
+ DividendIn = isCashBond
+ ? input.CurrentDayFloatingDividend.ToString("0.00")
+ : string.Empty,
+ PeriodDividend = isCashBond
+ ? string.Empty
+ : input.CurrentDayFloatingDividend.ToString("0.00"),
PosiNetPrice = ((settlementPosition?.PosiGrossPrice ?? 0m) * 100m).ToString("0.00000000"),
InitYtm = isCashBond && input.Trade.InitYtm.HasValue
? input.Trade.InitYtm.Value.ToString("0.####%")