fix: 日终债券来源固定中债估值、人工改动显示操作人并补上传溯源
china_bond_valuation 来源恒为中债估值(聚源仅转发,无人手工维护),不再按 JSID 推断系统/人工;eod 两表仍用自带 DataSource(人工/系统)。债券被人工改动(update_user 非空)时,日终列表来源列显示操作人姓名,否则显示中债估值;操作人经已有 create_user/update_user 列溯源(零 DDL)。手工上传 xlsx 的债券分支补戳操作人,与表单编辑口径一致。配套单测 EodPriceDtoTest / EodPriceGoldenReplayTest + golden JSON。
This commit is contained in:
@@ -1,4 +1,6 @@
|
||||
using BaseOUDAL;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using BaseOUDAL;
|
||||
using DocumentFormat.OpenXml.Bibliography;
|
||||
using NPOI.POIFS.NIO;
|
||||
using YLErp.Helpers;
|
||||
@@ -25,21 +27,15 @@ namespace YLErp.Modules.EodModule
|
||||
var predicatEot = PredicateBuilder.Create<eod_stock_price>(source => source.ValueDate >= valueDtStart && source.ValueDate < valueDtEnd);
|
||||
var predicatEob = PredicateBuilder.Create<ChinaBondValuation>(source => source.valuation_date >= valueDtStart && source.valuation_date < valueDtEnd);
|
||||
|
||||
// 数据来源常量(统一引用,避免各处手写"人工"/"系统"对不齐)
|
||||
var srcManual = EodPriceBase.人工;
|
||||
var srcSystem = EodPriceBase.系统;
|
||||
|
||||
if (!string.IsNullOrEmpty(req.DataSource))
|
||||
{
|
||||
predicatEoc = predicatEoc.And(d => d.DataSource.Contains(req.DataSource));
|
||||
predicatEot = predicatEot.And(d => d.DataSource.Contains(req.DataSource));
|
||||
if (req.DataSource=="系统")
|
||||
// 债券来源恒为"中债估值"(聚源仅转发,无人手工维护),
|
||||
// 只有按"中债估值"筛选时才命中债券;人工/系统筛选不命中债券。
|
||||
if (req.DataSource != EodPriceBase.中债估值)
|
||||
{
|
||||
predicatEob= predicatEob.And(d => d.JSID!=null);
|
||||
}
|
||||
else
|
||||
{
|
||||
predicatEob = predicatEob.And(d => d.JSID==null);
|
||||
predicatEob = predicatEob.And(d => false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,8 +74,7 @@ namespace YLErp.Modules.EodModule
|
||||
SourceTime = source.SourceTime,
|
||||
DeciClosePrice=0,
|
||||
DeciSettlePrice = 0,
|
||||
DeciReferencePrice=0,
|
||||
JSID = null
|
||||
DeciReferencePrice=0
|
||||
};
|
||||
|
||||
var query2 = from un in queryUn
|
||||
@@ -106,8 +101,7 @@ namespace YLErp.Modules.EodModule
|
||||
SourceTime = stockClose.SourceTime,
|
||||
DeciClosePrice = 0,
|
||||
DeciSettlePrice = 0,
|
||||
DeciReferencePrice = 0,
|
||||
JSID=null
|
||||
DeciReferencePrice = 0
|
||||
};
|
||||
var query3 = from un in queryUn
|
||||
join bondClose in DbContext.china_bond_valuation.Where(predicatEob) on un.UnderlyingCode equals bondClose.bond_id
|
||||
@@ -115,7 +109,8 @@ namespace YLErp.Modules.EodModule
|
||||
{
|
||||
IsBond = true,
|
||||
id = bondClose.id,
|
||||
DataSource = bondClose.JSID != null ? srcSystem : srcManual,
|
||||
UpdateUser = bondClose.update_user,
|
||||
// 债券 DataSource 在后处理统一置为固定值"中债估值"(见下方 foreach)。
|
||||
LaunchState = un.LaunchState,
|
||||
MarketName = un.MarketName,
|
||||
UnderlyingId = un.id,
|
||||
@@ -133,8 +128,7 @@ namespace YLErp.Modules.EodModule
|
||||
UpdateTime = bondClose.update_time,
|
||||
ReferencePrice=0,
|
||||
DeciReferencePrice = bondClose.yield,
|
||||
SourceTime="",
|
||||
JSID=bondClose.JSID
|
||||
SourceTime=""
|
||||
};
|
||||
var unionQuery = query1.Concat(query2);
|
||||
var finalQuery = unionQuery.Concat(query3);
|
||||
@@ -143,11 +137,29 @@ namespace YLErp.Modules.EodModule
|
||||
req.sidx = "ValueDate";
|
||||
req.sord = "desc";
|
||||
}
|
||||
var result= finalQuery.ToSearchList(req);
|
||||
var result = finalQuery.ToSearchList(req);
|
||||
|
||||
// 解析手工改过估值的债券操作人姓名:update_user 非空 = 被人手工改过(聚源同步为 NULL)。
|
||||
// 此时来源列显示改这个人名,而非"中债估值",以便溯源到具体操作人。
|
||||
var manualBondRows = result.rows.Where(r => r.IsBond && r.UpdateUser.HasValue).ToList();
|
||||
Dictionary<long, string> operatorNameMap = null;
|
||||
if (manualBondRows.Any())
|
||||
{
|
||||
var operatorIds = manualBondRows.Select(r => r.UpdateUser.Value).Distinct().ToList();
|
||||
using (var erpCtx = DbContextFactory.GetErpBaseContext())
|
||||
{
|
||||
operatorNameMap = erpCtx.SystemUsers.AsNoTracking()
|
||||
.Where(u => operatorIds.Contains((long)u.Id))
|
||||
.ToDictionary(u => (long)u.Id, u => u.Name);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var item in result.rows)
|
||||
{
|
||||
if (item.IsBond)
|
||||
{
|
||||
// 人工改动过则显示改这个人名,否则显示"中债估值"。
|
||||
item.DataSource = ResolveBondDisplaySource(item.UpdateUser, operatorNameMap);
|
||||
item.SourceTime = item.UpdateTime.HasValue? item.UpdateTime.Value.ToString("yyyy-MM-dd HH:mm:ss"):"";
|
||||
item.SettlePrice=Convert.ToDouble(item.DeciSettlePrice);
|
||||
item.ClosePrice = Convert.ToDouble(item.DeciClosePrice);
|
||||
@@ -218,11 +230,50 @@ namespace YLErp.Modules.EodModule
|
||||
}
|
||||
UpdateChanges(dbmodel, req);
|
||||
}
|
||||
// 记录手工编辑人:写入登录用户ID到已有列(create_user/update_user),
|
||||
// 不新增字段。聚源同步路径(SettlementPriceImportService)不写这两列,故 NULL 即"自动同步"。
|
||||
StampBondOperator(dbmodel, UserId, req.id == 0);
|
||||
dbmodel.update_time = DateTime.Now;
|
||||
DbContext.SaveChanges();
|
||||
|
||||
return dbmodel;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 标记债券估值(china_bond_valuation)的操作人。
|
||||
/// 该表已有 create_user/update_user 两列(bigint),但聚源同步路径不写入,
|
||||
/// 因此:NULL = 聚源/中债自动同步;有值 = 被人手工编辑(记录登录用户ID)。
|
||||
/// 抽出为纯静态函数,供 SaveBondPrice 与单元测试共用。
|
||||
/// </summary>
|
||||
/// <param name="model">债券估值实体</param>
|
||||
/// <param name="userId">当前登录用户ID</param>
|
||||
/// <param name="isNew">是否为新增(true 时同时写 create_user)</param>
|
||||
public static void StampBondOperator(ChinaBondValuation model, int userId, bool isNew)
|
||||
{
|
||||
model.update_user = userId;
|
||||
if (isNew)
|
||||
{
|
||||
model.create_user = userId;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 债券来源列该显示什么:
|
||||
/// - update_user 有值(被人手工改过)且能解析到操作人姓名 → 显示改这个人名,便于溯源;
|
||||
/// - 否则(聚源/中债自动同步,update_user 为 NULL)→ 固定显示"中债估值"。
|
||||
/// 抽为纯静态函数,与解析姓名所需的 sys_user 查询解耦,便于无库单元测试。
|
||||
/// </summary>
|
||||
/// <param name="updateUser">china_bond_valuation.update_user(NULL = 自动同步)</param>
|
||||
/// <param name="operatorNameMap">update_user(ID) → 操作人姓名 的字典(由调用方按需从 sys_user 解析)</param>
|
||||
public static string ResolveBondDisplaySource(long? updateUser, IDictionary<long, string> operatorNameMap)
|
||||
{
|
||||
if (updateUser.HasValue && operatorNameMap != null
|
||||
&& operatorNameMap.TryGetValue(updateUser.Value, out var opName) && !string.IsNullOrEmpty(opName))
|
||||
{
|
||||
return opName;
|
||||
}
|
||||
return EodPriceBase.中债估值;
|
||||
}
|
||||
/// <summary>
|
||||
/// 保存日终股票价格
|
||||
/// </summary>
|
||||
@@ -346,6 +397,11 @@ namespace YLErp.Modules.EodModule
|
||||
|
||||
public bool IsBond { get; set; }
|
||||
|
||||
public long? JSID { get; set; }
|
||||
/// <summary>
|
||||
/// 手工改过估值时的操作人ID(china_bond_valuation.update_user)。
|
||||
/// NULL = 聚源/中债自动同步(无人手工维护);有值 = 被人手工改过、可溯源。
|
||||
/// 仅债券行可能非空,用于列表来源列显示改这个人名而非"中债估值"。
|
||||
/// </summary>
|
||||
public long? UpdateUser { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -128,6 +128,10 @@ namespace YLErp.Modules.EodModule
|
||||
if (item.ReferencePrice.HasValue)
|
||||
eodPrice.yield = Convert.ToDecimal(item.ReferencePrice);
|
||||
eodPrice.update_time = DateTime.Now;
|
||||
// 手工上传也是登录用户的人工动作,戳操作人到已有列(create_user/update_user),
|
||||
// 使列表来源列显示上传人姓名(与 SaveBondPrice 口径一致);聚源/中债自动同步(外部ETL)不写这两列。
|
||||
// eodPrice.id==0 表示本次新增(尚未落库),非0为命中已有行的更新。
|
||||
EodPriceService.StampBondOperator(eodPrice, UserId, eodPrice.id == 0);
|
||||
result.SuccessCount++;
|
||||
}
|
||||
else if (!underlying.CalcTypeIsStock())
|
||||
|
||||
Reference in New Issue
Block a user