- 仅国联民生收益互换支持在新增待确认、修改待确认、审批中生成交易确认书,期权、其他公司及其他交易状态保持原限制 - 交易确认书页面同步开放上述交易的“生成确认书”按钮,后端批量生成链路同步放开状态过滤 - 审批前生成仅校验客户、标的、初始持仓等模板必需核心数据;不以银行账户、联系人、保证金等非模板必填资料阻断 - 审批前已生成确认书的交易被修改时,使该交易原确认书关联失效,重新生成仍按原覆盖逻辑处理 - 审批拒绝时清理该交易审批前生成的确认书关联、OA 结果及用印队列;无其他有效引用时删除确认书数据,避免遗留无效确认书 - 保持原交易编号逻辑:自动生成和手工填写均不复用已拒绝交易编号 - 新增审批前适用范围、确认书关联及 OA 清理谓词专项单测
863 lines
37 KiB
C#
863 lines
37 KiB
C#
using BaseOUDAL;
|
|
using YLErp.BLL;
|
|
using YLErp.BLL.Eod;
|
|
using YLErp.Helpers;
|
|
using YLErp.Model;
|
|
using YLErp.Model.Enum;
|
|
using YLErp.Modules.ClientModule;
|
|
using YLErp.Modules.SwapModule;
|
|
using YLErp.Modules.TradeDalModule;
|
|
using YLErp.Modules.TradeModule.DocGenerateModule;
|
|
|
|
namespace YLErp.Modules.TradeModule.DealModule
|
|
{
|
|
/// <summary>
|
|
/// 交易审批操作
|
|
/// 来自:SetOpen
|
|
/// </summary>
|
|
public class TradeOpenService : TradeCashService
|
|
{
|
|
public TradeOpenService(YLBaseService baseService) : base(baseService)
|
|
{
|
|
|
|
}
|
|
|
|
public TradeOpenService(OptUserInfo userInfo) : base(userInfo)
|
|
{
|
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// 更新审批记录
|
|
/// </summary>
|
|
public TradeOpenResult UpdateTradeProcessLog(TradeOpenReqModel req)
|
|
{
|
|
if (req is null)
|
|
{
|
|
throw new ArgumentNullException(nameof(req));
|
|
}
|
|
|
|
try
|
|
{
|
|
if (string.IsNullOrEmpty(req.status))
|
|
{
|
|
throw new ServiceException("参数不能为空:status");
|
|
}
|
|
|
|
var td = DbContext.trade.Find(req.tradeId);
|
|
if (td == null)
|
|
{
|
|
throw new ServiceException("没有找到该交易");
|
|
}
|
|
|
|
if (td.TradeStatus != ConsTrade.审批中 && td.TradeStatus != ConsTrade.行权待复核 && td.TradeStatus != ConsTrade.平仓待复核 && td.TradeStatus != ConsTrade.互换待复核)
|
|
{
|
|
throw new ServiceException("该交易状态已变更,不能被审批,请先刷新页面");
|
|
}
|
|
|
|
if (req.status == "pass")
|
|
{
|
|
return TradePass(req, td);
|
|
}
|
|
|
|
if (req.status == "reject")
|
|
{
|
|
return TradeReject(req, td);
|
|
}
|
|
|
|
throw new ServiceException("未知的参数值[status]:" + req.status);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
LogFactory.GetLogger("交易审批").Error("提交交易审批", ex);
|
|
throw;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
///分组了结主交易 更新审批记录
|
|
/// </summary>
|
|
public TradeOpenResult UpdateParentTradeProcessLog(TradeOpenReqModel req)
|
|
{
|
|
if (req is null)
|
|
{
|
|
throw new ArgumentNullException(nameof(req));
|
|
}
|
|
|
|
try
|
|
{
|
|
if (string.IsNullOrEmpty(req.status))
|
|
{
|
|
throw new ServiceException("参数不能为空:status");
|
|
}
|
|
|
|
var td = DbContext.trade.Find(req.tradeId);
|
|
if (td == null)
|
|
{
|
|
throw new ServiceException("没有找到该交易");
|
|
}
|
|
|
|
if (td.TradeStatus != ConsTrade.审批中 && td.TradeStatus != ConsTrade.行权待复核 && td.TradeStatus != ConsTrade.平仓待复核 && td.TradeStatus != ConsTrade.互换待复核)
|
|
{
|
|
throw new ServiceException("该交易状态已变更,不能被审批,请先刷新页面");
|
|
}
|
|
|
|
if (req.status == "pass")
|
|
{
|
|
return ParentTradePass(req, td);
|
|
}
|
|
|
|
if (req.status == "reject")
|
|
{
|
|
return ParentTradeReject(req, td);
|
|
}
|
|
|
|
throw new ServiceException("未知的参数值[status]:" + req.status);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
LogFactory.GetLogger("交易审批").Error("提交交易审批", ex);
|
|
throw;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 放行交易
|
|
/// </summary>
|
|
private TradeOpenResult TradePass(TradeOpenReqModel req, trade td)
|
|
{
|
|
var result = new TradeOpenResult(td);
|
|
tradeBLL.SetFieldsByTradeType(td);
|
|
if (td.TradeStatus != ConsTrade.行权待复核 && td.TradeStatus != ConsTrade.平仓待复核 && td.TradeStatus != ConsTrade.互换待复核
|
|
&& !(req.ignoreMoneyCheck || td.IsGroup == 1) && !RealtimePnlCalc.TradeCanBeConfirm(td.ClientId, td, out var errorMsg))
|
|
{
|
|
result.ErrorMsg = errorMsg;
|
|
result.RetCode = TradeOpenRetCode.LackOfMoney;
|
|
if (!PS.Config.Is申万)
|
|
{
|
|
var client = ClientDataQueryService.GetClient(td.ClientId);
|
|
result.ErrorMsg = $"客户:{client?.Name},交易编号:{td.TradeNumber},{errorMsg}";
|
|
}
|
|
return result;
|
|
}
|
|
//TODO 如果是审批组
|
|
// 需求②:按交易状态推断开仓/了结流程。了结类(平仓/行权/互换待复核)走 CloseProcess。
|
|
var tradeProessQuery = TradeProcessByCategory(td);
|
|
var count = tradeProessQuery.Count();
|
|
if (count == 0 || td.ProcessOrderId == ProcessTradeLog.审批通过)//投资规模校验已经将数据设置为已通过
|
|
{
|
|
req.comments = FormatCommentsWithRole(td.ProcessOrderId, req.comments);
|
|
result.ChangeConfirmPath = SetTradeOpen(req, td);
|
|
return result;
|
|
}
|
|
var orderIdCount = tradeProessQuery.Where(x => x.order == td.ProcessOrderId);//判断当前节点是否有分支
|
|
var nextOrder = tradeProessQuery.FirstOrDefault(x => x.order > td.ProcessOrderId);
|
|
if (orderIdCount.Count()>1)//审批流程有分支情况
|
|
{
|
|
nextOrder = tradeProessQuery.FirstOrDefault(x => x.order > td.ProcessOrderId && x.node == td.ProcessOrderBranch && x.approvalGroupId == 0);
|
|
if (nextOrder==null)//已是子分支最后一个节点
|
|
{
|
|
nextOrder = tradeProessQuery.FirstOrDefault(x => x.order > td.ProcessOrderId && x.node ==0);//寻找下一主分支节点
|
|
}
|
|
}
|
|
else if (nextOrder!=null&& nextOrder.approvalGroupId!=0)//下一节点有分支
|
|
{
|
|
nextOrder = tradeProessQuery.FirstOrDefault(x => x.order > td.ProcessOrderId && x.node == td.ProcessOrderBranch&&x.approvalGroupId==0);
|
|
}
|
|
//else
|
|
//{
|
|
// td.ProcessOrderBranch = 0;
|
|
//}
|
|
// 节点触发条件(需求①):下一节点配置了 triggerCondition 时,满足才进入审批,不满足则跳过。
|
|
nextOrder = AdvanceThroughTriggerNodes(tradeProessQuery, nextOrder, BuildTriggerContext(td, UserId));
|
|
if (nextOrder==null)
|
|
{
|
|
|
|
req.comments = FormatCommentsWithRole(td.ProcessOrderId, req.comments);
|
|
result.ChangeConfirmPath = SetTradeOpen(req, td);
|
|
return result;
|
|
}
|
|
|
|
//-----------------------------------------------
|
|
// 继续审批流转
|
|
//-----------------------------------------------
|
|
|
|
var oldOrderId = td.ProcessOrderId;
|
|
var formattedComments = FormatCommentsWithRole(oldOrderId, req.comments);
|
|
td.ProcessOrderId = nextOrder.order;
|
|
//client.ProcessStatus = "审批中";
|
|
td.ProcessOptDate = OptDate;
|
|
td.OptId = UserId;
|
|
td.OptName = UserName;
|
|
td.OptDate = OptDate;
|
|
|
|
DbContext.processtradelog.Add(new ProcessTradeLog
|
|
{
|
|
TradeId = td.id,
|
|
ProcessType = "TradeProcess",
|
|
ProcessStatus = ProcessTradeStatus.通过审批.ToString(),
|
|
Log = req.comments,
|
|
OptId = UserId,
|
|
CreateTime = OptDate
|
|
});
|
|
|
|
if (!req.notNeedOperationHistory)
|
|
{
|
|
AddTradeOperationHistoryAndSetParentTradeInfo(false, td, req.ignoreMoneyCheck ? "交易特批-交易审批同意" : "交易审批同意", formattedComments);
|
|
}
|
|
|
|
if (td.TradeType == "收益互换")
|
|
{
|
|
new SwapEventService(UserInfo).AddSwapEventDate(DateTime.Now.Date, td.id, (int)SwapEventTypeEnum.审批通过, "", 0, true, formattedComments);
|
|
}
|
|
|
|
DbContext.SaveChanges();
|
|
|
|
return result;
|
|
}
|
|
|
|
private TradeOpenResult ParentTradePass(TradeOpenReqModel req, trade td)
|
|
{
|
|
var tradeCashGroupActions = DbContext.trade_cash_group_action.Where(x => x.ParentTradeId == td.id && x.Status == "待完成");
|
|
if (!tradeCashGroupActions.Any())
|
|
{
|
|
throw new ServiceException("未查询到该主交易的分组了结信息");
|
|
}
|
|
var parentTradeCashId = tradeCashGroupActions.FirstOrDefault().ParentTradeCashId;
|
|
var parentTradeCash = DbContext.trade_cash.Find(parentTradeCashId);
|
|
var childrenTradeIds = tradeCashGroupActions.Select(s => s.TradeId).ToList();
|
|
var childrenTrades = DbContext.trade.Where(x => childrenTradeIds.Contains(x.id)).ToList();
|
|
var result = new TradeOpenResult(td);
|
|
// 如果是审批组
|
|
// 需求②:分组了结按交易状态推断开仓/了结流程。
|
|
var tradeProessQuery = TradeProcessByCategory(td);
|
|
var count = tradeProessQuery.Count();
|
|
if (count == 0)
|
|
{
|
|
SetParentTradeOpen(req, td, childrenTrades, parentTradeCash);
|
|
return result;
|
|
}
|
|
var orderIdCount = tradeProessQuery.Where(x => x.order == td.ProcessOrderId);//判断当前节点是否有分支
|
|
var nextOrder = tradeProessQuery.FirstOrDefault(x => x.order > td.ProcessOrderId);
|
|
if (orderIdCount.Count() > 1)//审批流程有分支情况
|
|
{
|
|
nextOrder = tradeProessQuery.FirstOrDefault(x => x.order > td.ProcessOrderId && x.node == td.ProcessOrderBranch && x.approvalGroupId == 0);
|
|
if (nextOrder == null)//已是子分支最后一个节点
|
|
{
|
|
nextOrder = tradeProessQuery.FirstOrDefault(x => x.order > td.ProcessOrderId && x.node == 0);//寻找下一主分支节点
|
|
}
|
|
}
|
|
else if (nextOrder != null && nextOrder.approvalGroupId != 0)//下一节点有分支
|
|
{
|
|
nextOrder = tradeProessQuery.FirstOrDefault(x => x.order > td.ProcessOrderId && x.node == td.ProcessOrderBranch && x.approvalGroupId == 0);
|
|
}
|
|
// 节点触发条件(需求①):分组了结推进同样支持触发条件。
|
|
nextOrder = AdvanceThroughTriggerNodes(tradeProessQuery, nextOrder, BuildTriggerContext(td, UserId));
|
|
if (nextOrder == null)
|
|
{
|
|
SetParentTradeOpen(req, td, childrenTrades, parentTradeCash);
|
|
return result;
|
|
}
|
|
|
|
//-----------------------------------------------
|
|
// 继续审批流转
|
|
//-----------------------------------------------
|
|
|
|
td.ProcessOrderId = nextOrder.order;
|
|
td.ProcessOptDate = OptDate;
|
|
td.OptId = UserId;
|
|
td.OptName = UserName;
|
|
td.OptDate = OptDate;
|
|
childrenTrades.ForEach(x =>
|
|
{
|
|
x.ProcessOrderId = nextOrder.order;
|
|
x.ProcessOptDate = OptDate;
|
|
x.OptId = UserId;
|
|
x.OptName = UserName;
|
|
x.OptDate = OptDate;
|
|
});
|
|
DbContext.processtradelog.Add(new ProcessTradeLog
|
|
{
|
|
TradeId = td.id,
|
|
ProcessType = "TradeProcess",
|
|
ProcessStatus = ProcessTradeStatus.通过审批.ToString(),
|
|
Log = req.comments,
|
|
OptId = UserId,
|
|
CreateTime = OptDate
|
|
});
|
|
|
|
DbContext.SaveChanges();
|
|
|
|
return result;
|
|
}
|
|
/// <summary>
|
|
/// 拒绝交易
|
|
/// </summary>
|
|
private TradeOpenResult TradeReject(TradeOpenReqModel req, trade td)
|
|
{
|
|
var isGuolianPreApprovalTrade = GuolianSwapConfirmBookScope.IsPreApprovalTrade(td);
|
|
var oldOrderId = td.ProcessOrderId;
|
|
req.comments = FormatCommentsWithRole(oldOrderId, req.comments);
|
|
td.ProcessOrderId = Convert.ToInt32(PStatusEnum.reject);
|
|
td.ProcessOrderBranch = 0;
|
|
//td.IsApproval = false;
|
|
//行权或平仓审批拒绝时,状态变为提前终止拒绝
|
|
var swapTradeEventType = td.TradeStatus == ConsTrade.平仓待复核 ? (int)SwapEventTypeEnum.平仓 : (int)SwapEventTypeEnum.互换;
|
|
if (td.TradeStatus == ConsTrade.行权待复核 || td.TradeStatus == ConsTrade.平仓待复核 || td.TradeStatus == ConsTrade.互换待复核)
|
|
{
|
|
td.TradeStatus = ConsTrade.提前终止拒绝;
|
|
if (!req.notNeedOperationHistory)
|
|
{
|
|
AddTradeOperationHistoryAndSetParentTradeInfo(false, td, "提前终止拒绝", req.comments);
|
|
}
|
|
if (td.TradeType == "收益互换")
|
|
{
|
|
var swapEvent = DbContext.swap_event.Where(x => x.SwapTradeId == td.id && !x.Invalid && x.EventType == swapTradeEventType).OrderByDescending(o => o.id).FirstOrDefault();
|
|
if (swapEvent != null)
|
|
{
|
|
DbContext.swap_event.Remove(swapEvent);
|
|
var swapFlowEvents = DbContext.swap_flow_event.Where(x => x.SwapTradeId == td.id && x.EventType == swapTradeEventType && x.EventDate == swapEvent.ValueDate);
|
|
DbContext.swap_flow_event.RemoveRange(swapFlowEvents);
|
|
}
|
|
new SwapEventService(UserInfo).AddSwapEventDate(DateTime.Now.Date, td.id, (int)SwapEventTypeEnum.审批拒绝, "", 0, true, req.comments);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
td.TradeStatus = ConsTrade.已拒绝;
|
|
if (!req.notNeedOperationHistory)
|
|
{
|
|
AddTradeOperationHistoryAndSetParentTradeInfo(false, td, "交易审批拒绝", req.comments);
|
|
}
|
|
if (td.TradeType == "收益互换")
|
|
{
|
|
new SwapEventService(UserInfo).AddSwapEventDate(DateTime.Now.Date, td.id, (int)SwapEventTypeEnum.审批拒绝, "", 0, true, req.comments);
|
|
}
|
|
}
|
|
td.ProcessStatus = ProcessTradeStatus.已拒绝.ToString();
|
|
td.ProcessOptDate = OptDate;
|
|
td.CheckStatus = 0;
|
|
td.OptId = UserId;
|
|
td.OptName = UserName;
|
|
td.OptDate = OptDate;
|
|
|
|
if (td.TradeType == "结构化交易")
|
|
{
|
|
var childTrades = DbContext.trade.Where(x => x.ParentTradeId == td.id).ToList();
|
|
childTrades.ForEach(x =>
|
|
{
|
|
x.TradeStatus = td.TradeStatus;
|
|
x.OptId = UserId;
|
|
x.OptName = UserName;
|
|
x.OptDate = OptDate;
|
|
});
|
|
}
|
|
|
|
DbContext.processtradelog.Add(new ProcessTradeLog
|
|
{
|
|
TradeId = req.tradeId,
|
|
ProcessType = "TradeProcess",
|
|
ProcessStatus = "拒绝审批",
|
|
Log = req.comments,
|
|
OptId = UserId,
|
|
CreateTime = OptDate
|
|
});
|
|
|
|
//增加现金交割交易记录,查询待审的现金交割记录(Invalid 这边为无效或是待审核交割记录)
|
|
var tcId = DbContext.trade_cash.Where(t => t.TradeId == td.id && (t.Action == ClientCashInCashOut.系统操作_平仓费 || t.Action == ClientCashInCashOut.系统操作_互换) && t.ValidState == ConsGlobal.InValid && !t.IsDeleted).Select(O => O.id).OrderByDescending(x => x).FirstOrDefault();
|
|
var tcDetails = DbContext.trade_cash_detail.Where(O => O.TradeCashId == tcId);
|
|
DbContext.trade_cash_detail.RemoveRange(tcDetails);
|
|
|
|
if (isGuolianPreApprovalTrade)
|
|
{
|
|
new GuolianSwapConfirmBookCleanupService(this).CleanRejectedPreApprovalTrade(td);
|
|
}
|
|
|
|
DbContext.SaveChanges();
|
|
|
|
return new TradeOpenResult(td) { RetCode = TradeOpenRetCode.Success };
|
|
}
|
|
/// <summary>
|
|
///分组了结主交易 拒绝交易
|
|
/// </summary>
|
|
private TradeOpenResult ParentTradeReject(TradeOpenReqModel req, trade td)
|
|
{
|
|
var tradeCashGroupActions = DbContext.trade_cash_group_action.Where(x => x.ParentTradeId == td.id && x.Status == "待完成");
|
|
if (!tradeCashGroupActions.Any())
|
|
{
|
|
throw new ServiceException("未查询到该主交易的分组了结信息");
|
|
}
|
|
var parentTradeCashId = tradeCashGroupActions.FirstOrDefault().ParentTradeCashId;
|
|
var parentTradeCash = DbContext.trade_cash.Find(parentTradeCashId);
|
|
var childrenTradeIds = tradeCashGroupActions.Select(s => s.TradeId).ToList();
|
|
var childrenTrades = DbContext.trade.Where(x => childrenTradeIds.Contains(x.id)).ToList();
|
|
td.ProcessOrderId = Convert.ToInt32(PStatusEnum.reject);
|
|
td.ProcessOrderBranch = 0;
|
|
td.IsApproval = false;
|
|
td.TradeStatus = ConsTrade.确认成交;
|
|
td.ProcessStatus = ProcessTradeStatus.已拒绝.ToString();
|
|
td.ProcessOptDate = OptDate;
|
|
td.CheckStatus = 0;
|
|
td.OptId = UserId;
|
|
td.OptName = UserName;
|
|
td.OptDate = OptDate;
|
|
//行权或平仓审批拒绝时,状态变为提前终止拒绝
|
|
if (td.TradeStatus == ConsTrade.行权待复核 || td.TradeStatus == ConsTrade.平仓待复核 || td.TradeStatus == ConsTrade.互换待复核)
|
|
{
|
|
if (!req.notNeedOperationHistory)
|
|
{
|
|
AddTradeOperationHistoryAndSetParentTradeInfo(false, td, "提前终止拒绝", req.comments);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (!req.notNeedOperationHistory)
|
|
{
|
|
AddTradeOperationHistoryAndSetParentTradeInfo(false, td, "交易审批拒绝", req.comments);
|
|
}
|
|
}
|
|
childrenTrades.ForEach(x =>
|
|
{
|
|
x.ProcessOrderId = td.ProcessOrderId;
|
|
x.ProcessOrderBranch = td.ProcessOrderBranch;
|
|
x.TradeStatus = td.TradeStatus;
|
|
x.ProcessStatus = td.ProcessStatus;
|
|
x.ProcessOptDate = OptDate;
|
|
x.CheckStatus = td.CheckStatus;
|
|
x.OptId = UserId;
|
|
x.OptName = UserName;
|
|
x.OptDate = OptDate;
|
|
});
|
|
DbContext.processtradelog.Add(new ProcessTradeLog
|
|
{
|
|
TradeId = req.tradeId,
|
|
ProcessType = "TradeProcess",
|
|
ProcessStatus = "拒绝审批",
|
|
Log = req.comments,
|
|
OptId = UserId,
|
|
CreateTime = OptDate
|
|
});
|
|
childrenTradeIds.Add(req.tradeId);
|
|
var delTradeCashes = DbContext.trade_cash.Where(O =>O.ParentTradeCashId==parentTradeCashId);
|
|
var delTradeCashIds = delTradeCashes.Select(s=>s.id).ToList();
|
|
var clientCashs = DbContext.ClientCashInCashOut.Where(x=> delTradeCashIds.Contains(x.TradeCashId));
|
|
DbContext.trade_cash.RemoveRange(delTradeCashes);
|
|
DbContext.trade_cash_group_action.RemoveRange(tradeCashGroupActions);
|
|
DbContext.ClientCashInCashOut.RemoveRange(clientCashs);
|
|
DbContext.SaveChanges();
|
|
return new TradeOpenResult(td) { RetCode = TradeOpenRetCode.Success };
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// 设置交易开放
|
|
/// </summary>
|
|
private string SetTradeOpen(TradeOpenReqModel req, trade td)
|
|
{
|
|
try
|
|
{
|
|
if (td.Warning)
|
|
{
|
|
new TradeDalService(OptUser).RollbackToBeforeSettle(td, SystemValueDate);
|
|
}
|
|
//设置成开户状态,写日志
|
|
td.ProcessOrderId = Convert.ToInt32(PStatusEnum.pass);
|
|
td.TradeOldStatus = td.TradeStatus;
|
|
td.CheckTradeUpdate = Convert.ToInt32(TradeCheckEnum.StatusOfNew);
|
|
td.ProcessStatus = ProcessTradeStatus.通过审批.ToString();
|
|
td.ProcessOptDate = OptDate;
|
|
td.OptId = UserId;
|
|
td.OptName = UserName;
|
|
td.OptDate = OptDate;
|
|
td.IsApproval = false;
|
|
//写入processtradelog
|
|
DbContext.processtradelog.Add(new ProcessTradeLog
|
|
{
|
|
TradeId = req.tradeId,
|
|
ProcessType = "TradeProcess",
|
|
ProcessStatus = ProcessTradeStatus.通过审批.ToString(),
|
|
Log = req.comments,
|
|
OptId = UserId,
|
|
CreateTime = OptDate
|
|
});
|
|
new TradeConfirmService(this).EditReportStatus(td.id);
|
|
|
|
var changeConfirmPath = string.Empty;
|
|
|
|
if (td.TradeStatus == ConsTrade.行权待复核)
|
|
{
|
|
|
|
var tradeCashs = DbContext.trade_cash.Where(x => x.ValidState == "InValid" && !x.IsDeleted && x.Action == ClientCashInCashOut.系统操作_平仓费 && x.UnwindType == "部分行权" && x.TradeId == td.id);
|
|
if (req.isPartialExercise || tradeCashs.Any())
|
|
{
|
|
new TradeUnwindService(this).UnwindTrade(td, null, true, true);
|
|
}
|
|
else
|
|
{
|
|
ExecutionTradeCashInner(td, new TradeCashReq() { IsExpire = req.isExpire }, true);
|
|
}
|
|
|
|
if (!req.notNeedOperationHistory)
|
|
{
|
|
AddTradeOperationHistoryAndSetParentTradeInfo(false, td, "行权审批同意", req.comments);
|
|
}
|
|
|
|
DbContext.SaveChanges();
|
|
}
|
|
else if (td.TradeStatus == ConsTrade.平仓待复核)
|
|
{
|
|
if (td.TradeType == "收益互换")
|
|
{
|
|
//new TradeUnwindService(this).ApproveUnwindSwapTrade(td);
|
|
new SwapDealService(this).ApproveSwapTrade(td, (int)SwapEventTypeEnum.平仓);
|
|
}
|
|
else
|
|
{
|
|
new TradeUnwindService(this).UnwindTrade(td, null, true);
|
|
}
|
|
|
|
if (!req.notNeedOperationHistory)
|
|
{
|
|
AddTradeOperationHistoryAndSetParentTradeInfo(false, td, "平仓审批同意", req.comments);
|
|
}
|
|
|
|
DbContext.SaveChanges();
|
|
}
|
|
else if (td.TradeStatus == ConsTrade.互换待复核)
|
|
{
|
|
// new TradeUnwindService(this).ApproveSwapTrade(td);
|
|
new SwapDealService(this).ApproveSwapTrade(td,(int)SwapEventTypeEnum.互换);
|
|
if (!req.notNeedOperationHistory)
|
|
{
|
|
AddTradeOperationHistoryAndSetParentTradeInfo(false, td, "互换审批同意", req.comments);
|
|
}
|
|
|
|
DbContext.SaveChanges();
|
|
}
|
|
else if (td.TradeStatus == ConsTrade.审批中)
|
|
{
|
|
td.TradeStatus = ConsTrade.确认成交;
|
|
if (td.TradeType=="收益互换")
|
|
{
|
|
SwapTradeService swapTradeService = new SwapTradeService(this);
|
|
new SwapEventService(UserInfo).AddSwapEventDate(DateTime.Now.Date, td.id, (int)SwapEventTypeEnum.审批通过, "", 0, true, req.comments);
|
|
new TradeConfirmService(UserInfo).SwapTradeConfirm(td, "确认交易",false, optlog: "手工操作");
|
|
}
|
|
//组合交易(非互换)
|
|
if (td.IsGroup == 1)
|
|
{
|
|
//删掉trade_check相关的复核数据
|
|
new TradeCheckService(this).DeleteTradeCheck(td.id);
|
|
new TradeCashService(this).SaveGroupOpenTradeCash(td);
|
|
//if (td.TradeType == "收益互换")
|
|
//{
|
|
// var subtrades = DbContext.trade.Where(t => t.ParentTradeId == td.id).ToArray();
|
|
// foreach (var item in subtrades)
|
|
// {
|
|
// item.TradeOldStatus = item.TradeStatus;
|
|
// item.TradeStatus = ConsTrade.确认成交;
|
|
// //删掉trade_check相关的复核数据
|
|
// new TradeCheckService(this).DeleteTradeCheck(item.id);
|
|
// new ClientCashInCashOutService(this).SaveClientCashInCashOut(item);
|
|
// }
|
|
//}
|
|
}
|
|
//结构化交易(牛市熊市价差期权等等)或者多空组合互换交易
|
|
else if (td.TradeType == "结构化交易")
|
|
{
|
|
var subtrades = DbContext.trade.Where(t => t.ParentTradeId == td.id).ToArray();
|
|
foreach (var item in subtrades)
|
|
{
|
|
item.TradeOldStatus = item.TradeStatus;
|
|
item.TradeStatus = ConsTrade.确认成交;
|
|
//删掉trade_check相关的复核数据
|
|
new TradeCheckService(this).DeleteTradeCheck(item.id);
|
|
new ClientCashInCashOutService(this).SaveClientCashInCashOut(item);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//删掉trade_check相关的复核数据
|
|
new TradeCheckService(this).DeleteTradeCheck(td.id);
|
|
new ClientCashInCashOutService(this).SaveClientCashInCashOut(td);
|
|
}
|
|
|
|
if (!req.notNeedOperationHistory)
|
|
{
|
|
AddTradeOperationHistoryAndSetParentTradeInfo(false, td, req.ignoreMoneyCheck ? "交易特批-交易审批同意" : "交易审批同意", req.comments);
|
|
}
|
|
|
|
DbContext.SaveChanges();
|
|
|
|
//生成变更确认书
|
|
if (PS.Config.TradeElement.IsGenerateAmendDoc)
|
|
{
|
|
changeConfirmPath = new ChangeConfirmBookGenerator(this).GenerateChangeConfirmBook(td.id, out _);
|
|
}
|
|
}
|
|
|
|
return changeConfirmPath;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
LogFactory.GetLogger("交易审批").Error("设置审批状态出错", ex);
|
|
throw;
|
|
}
|
|
}
|
|
/// <summary>
|
|
/// 设置交易开放
|
|
/// </summary>
|
|
private void SetParentTradeOpen(TradeOpenReqModel req, trade td,List<trade> childrenTrades,trade_cash parentTradeCash)
|
|
{
|
|
try
|
|
{
|
|
parentTradeCash.ValidState = ConsGlobal.Valid;
|
|
if (td.Warning)
|
|
{
|
|
new TradeDalService(OptUser).RollbackToBeforeSettle(td, SystemValueDate);
|
|
}
|
|
//设置成开户状态,写日志
|
|
td.ProcessOrderId = Convert.ToInt32(PStatusEnum.pass);
|
|
td.TradeOldStatus = td.TradeStatus;
|
|
td.CheckTradeUpdate = Convert.ToInt32(TradeCheckEnum.StatusOfNew);
|
|
td.ProcessStatus = ProcessTradeStatus.通过审批.ToString();
|
|
td.ProcessOptDate = OptDate;
|
|
td.OptId = UserId;
|
|
td.OptName = UserName;
|
|
td.OptDate = OptDate;
|
|
td.IsApproval = false;
|
|
td.TradeAmount -= (parentTradeCash.UnwindTradeAmount ?? 0);
|
|
td.Notional -= (parentTradeCash.UnwindNotional ?? 0);
|
|
td.StockEqvNotional -= (td.OriginalStockEqvNotional * parentTradeCash.UnwindPercentRate ?? 0);
|
|
td.UnWindNotional = parentTradeCash.UnwindNotional;
|
|
td.UnWindDate = parentTradeCash.ValueDate;
|
|
td.FinalPrice = parentTradeCash.FinalPrice;
|
|
if (td.TradeStatus == ConsTrade.平仓待复核&& !req.notNeedOperationHistory)
|
|
{
|
|
AddTradeOperationHistoryAndSetParentTradeInfo(false, td, "平仓审批同意", req.comments);
|
|
}
|
|
else if (td.TradeStatus == ConsTrade.行权待复核 && !req.notNeedOperationHistory)
|
|
{
|
|
AddTradeOperationHistoryAndSetParentTradeInfo(false, td, "行权审批同意", req.comments);
|
|
}
|
|
else
|
|
{
|
|
if (!req.notNeedOperationHistory)
|
|
{
|
|
AddTradeOperationHistoryAndSetParentTradeInfo(false, td, req.ignoreMoneyCheck ? "交易特批-交易审批同意" : "交易审批同意", req.comments);
|
|
}
|
|
}
|
|
//写入processtradelog
|
|
DbContext.processtradelog.Add(new ProcessTradeLog
|
|
{
|
|
TradeId = req.tradeId,
|
|
ProcessType = "TradeProcess",
|
|
ProcessStatus = ProcessTradeStatus.通过审批.ToString(),
|
|
Log = req.comments,
|
|
OptId = UserId,
|
|
CreateTime = OptDate
|
|
});
|
|
if (parentTradeCash.UnwindType == "全部平仓")
|
|
{
|
|
td.TradeStatus = "已平仓";
|
|
}
|
|
else if (parentTradeCash.UnwindType == "全部行权"|| parentTradeCash.UnwindType == "到期行权")
|
|
{
|
|
td.TradeStatus = "已执行";
|
|
}
|
|
else if (parentTradeCash.UnwindType == "到期")
|
|
{
|
|
td.TradeStatus = "已到期";
|
|
}
|
|
else
|
|
{
|
|
td.TradeStatus = ConsTrade.确认成交;
|
|
}
|
|
var childrenTradeCashs = DbContext.trade_cash.Where(x=> x.ParentTradeCashId== parentTradeCash.id).ToList();
|
|
childrenTrades.ForEach(x =>
|
|
{
|
|
if (x.Warning)
|
|
{
|
|
new TradeDalService(OptUser).RollbackToBeforeSettle(x, SystemValueDate);
|
|
}
|
|
x.ProcessOrderId = Convert.ToInt32(PStatusEnum.pass);
|
|
x.TradeOldStatus = td.TradeOldStatus;
|
|
x.CheckTradeUpdate = Convert.ToInt32(TradeCheckEnum.StatusOfNew);
|
|
x.ProcessStatus = ProcessTradeStatus.通过审批.ToString();
|
|
x.ProcessOptDate = OptDate;
|
|
x.OptId = UserId;
|
|
x.OptName = UserName;
|
|
x.OptDate = OptDate;
|
|
var tradCash = childrenTradeCashs.Where(n => n.TradeId == x.id).OrderByDescending(o=>o.id).FirstOrDefault();
|
|
new TradeConfirmService(this).EditReportStatus(x.id);
|
|
tradCash.ValidState = "Valid";
|
|
if (parentTradeCash.UnwindType.Contains("到期"))
|
|
{
|
|
var tradeCashReq = new TradeCashReq()
|
|
{
|
|
ValueDate = x.UnWindDate,
|
|
TradeId = x.id,
|
|
TradeAmount = x.TradeAmount,
|
|
Notional = x.Notional,
|
|
UnwindFee = tradCash.Amount,
|
|
Amount = tradCash.Amount,
|
|
UnwindTradeAmount = tradCash.UnwindTradeAmount,
|
|
UnwindNotional = (tradCash.UnwindTradeAmount ?? 0) * (x.CountRatio ?? 1),
|
|
UnwindPercentRate = tradCash.UnwindPercentRate ?? 0,
|
|
UnwindStockEqvNotional = tradCash.UnwindStockEqvNotional,
|
|
CallPut = x.OptionType,
|
|
ExceciseType = "现金",
|
|
FinalPrice = tradCash.FinalPrice,
|
|
UnwindType = tradCash.UnwindType
|
|
};
|
|
new TradeCashService(this).ExecutionTradeCash(tradeCashReq);
|
|
}
|
|
else
|
|
{
|
|
new TradeUnwindService(this).UnwindTrade(x, null, true);
|
|
}
|
|
if (x.TradeStatus == ConsTrade.平仓待复核)//子交易复核只有平仓待复核
|
|
{
|
|
if (!req.notNeedOperationHistory)
|
|
{
|
|
AddTradeOperationHistoryAndSetParentTradeInfo(false, x, "平仓审批同意", req.comments);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (!req.notNeedOperationHistory)
|
|
{
|
|
AddTradeOperationHistoryAndSetParentTradeInfo(false, x, req.ignoreMoneyCheck ? "交易特批-交易审批同意" : "交易审批同意", req.comments);
|
|
}
|
|
}
|
|
|
|
if(td.TradeStatus != "确认成交")
|
|
{
|
|
x.TradeStatus = td.TradeStatus;
|
|
}
|
|
});
|
|
|
|
//存黑箱主交易ClientCashInCashOut需要赋值0
|
|
//TradeCash在下面FinishGroupTradeCash里会根据子交易重新统计赋值
|
|
parentTradeCash.Amount = 0;
|
|
new ClientCashinCashoutBLL(this).CloseTrade_ClientCashInCashOutSave(td, parentTradeCash, parentTradeCash.ValueDate);
|
|
|
|
DbContext.SaveChanges();
|
|
|
|
new TradeUnwindService(this).FinishGroupTradeCash(parentTradeCash.id);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
LogFactory.GetLogger("交易审批").Error("设置审批状态出错", ex);
|
|
throw;
|
|
}
|
|
}
|
|
|
|
private string GetRoleNameByOrderId(int orderId)
|
|
{
|
|
var node = DbContext.approvalprocess
|
|
.FirstOrDefault(x => x.processType == "TradeProcess" && x.order == orderId);
|
|
if (node == null)
|
|
return null;
|
|
|
|
return new ErpBaseContext().Roles
|
|
.Where(r => r.Id == node.roleId)
|
|
.Select(r => r.Name)
|
|
.FirstOrDefault();
|
|
}
|
|
|
|
private string FormatCommentsWithRole(int orderId, string comments)
|
|
{
|
|
var roleName = GetRoleNameByOrderId(orderId);
|
|
if (string.IsNullOrEmpty(roleName))
|
|
return comments ?? string.Empty;
|
|
return $"【角色:{roleName}】{comments}";
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 审批操作请求Model
|
|
/// </summary>
|
|
public class TradeOpenReqModel
|
|
{
|
|
public int tradeId;
|
|
public string status;
|
|
public string comments;
|
|
public bool ignoreMoneyCheck;
|
|
public bool notNeedOperationHistory;
|
|
public bool isPartialExercise;
|
|
public bool isExpire = false;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 审批操作结果
|
|
/// </summary>
|
|
public class TradeOpenResult
|
|
{
|
|
/// <summary>
|
|
/// 结果代码
|
|
/// </summary>
|
|
public TradeOpenRetCode RetCode;
|
|
|
|
public int TrialDataId;
|
|
public List<string> IgnoredRiskRuleIds;
|
|
public bool OldRiskNeedSpecialApproval;
|
|
|
|
/// <summary>
|
|
/// 错误信息
|
|
/// </summary>
|
|
public string ErrorMsg;
|
|
/// <summary>
|
|
/// 提示信息
|
|
/// </summary>
|
|
public string TipMsg;
|
|
|
|
/// <summary>
|
|
/// 变更确认书路径
|
|
/// </summary>
|
|
public string ChangeConfirmPath { get; set; }
|
|
|
|
public trade Trade;
|
|
|
|
public TradeOpenResult(trade trade)
|
|
{
|
|
Trade = trade ?? throw new ArgumentNullException(nameof(trade));
|
|
RetCode = TradeOpenRetCode.None;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 审批操作结果代码
|
|
/// </summary>
|
|
public enum TradeOpenRetCode
|
|
{
|
|
None = -1,
|
|
/// <summary>
|
|
/// 成功
|
|
/// </summary>
|
|
Success = 0,
|
|
|
|
/// <summary>
|
|
/// 缺少资金
|
|
/// </summary>
|
|
LackOfMoney,
|
|
/// <summary>
|
|
/// 限额试算失败
|
|
/// </summary>
|
|
QuotaTrialError,
|
|
/// <summary>
|
|
/// 资金状况
|
|
/// </summary>
|
|
FundStatus,
|
|
/// <summary>
|
|
/// 风控预警二次确认
|
|
/// </summary>
|
|
RiskWarning,
|
|
/// <summary>
|
|
/// 无审核权限
|
|
/// </summary>
|
|
NoRight
|
|
}
|
|
}
|