Files
zszq-trs/YLErpWeb/Controllers/SwapTrade2Controller.cs
T

1292 lines
51 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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.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,
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="swap_Deal"></param>
/// <returns></returns>
public JsonResult SwapUnwindJson(UnwindData unwindData)
{
new SwapDealService(CurUser).SwapUnwind(unwindData);
return JsonSuccess("平仓成功");
}
/// <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>
/// <returns></returns>
public JsonResult ApplyUnwind(UnwindData unwindData, int eventType)
{
new SwapDealService(CurUser).ApplySwapTrade(unwindData, eventType);
return JsonSuccess("提交成功");
}
/// <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 标记重提
var ignoreMoneyCheck = valuedateBLL.SystemDate.SpecialOperateForTrade == 1 && additionalProcessing == tradeBLL.LackOfMoney;
try
{
bool edit = req.id != 0;
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);
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);
}
#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-omsBondOmsInterface_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);
}
}
}