diff --git a/YLErpDAL/Modules/EodModule/EodPriceService.cs b/YLErpDAL/Modules/EodModule/EodPriceService.cs
index d23415b3..ce2ced60 100644
--- a/YLErpDAL/Modules/EodModule/EodPriceService.cs
+++ b/YLErpDAL/Modules/EodModule/EodPriceService.cs
@@ -1,8 +1,5 @@
-using System.Collections.Generic;
-using System.Linq;
using BaseOUDAL;
-using DocumentFormat.OpenXml.Bibliography;
-using NPOI.POIFS.NIO;
+using YLErp.BLL;
using YLErp.Helpers;
namespace YLErp.Modules.EodModule
@@ -32,6 +29,37 @@ namespace YLErp.Modules.EodModule
return (start, end);
}
+ ///
+ /// 校正 eod_commodity_future_price 行的 UnderlyingId,使其与 UnderlyingCode(=FutureContractId) 一致。
+ /// 背景:网页日终价格列表按 UnderlyingId(int) JOIN underlying_manager,而 EOD 结算(EodPriceProvider.Initialize)
+ /// 按 UnderlyingCode(string) JOIN。两列一旦失同步(典型如 FR007 的价格行 UnderlyingId 被错写成 511160.SH 的 id),
+ /// 会出现"网页能查到、结算却查不到"的错价缺失,进而 EodCheckSettlePrice 报"结算价格缺失"。
+ /// 这里以 UnderlyingCode 为准重新派生 UnderlyingId——该列才是上传/结算使用的自然键(FutureContractId),
+ /// 在入库前强制两列一致,既阻止产生新的错行,又通过告警日志把失同步暴露给运维追查上游写入来源。
+ ///
+ public static void SyncUnderlyingIdFromCode(YLContext db, eod_commodity_future_price row)
+ {
+ if (row == null || string.IsNullOrWhiteSpace(row.UnderlyingCode))
+ {
+ return;
+ }
+
+ var um = db.underlying_manager.FirstOrDefault(u => u.UnderlyingCode == row.UnderlyingCode);
+ if (um == null)
+ {
+ // 标的代码在 underlying_manager 不存在:无法校正,交由既有"标的代码不存在"等校验处理。
+ return;
+ }
+
+ if (row.UnderlyingId != um.id)
+ {
+ LogFactory.GetLogger("EodPrice").Info(
+ $"eod_commodity_future_price.UnderlyingId 与 UnderlyingCode 不一致,已自动校正: " +
+ $"FutureContractId={row.UnderlyingCode}, 原UnderlyingId={row.UnderlyingId}, 修正为={um.id}");
+ row.UnderlyingId = um.id;
+ }
+ }
+
public SearchListResult SearchUnderlyingList(EodCommodityFuturePriceReq req)
{
var (valueDtStart, valueDtEnd) = ResolveValueDateWindow(req.ValueDateStart, req.ValueDateEnd);
@@ -219,6 +247,9 @@ namespace YLErp.Modules.EodModule
dbmodel.DataSource = EodPriceBase.人工;
+ // 入库前强制 UnderlyingId 与 UnderlyingCode(FutureContractId) 一致,避免网页/结算两套 JOIN 失同步。
+ SyncUnderlyingIdFromCode(DbContext, dbmodel);
+
DbContext.SaveChanges();
return dbmodel;
diff --git a/YLErpDAL/Modules/EodModule/SettlementModule/EodSyntheticPriceSaveService.cs b/YLErpDAL/Modules/EodModule/SettlementModule/EodSyntheticPriceSaveService.cs
index d086b8bf..aac67efa 100644
--- a/YLErpDAL/Modules/EodModule/SettlementModule/EodSyntheticPriceSaveService.cs
+++ b/YLErpDAL/Modules/EodModule/SettlementModule/EodSyntheticPriceSaveService.cs
@@ -159,6 +159,9 @@ namespace YLErp.Modules.EodModule.SettlementModule
DataSource = EodPriceBase.系统
};
+ // 入库前强制 UnderlyingId 与 UnderlyingCode(FutureContractId) 一致,避免网页/结算两套 JOIN 失同步。
+ EodPriceService.SyncUnderlyingIdFromCode(DbContext, dto.CommodityPrice);
+
DbContext.eod_commodity_future_price.Add(dto.CommodityPrice);
}
diff --git a/YLErpDAL/Modules/EodModule/SettlementPriceImportService.cs b/YLErpDAL/Modules/EodModule/SettlementPriceImportService.cs
index 59e69bd2..594edcb4 100644
--- a/YLErpDAL/Modules/EodModule/SettlementPriceImportService.cs
+++ b/YLErpDAL/Modules/EodModule/SettlementPriceImportService.cs
@@ -158,6 +158,8 @@ namespace YLErp.Modules.EodModule
eodPrice.ValueDate = item.date;
eodPrice.UnderlyingCode = underlying.UnderlyingCode;
eodPrice.UnderlyingId = underlying.id;
+ // 入库前强制 UnderlyingId 与 UnderlyingCode(FutureContractId) 一致,避免网页/结算两套 JOIN 失同步。
+ EodPriceService.SyncUnderlyingIdFromCode(DbContext, eodPrice);
if (item.closePrice.HasValue)
eodPrice.ClosePrice = item.closePrice ?? 0;
if (item.settlePrice.HasValue)