feat(swap): 债券计算器C#契约对齐——targetDate估值日透传·错误处理透传真实原因·链路日志
- BondCalcHepler.BondCalc 新增可选 targetDate(估值日) 参数并写入请求体,透传至代理 zszq-bond-oms 的 targetDate(→bond-calc settlementDate);不传则沿用代理默认 T+1,与 bond-oms-ui 契约一致。 - 新增 out errorMsg 重载:地址未配/无响应/success=false/业务错误码 errCode!=0/异常 均返回 null 并透出真实中文原因;日志级别由 Info 升为 Error,try/catch 包裹。 - BondController.CalcBond 把 errorMsg 透传给 JsonError,不再硬编码"计算价格失败"。 - BondCalcByDate(自动结算路径) 同步加 errCode/空守卫,避免回写坏数据。
This commit is contained in:
@@ -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
|
||||
{
|
||||
/// <summary>
|
||||
/// 计算器帮助类
|
||||
/// 调用链: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=中文原因(债券不存在/信息不全/参数非法/服务异常)
|
||||
/// </summary>
|
||||
public class BondCalcHepler
|
||||
{
|
||||
private const string CalcUrl = "/calc/cal_bond_value";
|
||||
|
||||
/// <summary>
|
||||
/// 计算器
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static CalBondResult BondCalc(string underlyingCode,decimal price,string priceType="DP")
|
||||
/// 计算器(债券净价/全价/收益率互算)。
|
||||
/// 兼容旧调用方(如 RealtimePnlCalc):返回 CalBondResult,失败返回 null。
|
||||
/// targetDate 可选:估值日(yyyy-MM-dd),不传则沿用计算器代理默认 T+1。
|
||||
/// </summary>
|
||||
public static CalBondResult BondCalc(string underlyingCode, decimal price, string priceType = "DP", string targetDate = null)
|
||||
{
|
||||
string _err;
|
||||
return BondCalc(underlyingCode, price, priceType, out _err, targetDate);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 计算器(带错误信息输出)。
|
||||
/// 任何失败(地址未配/无响应/success=false/业务错误码 errCode!=0/异常)都返回 null,
|
||||
/// 并通过 errorMsg 带上**真实原因**,供上层(BondController)清晰反馈给用户。
|
||||
/// 关键:即使 success=true,只要内部 errCode!=0(债券不存在/信息不全/参数非法)也视为失败,
|
||||
/// 避免把 0/异常价格静默回写覆盖用户手工输入。
|
||||
/// targetDate 可选:估值日(yyyy-MM-dd),透传给代理的 targetDate(底层 bond-calc 的 settlementDate);
|
||||
/// 不传则代理默认取 T+1(下一工作日)。
|
||||
/// </summary>
|
||||
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<CalcBondRequest, CalcBondReponse>(calculateUrl, request).Result;
|
||||
if (result != null && !result.success)
|
||||
var result = httpHelper.PostRequestNoAuth<CalcBondRequest, CalcBondReponse>(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;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 按结算日计算(自动结算路径用)。与 BondCalc 同款健壮处理:
|
||||
/// 地址未配/无响应/success=false/业务错误码/异常 均返回 null(不回写坏数据)。
|
||||
/// </summary>
|
||||
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<CalcBondRequest, CalcBondReponse>(calculateUrl, request).Result;
|
||||
var result = httpHelper.PostRequestNoAuth<CalcBondRequest, CalcBondReponse>(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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user