diff --git a/YLErpDAL/Helpers/BondCalcHepler.cs b/YLErpDAL/Helpers/BondCalcHepler.cs
index 3247ae21..adf92b19 100644
--- a/YLErpDAL/Helpers/BondCalcHepler.cs
+++ b/YLErpDAL/Helpers/BondCalcHepler.cs
@@ -1,4 +1,4 @@
-using Org.BouncyCastle.Asn1.Ocsp;
+using Org.BouncyCastle.Asn1.Ocsp;
using System;
using System.Collections.Generic;
using System.Linq;
@@ -10,44 +10,103 @@ namespace YLErp.Helpers
{
///
/// 计算器帮助类
+ /// 调用链:zszq-trs → zszq-bond-oms(/calc/cal_bond_value) → bond-calc 微服务。
+ /// 契约(与 bond-oms-ui / zszq-bond-oms 保持一致):
+ /// 请求体 { bondId, price, priceType(DP全价/CP净价/YD收益率), targetDate?(估值日 yyyy-MM-dd,缺省代理取 T+1) }
+ /// 成功响应 data:{ errCode:0, errMsg:null, dirtyPrice(全价), cleanPrice(净价), ytm(收益率%) }
+ /// 失败响应:success=false 且 message=中文原因(债券不存在/信息不全/参数非法/服务异常)
///
public class BondCalcHepler
{
+ private const string CalcUrl = "/calc/cal_bond_value";
+
///
- /// 计算器
- ///
- ///
- public static CalBondResult BondCalc(string underlyingCode,decimal price,string priceType="DP")
+ /// 计算器(债券净价/全价/收益率互算)。
+ /// 兼容旧调用方(如 RealtimePnlCalc):返回 CalBondResult,失败返回 null。
+ /// targetDate 可选:估值日(yyyy-MM-dd),不传则沿用计算器代理默认 T+1。
+ ///
+ public static CalBondResult BondCalc(string underlyingCode, decimal price, string priceType = "DP", string targetDate = null)
+ {
+ string _err;
+ return BondCalc(underlyingCode, price, priceType, out _err, targetDate);
+ }
+
+ ///
+ /// 计算器(带错误信息输出)。
+ /// 任何失败(地址未配/无响应/success=false/业务错误码 errCode!=0/异常)都返回 null,
+ /// 并通过 errorMsg 带上**真实原因**,供上层(BondController)清晰反馈给用户。
+ /// 关键:即使 success=true,只要内部 errCode!=0(债券不存在/信息不全/参数非法)也视为失败,
+ /// 避免把 0/异常价格静默回写覆盖用户手工输入。
+ /// targetDate 可选:估值日(yyyy-MM-dd),透传给代理的 targetDate(底层 bond-calc 的 settlementDate);
+ /// 不传则代理默认取 T+1(下一工作日)。
+ ///
+ public static CalBondResult BondCalc(string underlyingCode, decimal price, string priceType, out string errorMsg, string targetDate = null)
+ {
+ errorMsg = null;
+ var baseUrl = Environment.GetEnvironmentVariable("BondOmsInterface_BaseUrl");
+ CalcBondRequest request = new CalcBondRequest()
{
- var baseUrl = Environment.GetEnvironmentVariable("BondOmsInterface_BaseUrl");
- var calculateUrl = "/calc/cal_bond_value";
- CalcBondRequest request = new CalcBondRequest() {
- bondId= underlyingCode,
- price = price.ToString(),
- priceType = priceType,
- };
- if (!string.IsNullOrEmpty(baseUrl))
+ bondId = underlyingCode,
+ price = price.ToString(),
+ priceType = priceType,
+ targetDate = targetDate,
+ };
+ if (string.IsNullOrEmpty(baseUrl))
{
+ errorMsg = "计算器服务地址未配置(BondOmsInterface_BaseUrl)";
+ return null;
+ }
+ try
+ {
+ LogFactory.GetLogger("BondCalcHepler").Info(
+ $"债券计算器请求: url={baseUrl}{CalcUrl} bondId={underlyingCode} price={price} priceType={priceType} targetDate={(string.IsNullOrEmpty(targetDate) ? "(空→代理默认T+1)" : targetDate)}");
var httpHelper = new HttpHelper(baseUrl, null);
// http 请求 Web项目接口
- var result = httpHelper.PostRequestNoAuth(calculateUrl, request).Result;
- if (result != null && !result.success)
+ var result = httpHelper.PostRequestNoAuth(CalcUrl, request).Result;
+ if (result == null)
{
- LogFactory.GetLogger("BondCalcHepler").Info("计算器计算失败:" + result.message);
+ errorMsg = "计算器服务无响应";
+ LogFactory.GetLogger("BondCalcHepler").Error("债券计算器无响应,地址:" + baseUrl + CalcUrl);
+ return null;
}
- else
+ if (!result.success)
{
- return result.data;
+ errorMsg = result.message ?? "债券计算失败";
+ LogFactory.GetLogger("BondCalcHepler").Error("债券计算失败:" + errorMsg);
+ return null;
}
+ if (result.data == null)
+ {
+ errorMsg = "计算器返回数据为空";
+ LogFactory.GetLogger("BondCalcHepler").Error("债券计算器返回 data 为空");
+ return null;
+ }
+ // 业务层错误码(债券不存在 / 债券信息不全 / 参数非法),zszq-bond-oms 在 success=true 时仍可能带 errCode!=0
+ if (result.data.errCode != 0)
+ {
+ errorMsg = result.data.errMsg ?? "债券计算业务错误";
+ LogFactory.GetLogger("BondCalcHepler").Error("债券计算业务错误(code=" + result.data.errCode + "):" + errorMsg);
+ return null;
+ }
+ LogFactory.GetLogger("BondCalcHepler").Info(
+ $"债券计算器成功: bondId={underlyingCode} targetDate={targetDate} cleanPrice={result.data.cleanPrice} dirtyPrice={result.data.dirtyPrice} ytm={result.data.ytm}");
+ return result.data;
+ }
+ catch (Exception ex)
+ {
+ errorMsg = "请求债券计算器异常:" + ex.Message;
+ LogFactory.GetLogger("BondCalcHepler").Error("请求债券计算器时发生异常", ex);
+ return null;
}
- return null;
}
-
+ ///
+ /// 按结算日计算(自动结算路径用)。与 BondCalc 同款健壮处理:
+ /// 地址未配/无响应/success=false/业务错误码/异常 均返回 null(不回写坏数据)。
+ ///
public static CalBondResult BondCalcByDate(string underlyingCode, decimal price, String targetDate, string priceType = "DP")
{
var baseUrl = Environment.GetEnvironmentVariable("BondOmsInterface_BaseUrl");
- var calculateUrl = "/calc/cal_bond_value";
CalcBondRequest request = new CalcBondRequest()
{
bondId = underlyingCode,
@@ -61,7 +120,13 @@ namespace YLErp.Helpers
try
{
// http 请求 Web项目接口
- var result = httpHelper.PostRequestNoAuth(calculateUrl, request).Result;
+ var result = httpHelper.PostRequestNoAuth(CalcUrl, request).Result;
+ if (result == null || !result.success || result.data == null || result.data.errCode != 0)
+ {
+ var msg = result != null ? (result.message ?? (result.data != null ? result.data.errMsg : null)) : "计算器服务无响应";
+ LogFactory.GetLogger("BondCalcHelper").Error("债券计算失败:" + msg);
+ return null;
+ }
return result.data;
}
catch (Exception ex)
diff --git a/YLErpWeb/Controllers/BondController.cs b/YLErpWeb/Controllers/BondController.cs
index ae8a74a1..36ef4f85 100644
--- a/YLErpWeb/Controllers/BondController.cs
+++ b/YLErpWeb/Controllers/BondController.cs
@@ -7,12 +7,14 @@ namespace YLErp.Web.Controllers
{
[AllowAnonymous]
- public JsonResult CalcBond(string underlyingCode, decimal price, string priceType)
+ public JsonResult CalcBond(string underlyingCode, decimal price, string priceType, string targetDate = null)
{
- var obj = BondCalcHepler.BondCalc(underlyingCode, price, priceType);
+ string errorMsg;
+ var obj = BondCalcHepler.BondCalc(underlyingCode, price, priceType, out errorMsg, targetDate);
if (obj == null)
{
- return JsonError("计算价格失败");
+ // 透传计算器返回的真实原因(债券不存在/信息不全/参数非法/服务异常),前端以非阻塞 toast 展示
+ return JsonError(errorMsg ?? "计算价格失败");
}
return JsonSuccess("", obj);