Files
zszq-trs/YLErpDAL/Modules/SwapModule/SwapEndConfirmService.cs
T

261 lines
13 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 BaseOUDAL;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using YLErp.Model.Enum;
using YLErp.Model;
using YLErp.DBModels.Consts;
using System.Linq.Expressions;
using YLErp.QdpModule;
using static YLErp.ConsGlobal;
using YLErp.Helpers;
using YLErp.Models;
namespace YLErp.Modules.SwapModule
{
public class SwapEndConfirmService : YLBaseService
{
public SwapEndConfirmService(OptUserInfo optUser) : base(optUser)
{
}
/// <summary>
/// 查询 到期结算报告和提前终止报告
/// </summary>
public SearchListResult<SwapTradeContractGroup> SearchEitherTradeWithCashList(SwapEndConfirmReq req)
{
var db = DbContext;
var actionList = new List<int>() { (int)SwapEventTypeEnum.平仓, (int)SwapEventTypeEnum.合成持仓 };
var types = new List<string>() { ContractTypeEnum.Clearing, ContractTypeEnum.UnWind };
var flowQuery = PredicateBuilder.Create<swap_flow_event>(n => actionList.Contains(n.EventType) && n.PayDirection > 0);
var eventQuery = PredicateBuilder.Create<swap_event>(n => actionList.Contains(n.EventType) && !n.Invalid);
var tradeQuery = buildTradeQuery(req);
if (!string.IsNullOrEmpty(req.UnderlyingCodes))
{
flowQuery = flowQuery.And(d => req.UnderlyingCodeList.Contains(d.UnderlyingCode));
}
if (req.UnWindDateEnd == null)
{
req.UnWindDateEnd = DateTime.MaxValue;
}
if (req.UnWindDateStart == null)
{
req.UnWindDateStart = DateTime.MinValue;
}
eventQuery = eventQuery.And(d => d.ValueDate >= req.UnWindDateStart && d.ValueDate <= req.UnWindDateEnd);
var query = from trade in db.trade.Where(tradeQuery)
join swapEvent in db.swap_event.Where(eventQuery) on trade.id equals swapEvent.SwapTradeId
join flowEvent in db.swap_flow_event.Where(flowQuery) on swapEvent.id equals flowEvent.EventId
join position in db.swap_position on flowEvent.PositionId equals position.PositionId
join tcrConfirm in db.trade_contract_r.Where(O => O.Type == ContractTypeEnum.Trade && O.IsValid) on trade.id equals tcrConfirm.TradeId into tcrConfirms
from tcrConfirm in tcrConfirms.DefaultIfEmpty()
select new SwapTradeContractGroup
{
id = flowEvent.id,
trade = trade,
swap_flow_event = flowEvent,
swap_event = swapEvent,
swap_position = position,
ConfirmContractR = tcrConfirm,
};
query = query.OrderByDescending(s => s.swap_flow_event.UnwindDate);
var retListResult = query.ToSearchList(req, isWithOrder: false);
var tradeIds = retListResult.rows.Select(s => s.swap_flow_event.SwapTradeId).Distinct().ToList();
var underlyingCodes = retListResult.rows.Select(r => r.swap_flow_event.UnderlyingCode).ToList();
var underlyings = DbContext.underlying_manager.Where(x => underlyingCodes.Contains(x.UnderlyingCode)).AsNoTracking().ToList();
List<trade_extend> extendList = DbContext.trade_extend.AsNoTracking().Where(p => tradeIds.Contains(p.TradeId)).ToList();
if (extendList == null)
{
extendList = new List<trade_extend>();
}
foreach (var x in retListResult.rows)
{
x.trade_contract_r = db.trade_contract_r.Where(O => types.Contains(O.Type) && O.IsValid && O.TradeId == x.trade.id && O.SwapFlowEventId == x.swap_flow_event.id).FirstOrDefault();
var swapEventFlow = x.swap_flow_event;
var um = underlyings.FirstOrDefault(x => x.UnderlyingCode == swapEventFlow.UnderlyingCode);
if (um != null && um.IsBond())
{
x.swap_flow_event.TradingAmountAvg = BondPriceConverter.ToDisplay(x.swap_flow_event.TradingAmountAvg);
x.swap_flow_event.TradingAmountFeeAvg = BondPriceConverter.ToDisplay(x.swap_flow_event.TradingAmountFeeAvg);
x.swap_flow_event.TradingAmountNetAvg = x.swap_flow_event.TradingAmountNetAvg.HasValue ? BondPriceConverter.ToDisplay(x.swap_flow_event.TradingAmountNetAvg.Value) : x.swap_flow_event.TradingAmountNetAvg;
x.swap_flow_event.TradingAmountNetFeeAvg = x.swap_flow_event.TradingAmountNetFeeAvg.HasValue ? BondPriceConverter.ToDisplay(x.swap_flow_event.TradingAmountNetFeeAvg.Value) : x.swap_flow_event.TradingAmountNetFeeAvg;
}
if (x.trade_contract_r != null)
{
GetTradeDocumentResults(req, x);
}
if (x.swap_event != null)
{
x.swap_event.unwindData = JsonHelper.Deserialize<UnwindData>(x.swap_event.EventData);
if (x.trade.StructureType == "多空组合")
{
UnwindData unwindData = new UnwindData();
unwindData.SwapCloseAmount = x.swap_flow_event.FloatPnlSum;
x.swap_event.unwindData = unwindData;
}
}
var extend = extendList.FirstOrDefault(p => p.TradeId == x.swap_flow_event.SwapTradeId);
if (x.swap_flow_event.PayDate == null || x.swap_flow_event.EventType != (int)SwapEventTypeEnum.平仓)
{
if (extend != null)
{
x.swap_flow_event.PayDate = x.swap_flow_event.EventDate.AddDays(extend.ExtendObj.SettlementRules);
}
}
}
return retListResult;
}
private Expression<Func<trade, bool>> buildTradeQuery(SwapEndConfirmReq req)
{
var tradeQuery = PredicateBuilder.Create<trade>(n => n.TradeType == "收益互换" && n.ValidState != ConsGlobal.InValid);
if (req.UserAssets != null && req.UserClients != null)
{
tradeQuery = tradeQuery.And(x => req.UserAssets.Contains(x.AssetId) || req.UserClients.Contains(x.ClientId));
}
if (!string.IsNullOrEmpty(req.TradeNumber))
{
tradeQuery = tradeQuery.And(d => d.TradeNumber.Contains(req.TradeNumber));
}
if (req.StartDateStart != DateTime.MinValue)
{
tradeQuery = tradeQuery.And(d => d.StartDate >= req.StartDateStart);
}
if (req.StartDateEnd != DateTime.MinValue)
{
var StartDateTemp = req.StartDateEnd.AddDays(1);
tradeQuery = tradeQuery.And(d => d.StartDate < StartDateTemp);
}
if (!string.IsNullOrEmpty(req.ClientIds))
{
tradeQuery = tradeQuery.And(d => req.ClientIdsInt.Contains(d.ClientId));
}
if (req.AssetIdList.Any())
{
tradeQuery = tradeQuery.And(d => req.AssetIdList.Contains(d.AssetId));
}
if (!string.IsNullOrEmpty(req.TraderNames))
{
tradeQuery = tradeQuery.And(d => req.TraderNamesList.Contains(d.TraderId));
}
if (req.ExerciseDateStart != null || req.ExerciseDateEnd != null)
{
if (req.ExerciseDateEnd == null)
{
req.ExerciseDateEnd = DateTime.MaxValue;
}
if (req.ExerciseDateStart == null)
{
req.ExerciseDateStart = DateTime.MinValue;
}
tradeQuery = tradeQuery.And(d => d.ExerciseDate >= req.ExerciseDateStart && d.ExerciseDate <= req.ExerciseDateEnd);
}
return tradeQuery;
}
private void GetTradeDocumentResults(SwapEndConfirmReq req, SwapTradeContractGroup x)
{
var documentQuery = (from trade in DbContext.trade_contract_document where trade.Code == x.trade_contract_r.ContractCode && trade.Type == x.trade_contract_r.Type select trade);
x.trade_contract_document = documentQuery.FirstOrDefault();
x.ContractDocUrl = x.trade_contract_document?.RelativePath;
x.ContractCode = x.trade_contract_r.ContractCode;
}
/// <summary>
/// 发送交易确认书邮件
/// </summary>
/// <param name="tradeId"></param>
/// <returns></returns>
///
public string SendConfirmEamil(int tradeId)
{
var tradeContract = DbContext.trade_contract_r.Where(x => x.IsValid && x.TradeId == tradeId && x.Type == ContractTypeEnum.Trade).FirstOrDefault();
if (tradeContract == null)
{
// 定位要点:此处历史上静默 return "",前端当"已发送"但实际未发任何邮件。
// 打出 warn 并把失败原因透传给前端,便于区分"没生成过交易确认书"与"被重生成作废(IsValid=false)"。
var rows = DbContext.trade_contract_r.Where(x => x.TradeId == tradeId).Select(x => new { x.Type, x.IsValid, x.ContractCode }).ToList();
var detail = rows.Any()
? string.Join("", rows.Select(r => $"Type={r.Type},IsValid={r.IsValid},Code={r.ContractCode}"))
: "trade_contract_r 无任何行";
LogFactory.GetLogger("SwapEndConfirm").Error(
$"发送交易确认书邮件中止: tradeId={tradeId} 无有效交易确认书(需 IsValid=true 且 Type={ContractTypeEnum.Trade}); 库内实际行: {detail}");
return "发送失败:未找到有效交易确认书,请先生成后再发送";
}
tradeContract.send_email_result = "发送中";
DbContext.SaveChanges();
var sendResult = SendEmail(tradeContract.ContractCode);
if (string.IsNullOrEmpty(sendResult))
{
tradeContract.send_email_result = "已发送";
}
else
{
tradeContract.send_email_result = "发送失败:" + sendResult;
}
DbContext.SaveChanges();
return string.IsNullOrEmpty(sendResult) ? "已发送" : "发送失败:" + sendResult;
}
public string SendConfirmEamil(string ContractCode)
{
//var tradeContract = DbContext.trade_contract_r.Where(x => x.IsValid && x.TradeId == tradeId && x.Type == ContractTypeEnum.Trade).FirstOrDefault();
//if (tradeContract == null)
//{
// return "";
//}
var contracts = DbContext.trade_contract_r.Where(o => o.ContractCode == ContractCode && o.Type == ContractTypeEnum.Trade && o.IsValid).ToArray();
foreach (var tradeContract in contracts)
{
tradeContract.send_email_result = "发送中";
DbContext.SaveChanges();
}
var contractCode = contracts.FirstOrDefault()?.ContractCode;
var sendResult = SendEmail(contractCode);
foreach (var tradeContract in contracts)
{
if (string.IsNullOrEmpty(sendResult))
{
tradeContract.send_email_result = "已发送";
}
else
{
tradeContract.send_email_result = "发送失败:" + sendResult;
}
}
DbContext.SaveChanges();
return string.IsNullOrEmpty(sendResult) ? "已发送" : "发送失败:" + sendResult;
}
/// <summary>
/// 发送邮件
/// </summary>
/// <returns></returns>
private string SendEmail(string contractCode)
{
var baseUrl = Environment.GetEnvironmentVariable("BondOmsInterface_BaseUrl");
//换成contractCode
var sendEmailPUrl = "/swap/email/confirm/send?contractCode=" + contractCode;
if (!string.IsNullOrEmpty(baseUrl))
{
var httpHelper = new HttpHelper(baseUrl, null);
var result = httpHelper.GetRequestNoAuth<SendEmailResult>(sendEmailPUrl).Result;
if (result != null && result.success && !string.IsNullOrEmpty(result.data))
{
return "";
}
else
{
LogFactory.GetLogger().Error("发送邮件失败:contractCode=" + contractCode, new Exception(result?.message));
return result?.message ?? "发送邮件失败";
}
}
return "未配置邮件接口地址";
}
}
}