685 lines
32 KiB
C#
685 lines
32 KiB
C#
using BaseOUDAL;
|
||
using YLErp.BLL;
|
||
using YLErp.DBModels.Consts;
|
||
using YLErp.DBModels.Enums;
|
||
using YLErp.Helpers;
|
||
|
||
namespace YLErp.Modules.TradeModule
|
||
{
|
||
/// <summary>
|
||
/// 交易服务基类
|
||
/// </summary>
|
||
public class TradeServiceBase : YLBaseService
|
||
{
|
||
int? _tradeProcessCount;
|
||
|
||
public TradeServiceBase(YLBaseService baseService) : base(baseService)
|
||
{
|
||
|
||
}
|
||
|
||
public TradeServiceBase(OptUserInfo userInfo) : base(userInfo)
|
||
{
|
||
}
|
||
|
||
public TradeServiceBase(OptUserInfo userInfo, YLContext dbContext) : base(userInfo, dbContext)
|
||
{
|
||
|
||
}
|
||
|
||
/// <summary>
|
||
/// 是否有交易审批(复核)任务
|
||
/// </summary>
|
||
protected bool HasTradeProcess()
|
||
{
|
||
return TradeProcessCount() > 0;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 交易审批(复核)任务数量
|
||
/// </summary>
|
||
public int TradeProcessCount()
|
||
{
|
||
if (_tradeProcessCount == null)
|
||
{
|
||
_tradeProcessCount = DbContext.approvalprocess.Count(t => t.processType == "TradeProcess");
|
||
}
|
||
return _tradeProcessCount.Value;
|
||
}
|
||
/// <summary>
|
||
/// 获取所有交易审批节点(开仓流程 TradeProcess)。
|
||
/// </summary>
|
||
public List<approvalprocess> TradeProcess()
|
||
{
|
||
var tradeOrders = DbContext.approvalprocess.Where(t => t.processType == "TradeProcess").OrderBy(o => o.order).ToList();
|
||
return tradeOrders;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 按交易推断流程类别(开仓/了结)获取审批节点(需求②)。
|
||
/// <para>了结类(平仓待复核/行权待复核/互换待复核)取 CloseProcess;开仓类取 TradeProcess。</para>
|
||
/// <para>未配置对应流程时返回空列表(由调用方决定是否直接通过)。</para>
|
||
/// </summary>
|
||
public List<approvalprocess> TradeProcessByCategory(trade td)
|
||
{
|
||
var category = ResolveProcessCategory(td);
|
||
return DbContext.approvalprocess.Where(t => t.processType == category).OrderBy(o => o.order).ToList();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 按类别统计审批节点数(需求②)。
|
||
/// </summary>
|
||
public int TradeProcessCountByCategory(trade td)
|
||
{
|
||
return TradeProcessByCategory(td).Count;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 初始化交易 审批点
|
||
/// </summary>
|
||
/// <param name="td"></param>
|
||
public void InitTradeProcessOrder(trade td,int userId)
|
||
{
|
||
var tradeProcess = TradeProcessByCategory(td);
|
||
// 该交易类别未配置审批流程 → 直接审批通过,无需审核
|
||
if (tradeProcess == null || tradeProcess.Count == 0)
|
||
{
|
||
td.ProcessOrderId = ProcessTradeLog.审批通过;
|
||
td.ProcessStatus = ProcessTradeStatus.通过审批.ToString();
|
||
td.ProcessOptDate = DateTime.Now;
|
||
return;
|
||
}
|
||
td.ProcessOrderId = ProcessTradeLog.审批中;
|
||
td.ProcessStatus = ProcessTradeStatus.审批中.ToString();
|
||
var groupId = UserBLL.GetApprovalProcessGroup(userId);
|
||
bool approvalBranch = tradeProcess.Any(x => x.approvalGroupId != 0);//审批流程有分支情况
|
||
if (td.ProcessOrderId == 1)
|
||
{
|
||
if (approvalBranch)//审批流程有分支情况
|
||
{
|
||
//该审批组属于流程的审批组或该审批组不属于流程审批组
|
||
var tradeProessBranchQuery = tradeProcess.FirstOrDefault(x => (x.approvalGroupId == groupId && x.approvalCondition == 1) || (x.approvalGroupId != groupId && x.approvalCondition == 2));
|
||
if (tradeProessBranchQuery == null)//都没有情况
|
||
{
|
||
throw new ServiceException("当前存在分支交易审批流程,检测到申请人不满足任意一个分支进入条件,无法提交审批,请更换申请人或调整审批组");
|
||
}
|
||
td.ProcessOrderBranch = tradeProessBranchQuery.node ?? 1;//审批组分子
|
||
}
|
||
else
|
||
{
|
||
td.ProcessOrderBranch = 0;
|
||
}
|
||
}
|
||
var branch = tradeProcess.Where(x=>x.node==td.ProcessOrderBranch).OrderBy(o=>o.order);
|
||
var branchFirst= branch.FirstOrDefault();
|
||
if (branchFirst!=null&& branchFirst.order==1&& td.ProcessOrderBranch!=0)
|
||
{
|
||
td.ProcessOrderId = 2;
|
||
}
|
||
|
||
// 需求①:进入审批流程时即应用触发条件——从起始节点开始,跳过所有不满足触发条件的节点。
|
||
// 若所有节点均不满足 → 直接审批通过(无需任何人审核)。
|
||
ApplyTriggerFromStart(tradeProcess, td, userId);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 从当前 ProcessOrderId 起点开始,按触发条件跳过无需审批的节点(需求①)。
|
||
/// <para>场景:交易提交进入审批流程时,若节点1、2配置的触发条件均不满足,则直接跳到节点3;
|
||
/// 若全部节点都不满足,则直接审批通过。</para>
|
||
/// </summary>
|
||
private void ApplyTriggerFromStart(List<approvalprocess> tradeProcess, trade td, int userId)
|
||
{
|
||
if (tradeProcess == null || tradeProcess.Count == 0) return;
|
||
|
||
// 取当前起点节点(主干 node=0)
|
||
var current = tradeProcess.FirstOrDefault(x => x.order == td.ProcessOrderId && x.node == 0);
|
||
// 若起点不在主干(如分支调整后 ProcessOrderId=2),取该 order 的主干节点
|
||
if (current == null)
|
||
{
|
||
current = tradeProcess.FirstOrDefault(x => x.order >= td.ProcessOrderId && x.node == 0);
|
||
}
|
||
if (current == null) return;
|
||
|
||
var ctx = BuildTriggerContext(td, userId);
|
||
var target = ConditionEvaluator.FindFirstTriggeredNode(tradeProcess, current, ctx);
|
||
if (target == null)
|
||
{
|
||
// 所有节点都不满足触发条件 → 直接审批通过,无需审核
|
||
td.ProcessOrderId = ProcessTradeLog.审批通过;
|
||
td.ProcessStatus = ProcessTradeStatus.通过审批.ToString();
|
||
td.ProcessOptDate = DateTime.Now;
|
||
return;
|
||
}
|
||
// target 即为第一个满足触发条件、需实际审批的节点
|
||
if (target.order != td.ProcessOrderId)
|
||
{
|
||
td.ProcessOrderId = target.order;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 节点触发条件(需求①):在已确定下一审批节点 nextOrder 后,若该节点配置了 triggerCondition,
|
||
/// 则只有「满足触发条件」才进入该节点审批;不满足则跳过该节点,继续向后寻找,直到找到可进入的节点或抵达流程末尾。
|
||
/// <para>语义:triggerCondition 为空 → 无条件进入审批;非空 → 满足才进入,不满足则跳过。</para>
|
||
/// <para>非侵入式:原有分支推进逻辑不变,仅在其结果之上叠加触发判断循环。</para>
|
||
/// </summary>
|
||
/// <param name="tradeProcess">当前流程的全部节点(已按 order 排序)</param>
|
||
/// <param name="nextOrder">原逻辑计算出的下一节点(可能为 null)</param>
|
||
/// <param name="ctx">条件求值业务上下文(已含 trade、本次交易名义本金等)</param>
|
||
/// <returns>最终应推进到的节点;若应结束流程则返回 null</returns>
|
||
protected static approvalprocess AdvanceThroughTriggerNodes(
|
||
List<approvalprocess> tradeProcess,
|
||
approvalprocess nextOrder,
|
||
ConditionContext ctx)
|
||
{
|
||
// 不满足触发条件的节点需跳过:循环向后找第一个可进入的节点。
|
||
while (nextOrder != null && !string.IsNullOrWhiteSpace(nextOrder.triggerCondition))
|
||
{
|
||
if (ConditionEvaluator.Evaluate(nextOrder.triggerCondition, ctx))
|
||
{
|
||
break; // 满足触发条件 → 进入该节点审批,停止跳过。
|
||
}
|
||
|
||
// 不满足触发条件 → 跳过该节点,向后取下一个主干节点(node=0),继续判断。
|
||
nextOrder = tradeProcess.FirstOrDefault(x => x.order > nextOrder.order && x.node == 0);
|
||
}
|
||
return nextOrder;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 构建触发条件求值上下文:从 trade 及其关联的 trade_cash 取本次交易名义本金(了结场景)。
|
||
/// <para>本次交易名义本金 = 本次了结操作的 trade_cash.UnwindStockEqvNotional 绝对值。</para>
|
||
/// </summary>
|
||
protected ConditionContext BuildTriggerContext(trade td, int userId)
|
||
{
|
||
var ctx = new ConditionContext
|
||
{
|
||
UserId = userId,
|
||
Trade = td,
|
||
ProcessCategory = ResolveProcessCategory(td),
|
||
InitGroupId = UserBLL.GetApprovalProcessGroup(userId)
|
||
};
|
||
// 了结场景:当次平仓名义本金 = 期初名义本金 × 平仓比例(UnwindPercentRate),取绝对值
|
||
if (td != null && ctx.ProcessCategory == ProcessCategoryConst.Close)
|
||
{
|
||
var tc = DbContext.trade_cash
|
||
.Where(t => t.TradeId == td.id && t.ValidState == ConsGlobal.InValid && !t.IsDeleted)
|
||
.OrderByDescending(t => t.id)
|
||
.FirstOrDefault();
|
||
if (tc != null && tc.UnwindPercentRate.HasValue && td.OriginalStockEqvNotional.HasValue)
|
||
{
|
||
ctx.CurrentNotional = Math.Abs(td.OriginalStockEqvNotional.Value * tc.UnwindPercentRate.Value);
|
||
}
|
||
}
|
||
return ctx;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 按交易状态推断流程类别:开仓(TradeProcess) / 了结(CloseProcess)。需求②。
|
||
/// <para>委托给 ProcessCategoryConst.Resolve,供全局复用。</para>
|
||
/// </summary>
|
||
protected static string ResolveProcessCategory(trade td)
|
||
{
|
||
return ProcessCategoryConst.Resolve(td);
|
||
}
|
||
/// <summary>
|
||
/// 添加交易操作日志
|
||
/// </summary>
|
||
protected void AddTradeOperationHistoryAndSetParentTradeInfo(bool saveChanges, OtcTradeBase trade, string optType, string comments = null)
|
||
{
|
||
DbContext.TradeAuditLog.Add(new TradeAuditLog
|
||
{
|
||
TradeId = trade.id,
|
||
AuditFlag = TradeAuditFlag.operation,
|
||
OptType = optType,
|
||
Changes = comments ?? string.Empty,
|
||
DataType = "00",
|
||
OptId = UserId,
|
||
OptName = UserName,
|
||
OptDate = OptDate
|
||
});
|
||
|
||
if (trade.IsGroup == 0)
|
||
{
|
||
SetParentTrade(trade);
|
||
}
|
||
|
||
if (saveChanges)
|
||
{
|
||
DbContext.SaveChanges();
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 保存交易操作日志(调用SaveChanges)
|
||
/// </summary>
|
||
protected void SaveTradeOperationHistory(OtcTradeBase trade, string optType, string Comments = null)
|
||
{
|
||
AddTradeOperationHistoryAndSetParentTradeInfo(true, trade, optType, Comments);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 添加交易元数据
|
||
/// </summary>
|
||
public void AddTradeMeta(bool saveChanges, int tradeId, string metaKey, string metaValue)
|
||
{
|
||
DbContext.TradeMeta.Add(new TradeMeta
|
||
{
|
||
TradeId = tradeId,
|
||
MetaKey = metaKey,
|
||
MetaValue = metaValue,
|
||
CreateTime = DateTime.Now
|
||
});
|
||
if (saveChanges)
|
||
{
|
||
DbContext.SaveChanges();
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 添加或更新交易元数据
|
||
/// </summary>
|
||
protected void AddOrUpdateTradeMeta(bool saveChanges, int tradeId, string metaKey, string metaValue)
|
||
{
|
||
new TradeMetaService(this).AddTradeMeta(tradeId, metaKey, metaValue, saveChanges);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 设置交易元数据
|
||
/// </summary>
|
||
protected void SaveTradeMeta(int tradeId, string metaKey, string metaValue)
|
||
{
|
||
new TradeMetaService(this).AddTradeMeta(tradeId, metaKey, metaValue, true);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 移除指定交易的相关数据
|
||
/// </summary>
|
||
/// <param name="saveChanges"></param>
|
||
/// <param name="tradeId">交易Id</param>
|
||
/// <param name="removeStartDate">删除数据开始日期</param>
|
||
/// <param name="tradeCashIds">指定要删除的TradeCash记录</param>
|
||
public void RemoveEodTradeAndFutureInfo(bool saveChanges, int tradeId, DateTime removeStartDate, IEnumerable<int> tradeCashIds = null, bool deleteOtherCashs = false, IEnumerable<int> tradeCashPreIds = null, bool isDelTradeCashIncludeStartDay = false, bool backToBegin = false)
|
||
{
|
||
var tradeIds = new List<int> { tradeId };
|
||
var trade = DbContext.trade.Find(tradeId);
|
||
if (removeStartDate.Year < 2000)
|
||
{
|
||
removeStartDate = new DateTime(2000, 1, 1);
|
||
}
|
||
if (trade.ParentTradeId > 0 && trade.IsGroup == 0)
|
||
{
|
||
var pTrideId = trade.ParentTradeId;
|
||
//DbContext.SetDebugLog();
|
||
var subIds =
|
||
DbContext.eod_trade
|
||
.Where(O => O.ValueDate >= removeStartDate && O.ParentTradeId == pTrideId)
|
||
.Select(O => O.TradeId)
|
||
.ToArray()
|
||
.GroupBy(O => O)
|
||
.Select(O => O.Key)
|
||
.ToArray();
|
||
//查询eodTrade表中相同父交易id仅有一条记录,且包含当前Id,表示不存在兄弟交易,应同步删除主交易
|
||
if (subIds.Length <= 1 && subIds.Contains(tradeId))
|
||
{
|
||
tradeIds.Add(trade.ParentTradeId);
|
||
}
|
||
}
|
||
|
||
var delEodArr = DbContext.eod_trade.Where(O => tradeIds.Contains(O.TradeId) && O.ValueDate >= removeStartDate);
|
||
DbContext.eod_trade.RemoveRange(delEodArr);
|
||
var delBodArr = DbContext.bod_Trade.Where(O => tradeIds.Contains(O.TradeId) && O.ValueDate > removeStartDate);
|
||
DbContext.bod_Trade.RemoveRange(delBodArr);
|
||
|
||
if (deleteOtherCashs)
|
||
{
|
||
//其他收入其他收入/支出在删除资金记录时跟着删除
|
||
var delTcOthers = DbContext.trade_cash.Where(x => x.TradeId == tradeId && !x.IsDeleted && x.Action == ClientCashInCashOut.人工操作_其他);
|
||
delTcOthers.ToList().ForEach(O => { O.ValidState = "InValid"; O.OptDate = DateTime.Now; O.IsDeleted = true; });
|
||
var delCashInCashOutOthers = DbContext.ClientCashInCashOut.Where(x => x.TradeId == tradeId && x.Action == ClientCashInCashOut.人工操作_其他);
|
||
DbContext.ClientCashInCashOut.RemoveRange(delCashInCashOutOthers);
|
||
}
|
||
|
||
var delTCArr = new List<trade_cash>();
|
||
var delTCPreArr = new List<trade_cash_pre>();
|
||
if (tradeCashIds != null && tradeCashIds.Any() || tradeCashPreIds != null && tradeCashPreIds.Any())
|
||
{
|
||
if (tradeCashIds != null && tradeCashIds.Any())
|
||
{
|
||
delTCArr = DbContext.trade_cash.Where(O => tradeCashIds.Contains(O.id) && !O.IsDeleted).ToList();
|
||
}
|
||
if (tradeCashPreIds != null && tradeCashPreIds.Any())
|
||
{
|
||
delTCPreArr = DbContext.trade_cash_pre.Where(O => tradeCashPreIds.Contains(O.id)).ToList();
|
||
}
|
||
}
|
||
else
|
||
{
|
||
if(isDelTradeCashIncludeStartDay)
|
||
{
|
||
delTCArr = DbContext.trade_cash.Where(O => O.TradeId == tradeId && (O.ValueDate >= removeStartDate && (O.HappenedDate == null || O.HappenedDate >= removeStartDate)) && O.ValidState != ConsGlobal.InValid && !O.IsDeleted).ToList();
|
||
if (removeStartDate.Year > 2000)
|
||
{
|
||
delTCArr = delTCArr.Where(O => O.Action != "系统操作-期权费" || O.Action == "系统操作-期权费" && O.ValueDate != trade.TradeDate && O.ValueDate != trade.PremiumPayDate).ToList();
|
||
}
|
||
|
||
delTCPreArr = DbContext.trade_cash_pre.Where(x => x.TradeId == tradeId && x.HappenedDate >= removeStartDate).ToList();
|
||
}
|
||
else
|
||
{
|
||
delTCArr = DbContext.trade_cash.Where(O => O.TradeId == tradeId && (O.ValueDate > removeStartDate && (O.HappenedDate == null || O.HappenedDate > removeStartDate)) && O.ValidState != ConsGlobal.InValid && !O.IsDeleted).ToList();
|
||
if (removeStartDate.Year > 2000)
|
||
{
|
||
delTCArr = delTCArr.Where(O => O.Action != "系统操作-期权费" || O.Action == "系统操作-期权费" && O.ValueDate != trade.TradeDate && O.ValueDate != trade.PremiumPayDate).ToList();
|
||
}
|
||
|
||
delTCPreArr = DbContext.trade_cash_pre.Where(x => x.TradeId == tradeId && x.HappenedDate > removeStartDate).ToList();
|
||
}
|
||
}
|
||
|
||
if (trade.IsGroup == 1)
|
||
{
|
||
var delTCArrIds = delTCArr.Select(x => x.id).ToArray();
|
||
//如果回退到开仓日,则删除所有的group action
|
||
var groupActions = DbContext.trade_cash_group_action.Where(x => x.ParentTradeId == tradeId && (delTCArrIds.Contains(x.ParentTradeCashId) || backToBegin));
|
||
if (groupActions.Any())
|
||
{
|
||
DbContext.trade_cash_group_action.RemoveRange(groupActions);
|
||
}
|
||
}
|
||
|
||
var mindate = removeStartDate;
|
||
if (delTCArr.Any())
|
||
{
|
||
delTCArr.ToList().ForEach(O => { O.ValidState = "InValid"; O.Status = TradeCashStatusEnum.已执行; O.OptDate = DateTime.Now; O.IsDeleted = true; });
|
||
mindate = delTCArr.Min(O => (DateTime?)O.ValueDate).GetValueOrDefault();
|
||
//如果权利金支付日在回退日期以后,则需要将权利金记录还原;
|
||
if (trade.PremiumPayDate != null && trade.TradeDate != trade.PremiumPayDate && trade.PremiumPayDate >= mindate)
|
||
{
|
||
DbContext.trade_cash
|
||
.Where(O =>
|
||
O.TradeId == tradeId &&
|
||
O.Action == ClientCashInCashOut.系统操作_期权费 &&
|
||
O.ValidState != "InValid" &&
|
||
!O.IsDeleted)
|
||
.ToList().ForEach(O =>
|
||
{
|
||
if (O.Status != TradeCashStatusEnum.冻结)
|
||
{
|
||
O.Comments = "";
|
||
O.OptId = UserId;
|
||
O.OptDate = DateTime.Now;
|
||
O.OptName = UserName;
|
||
O.Status = TradeCashStatusEnum.冻结;
|
||
}
|
||
});
|
||
}
|
||
}
|
||
var codeList = DbContext.trade_contract_r.Where(O => O.TradeId == tradeId && O.Type == "交易确认书").Select(O => O.ContractCode).ToList();
|
||
foreach (var code in codeList)
|
||
{
|
||
var infoTag = "_" + code.Replace("_", "-") + "_" + "了结_";
|
||
var notes = from note in DbContext.sac_report_notes
|
||
where
|
||
note.IsValid &&
|
||
note.InfoTag.Contains(infoTag) &&
|
||
note.ReportDate >= mindate
|
||
select note;
|
||
foreach (var item in notes)
|
||
{
|
||
item.changeStatus = true;
|
||
}
|
||
}
|
||
//DbContext.trade_cash.RemoveRange(delTCArr);
|
||
|
||
var tcIds = delTCArr.Select(O => O.id).ToArray();
|
||
var predicate_detail = PredicateBuilder.Create<trade_cash_detail>(x => tcIds.Contains(x.TradeCashId));
|
||
//如果权利金支付日在回退日期以后,则需要将权利金记录一起删除;
|
||
if (trade.PremiumPayDate != null && trade.TradeDate != trade.PremiumPayDate && trade.PremiumPayDate >= mindate)
|
||
{
|
||
predicate_detail = predicate_detail.Or(O => O.TradeId == tradeId && O.Action == ClientCashInCashOut.系统操作_期权费);
|
||
}
|
||
var tradeCashDetials = DbContext.trade_cash_detail.Where(predicate_detail);
|
||
if (tradeCashDetials.Any())
|
||
{
|
||
DbContext.trade_cash_detail.RemoveRange(tradeCashDetials);
|
||
}
|
||
if (PS.Config.SalesCommissionCalculation == "公式1")
|
||
{
|
||
//删除销售提成数据
|
||
var commissionInfos = DbContext.SalesCommissionDetail.Where(l => l.TradeID == tradeId && tcIds.Contains(l.TradeCashID)).ToList();
|
||
var useZero = DbContext.SalesCommissionDetail.Where(l => l.TradeID == tradeId && l.TradeCashID == 0).Any();//有tradeCashId为0的记录,则直接将有TradeCashId不为0的记录置为无效;
|
||
commissionInfos.ForEach(l =>
|
||
{
|
||
l.IsValid = false;
|
||
l.TradeCashID = (!useZero && l.TradeCashID == tcIds.First()) ? 0 : -1;
|
||
});
|
||
}
|
||
|
||
var trade_cash_swaps = DbContext.trade_cash_swap.Where(x => tcIds.Contains(x.TradeCashId));
|
||
if (trade_cash_swaps.Any())
|
||
{
|
||
if (PS.Config.IsGuoJun)
|
||
{
|
||
var flowid = trade_cash_swaps.Select(x => x.FlowId).ToList();
|
||
var swapflowmore = DbContext.trade_swap_flow_more.Where(x => flowid.Contains(x.id)).ToList();
|
||
swapflowmore.ForEach(x =>
|
||
{
|
||
x.IsDelete = true;
|
||
});
|
||
}
|
||
DbContext.trade_cash_swap.RemoveRange(trade_cash_swaps);
|
||
}
|
||
|
||
if (delTCPreArr.Any())
|
||
{
|
||
var tcPreIds = delTCPreArr.Select(O => O.id).ToArray();
|
||
|
||
var tradeCashDetialsPre = DbContext.trade_cash_detail.Where(x => tcPreIds.Contains(x.TradeCashPreId));
|
||
if (tradeCashDetials.Any())
|
||
{
|
||
DbContext.trade_cash_detail.RemoveRange(tradeCashDetials);
|
||
}
|
||
|
||
var trade_cash_swapsPre = DbContext.trade_cash_swap.Where(x => tcPreIds.Contains(x.TradeCashPreId));
|
||
if (trade_cash_swaps.Any())
|
||
{
|
||
DbContext.trade_cash_swap.RemoveRange(trade_cash_swaps);
|
||
}
|
||
|
||
DbContext.trade_cash_pre.RemoveRange(delTCPreArr);
|
||
}
|
||
|
||
var predicate_cashIncashOut = PredicateBuilder.Create<ClientCashInCashOut>(x => tcIds.Contains(x.TradeCashId));
|
||
//如果权利金支付日在回退日期以后,则需要将权利金记录一起删除;
|
||
if (trade.PremiumPayDate != null && trade.TradeDate != trade.PremiumPayDate && trade.PremiumPayDate >= mindate)
|
||
{
|
||
predicate_cashIncashOut = predicate_cashIncashOut.Or(O => O.TradeId == tradeId && O.Action == ClientCashInCashOut.系统操作_期权费);
|
||
}
|
||
var delCashInCashOutArr = DbContext.ClientCashInCashOut.Where(predicate_cashIncashOut);
|
||
|
||
DbContext.ClientCashInCashOut.RemoveRange(delCashInCashOutArr);
|
||
var delContractArr = DbContext.trade_contract_r.Where(O => tcIds.Contains(O.TradeCashId ?? 0) && O.IsValid).ToList();
|
||
//DbContext.trade_contract_r.RemoveRange(delContractArr);
|
||
delContractArr.ForEach(O => O.IsValid = false);
|
||
if (trade.TradeType == "远期")
|
||
{
|
||
var forwardMargin = DbContext.eod_forward_margin
|
||
.Where(x => x.TradeId == trade.id && x.ValueDate > removeStartDate);
|
||
DbContext.eod_forward_margin.RemoveRange(forwardMargin);
|
||
}
|
||
var tradeChanges = DbContext.trade_changes.Where(O => O.RecordId == trade.id && (O.OptDate > removeStartDate || (O.ChangeType == ConsInfoChangeType.Dividend && O.OptDate >= removeStartDate)));
|
||
DbContext.trade_changes.RemoveRange(tradeChanges);
|
||
if (saveChanges)
|
||
{
|
||
DbContext.SaveChanges();
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 移除指定交易的相关数据
|
||
/// </summary>
|
||
/// <param name="tradeId">交易Id</param>
|
||
/// <param name="removeStartDate">删除数据开始日期</param>
|
||
/// <param name="tradeCashIds">指定要删除的TradeCash记录</param>
|
||
protected void RemoveGroupEodTradeAndFutureInfo(IEnumerable<int> tradeIds, DateTime removeStartDate, IEnumerable<int> tradeCashIds = null)
|
||
{
|
||
if (removeStartDate.Year < 2000)
|
||
{
|
||
removeStartDate = new DateTime(2000, 1, 1);
|
||
}
|
||
|
||
var delEodArr = DbContext.eod_trade.Where(O => tradeIds.Contains(O.TradeId) && O.ValueDate >= removeStartDate);
|
||
DbContext.eod_trade.RemoveRange(delEodArr);
|
||
var delBodArr = DbContext.bod_Trade.Where(O => tradeIds.Contains(O.TradeId) && O.ValueDate > removeStartDate);
|
||
DbContext.bod_Trade.RemoveRange(delBodArr);
|
||
|
||
var tradeCashDetials = DbContext.trade_cash_detail.Where(x => tradeCashIds.Contains(x.TradeCashId));
|
||
if (tradeCashDetials.Any())
|
||
{
|
||
DbContext.trade_cash_detail.RemoveRange(tradeCashDetials);
|
||
}
|
||
|
||
var trade_cash_swaps = DbContext.trade_cash_swap.Where(x => tradeCashIds.Contains(x.TradeCashId));
|
||
if (trade_cash_swaps.Any())
|
||
{
|
||
DbContext.trade_cash_swap.RemoveRange(trade_cash_swaps);
|
||
}
|
||
|
||
var delCashInCashOutArr = DbContext.ClientCashInCashOut.Where(O => tradeCashIds.Contains(O.TradeCashId));
|
||
|
||
DbContext.ClientCashInCashOut.RemoveRange(delCashInCashOutArr);
|
||
var delContractArr = DbContext.trade_contract_r.Where(O => tradeCashIds.Contains(O.TradeCashId ?? 0) && O.IsValid).ToList();
|
||
delContractArr.ForEach(O => O.IsValid = false);
|
||
|
||
var tradeChanges = DbContext.trade_changes.Where(O => tradeIds.Contains(O.RecordId) && (O.OptDate > removeStartDate || (O.ChangeType == ConsInfoChangeType.Dividend && O.OptDate >= removeStartDate)));
|
||
DbContext.trade_changes.RemoveRange(tradeChanges);
|
||
DbContext.SaveChanges();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 设置子交易数据到父交易,
|
||
/// 这个方法在AddTradeOperationHistory和SaveTradeOperationHistory中调用,
|
||
/// 除非必要才公开此方法以便调用
|
||
/// </summary>
|
||
protected void SetParentTrade(OtcTradeBase subTrade, trade parent = null)
|
||
{
|
||
if (subTrade is null)
|
||
{
|
||
throw new ArgumentNullException(nameof(subTrade));
|
||
}
|
||
|
||
if (parent is null)
|
||
{
|
||
if (subTrade.ParentTradeId == 0)
|
||
{
|
||
return;
|
||
}
|
||
|
||
parent = DbContext.trade.Find(subTrade.ParentTradeId);
|
||
if (parent == null)
|
||
{
|
||
throw new ServiceException("结构化交易父交易不存在");
|
||
}
|
||
}
|
||
|
||
//分组交易单独逻辑处理
|
||
if (subTrade.IsGroup == 2 && subTrade.TradeStatus == "审批中")
|
||
{
|
||
parent.OptId = subTrade.OptId;
|
||
parent.OptName = subTrade.OptName;
|
||
parent.OptDate = subTrade.OptDate;
|
||
parent.ProcessStatus = subTrade.ProcessStatus;
|
||
parent.ProcessOptDate = subTrade.OptDate;
|
||
parent.ProcessOrderId = subTrade.ProcessOrderId;
|
||
}
|
||
else
|
||
{
|
||
parent.OptId = subTrade.OptId;
|
||
parent.OptName = subTrade.OptName;
|
||
parent.OptDate = subTrade.OptDate;
|
||
parent.UnderlyingCode = subTrade.UnderlyingCode;
|
||
parent.UnderlyingId = subTrade.UnderlyingId;
|
||
parent.TradePrice = subTrade.TradePrice;
|
||
parent.TradeSinglePrice = subTrade.TradeSinglePrice;
|
||
parent.UnWindNotional = subTrade.UnWindNotional;
|
||
parent.Notional = subTrade.Notional;
|
||
parent.TradeAmount = subTrade.TradeAmount;
|
||
parent.StockEqvNotional = subTrade.StockEqvNotional;
|
||
parent.StockEqvNotionalReal = subTrade.StockEqvNotionalReal;
|
||
parent.OriginalNotional = subTrade.OriginalNotional;
|
||
parent.OriginalStockEqvNotional = subTrade.OriginalStockEqvNotional;
|
||
parent.HasPartialUnWind = subTrade.HasPartialUnWind;
|
||
parent.UnWindDate = subTrade.UnWindDate;
|
||
parent.ExerciseDate = subTrade.ExerciseDate;
|
||
parent.ValidState = subTrade.ValidState;
|
||
parent.DividendDate = subTrade.DividendDate;
|
||
parent.ProcessStatus = subTrade.ProcessStatus;
|
||
parent.ProcessOptDate = subTrade.OptDate;
|
||
parent.ProcessOrderId = subTrade.ProcessOrderId;
|
||
parent.ClientId = subTrade.ClientId;
|
||
parent.ClientName = subTrade.ClientName;
|
||
}
|
||
|
||
if (parent.id > 0 && ConsTrade.TradeCompleteStatus.Contains(subTrade.TradeStatus))
|
||
{
|
||
parent.TradeStatus = DbContext.trade
|
||
.Where(n => n.ParentTradeId == parent.id && n.ValidState != "InValid" && !ConsTrade.TradeCompleteStatus.Contains(n.TradeStatus))
|
||
.Select(n => n.TradeStatus).FirstOrDefault() ?? subTrade.TradeStatus;
|
||
}
|
||
else
|
||
{
|
||
parent.TradeStatus = subTrade.TradeStatus;
|
||
}
|
||
|
||
if (parent.ExerciseDate < subTrade.ExerciseDate)
|
||
{
|
||
parent.ExerciseDate = subTrade.ExerciseDate;
|
||
}
|
||
}
|
||
/// <summary>
|
||
/// 计息方式
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
public string GetRateCalcMode(string rateCalcMode)
|
||
{
|
||
Dictionary<string,string> ret = new Dictionary<string,string>();
|
||
//11:算头算尾;10:算头不算尾;01:不算头算尾;00:不算头不算尾
|
||
ret.Add("算头算尾","11");
|
||
ret.Add("算头不算尾", "10");
|
||
ret.Add("不算头算尾", "01");
|
||
ret.Add("不算头不算尾", "00");
|
||
string rateCalcModeValue = "11";
|
||
ret.TryGetValue(rateCalcMode,out rateCalcModeValue);
|
||
return rateCalcModeValue;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 交易流程类别常量(需求②):对应 approvalprocess.processType 的取值。
|
||
/// </summary>
|
||
public static class ProcessCategoryConst
|
||
{
|
||
/// <summary>开仓审批流程</summary>
|
||
public const string Open = "TradeProcess";
|
||
|
||
/// <summary>了结/平仓/行权审批流程</summary>
|
||
public const string Close = "CloseProcess";
|
||
|
||
/// <summary>
|
||
/// 按交易状态推断流程类别:处于平仓/行权/互换待复核的交易视为「了结」类操作。
|
||
/// </summary>
|
||
public static string Resolve(trade td)
|
||
{
|
||
if (td == null) return Open;
|
||
if (td.TradeStatus == ConsTrade.平仓待复核
|
||
|| td.TradeStatus == ConsTrade.行权待复核
|
||
|| td.TradeStatus == ConsTrade.互换待复核)
|
||
{
|
||
return Close;
|
||
}
|
||
return Open;
|
||
}
|
||
}
|
||
}
|