BugFix 特批路径没法走通

This commit is contained in:
锦麟 王
2026-08-24 17:21:21 +08:00
parent c35befbe8f
commit 8a0659312b
4 changed files with 77 additions and 11 deletions
@@ -80,10 +80,13 @@ namespace YLErp.Modules.SwapModule
}
/// <summary>
/// 互换交易保存
/// ignoreMoneyCheck=true:资金不足特批放行(additionalProcessing=LackOfMoneycontroller 按 系统参数"允许交易特批"
/// 判定后传入,与确认/审批环节 ignoreMoneyCheck 同口径);确认成交时资金校验独立再跑,特批链路在那边仍有兜底。
/// </summary>
/// <param name="td"></param>
/// <param name="ignoreMoneyCheck"></param>
/// <returns></returns>
public trade SaveTrade(trade req)
public trade SaveTrade(trade req, bool ignoreMoneyCheck = false)
{
var um = checkUnderlying(req);
trade dbTrade = new trade();
@@ -91,11 +94,12 @@ namespace YLErp.Modules.SwapModule
//资金校验须在其后取值,否则互换表单不填平铺 InitialMargin 时校验会按 0 放行)
var tradeNumberGenerated = PrepareTrade(req, TradeSourceEnum., um);
// R4 簿记资金校验:可用资金(现金结存+授信−已使用授信,口径见 RealtimePnlCalc.TradeCanBeConfirm
// 需覆盖 应付预付金+成交金额不足拦截抛错;特批放行发生在确认成交环节(ignoreMoneyCheck)。
// 需覆盖 应付预付金+成交金额不足时抛 TradeLackOfMoneyException——controller 依"允许交易特批"开关
// 走 AdditionalProcessing/LackOfMoney 特批协议(与确认/审批环节一致)或按保存失败拦截。
// ExerciseDate 为空(异常数据)时跳过该校验,避免 TradeCanBeConfirm 内部解引用抛错。
if (req.ExerciseDate.HasValue && !RealtimePnlCalc.TradeCanBeConfirm(req.ClientId, req, out var fundErrorMsg))
if (!ignoreMoneyCheck && req.ExerciseDate.HasValue && !RealtimePnlCalc.TradeCanBeConfirm(req.ClientId, req, out var fundErrorMsg))
{
throw new ServiceException(fundErrorMsg);
throw new TradeLackOfMoneyException(fundErrorMsg);
}
var trans = DbContext.Database.BeginTransaction();
@@ -0,0 +1,17 @@
using BaseOUDAL;
namespace YLErp.Modules.SwapModule
{
/// <summary>
/// R4 簿记资金校验:保存交易时资金不足(走现金部分超现金结存)的标记异常。
/// controller 识别本类型后按确认/审批环节同一协议处理——系统参数 允许交易特批(SpecialOperateForTrade) 开启时
/// 返回 AdditionalProcessing/LackOfMoney 结构化响应(UI 弹"交易特批",带 additionalProcessing=LackOfMoney 重提放行),
/// 开关关闭时按普通保存失败拦截。此前保存环节直接抛 ServiceException 无特批出口,资金不足的交易无法落库走到确认环节。
/// </summary>
public class TradeLackOfMoneyException : ServiceException
{
public TradeLackOfMoneyException(string message) : base(message)
{
}
}
}
+18 -2
View File
@@ -477,9 +477,10 @@ namespace YLErp.Web.Controllers
/// 框架合约保存
/// </summary>
/// <param name="req"></param>
/// <param name="additionalProcessing">特批重提标记:LackOfMoney=资金不足交易特批放行(须系统参数"允许交易特批"开启)</param>
/// <returns></returns>
[HttpPost]
public JsonResult tradeEditJson(trade req)
public JsonResult tradeEditJson(trade req, string additionalProcessing = null)
{
if (req == null)
{
@@ -490,16 +491,31 @@ namespace YLErp.Web.Controllers
{
req.id = DecryptInt(req.EncryptId);
}
//特批放行判定与确认/审批环节同口径(processtradelogController/ApprovalService):
//系统参数 允许交易特批(SpecialOperateForTrade) 开启 且 显式带 LackOfMoney 标记重提
var ignoreMoneyCheck = valuedateBLL.SystemDate.SpecialOperateForTrade == 1 && additionalProcessing == tradeBLL.LackOfMoney;
try
{
bool edit = req.id != 0;
var r= swapTradeService.SaveTrade(req);
var r= swapTradeService.SaveTrade(req, ignoreMoneyCheck);
Task.Run(() =>
{
RealtimePnlCalc.RealtimeSwapPosition(new OptUserInfo(0, "互换实时持仓服务", OptUserFrom.Service));
});
return JsonSuccess("更新成功", r);
}
catch (TradeLackOfMoneyException e)
{
//保存环节资金不足:开关开启时按确认/审批同一协议返回 AdditionalProcessing/LackOfMoney
//UI 弹"交易特批"确认后带 additionalProcessing=LackOfMoney 重提放行;开关关闭时按保存失败拦截
if (valuedateBLL.SystemDate.SpecialOperateForTrade == 1)
{
LogFactory.GetLogger("交易保存").Info("保存资金不足待特批:" + e.Message);
return JsonSuccessData(new { proccessType = "AdditionalProcessing", type = tradeBLL.LackOfMoney, message = e.Message });
}
LogFactory.GetLogger("交易保存").Error(e);
return JsonError("保存失败:" + e.Message);
}
catch (Exception e)
{
LogFactory.GetLogger("交易保存").Error(e);
@@ -817,12 +817,41 @@ const vue = new Vue({
"补充协议编号": $("#SupProtocolCode").val()
};
this.trade.trade_extend.ExtendJson = JSON.stringify(this.trade.trade_extend.ExtendObj);
main.post("/swaptrade2/tradeEditJson", this.trade).done(function (resp) {
window.location.href = "/swaptrade2/tradeview?enid=" + resp.obj.EncryptId;
if (window.parent && window.parent.reloadtrade) {
window.parent.reloadtrade();
//R4 保存环节资金校验:资金不足且系统开启"允许交易特批"时,服务端按确认/审批同一协议返回
//AdditionalProcessing/LackOfMoney——弹"交易特批"确认,带 additionalProcessing=LackOfMoney 重提放行
var thisObj = this;
var doSave = function (additionalProcessing) {
var url = "/swaptrade2/tradeEditJson";
if (!main.isEmpty(additionalProcessing)) {
url += "?additionalProcessing=" + additionalProcessing;
}
});
main.post(url, thisObj.trade).done(function (resp) {
if (resp.obj && resp.obj.proccessType == "AdditionalProcessing") {
if (resp.obj.type == "LackOfMoney") {
var htmlContent = '<div style="padding:10px">' + resp.obj.message + '</div>';
var lackMoneyConfirmLayer = main.open2("提示",
htmlContent,
{
area: ["430px", "175px"],
btn: ['交易特批', '取消'],
yes: function (index, layero) {
var layerIndex = lackMoneyConfirmLayer;
main.confirm("客户资金或授信不足,强制保存会导致本机构产生风险!要继续特批保存?", function () {
layer.close(layerIndex);
doSave("LackOfMoney");
});
}
});
}
return;
}
window.location.href = "/swaptrade2/tradeview?enid=" + resp.obj.EncryptId;
if (window.parent && window.parent.reloadtrade) {
window.parent.reloadtrade();
}
});
};
doSave();
},
changeMainProtocolCode() {
this.getSupProtocolCode();