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);