1425 lines
58 KiB
C#
1425 lines
58 KiB
C#
using Autofac.Core;
|
||
using BaseOUDAL;
|
||
using CsvHelper;
|
||
using DocumentFormat.OpenXml.Spreadsheet;
|
||
using Microsoft.AspNetCore.Authorization;
|
||
using System.Collections.Concurrent;
|
||
using System.Linq;
|
||
using System.Web.Mvc;
|
||
using YLErp.BLL;
|
||
using YLErp.BLL.Eod;
|
||
using YLErp.Configuration;
|
||
using YLErp.DBModels;
|
||
using YLErp.DBModels.Consts;
|
||
using YLErp.Enums;
|
||
using YLErp.Model.Enum;
|
||
using YLErp.Modules.RiskEngine;
|
||
using YLErp.Modules.RiskModule;
|
||
using YLErp.Modules.SalesModule;
|
||
using YLErp.Modules.SwapModule;
|
||
using YLErp.Modules.SwapModule.Dto;
|
||
using YLErp.Modules.TradeModule;
|
||
using YLErp.Modules.TradeModule.DealModule;
|
||
using YLErp.Modules.TradeModule.DocGenerateModule;
|
||
using YLErp.Modules.TradeMsgOutputModule;
|
||
using YLErp.QdpModule;
|
||
|
||
namespace YLErp.Web.Controllers
|
||
{
|
||
/// <summary>
|
||
/// 新版交易互换
|
||
/// </summary>
|
||
public class SwapTrade2Controller : BaseController
|
||
{
|
||
#region 框架合约
|
||
//按年份判断是否有IB日历,优先用IB,没有则用CHN
|
||
private string GetBestCountry(int year)
|
||
{
|
||
var hasIB = CalendarBLL.GetAllcalendarModel()
|
||
.Any(c => c.Year == year && "ib".Equals(c.Country, StringComparison.OrdinalIgnoreCase));
|
||
return hasIB ? "ib" : "chn";
|
||
}
|
||
|
||
[MyAuthorize("交易管理-互换交易")]
|
||
public ActionResult TradeList(string settleDate = null, string observationDate = null)
|
||
{
|
||
ViewBag.settleDate = settleDate;
|
||
ViewBag.observationDate = observationDate;
|
||
return View();
|
||
}
|
||
public ActionResult TradeEdit(string enid, string renewEnid = null, bool isUseApproval = false)
|
||
{
|
||
ViewBag.isUseApproval = isUseApproval;
|
||
if (!string.IsNullOrWhiteSpace(renewEnid) && !CurUser.交易管理_交易续作)
|
||
{
|
||
return ShowError("没有续作交易权限");
|
||
}
|
||
// The new/renew flow uses the literal "0" to indicate that no trade exists yet.
|
||
var intid = enid == "0" ? 0 : DecryptInt(enid);
|
||
trade r = null;
|
||
if (intid == 0)
|
||
{
|
||
r = CreateNewTrade();
|
||
var renewTradeId = DecryptInt(renewEnid);
|
||
if (renewTradeId > 0)
|
||
{
|
||
var sourceTrade = new SwapTradeService(CurUser).GetSwapTrade(renewTradeId);
|
||
if (sourceTrade == null)
|
||
{
|
||
return ShowError("没有找到交易数据");
|
||
}
|
||
|
||
r = CreateRenewTrade(sourceTrade, r);
|
||
}
|
||
return View(r);
|
||
}
|
||
SwapTradeService swapTradeService = new SwapTradeService(CurUser);
|
||
r = swapTradeService.GetSwapTrade(intid);
|
||
if (r == null)
|
||
{
|
||
return ShowError("没有找到交易数据");
|
||
}
|
||
|
||
return View(r);
|
||
}
|
||
|
||
private trade CreateNewTrade()
|
||
{
|
||
var defaultMarginTemplateName = SwapMarginTemplateConfigService.GetConfig().defaultValue;
|
||
var tradeExtendJson = new TradeExtendJson()
|
||
{
|
||
FlowBookMode = (int)FlowBookModeEnum.先进先出,
|
||
FloatingPnlAnnualized = false,
|
||
NeedOpenFee = false,
|
||
OpenFeeType = 0,
|
||
InterestCalcMode = "10",
|
||
SettlementRules = 0,
|
||
DividendPayDate = 0
|
||
};
|
||
var tradeDateCountry = GetBestCountry(valuedateBLL.ValueDate.Year);
|
||
return new trade()
|
||
{
|
||
TradeType = "收益互换",
|
||
UnderlyingInstrumentType = "Stock",
|
||
StartDate = valuedateBLL.ValueDate,
|
||
TradeDate = QdpCalendarHelper.GetNonHolidayDefore(valuedateBLL.ValueDate.AddDays(-1), tradeDateCountry),
|
||
TraderId = CurUser.UserId,
|
||
TraderName = CurUser.UserName,
|
||
MarginTemplateName = defaultMarginTemplateName,
|
||
//资金来源必填(现金/授信),新交易默认现金
|
||
MarginFundSource = ConsFundTag.Cash,
|
||
OpponentRole = "乙方",
|
||
OriginalStockEqvNotional = 0,
|
||
StructureType = "普通债券类收益互换",
|
||
InitialMargin = 0,
|
||
trade_extend = new trade_extend()
|
||
{
|
||
ExtendJson = JsonHelper.Serialize(tradeExtendJson)
|
||
},
|
||
MetaDic = new Dictionary<string, string>
|
||
{
|
||
{ "清算机构", "甲方" }
|
||
}
|
||
};
|
||
}
|
||
|
||
private trade CreateRenewTrade(trade sourceTrade, trade defaultTrade)
|
||
{
|
||
var renewTrade = sourceTrade.Clone();
|
||
renewTrade.id = 0;
|
||
renewTrade.TradeNumber = string.Empty;
|
||
renewTrade.ParentTradeId = 0;
|
||
renewTrade.IsGroup = 0;
|
||
renewTrade.IsApproval = false;
|
||
renewTrade.TradeDate = defaultTrade.TradeDate;
|
||
renewTrade.StartDate = defaultTrade.StartDate;
|
||
renewTrade.ExerciseDate = null;
|
||
renewTrade.MaturityDate = null;
|
||
renewTrade.SettlementDate = null;
|
||
renewTrade.UnWindDate = null;
|
||
renewTrade.PremiumPayDate = null;
|
||
renewTrade.SettlementFlagDate = null;
|
||
renewTrade.HasPartialUnWind = null;
|
||
renewTrade.TradeStatus = null;
|
||
renewTrade.CheckStatus = null;
|
||
renewTrade.ProcessStatus = null;
|
||
renewTrade.ProcessOrderId = 0;
|
||
renewTrade.ProcessOrderBranch = 0;
|
||
renewTrade.ProcessOptDate = null;
|
||
renewTrade.ValidState = null;
|
||
renewTrade.CreateDate = null;
|
||
renewTrade.TradeSource = null;
|
||
// 恢复初始名义本金(源交易若有过部分平仓,StockEqvNotional/TradeAmount/Notional 已递减,
|
||
// 但 OriginalStockEqvNotional 和 OriginalNotional 始终保留原始值不被递减)
|
||
if (renewTrade.OriginalStockEqvNotional != null)
|
||
{
|
||
renewTrade.StockEqvNotional = (double)renewTrade.OriginalStockEqvNotional;
|
||
}
|
||
renewTrade.Notional = renewTrade.OriginalNotional ?? renewTrade.TradeAmount;
|
||
renewTrade.TradeAmount = renewTrade.OriginalNotional ?? renewTrade.TradeAmount;
|
||
// 结算标识 — 源交易可能为"延期结算",续做时重置为正常结算
|
||
renewTrade.SettlementFlag = 0;
|
||
renewTrade.SettlementFlagOptId = null;
|
||
// trade_swap — 重置源交易遗留的 PK/FK 和运行时字段
|
||
if (renewTrade.trade_swap != null)
|
||
{
|
||
renewTrade.trade_swap.id = 0;
|
||
renewTrade.trade_swap.TradeId = 0;
|
||
renewTrade.trade_swap.FlowId = null;
|
||
renewTrade.trade_swap.OriginalTradeId = null;
|
||
|
||
// The renewed payment floating leg opens the opposite underlying side.
|
||
// 这里只需要对【支付】相关腿进行操作
|
||
// 原收取腿不变
|
||
// 支付 多头 = 空头
|
||
// 支付 空头 = 多头
|
||
// 收取 空头 = 空头
|
||
// 收取 多头 = 多头
|
||
//
|
||
// if (renewTrade.trade_swap.IsPayFloatingProfit)
|
||
// {
|
||
// renewTrade.trade_swap.PayLongShort = ReverseLongShort(renewTrade.trade_swap.PayLongShort);
|
||
// }
|
||
}
|
||
renewTrade.trade_extend = sourceTrade.trade_extend?.Clone() ?? defaultTrade.trade_extend;
|
||
renewTrade.trade_extend.TradeId = 0;
|
||
renewTrade.trade_Initial_Margin = sourceTrade.trade_Initial_Margin?.Clone() ?? new trade_initial_margin();
|
||
renewTrade.trade_Initial_Margin.TradeId = 0;
|
||
renewTrade.MetaDic = sourceTrade.MetaDic == null
|
||
? new Dictionary<string, string>()
|
||
: new Dictionary<string, string>(sourceTrade.MetaDic);
|
||
// 只克隆初始持仓(IsInitial=true),避免将部分平仓后的实时持仓(名义本金已递减)带入续做交易
|
||
renewTrade.swap_positions = sourceTrade.swap_positions
|
||
?.Where(p => p.IsInitial)
|
||
.Select(position =>
|
||
{
|
||
var renewPosition = position.Clone();
|
||
renewPosition.id = 0;
|
||
renewPosition.PositionId = 0;
|
||
renewPosition.SwapTradeId = 0;
|
||
renewPosition.PosiNumber = null;
|
||
renewPosition.PosiStartDate = defaultTrade.StartDate.Value;
|
||
renewPosition.PosiMatuirityDate = null;
|
||
// 预付金腿的 HappenDate 用于后续生成资金流水(ResetMarginAmount 按 HappenDate 过滤),
|
||
// 续做时设为新交易的起始日;非预付金腿的 HappenDate 无实际用途,置 null
|
||
renewPosition.HappenDate =
|
||
position.InterestMode == (int)YLErp.DBModels.InterestModeEnum.初始预付金
|
||
? defaultTrade.StartDate
|
||
: null;
|
||
// 清空运行时累计字段(这些字段在源交易存续期间可能被累计)
|
||
renewPosition.InterestAmount = 0;
|
||
renewPosition.InterestFeePending = 0;
|
||
renewPosition.FloatRate = 0;
|
||
renewPosition.PosiDividendIncome = 0;
|
||
renewPosition.InterestSwapInterval = null;
|
||
renewPosition.Obervation = null;
|
||
if (renewPosition.PosiDirection == 2)
|
||
{
|
||
renewPosition.PositionType = ReverseLongShort(renewPosition.PositionType);
|
||
}
|
||
return renewPosition;
|
||
}).ToList() ?? new List<swap_position>();
|
||
// 清空源交易的事件/持仓快照等集合,避免与源交易共享引用
|
||
renewTrade.swap_Events = new List<swap_event>();
|
||
renewTrade.swap_Flow_Events = new List<swap_flow_event>();
|
||
renewTrade.eod_swaps = new List<eod_swap>();
|
||
renewTrade.inital_eod_swap_positions = new List<eod_swap_position>();
|
||
renewTrade.eod_swap_positions = new List<eod_swap_position>();
|
||
renewTrade.ClientCashInCashOutList = new List<ClientCashInCashOut>();
|
||
return renewTrade;
|
||
}
|
||
|
||
private static int ReverseLongShort(int PositionType)
|
||
{
|
||
if (PositionType == 1)
|
||
{
|
||
return 2;
|
||
}
|
||
|
||
if (PositionType == 2)
|
||
{
|
||
return 1;
|
||
}
|
||
|
||
return PositionType;
|
||
}
|
||
/// <summary>
|
||
/// 详情
|
||
/// </summary>
|
||
/// <param name="enid"></param>
|
||
/// <param name="isFromPositionReport"></param>
|
||
/// <param name="isOnlyCloseButton"></param>
|
||
/// <param name="operationStatus"></param>
|
||
/// <returns></returns>
|
||
public ActionResult TradeView(string enid, bool isFromPositionReport = false, bool isOnlyCloseButton = false, string operationStatus = "")
|
||
{
|
||
var intid = DecryptInt(enid);
|
||
SwapTradeService swapTradeService = new SwapTradeService(CurUser);
|
||
var tradeObj = swapTradeService.GetSwapTrade(intid);
|
||
if (tradeObj == null)
|
||
{
|
||
return ShowError("没有找到交易数据");
|
||
}
|
||
//保证金模板V2迁移:不再把非模板的历史值回退为默认值,MarginTemplateName 原样展示
|
||
//var marginTemplateConfig = SwapMarginTemplateConfigService.GetConfig();
|
||
//if (string.IsNullOrWhiteSpace(tradeObj.MarginTemplateName)
|
||
// || !marginTemplateConfig.options.Any(item => item.Value == tradeObj.MarginTemplateName))
|
||
//{
|
||
// tradeObj.MarginTemplateName = marginTemplateConfig.defaultValue;
|
||
//}
|
||
TradeViewModel model;
|
||
|
||
model = new TradeViewModel(tradeObj)
|
||
{
|
||
IsFromPositionReport = false,
|
||
BinaryCalculation = valuedateBLL.BinaryCalculation,
|
||
IsOnlyCloseButton = isOnlyCloseButton,
|
||
OperationStatus = operationStatus
|
||
};
|
||
//获取交易销售提成数据
|
||
model.SalesCommission = new SalesCommissionDataService(CurUser).GetSalesCommissionInfoDtos(intid);
|
||
return View(model);
|
||
}
|
||
/// <summary>
|
||
/// 多空组合平仓详情
|
||
/// </summary>
|
||
/// <param name="enid"></param>
|
||
/// <param name="valueDate"></param>
|
||
/// <returns></returns>
|
||
public ActionResult CloseDetial(string enid, DateTime valueDate)
|
||
{
|
||
var intid = DecryptInt(enid);
|
||
var closeModel = new SwapEodPositionService(CurUser).GetCloseDetails(intid, valueDate);
|
||
return View(closeModel);
|
||
}
|
||
/// <summary>
|
||
/// 撤销审批
|
||
/// </summary>
|
||
/// <param name="enid"></param>
|
||
/// <returns></returns>
|
||
public JsonResult traderevoke(string enid)
|
||
{
|
||
var intid = DecryptInt(enid);
|
||
new SwapTradeService(CurUser).TradeRevoke(intid);
|
||
return JsonSuccess("");
|
||
}
|
||
/// <summary>
|
||
/// 校验交易上一日是否收盘
|
||
/// </summary>
|
||
/// <param name="enid"></param>
|
||
/// <returns></returns>
|
||
public JsonResult CheckEodTrade(string enid)
|
||
{
|
||
var intid = DecryptInt(enid);
|
||
new SwapDealService(CurUser).CheckEodTrade(intid);
|
||
return JsonSuccess("");
|
||
}
|
||
/// <summary>
|
||
/// 校验收益结算操作(不检查收盘限制)
|
||
/// </summary>
|
||
/// <param name="enid"></param>
|
||
/// <returns></returns>
|
||
public JsonResult CheckEodTradeForIncome(string enid)
|
||
{
|
||
var intid = DecryptInt(enid);
|
||
new SwapDealService(CurUser).CheckEodTradeForIncome(intid);
|
||
return JsonSuccess("");
|
||
}
|
||
/// <summary>
|
||
/// 收益互换 平仓
|
||
/// </summary>
|
||
/// <param name="enid"></param>
|
||
/// <returns></returns>
|
||
public ActionResult SwapUnwind(string enid, bool isUseApproval = false)
|
||
{
|
||
var intid = DecryptInt(enid);
|
||
var model = new SwapDealService(CurUser).InitUnwind(intid);
|
||
ViewBag.isUseApproval = isUseApproval;
|
||
var hasProcess = new SwapDealService(CurUser).HasTradeProcess();
|
||
//需要审批或者复核的交易都会显示行权审核提交按钮
|
||
ViewBag.IsShowReCheckClose = (valuedateBLL.SystemDate.CloseReCheck == 1) || (valuedateBLL.SystemDate.CloseReApprove == 1 && hasProcess);
|
||
return View(model);
|
||
}
|
||
/// <summary>
|
||
/// 收益互换 互换
|
||
/// </summary>
|
||
/// <param name="enid"></param>
|
||
/// <returns></returns>
|
||
public ActionResult SwapIncome(string enid, bool isUseApproval = false)
|
||
{
|
||
var intid = DecryptInt(enid);
|
||
var model = new SwapDealService(CurUser).InitIncome(intid);
|
||
ViewBag.isUseApproval = isUseApproval;
|
||
var hasProcess = new SwapDealService(CurUser).HasTradeProcess();
|
||
//需要审批或者复核的交易都会显示行权审核提交按钮
|
||
ViewBag.IsShowReCheckClose = (valuedateBLL.SystemDate.CloseReCheck == 1) || (valuedateBLL.SystemDate.CloseReApprove == 1 && hasProcess);
|
||
return View(model);
|
||
}
|
||
/// <summary>
|
||
/// 操作历史
|
||
/// </summary>
|
||
/// <param name="enid"></param>
|
||
/// <returns></returns>
|
||
public ActionResult OperationHistory(string enid)
|
||
{
|
||
ViewBag.Enid = enid;
|
||
return View();
|
||
}
|
||
public ActionResult tradeBack(string enid)
|
||
{
|
||
var id = DecryptInt(enid);
|
||
var trade = new SwapTradeService(CurUser).GetTrade(id);
|
||
var model = new TradeBackModel()
|
||
{
|
||
TradeId = id,
|
||
ValueDate = valuedateBLL.ValueDate <= trade.ExerciseDate ? valuedateBLL.ValueDate : trade.ExerciseDate.Value,
|
||
TradeDate = trade.TradeDate.Value
|
||
};
|
||
return View(model);
|
||
}
|
||
/// <summary>
|
||
/// 操作历史查询
|
||
/// </summary>
|
||
/// <param name="enid"></param>
|
||
/// <returns></returns>
|
||
public JsonResult GetOperationHistorys(string enid)
|
||
{
|
||
var intid = DecryptInt(enid);
|
||
var result = new SwapEventService(CurUser).GetOpreationHistorys(intid);
|
||
return JsonSuccess("", result);
|
||
}
|
||
/// <summary>
|
||
/// 交易回退
|
||
/// </summary>
|
||
/// <param name="tradeId"></param>
|
||
/// <returns></returns>
|
||
public JsonResult TradeBackByDate(TradeBackModel model)
|
||
{
|
||
new SwapTradeService(CurUser).TradeBack(model.TradeId, model.TradeDate);
|
||
return JsonSuccess("回退成功");
|
||
}
|
||
/// <summary>
|
||
/// 根据平仓日期刷新持仓基线(处理公司行为除权)
|
||
/// </summary>
|
||
/// <param name="tradeId">交易ID</param>
|
||
/// <param name="valueDate">事件日期/平仓日期</param>
|
||
/// <returns>返回最新的持仓数量、价格等基线数据</returns>
|
||
public JsonResult RefreshUnwindBaseline(int tradeId, DateTime valueDate)
|
||
{
|
||
var (positionQty, posiNotionalValue, posiGrossPrice, posiNetPrice, isRestored) =
|
||
new SwapDealService(CurUser).RefreshFloatLegBaseline(tradeId, valueDate);
|
||
|
||
var result = new
|
||
{
|
||
PositionQty = positionQty,
|
||
PosiNotionalValue = posiNotionalValue,
|
||
PosiGrossPrice = posiGrossPrice,
|
||
PosiNetPrice = posiNetPrice,
|
||
IsRestored = isRestored,
|
||
// 全平时,平仓数量等于持仓数量
|
||
CloseQty = positionQty,
|
||
CloseNotionalValue = posiNotionalValue
|
||
};
|
||
|
||
return JsonSuccess("", result);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 平仓利息腿信息
|
||
/// </summary>
|
||
/// <param name="valueDate"></param>
|
||
/// <param name="tradeId"></param>
|
||
/// <param name="closePercent"></param>
|
||
/// <returns></returns>
|
||
public JsonResult GetUnwindInterestList(DateTime valueDate,DateTime unwindDate, int tradeId, decimal closePercent, int eventType, decimal notionalValue = 0, decimal posiNotionalValue = 0, bool isPenaltyInterest = false)
|
||
{
|
||
unwindDate = valueDate;
|
||
// 前端按"占期初(original)"语义传 closePercent(A);后端 GetUnwindInterests 按"占剩余(remaining)"语义(B)计算。
|
||
// 多空互换前端不传 notionalValue/posiNotionalValue(默认 0),则跳过转换保持原行为。
|
||
var convertedClosePercent = SwapDealService.ToRemainingClosePercent(closePercent, notionalValue, posiNotionalValue);
|
||
var interests = new SwapDealService(CurUser).GetUnwindInterests(valueDate, unwindDate, tradeId, convertedClosePercent, eventType, isPenaltyInterest);
|
||
foreach (var interest in interests)
|
||
{
|
||
interest.TdInterestAmount=Math.Round(interest.TdInterestAmount, ConsGlobal.MoneyRound,MidpointRounding.AwayFromZero);
|
||
interest.InterestAmount=Math.Round(interest.InterestAmount, ConsGlobal.MoneyRound,MidpointRounding.AwayFromZero);
|
||
interest.InterestClosePnL=Math.Round(interest.InterestClosePnL, ConsGlobal.MoneyRound,MidpointRounding.AwayFromZero);
|
||
}
|
||
return JsonSuccess("", interests);
|
||
}
|
||
/// <summary>
|
||
///单标的 平仓
|
||
/// </summary>
|
||
/// <param name="unwindData">本次单标的平仓数据。</param>
|
||
/// <param name="trialDataId">首次新风控试算记录ID;二次确认时传入。</param>
|
||
/// <param name="ignoreRiskRuleIds">首次试算返回的需忽略规则ID;二次确认时传入。</param>
|
||
/// <returns>平仓结果或新风控确认信息。</returns>
|
||
public JsonResult SwapUnwindJson(UnwindData unwindData, int? trialDataId = null, string ignoreRiskRuleIds = null)
|
||
{
|
||
var result = new SwapDealService(CurUser).SwapUnwind(unwindData, CreateRiskTrialConfirmation(trialDataId, ignoreRiskRuleIds));
|
||
return BuildCloseRiskResult(result, "平仓成功");
|
||
}
|
||
/// <summary>
|
||
/// 互换
|
||
/// </summary>
|
||
/// <param name="swap_Deal"></param>
|
||
/// <returns></returns>
|
||
public JsonResult SwapIncomeJson(UnwindData unwindData)
|
||
{
|
||
new SwapDealService(CurUser).SwapIncome(unwindData);
|
||
return JsonSuccess("互换成功");
|
||
}
|
||
/// <summary>
|
||
/// 互换/平仓提交申请
|
||
/// </summary>
|
||
/// <param name="unwindData">本次互换或平仓数据。</param>
|
||
/// <param name="eventType">事件类型。</param>
|
||
/// <param name="trialDataId">首次新风控试算记录ID;平仓二次确认时传入。</param>
|
||
/// <param name="ignoreRiskRuleIds">首次试算返回的需忽略规则ID;二次确认时传入。</param>
|
||
/// <returns>提交结果或新风控确认信息。</returns>
|
||
public JsonResult ApplyUnwind(UnwindData unwindData, int eventType, int? trialDataId = null, string ignoreRiskRuleIds = null)
|
||
{
|
||
var result = new SwapDealService(CurUser).ApplySwapTrade(unwindData, eventType, CreateRiskTrialConfirmation(trialDataId, ignoreRiskRuleIds));
|
||
return BuildCloseRiskResult(result, "提交成功");
|
||
}
|
||
|
||
/// <summary>
|
||
/// 保存平仓风控特批说明,不改变首次试算时间。
|
||
/// 平仓二次确认会重新执行风控并生成新的 quotaTrial 快照,本接口只补充首次试算记录的用户说明和审计日志。
|
||
/// </summary>
|
||
/// <param name="trialDataId">平仓风控试算记录ID。</param>
|
||
/// <param name="remark">用户填写的特批说明。</param>
|
||
/// <returns>保存结果。</returns>
|
||
public JsonResult SaveCloseRiskTrialRemark(int trialDataId, string remark)
|
||
{
|
||
try
|
||
{
|
||
var trial = new QuotaMonitorService(CurUser)
|
||
.SaveCloseRiskTrialRemark(trialDataId, remark);
|
||
new TradeRiskCheckLogService(CurUser).AddLog(trial);
|
||
return JsonSuccess();
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogFactory.GetLogger("SaveCloseRiskTrialRemark").Error(ex);
|
||
return JsonError("保存平仓风控试算说明失败!");
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 根据首次试算记录ID创建平仓新风控二次确认参数。
|
||
/// </summary>
|
||
/// <param name="trialDataId">首次新风控试算记录ID。</param>
|
||
/// <param name="ignoreRiskRuleIds">首次试算返回的需忽略规则ID,多个ID使用逗号分隔。</param>
|
||
/// <returns>首次提交返回空,二次确认返回包含有效期和需忽略规则ID的确认参数。</returns>
|
||
private static RiskTrialConfirmation CreateRiskTrialConfirmation(int? trialDataId, string ignoreRiskRuleIds)
|
||
{
|
||
if (!trialDataId.HasValue)
|
||
{
|
||
return null;
|
||
}
|
||
|
||
var expireSeconds = 300;
|
||
var expireSecondsConfig = AppManager.GetAppConfigValue("ProjectConfig", "Trade.RiskWarningConfirmExpireSeconds");
|
||
if (!string.IsNullOrWhiteSpace(expireSecondsConfig)
|
||
&& int.TryParse(expireSecondsConfig, out var configuredExpireSeconds)
|
||
&& configuredExpireSeconds > 0)
|
||
{
|
||
expireSeconds = configuredExpireSeconds;
|
||
}
|
||
return new RiskTrialConfirmation
|
||
{
|
||
TrialDataId = trialDataId.Value,
|
||
ExpireSeconds = expireSeconds,
|
||
IgnoreRiskRuleIds = ParseIgnoreRiskRuleIds(ignoreRiskRuleIds)
|
||
};
|
||
}
|
||
|
||
private static List<string> ParseIgnoreRiskRuleIds(string ignoreRiskRuleIds)
|
||
{
|
||
return (ignoreRiskRuleIds ?? string.Empty)
|
||
.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries)
|
||
.Select(ruleId => ruleId.Trim())
|
||
.Where(ruleId => !string.IsNullOrWhiteSpace(ruleId))
|
||
.Distinct()
|
||
.ToList();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 将平仓新风控结果转换为控制器统一JSON响应。
|
||
/// </summary>
|
||
/// <param name="result">新风控试算结果;互换事件不执行平仓风控时为空。</param>
|
||
/// <param name="successMessage">业务执行成功后的提示。</param>
|
||
/// <returns>阻断、二次确认或业务成功响应。</returns>
|
||
private JsonResult BuildCloseRiskResult(RiskTrialResult result, string successMessage)
|
||
{
|
||
if (result == null || result.Passed)
|
||
{
|
||
return JsonSuccess(successMessage, result?.ShowTip == true ? new { result.TrialDataId, result.Message } : null);
|
||
}
|
||
if (result.Blocked)
|
||
{
|
||
// 风控阻断属于可预期的业务结果,返回成功协议供前端打开只读试算详情,不进入通用请求失败分支。
|
||
return JsonSuccessData(new
|
||
{
|
||
proccessType = "QuotaTrialError",
|
||
result.TrialDataId,
|
||
message = string.IsNullOrWhiteSpace(result.Message)
|
||
? "平仓风控校验未通过"
|
||
: result.Message
|
||
});
|
||
}
|
||
return JsonSuccessData(new
|
||
{
|
||
proccessType = "AdditionalProcessing",
|
||
source = "RiskWarning",
|
||
type = "RiskWarningConfirm",
|
||
result.TrialDataId,
|
||
ignoreRiskRuleIds = result.ApprovalRuleIds,
|
||
message = result.ConfirmationExpired ? $"原风控确认已超时,请重新确认。{result.Message}" : result.Message
|
||
});
|
||
}
|
||
/// <summary>
|
||
/// 框架合约保存
|
||
/// </summary>
|
||
/// <param name="req"></param>
|
||
/// <param name="additionalProcessing">特批重提标记:LackOfMoney=资金不足交易特批放行(须系统参数"允许交易特批"开启)</param>
|
||
/// <returns></returns>
|
||
[HttpPost]
|
||
public JsonResult tradeEditJson(trade req, string additionalProcessing = null)
|
||
{
|
||
if (req == null)
|
||
{
|
||
return JsonError("数据不能为空");
|
||
}
|
||
SwapTradeService swapTradeService = new SwapTradeService(CurUser);
|
||
if (!string.IsNullOrEmpty(req.EncryptId))
|
||
{
|
||
req.id = DecryptInt(req.EncryptId);
|
||
}
|
||
//特批放行判定与确认/审批环节同口径(processtradelogController/ApprovalService):
|
||
//系统参数 允许交易特批(SpecialOperateForTrade) 开启 且 显式带 LackOfMoney 标记重提。
|
||
//additionalProcessing 支持逗号分隔多标记(保存前授信拆单与资金特批可链式确认):
|
||
//MarginCreditSplit=预付金授信不足拆单确认(标准流程,不受特批开关控制)
|
||
var processings = (additionalProcessing ?? "").Split(',', StringSplitOptions.RemoveEmptyEntries).ToHashSet();
|
||
var ignoreMoneyCheck = valuedateBLL.SystemDate.SpecialOperateForTrade == 1 && processings.Contains(tradeBLL.LackOfMoney);
|
||
var allowMarginCreditSplit = processings.Contains(tradeBLL.MarginCreditSplit);
|
||
try
|
||
{
|
||
bool edit = req.id != 0;
|
||
var r= swapTradeService.SaveTrade(req, ignoreMoneyCheck, allowMarginCreditSplit);
|
||
Task.Run(() =>
|
||
{
|
||
RealtimePnlCalc.RealtimeSwapPosition(new OptUserInfo(0, "互换实时持仓服务", OptUserFrom.Service));
|
||
});
|
||
return JsonSuccess("更新成功", r);
|
||
}
|
||
catch (TradeMarginCreditSplitException e)
|
||
{
|
||
//保存前授信拆单(§2.3):预付金授信不足,UI 确认后带 additionalProcessing=MarginCreditSplit
|
||
//重提,按 剩余授信+现金差额 物理拆腿后保存
|
||
LogFactory.GetLogger("交易保存").Info("保存授信不足待拆单确认:" + e.Message);
|
||
return JsonSuccessData(new { proccessType = "AdditionalProcessing", type = tradeBLL.MarginCreditSplit, message = e.Message });
|
||
}
|
||
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);
|
||
return JsonError("保存失败:" + e.GetBaseException().Message, e.ToJson());
|
||
}
|
||
}
|
||
/// <summary>
|
||
/// 删除交易
|
||
/// </summary>
|
||
/// <param name="id"></param>
|
||
/// <returns></returns>
|
||
[HttpPost]
|
||
public JsonResult deletetrade(string id)
|
||
{
|
||
var intid = DecryptInt(id);
|
||
new SwapTradeService(CurUser).deleteTrade(intid);
|
||
return JsonSuccess("操作成功");
|
||
}
|
||
/// <summary>
|
||
/// 互换列表查询json
|
||
/// </summary>
|
||
/// <param name="req"></param>
|
||
/// <returns></returns>
|
||
[HttpPost]
|
||
public JsonResult TradeQuery(SwapTradeQueryRequest req)
|
||
{
|
||
var swapTradeService = new SwapTradeService(CurUser);
|
||
req.AssetIds = AssetUnitModel.IntersectAssetUnits(req.AssetIdGroupList, req.AssetIds).ToList();
|
||
var sList = swapTradeService.SearchList(req, out var gsum);
|
||
return Json(sList);
|
||
}
|
||
/// <summary>
|
||
/// 日终归档测试
|
||
/// </summary>
|
||
/// <param name="settleDate"></param>
|
||
/// <param name="preSettleDate"></param>
|
||
/// <returns></returns>
|
||
public JsonResult AutoSwapEod(DateTime settleDate, DateTime preSettleDate)
|
||
{
|
||
new SwapEodPositionService(CurUser).SwapPositionCompose(settleDate, preSettleDate, null);
|
||
return JsonSuccess("归档成功");
|
||
}
|
||
#region 展期
|
||
/// <summary>
|
||
/// 展期信息
|
||
/// </summary>
|
||
/// <param name="enid">交易加密id</param>
|
||
/// <returns></returns>
|
||
public ActionResult ExtensionTime(string enid)
|
||
{
|
||
ViewBag.Enid = enid;
|
||
var intid = DecryptInt(enid);
|
||
var extension = new SwapEventService(CurUser).GetExtensionTime(intid);
|
||
return View(extension);
|
||
}
|
||
/// <summary>
|
||
/// 获取展期历史操作记录
|
||
/// </summary>
|
||
/// <param name="enid"></param>
|
||
/// <returns></returns>
|
||
public JsonResult GetHistoryExtensions(string enid)
|
||
{
|
||
var intid = DecryptInt(enid);
|
||
var list = new SwapEventService(CurUser).GetExtenstionTimeEvents(intid);
|
||
return JsonSuccess("", list);
|
||
}
|
||
/// <summary>
|
||
/// 保存展期信息
|
||
/// </summary>
|
||
/// <param name="swap_Event"></param>
|
||
/// <returns></returns>
|
||
public JsonResult SaveExtension(swap_event swap_Event)
|
||
{
|
||
var id = new SwapEventService(CurUser).SaveExtensionTime(swap_Event);
|
||
return JsonSuccess("保存成功", id);
|
||
}
|
||
/// <summary>
|
||
/// 删除展期信息
|
||
/// </summary>
|
||
/// <param name="id"></param>
|
||
/// <returns></returns>
|
||
public JsonResult DeleteExtension(long id)
|
||
{
|
||
new SwapEventService(CurUser).DeleteExtensionTime(id);
|
||
return JsonSuccess("删除成功");
|
||
}
|
||
#endregion
|
||
#endregion
|
||
#region 互换清算
|
||
#region 场内资金账号
|
||
public ActionResult OnSiteCapitalAccount()
|
||
{
|
||
return View();
|
||
}
|
||
/// <summary>
|
||
/// 获取交易对手方交易编码
|
||
/// </summary>
|
||
/// <param name="clientId"></param>
|
||
/// <returns></returns>
|
||
public JsonResult GetClientTradeNumbers(int clientId)
|
||
{
|
||
var tradeNumbers = new SwapTradeService(CurUser).GetSwapTradeNumbers(clientId);
|
||
return JsonSuccess("", tradeNumbers);
|
||
}
|
||
/// <summary>
|
||
/// 获取场内交易资金账号列表
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
public JsonResult GetCapitalAcountList(SwapCapitalAccountQueryRequest req)
|
||
{
|
||
var retListResult = new SwapCapitalAccountService(CurUser).SearchList(req);
|
||
return Json(retListResult);
|
||
}
|
||
/// <summary>
|
||
/// 保存场内资金账号
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
public JsonResult SaveCapitalAccount(swap_fund_account req)
|
||
{
|
||
req.id = DecryptInt(req.EncryptId);
|
||
new SwapCapitalAccountService(CurUser).SaveCapitalAccount(req);
|
||
return JsonSuccess("");
|
||
}
|
||
/// <summary>
|
||
/// 删除场内资金账号
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
public JsonResult DeleteCapitalAccount(string enid)
|
||
{
|
||
var intid = DecryptInt(enid);
|
||
new SwapCapitalAccountService(CurUser).DeleteCapitalAccount(intid);
|
||
return JsonSuccess("");
|
||
}
|
||
/// <summary>
|
||
/// 获取场内资金账号
|
||
/// </summary>
|
||
/// <param name="enid"></param>
|
||
/// <returns></returns>
|
||
public JsonResult GetCapitalAccount(string enid)
|
||
{
|
||
var intid = DecryptInt(enid);
|
||
var capitalAccount = new SwapCapitalAccountService(CurUser).GetCapitalAccount(intid);
|
||
return Json(capitalAccount);
|
||
}
|
||
/// <summary>
|
||
/// 根据资金账号获取详情
|
||
/// </summary>
|
||
/// <param name="foundAccount"></param>
|
||
/// <returns></returns>
|
||
public JsonResult GetCapitalAccountByFoundAccount(string foundAccount)
|
||
{
|
||
var capitalAccount = new SwapCapitalAccountService(CurUser).GetCapitalAccountByFoundAccount(foundAccount);
|
||
return JsonSuccessData(capitalAccount);
|
||
}
|
||
|
||
#endregion
|
||
#region 成交簿记
|
||
#region step1 导入
|
||
/// <summary>
|
||
/// 成交流水簿记导入列表
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
public ActionResult SwapflowList()
|
||
{
|
||
return View();
|
||
}
|
||
/// <summary>
|
||
/// 从电子盘数据库导入流水
|
||
/// </summary>
|
||
/// <param name="tradeDate"></param>
|
||
/// <returns></returns>
|
||
public JsonResult GenerateSwapTradeFromDb(DateTime? tradeDate, bool reset)
|
||
{
|
||
tradeDate = tradeDate == null ? valuedateBLL.ValueDate : tradeDate.Value;
|
||
var service = new SwapTradeAutoService(CurUser);
|
||
service.GenerateSwapTradeFromDb(tradeDate.Value, reset);
|
||
return JsonSuccess();
|
||
}
|
||
/// <summary>
|
||
/// 成交流水簿记导入查询
|
||
/// </summary>
|
||
/// <param name="req"></param>
|
||
/// <returns></returns>
|
||
public JsonResult SwapflowQuery(SwapFlowQueryRequest req)
|
||
{
|
||
req.step = req.step == 0 ? 1 : req.step;
|
||
var service = new SwapFlowService(CurUser);
|
||
if (req.step == 1)//流水导入
|
||
{
|
||
var retListResult = service.SearchList(req);
|
||
return Json(retListResult);
|
||
|
||
}
|
||
else if (req.step == 2)//流水汇总
|
||
{
|
||
var retListResult = service.SearchMergeList(req);
|
||
return Json(retListResult);
|
||
}
|
||
else if (req.step == 3)//流水开平仓
|
||
{
|
||
var retListResult = service.SearchEventList(req);
|
||
return Json(retListResult);
|
||
|
||
}
|
||
else//合成持仓
|
||
{
|
||
var retListResult = service.SearchComposeList(req);
|
||
return Json(retListResult);
|
||
|
||
}
|
||
|
||
}
|
||
/// <summary>
|
||
/// 删除流水
|
||
/// </summary>
|
||
/// <param name="id"></param>
|
||
/// <returns></returns>
|
||
public JsonResult DeleteSwapflow(string enid, int step)
|
||
{
|
||
var intid = DecryptLong(enid);
|
||
step = step == 0 ? 1 : step;
|
||
var service = new SwapFlowService(CurUser);
|
||
if (step == 1)
|
||
{
|
||
service.DeleteSwapFlow(intid);
|
||
}
|
||
else
|
||
{
|
||
service.DeleteSwapFlowMerge(intid);
|
||
}
|
||
return JsonSuccess("");
|
||
}
|
||
/// <summary>
|
||
/// 获取流水详情
|
||
/// </summary>
|
||
/// <param name="id"></param>
|
||
/// <returns></returns>
|
||
public JsonResult GetSwapflow(string enid, int step)
|
||
{
|
||
var intid = DecryptLong(enid);
|
||
step = step == 0 ? 1 : step;
|
||
var service = new SwapFlowService(CurUser);
|
||
if (step == 1)
|
||
{
|
||
var swapflow = service.GetSwapFlow(intid);
|
||
return Json(swapflow);
|
||
}
|
||
else
|
||
{
|
||
var swapflow = service.GetSwapFlowMerge(intid);
|
||
return Json(swapflow);
|
||
}
|
||
|
||
}
|
||
/// <summary>
|
||
/// 保存流水
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
public JsonResult SaveSwapflow(swap_flow req, int step)
|
||
{
|
||
req.id = DecryptLong(req.EncryptId);
|
||
step = step == 0 ? 1 : step;
|
||
var service = new SwapFlowService(CurUser);
|
||
if (step == 1)
|
||
{
|
||
service.SaveSwapFlow(req);
|
||
}
|
||
else
|
||
{
|
||
service.SaveSwapFlowMerge(req);
|
||
}
|
||
return JsonSuccess("");
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取任务状态
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
public JsonResult GetJobState()
|
||
{
|
||
var job = yldb.system_job.FirstOrDefault(x => x.JobName == "互换流水合成持仓");
|
||
if (job == null)
|
||
{
|
||
return Json(0);
|
||
}
|
||
return Json(job.JobState);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 互换成交流水导入
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
public JsonResult ImportSwapflow()
|
||
{
|
||
if (Request.Form.Files.Count == 0)
|
||
{
|
||
return JsonError("上传文件不存在");
|
||
}
|
||
|
||
var file = Request.Form.Files[0];
|
||
if (!System.IO.Path.GetExtension(file.FileName).Equals(".xlsx", StringComparison.OrdinalIgnoreCase))
|
||
{
|
||
return JsonError("请上传压缩包(.xlsx)格式文件");
|
||
}
|
||
using var stream = file.OpenReadStream();
|
||
new SwapFlowImportService(CurUser).ImportSwapTradesFromExcel(stream, out var TotalNum, out var SuccessNum);
|
||
|
||
return Json(new
|
||
{
|
||
success = true,
|
||
totalNum = TotalNum,
|
||
successNum = SuccessNum
|
||
});
|
||
}
|
||
#endregion
|
||
#region step2 汇总
|
||
/// <summary>
|
||
/// 成交流水簿记导入查询
|
||
/// </summary>
|
||
/// <param name="req"></param>
|
||
/// <returns></returns>
|
||
public JsonResult SwapflowMergeQuery(SwapFlowQueryRequest req)
|
||
{
|
||
var retListResult = new SwapFlowService(CurUser).SearchMergeList(req);
|
||
return Json(retListResult);
|
||
}
|
||
/// <summary>
|
||
/// 流水汇总
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
public JsonResult SwapFlowMerge(DateTime tradeDate)
|
||
{
|
||
new SwapFlowService(CurUser).SwapFlowMerge(tradeDate);
|
||
return JsonSuccess();
|
||
}
|
||
#endregion
|
||
#region step3 开平仓事件
|
||
public JsonResult SwapFlowEvent(DateTime tradeDate)
|
||
{
|
||
new SwapFlowEventService(CurUser).SwapFlowEvent(tradeDate);
|
||
return JsonSuccess();
|
||
}
|
||
[MyAuthorize("交易管理-互换开平仓事件流水")]
|
||
public ActionResult EventList()
|
||
{
|
||
return View();
|
||
}
|
||
/// <summary>
|
||
/// 开平仓事件导出
|
||
/// </summary>
|
||
/// <param name="req"></param>
|
||
/// <returns></returns>
|
||
public object ExportSwapFlowEvent(SwapFlowQueryRequest req)
|
||
{
|
||
req.page = 1;
|
||
req.rows = 10000;
|
||
var bytes = new SwapFlowService(CurUser).exprotSwapFlowEventExcel(req);
|
||
return File(bytes, xlsxMimeType, $"互换开平仓事件流水_{DateTime.Now:yyyyMMddHHmmss}.xlsx");
|
||
}
|
||
#endregion
|
||
#region 合成持仓
|
||
public JsonResult SwapFlowEventCompose(DateTime tradeDate)
|
||
{
|
||
new SwapEodPositionService(CurUser).SwapFlowEventCompose(tradeDate);
|
||
return JsonSuccess();
|
||
}
|
||
#endregion
|
||
#endregion
|
||
#region fr007
|
||
/// <summary>
|
||
/// 查询最新一条FR007数据
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
public JsonResult SearchTodayWhetherFRData(DateTime dateTime)
|
||
{
|
||
var service = new SwapFlowService(CurUser);
|
||
var data = service.SearchTodayFRData(dateTime);
|
||
return Json(data);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 删除FR007数据
|
||
/// </summary>
|
||
/// <param name="id">要删除的RF007数据Id</param>
|
||
/// <returns></returns>
|
||
public JsonResult DeleteFRData(int id)
|
||
{
|
||
var service = new SwapFlowService(CurUser);
|
||
bool flag = service.DeleteFRData(id);
|
||
return Json(flag);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 新增或者修改FR007数据
|
||
/// </summary>
|
||
/// <param name="id">新增为空 修改时是要修改的FR007数据</param>
|
||
/// <param name="price">FR007价格</param>
|
||
/// <param name="dateTime">新增或者修改时间</param>
|
||
[AllowAnonymous]
|
||
public JsonResult AddOrUpdateFRData(double price, DateTime dateTime)
|
||
{
|
||
var service = new SwapFlowService(CurUser);
|
||
bool flag = service.AddOrUpdateFRdata(price, dateTime);
|
||
return Json(flag);
|
||
}
|
||
#endregion
|
||
#endregion
|
||
#region 估值
|
||
#region 风险控制-日终持仓
|
||
/// <summary>
|
||
/// 日终持仓-互换
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
[MyAuthorize("风险控制-日终持仓风险_互换")]
|
||
public ViewResult EodPositionRisks(int? index)
|
||
{
|
||
index = index == null ? 1 : index;
|
||
ViewBag.TabIndex = index;
|
||
ViewBag.lastDate_eod = EodOperationBase.GetLastSettlementDate(valuedateBLL.ValueDate);
|
||
return View();
|
||
}
|
||
/// <summary>
|
||
/// 日终持仓-互换查询
|
||
/// </summary>
|
||
/// <param name="req"></param>
|
||
/// <returns></returns>
|
||
public JsonResult EodPositionRiskQuery(EodSwapPositionQueryRequest req)
|
||
{
|
||
req.BookIds = AssetUnitModel.IntersectAssetUnits(req.AssetIdGroupList, req.BookIds).ToList();
|
||
req.UserAssets = CurUser.GetAssetUnitIds();
|
||
req.UserClients = CurUser.GetClientIdsByCurUser();
|
||
var service = new SwapEodPositionService(CurUser);
|
||
var retListResult = service.SearchEodPositionList(req);
|
||
return Json(retListResult);
|
||
}
|
||
/// <summary>
|
||
/// 日终持仓-互换框架合约查询
|
||
/// </summary>
|
||
/// <param name="req"></param>
|
||
/// <returns></returns>
|
||
public JsonResult EodSwapRiskQuery(EodSwapQueryRequest req)
|
||
{
|
||
req.BookIds = AssetUnitModel.IntersectAssetUnits(req.AssetIdGroupList, req.BookIds).ToList();
|
||
req.UserAssets = CurUser.GetAssetUnitIds();
|
||
req.UserClients = CurUser.GetClientIdsByCurUser();
|
||
var service = new SwapEodPositionService(CurUser);
|
||
var retListResult = service.SearchEodSwapList(req);
|
||
return Json(retListResult);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 日终持仓-互换新框架合约查询。
|
||
/// 先与旧框架合约接口执行相同的账簿、资产单元和客户权限收敛,
|
||
/// 再返回 EQD-7084 拆分后的展示字段;不能直接绕过这些条件调用服务层。
|
||
/// </summary>
|
||
/// <param name="req"></param>
|
||
/// <returns></returns>
|
||
public JsonResult EodSwapRiskNewQuery(EodSwapQueryRequest req)
|
||
{
|
||
req.BookIds = AssetUnitModel.IntersectAssetUnits(req.AssetIdGroupList, req.BookIds).ToList();
|
||
req.UserAssets = CurUser.GetAssetUnitIds();
|
||
req.UserClients = CurUser.GetClientIdsByCurUser();
|
||
var service = new SwapEodPositionService(CurUser);
|
||
var retListResult = service.SearchEodSwapNewList(req);
|
||
return Json(retListResult);
|
||
}
|
||
#endregion
|
||
#region 结算报告
|
||
/// <summary>
|
||
/// 互换持仓
|
||
/// </summary>
|
||
/// <param name="clientId"></param>
|
||
/// <param name="startTime"></param>
|
||
/// <param name="endTime"></param>
|
||
/// <returns></returns>
|
||
[MyAuthorize("结算管理-每日估值报告")]
|
||
public ActionResult TradeMarketReport_PositionSwapFlow(int? clientId, string startTime, string endTime, bool ParentFlag)
|
||
{
|
||
ViewBag.ClientId = clientId;
|
||
ViewBag.StartTime = startTime;
|
||
ViewBag.EndTime = endTime;
|
||
ViewBag.ParentFlag = ParentFlag;
|
||
return View();
|
||
}
|
||
/// <summary>
|
||
/// 互换交易流水
|
||
/// </summary>
|
||
/// <param name="clientId"></param>
|
||
/// <param name="startTime"></param>
|
||
/// <param name="endTime"></param>
|
||
/// <returns></returns>
|
||
[MyAuthorize("结算管理-每日估值报告")]
|
||
public ActionResult TradeMarketReport_HistoricalPositionSwapFlow(int? clientId, string startTime, string endTime, bool ParentFlag)
|
||
{
|
||
ViewBag.ClientId = clientId;
|
||
ViewBag.StartTime = startTime;
|
||
ViewBag.EndTime = endTime;
|
||
ViewBag.ParentFlag = ParentFlag;
|
||
return View();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 互换估值
|
||
/// </summary>
|
||
/// <param name="clientId"></param>
|
||
/// <param name="startTime"></param>
|
||
/// <param name="endTime"></param>
|
||
/// <returns></returns>
|
||
[MyAuthorize("结算管理-每日估值报告")]
|
||
public ActionResult TradeMarketReport_EodPosition(int? clientId, string startTime, string endTime, bool ParentFlag)
|
||
{
|
||
ViewBag.ClientId = clientId;
|
||
ViewBag.StartTime = startTime;
|
||
ViewBag.EndTime = endTime;
|
||
ViewBag.ParentFlag = ParentFlag;
|
||
ViewBag.StructureType = "普通债券类收益互换";
|
||
return View();
|
||
}
|
||
/// <summary>
|
||
/// 互换持仓明细
|
||
/// </summary>
|
||
/// <param name="req"></param>
|
||
/// <returns></returns>
|
||
[HttpPost]
|
||
public JsonResult clientTradePositionSwapFlowQuery(ClientSwapPositionRequest req)
|
||
{
|
||
var result = new SwapEodPositionService(CurUser).SearchPositionList(req);
|
||
return Json(result);
|
||
}
|
||
/// <summary>
|
||
/// 互换交易流水
|
||
/// </summary>
|
||
/// <param name="req"></param>
|
||
/// <returns></returns>
|
||
[HttpPost]
|
||
public JsonResult clientTradePositionSwapFlowEventQuery(ClientSwapPositionRequest req)
|
||
{
|
||
var result = new SwapFlowEventService(CurUser).SearchPositionFlowEvent(req);
|
||
return Json(result);
|
||
}
|
||
/// <summary>
|
||
/// 互换估值
|
||
/// </summary>
|
||
/// <param name="req"></param>
|
||
/// <returns></returns>
|
||
[HttpPost]
|
||
public JsonResult clientEodSwapPositionQuery(ClientSwapPositionRequest req)
|
||
{
|
||
var result = new SwapEodPositionService(CurUser).SearchEodPositionList(req);
|
||
return Json(result);
|
||
}
|
||
#endregion
|
||
#endregion
|
||
|
||
#region 结算通知书
|
||
public ActionResult tradeEndConfirmList()
|
||
{
|
||
return View();
|
||
}
|
||
/// <summary>
|
||
/// 包括提前确认书和到期结算书
|
||
/// </summary>
|
||
public JsonResult EitherEndTradeReportQuery(SwapEndConfirmReq req)
|
||
{
|
||
req.AssetIdList = AssetUnitModel.IntersectAssetUnits(req.AssetIdGroupList, req.AssetIdList).ToList();
|
||
req.UserAssets = CurUser.GetAssetUnitIds();
|
||
req.UserClients = CurUser.GetClientIdsByCurUser(CurUser.交易管理_查看所有交易);
|
||
req.CurUserTradeIds = CurUser.GetTradeIdsByCurUser();
|
||
var sList = new SwapEndConfirmService(CurUser).SearchEitherTradeWithCashList(req);
|
||
return Json(sList);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 生成结算确认书
|
||
/// </summary>
|
||
public JsonResult GJGenerateSettleBillByFlowEventIds(List<long> flowEventIds, string docType)
|
||
{
|
||
if ("doc".Equals(docType, StringComparison.OrdinalIgnoreCase))
|
||
{
|
||
docType = "DOCX";
|
||
}
|
||
docType = docType.ToLower();
|
||
var results = new List<TradeDocGenerateResult>();
|
||
var files = new List<string>();
|
||
var errors = new List<string>();
|
||
results = new SwapSettlementBillGenerateService(CurUser).Generate(flowEventIds, docType, CurUser.UserId, CurUser.UserName).ToList();
|
||
errors = results.Where(n => !string.IsNullOrWhiteSpace(n.ErrorMessage)).Select(n => n.ErrorMessage).ToList();
|
||
var outPutFilePaths = results.Select(n => n.OutputFilePath).Distinct();
|
||
files = DocFileHelper.CheckResultDocFilePath(outPutFilePaths);
|
||
if (errors.Any())
|
||
{
|
||
return JsonError(string.Join("\r\n", errors.AsEnumerable()), files);
|
||
}
|
||
return JsonSuccess("生成成功", files);
|
||
}
|
||
/// <summary>
|
||
/// 批量删除结算确认书
|
||
/// </summary>
|
||
/// <param name="flowEventIds"></param>
|
||
/// <returns></returns>
|
||
public JsonResult BatchDelDoc(List<long> flowEventIds)
|
||
{
|
||
new SwapSettlementBillGenerateService(CurUser).DelDoc(flowEventIds);
|
||
return JsonSuccess("");
|
||
}
|
||
/// <summary>
|
||
/// 批量下载结算确认书
|
||
/// </summary>
|
||
public async Task<ActionResult> BatchDownLoadDoc(DownloadDocReq req)
|
||
{
|
||
if (req.docpdf == null)
|
||
{
|
||
return ShowError("请选择文档类型!");
|
||
}
|
||
if (string.IsNullOrWhiteSpace(req.docpdf[0]))
|
||
{
|
||
return ShowError("请选择文档类型!");
|
||
}
|
||
var types = new List<string>() { ContractTypeEnum.Clearing, ContractTypeEnum.UnWind };
|
||
if (req.TradeDateStart == null) { req.TradeDateStart = DateTime.MinValue; }
|
||
if (req.TradeDateEnd == null) { req.TradeDateEnd = DateTime.MaxValue; }
|
||
var db_trade_contract_r = yldb.trade_contract_r.AsQueryable();
|
||
|
||
var db_swap_flow_event = yldb.swap_flow_event.Where(s => s.EventType == (int)SwapEventTypeEnum.平仓);
|
||
var query = from doc in yldb.trade_contract_document
|
||
join r in db_trade_contract_r
|
||
on doc.Code equals r.ContractCode
|
||
join fe in db_swap_flow_event
|
||
on r.SwapFlowEventId equals fe.id
|
||
where doc.Type == r.Type && fe.EventDate >= req.TradeDateStart && fe.EventDate <= req.TradeDateEnd && r.IsValid && types.Contains(r.Type)
|
||
select new
|
||
{
|
||
doc.ClientId,
|
||
doc.Paths,
|
||
TradeCashId = r.TradeCashId ?? 0,
|
||
r.Type,
|
||
r.TradeId,
|
||
r.TradeNumber,
|
||
r.ContractCode,
|
||
r.SwapFlowEventId,
|
||
doc.SealResult,
|
||
doc.StampDocumentFileName,
|
||
doc.EncryptId,
|
||
doc.Comments,
|
||
doc.FileName
|
||
};
|
||
|
||
var isSelect = false;
|
||
if (req.TradeIds != null && req.TradeIds.Any(O => O != 0))
|
||
{
|
||
isSelect = true;
|
||
query = query.Where(O => req.TradeIds.Contains(O.TradeId));
|
||
}
|
||
if (req.FlowEventIds != null && req.FlowEventIds.Any(O => O != 0))
|
||
{
|
||
isSelect = true;
|
||
query = query.Where(O => req.FlowEventIds.Contains(O.SwapFlowEventId ?? 0));
|
||
}
|
||
if (req.DocType != null)
|
||
{
|
||
query = query.Where(O => O.Type == req.DocType);
|
||
}
|
||
if (!isSelect && !req.TradeNumber.IsNullOrWhiteSpace())
|
||
{
|
||
query = query.Where(O => O.TradeNumber == req.TradeNumber);
|
||
}
|
||
if (!isSelect && !req.ContractCode.IsNullOrWhiteSpace())
|
||
{
|
||
query = query.Where(O => O.ContractCode == req.ContractCode);
|
||
}
|
||
if (!isSelect && req.ClientIds != null && req.ClientIds.Any(O => O != 0))
|
||
{
|
||
query = query.Where(O => req.ClientIds.Contains(O.ClientId ?? 0));
|
||
}
|
||
|
||
var datas = query.ToList();
|
||
|
||
if (datas.Count == 0)
|
||
{
|
||
return ShowError("未找到确认书文件,请确认筛选条件是否有效!");
|
||
}
|
||
|
||
var filePathList = new List<string>(datas.Count * req.docpdf.Count());
|
||
|
||
foreach (var item in datas)
|
||
{
|
||
var path = item.Paths;
|
||
if (!string.IsNullOrEmpty(path))
|
||
{
|
||
var fName = GetFileName(path, ".xlsx");
|
||
if (!string.IsNullOrEmpty(fName))
|
||
{
|
||
filePathList.Add(fName);
|
||
}
|
||
}
|
||
}
|
||
|
||
var fileName = $"确认书文件{DateTime.Now:yyyyMMddHHmmss}.zip";
|
||
ZipHelper.zipFiles(filePathList.Distinct().ToArray(), filePathList[0], out var buffer);
|
||
return File(buffer, "application/zip", fileName);
|
||
}
|
||
private string GetFileName(string baseName, string sufferFix)
|
||
{
|
||
var fName = Path.ChangeExtension(baseName, sufferFix);
|
||
|
||
if (!string.IsNullOrWhiteSpace(fName) && (fName[0] != '/' || fName[0] != '\\'))
|
||
{
|
||
fName = fName.Insert(0, "/");
|
||
}
|
||
|
||
fName = OtcAppContext.MapPath(fName);
|
||
|
||
if (!System.IO.File.Exists(fName))
|
||
{ fName += "x"; }//解决数据库中存的后缀名是doc但实际文件是docx的问题;
|
||
if (System.IO.File.Exists(fName))
|
||
{ return fName; }
|
||
else
|
||
{ return null; }
|
||
}
|
||
#endregion
|
||
|
||
|
||
/// <summary>
|
||
/// 更新支付日期
|
||
/// </summary>
|
||
/// <param name="req"></param>
|
||
/// <returns></returns>
|
||
[HttpPost]
|
||
public JsonResult UpdatePayDate(UpdatePayDateDto req)
|
||
{
|
||
if (req == null)
|
||
{
|
||
return JsonError("数据不能为空");
|
||
}
|
||
SwapFlowService service = new SwapFlowService(CurUser);
|
||
service.UpdatePayDate(req);
|
||
return JsonSuccess("更新成功");
|
||
|
||
}
|
||
/// <summary>
|
||
/// 发送确认书邮件
|
||
/// </summary>
|
||
/// <param name="tradeId"></param>
|
||
/// <returns></returns>
|
||
public JsonResult SendConfimEmail(int tradeId)
|
||
{
|
||
SwapEndConfirmService service = new SwapEndConfirmService(CurUser);
|
||
var result = service.SendConfirmEamil(tradeId);
|
||
return JsonSuccess(result);
|
||
}
|
||
|
||
/// <summary>
|
||
/// EQD-5320 批量发送结算确认书邮件——经服务端代理 bond-oms(BondOmsInterface_BaseUrl 出口),
|
||
/// 替代前端直连 /trs_hub_api 反向代理(未配 nginx 的环境 404)。
|
||
/// </summary>
|
||
/// <param name="swapFlowEventIds">平仓流水id,逗号分隔;单个令牌兼容【数字】与【EncryptId 加密串】两种形态
|
||
/// (批量按钮传网格数字id,单行按钮传 swap_flow_event.EncryptId——全站 enid 惯例)</param>
|
||
[HttpPost]
|
||
public JsonResult BatchSendSettleEmail(string swapFlowEventIds)
|
||
{
|
||
if (string.IsNullOrWhiteSpace(swapFlowEventIds))
|
||
{
|
||
return JsonError("请选择交易");
|
||
}
|
||
var ids = new List<long>();
|
||
foreach (var s in swapFlowEventIds.Split(',', StringSplitOptions.RemoveEmptyEntries))
|
||
{
|
||
var token = s.Trim();
|
||
long id;
|
||
if (!long.TryParse(token, out id) || id <= 0)
|
||
{
|
||
// 非数字令牌按 EncryptId 解密(解密失败/非法串返回0,不抛出)
|
||
try { id = DecryptLong(token); } catch { id = 0; }
|
||
}
|
||
if (id > 0)
|
||
{
|
||
ids.Add(id);
|
||
}
|
||
}
|
||
if (ids.Count == 0)
|
||
{
|
||
return JsonError("平仓流水id解析为空(既非数字也非有效加密ID):" + swapFlowEventIds);
|
||
}
|
||
var result = new SwapEndConfirmService(CurUser).BatchSendSettleEmail(ids);
|
||
return string.IsNullOrEmpty(result) ? JsonSuccess("发送成功") : JsonError(result);
|
||
}
|
||
|
||
|
||
}
|
||
}
|