Files
zszq-trs/YLErpDAL/Modules/TradeModule/QueryModule/TradeSwapDetailsQueryService.cs
T
2024-05-09 14:06:26 +08:00

734 lines
27 KiB
C#

using BaseOUDAL;
using System.Text.RegularExpressions;
using YieldChain.Helpers;
using YLErp.Enums;
using YLErp.Helpers;
using YLErp.Modules.DataCacheModule;
using YLErp.MsOffice;
using YLErp.Office;
using YLErp.Office.Converters;
namespace YLErp.Modules.TradeModule.QueryModule
{
public class TradeSwapDetailsQueryService : YLBaseService
{
public TradeSwapDetailsQueryService(OptUserInfo userInfo) : base(userInfo)
{
}
public TradeSwapDetailsQueryService(YLBaseService baseService) : base(baseService)
{
}
public TradeSwapDetailsReport TradeSwapDetailsReport { private set; get; }
public string ExportReport(TradeDetailsReq req, string biaoTou = null, string biaoWei = null)
{
var client = DataCacheProvider.GetClientDataSource().GetData(req.ClientId != 0 ? req.ClientId : req.ClientIdsInt[0]);
if (client == null)
{
throw new ServiceException("系统中没有此客户,clientId:" + req.ClientId);
}
var resultList = SearchFlowMoreDetails(req);
return ConfirmDanzhang(resultList, client, req, biaoTou, biaoWei);
}
private string ConfirmDanzhang(SearchListResult<TradeFlowMoreDetails> resultList, Client client, TradeDetailsReq req, string biaoTou = null, string biaoWei = null)
{
if (!resultList.rows.Any())
{
throw new ServiceException(client.Name + "没有交易明细");
}
var report = new TradeSwapDetailsReport();
report.TradeFlowListAll = resultList.rows.ToList();
report.TradeFlowListSum = (TradeFlowMoreSum)resultList.Sum;
report.ClientId = client.id;
report.ClientName = string.IsNullOrEmpty(client.Abbreviation) ? client.Name : client.Abbreviation;
report.ClientFullName = client.Name;
report.ClientNumber = client.Number;
report.ClientAbbreviation = client.Abbreviation;
report.CompanyName = PS.Config.CompanyFullName;
report.ReportStart = req.StartDate == null ? DateTime.MinValue : req.StartDate.Value;
report.ReportEnd = req.EndDate.Value;
// 主 客户编号+A; 补充 客户编号+B;履约 客户编号+D; 主确认书:客户编号 + W
report.ClientNumberA = client.Number + "A";
report.ClientNumberB = client.Number + "B";
report.ClientNumberD = client.Number + "D";
report.ClientNumberW = client.Number + "W";
var startDate = report.ReportStart;
if (startDate == DateTime.MinValue)
{
report.TradeDetailsCode = client.Number + "_" + report.ReportEnd.ToString("yyyyMMdd");
}
else
{
report.TradeDetailsCode = client.Number + "_" + report.ReportStart.ToString("yyyyMMdd") + "_" + report.ReportEnd.ToString("yyyyMMdd");
}
#region 处理表头表尾
var biaoTouList = Regex.Split(biaoTou, "</p>", RegexOptions.IgnoreCase).Where(x => !string.IsNullOrWhiteSpace(x)).ToList();
var newBiaoTouList = new List<string>();
biaoTouList.ForEach(x =>
{
x = Regex.Replace(x, "<[^>]+>", "");
x = Regex.Replace(x, "&[^;]+;", "");
newBiaoTouList.Add(x);
});
report.BiaoTouLines = newBiaoTouList;
report.BiaoTou = string.Join("\n", newBiaoTouList);
var biaoWeiList = Regex.Split(biaoWei, "</p>", RegexOptions.IgnoreCase).Where(x => !string.IsNullOrWhiteSpace(x)).ToList();
var newBiaoWeiList = new List<string>();
biaoWeiList.ForEach(x =>
{
x = Regex.Replace(x, "<[^>]+>", "");
x = Regex.Replace(x, "&[^;]+;", "");
newBiaoWeiList.Add(x);
});
report.BiaoWeiLines = newBiaoWeiList;
report.BiaoWei = string.Join("\n", newBiaoWeiList);
#endregion
report.OutputFolder = req.OutputFolder;
TradeSwapDetailsReport = report;
return GenerateTradeDetailsReportV2(report, client);
}
private string GenerateTradeDetailsReportV2(TradeSwapDetailsReport report, Client client)
{
//获取盯市报告模板信息
var templateFile = OtcAppContext.MapPath("~/App_Docs/导出模板/收益互换明细模板-单章.xlsx");
//if (client.ConfirmBookMode == "双章版")
var targetFolder = report.OutputFolder;
if (string.IsNullOrEmpty(targetFolder))
{
var date = report.ReportEnd;
targetFolder = OtcAppContext.MapPath($"~/App_Docs/Download/{date:yyyyMM}/");
}
string excelFileName;
var startDate = report.ReportStart;
if (startDate == DateTime.MinValue)
{
excelFileName = $"收益互换交易结算确认书_{report.ReportEnd:MMdd}_{report.ClientName}.xlsx";
}
else
{
excelFileName = $"收益互换交易结算确认书_{startDate:MMdd}_{report.ReportEnd:MMdd}_{report.ClientName}.xlsx";
}
var excelFilePath = Path.Combine(targetFolder, excelFileName);
Directory.CreateDirectory(targetFolder);
ExcelTemplate.GeneratePDFFromExeclTemplateV2(templateFile, excelFilePath,
new Dictionary<string, object> { { "交易明细", report } },
shouldDeleteSheet: true, needToPdf: false);
return excelFilePath;
}
public SearchListResult<TradeFlowMoreDetails> SearchFlowMoreDetails(TradeDetailsReq req)
{
if (req.ClientId < 1 && string.IsNullOrWhiteSpace(req.ClientIds))
{
return new SearchListResult<TradeFlowMoreDetails>();
}
if (req.EndDate == null)
{
throw new ServiceException("请选择结束日期");
}
if (req.StartDate != null && req.StartDate > req.EndDate)
{
throw new ServiceException("起始日期不能大于结束日期");
}
var clientIdsInt = new List<int>();
if (!string.IsNullOrWhiteSpace(req.ClientIds))
{
clientIdsInt.AddRange(req.ClientIdsInt);
}
else if (req.ClientId > 0)
{
clientIdsInt.Add(req.ClientId);
}
if (req.ParentFlag)
{
var clientIdList = DataCacheProvider.GetClientDataSource().AsQueryable(O => clientIdsInt.Contains(O.ParentId)).Select(O => O.id).ToList().ToHashSet();
clientIdsInt.AddRange(clientIdList);
}
var query = from source in DbContext.trade_swap_flow_more
join tradecashswap in DbContext.trade_cash_swap on source.id equals tradecashswap.FlowId into tradecashswap
from swap in tradecashswap.DefaultIfEmpty()
where !source.IsDelete && source.IsCompose && clientIdsInt.Contains(source.ClientId)
select new TradeFlowMoreDetails
{
id = source.id,
BuySell = source.BuySell,
TradeNumber = source.TradeNumber,
UnderlyingCode = source.UnderlyingCode,
TradeDate = source.TradeDate,
ExerciseDate = source.ExerciseDate,
Price = source.Price,
Notional = -source.Notional,
AnnualRate = -source.AnnualRate,
CurrencyRate = source.BuySell == "开仓" ? null : source.CurrencyRate,
UnwindDate = source.BuySell == "开仓" ? null : source.UnwindDate,
UnwindPrice = source.BuySell == "开仓" ? null : source.UnwindPrice,
UnwindNotional = source.BuySell == "开仓" ? null : -source.UnwindNotional,
TradeId = swap.TradeId,
TradeCashId = swap.TradeCashId,
TradeType = source.BuySell,
TotalFee = (source.TotalFee ?? 0),
StockEqvNotional = Math.Abs(source.Notional) * source.Price,
LongShort = source.LongShort,
OrderbyDate = source.BuySell == "开仓" ? source.TradeDate : source.UnwindDate,
OrderbyNumber = source.TradeNumber.Length >= 5 ? source.TradeNumber.Substring(source.TradeNumber.Length - 5, 5) : source.TradeNumber
};
if (req.DetailStatuses == "成交")
{
query = query.Where(x => x.BuySell == "开仓");
if (req.StartDate.HasValue)
{
query = query.Where(x => x.TradeDate >= req.StartDate);
}
if (req.EndDate.HasValue)
{
DateTime TradeDateTemp = req.EndDate.Value.AddDays(1);
query = query.Where(x => x.TradeDate < TradeDateTemp);
}
}
else if (req.DetailStatuses == "了结")
{
query = query.Where(x => x.BuySell == "平仓");
if (req.StartDate.HasValue)
{
query = query.Where(x => x.UnwindDate >= req.StartDate);
}
if (req.EndDate.HasValue)
{
DateTime TradeDateTemp = req.EndDate.Value.AddDays(1);
query = query.Where(x => x.UnwindDate < TradeDateTemp);
}
}
else
{
if (req.StartDate.HasValue)
{
query = query.Where(x => (x.BuySell == "开仓" && x.TradeDate >= req.StartDate) || (x.BuySell == "平仓" && x.UnwindDate >= req.StartDate));
}
if (req.EndDate.HasValue)
{
DateTime TradeDateTemp = req.EndDate.Value.AddDays(1);
query = query.Where(x => (x.BuySell == "开仓" && x.TradeDate < TradeDateTemp) || (x.BuySell == "平仓" && x.UnwindDate < TradeDateTemp));
}
}
if (string.IsNullOrEmpty(req.sidx))
{
req.sidx = "OrderbyDate,OrderbyNumber";
req.sord = "asc";
}
var retListResult = query.ToSearchList(req);
var tcids = retListResult.rows.Select(x => x.TradeCashId).ToHashSet();
var tradedetail = DbContext.trade_cash_detail.Where(x => tcids.Contains(x.TradeCashId)).ToList();
var tradenumbers = retListResult.rows.Select(x => x.TradeNumber).ToHashSet();
var opentradeswapflowmore = DbContext.trade_swap_flow_more.Where(x => tradenumbers.Contains(x.TradeNumber) && x.BuySell == "开仓" && !x.IsDelete && x.IsCompose).ToList();
var underlying = DataCacheProvider.GetUnderlyingDataSource();
var instrumentTypeArr = new List<string>() { ConsGlobal.InstrumentType.Stock, ConsGlobal.InstrumentType.StockIF };
foreach (var item in retListResult.rows)
{
var un = underlying.GetData(item.UnderlyingCode);
if (un != null && un.IsCommodity())
{
item.UnderlyingCode = un.MarketCode == null || un.MarketCode == "" ? un.UnderlyingCode : un.UnderlyingCode + "." + un.MarketCode;
}
var detail = tradedetail.Where(x => x.TradeCashId == item.TradeCashId);
if (detail.Any() && item.BuySell == "平仓")
{
//item.FloatIncome = (-detail.FirstOrDefault(x => x.TradeCashType == TradeCashTypeEnum.浮动收益.ToString())?.Amount ?? 0);
item.FixedIncome = (-detail.FirstOrDefault(x => x.TradeCashType == TradeCashTypeEnum.利息.ToString())?.Amount ?? 0);
item.Amount = (-detail.Sum(x => x.Amount) ?? 0);
item.FloatIncome = item.Amount - item.FixedIncome;
}
if (item.BuySell == "开仓")
{
var totalFee = (item.TotalFee / Math.Abs(item.Notional)).Normalize() * (item.LongShort == "多头" ? -1 : 1);
item.Price += totalFee;
}
else
{
var openflow = opentradeswapflowmore.Where(x => x.TradeNumber == item.TradeNumber).FirstOrDefault();
var optotalFee = ((openflow.TotalFee ?? 0) / Math.Abs(item.Notional)).Normalize() * (openflow.LongShort == "多头" ? -1 : 1);
var totalFee = (item.TotalFee / Math.Abs(item.UnwindNotional ?? 0)).Normalize() * (openflow.LongShort == "多头" ? 1 : -1);
item.Price += optotalFee;
item.UnwindPrice += totalFee;
}
item.TradeNumber = item.OrderbyNumber;
}
TradeFlowMoreSum sum = new TradeFlowMoreSum();
if (retListResult.rows.Any())
{
sum.FloatIncomeSum = retListResult.rows.Sum(x => (x.FloatIncome ?? 0));
sum.FixedIncomeSum = retListResult.rows.Sum(x => (x.FixedIncome ?? 0));
sum.AmountSum = retListResult.rows.Sum(x => (x.Amount ?? 0));
}
retListResult.Sum = sum;
return retListResult;
}
public SendTradeDetailReportResult SendTradeDetailReport(TradeDetailsReq req, TradeSwapDetailsReport report, string luoKuan,
string reportFilePath, string template, List<string> receiver = null, bool skip = false)
{
var AppendixType = DBCacheManager.Single.GetStr(CacheTable.TradeSwapDerailsNeedAppendix, template);
var path = string.Empty;
if (AppendixType == "PDF")
{
path = FileHelper.ReplaceExtension(reportFilePath, ".pdf");
path = GeneratePDFReport(reportFilePath);
}
else
{
path = reportFilePath;
}
var filePathes = new List<string>() { path };
var clientContacts = new ClientDBContext().clientduty.Where(x => x.ApprovalOrder < 1 && x.ClientId == req.ClientId
&& (x.DeadLine == null || x.DeadLine > DateTime.Now)
&& x.IsReceiveEmail.HasValue
&& x.IsReceiveEmail == 1).ToList();
var clientContactMails = new List<string>();
if (receiver != null && receiver.Count > 0)
{
foreach (var item in clientContacts)
{
var ids = item.ContactTypeId.Split(',');
if (ids.Intersect(receiver).Count() != 0)
{
clientContactMails.Add(item.Email);
}
}
}
else
{
clientContactMails = clientContacts.Select(o => o.Email).ToList();
}
var emails = DataConvert.EmailsSplitByComma(clientContactMails);
// var attachFiles = new List<string> { reportFilePath };
var startstr = req.StartDate.HasValue ? req.StartDate.Value.ToString("yyyy-MM-dd") : "";
var gh = req.StartDate.HasValue && req.EndDate.HasValue ? "-" : "";
var endstr = req.EndDate.HasValue ? req.EndDate.Value.ToString("yyyy-MM-dd") : "";
var endPart = (startstr == endstr) ? startstr : (startstr + gh + endstr);
//邮件标题格式 "【当前公司】"+ 客户名称 + "-场外交易确认-" + 确认日期或区间
var title = $"【国君风管】{report.ClientName}-场外商品互换交易确认-{endPart}";
if (PS.Config.IsGuoJun)
{
title = $"【国君风管】{report.ClientName}-场外商品互换交易确认-{endPart}";
}
var status = EmailTradeConfirmResultType.Succeed;
string sendMailMsg = null;
var ccemail = DBCacheManager.Single.GetStr(CacheTable.CCEmail, template);
var sendUser = DBCacheManager.Single.GetStr(CacheTable.TradeDetailsSendUser, template);
if (emails.All(o => string.IsNullOrWhiteSpace(o)))
{
status = EmailTradeConfirmResultType.NoEmailSetting;
}
else
{
emails = emails.Where(o => !string.IsNullOrWhiteSpace(o));
if (!string.IsNullOrWhiteSpace(AppendixType))
{
sendMailMsg = EmailHelper.SendMail(string.Join(";", emails), $"{report.ClientAbbreviation ?? ""}{title}", $"{luoKuan}", true, filePathes, ccemail, mailFrom: sendUser);
}
else
{
sendMailMsg = EmailHelper.SendMail(string.Join(";", emails), $"{report.ClientAbbreviation ?? ""}{title}", $"{luoKuan}", true, null, ccemail, mailFrom: sendUser);
}
if (!string.IsNullOrEmpty(sendMailMsg))
{
status = EmailTradeConfirmResultType.EmailSentFailed;
}
}
return new SendTradeDetailReportResult
{
ResultType = status,
ErrorMsg = sendMailMsg
};
}
private string GeneratePDFReport(string excelPath)
{
var tempFolder = OtcAppContext.MapPath("~/App_Docs/Temp");
if (!Directory.Exists(tempFolder))
{
Directory.CreateDirectory(tempFolder);
}
var tempExcelFilePath = FileHelper.GetTargetFilePath(excelPath, tempFolder, true);
File.Copy(excelPath, tempExcelFilePath);
var pdfFilePath = FileHelper.ReplaceExtension(excelPath, ".pdf");
var excelfilepath2 = FileHelper.ReplaceExtension(excelPath, ".xlsx");
var wordfilepath = FileHelper.ReplaceExtension(excelPath, ".docx");
if (File.Exists(excelfilepath2))
{
OfficeFileConverter.ConvertFileFormat(excelfilepath2, pdfFilePath);
}
else
{
OfficeFileConverter.ConvertDocxToPDF(wordfilepath, pdfFilePath);
}
return pdfFilePath;
}
}
public class TradeSwapDetailsReport
{
public YLErp.Configuration.IErpConfig Config => PS.Config.ErpElement;
public string CompanyName { get; set; }
public string TradeDetailsCode { get; set; }
public string ClientNumber { get; set; }
/// <summary>
/// 主 客户编号+A; 补充 客户编号+B;履约 客户编号+D; 主确认书:客户编号 + W
/// </summary>
public string ClientNumberA { get; set; }
public string ClientNumberB { get; set; }
public string ClientNumberD { get; set; }
public string ClientNumberW { get; set; }
public int? ClientId { get; set; }
/// <summary>
/// 有简称则用简称(应该是国君的需求)
/// </summary>
public string ClientName { get; set; }
/// <summary>
/// 客户全称
/// </summary>
public string ClientFullName { get; set; }
/// <summary>
/// 客户简称
/// </summary>
public string ClientAbbreviation { get; set; }
public DateTime ReportStart { get; set; }
public DateTime ReportEnd { get; set; }
public string ReportEndString => (ReportStart != DateTime.MinValue ? ($"{ReportStart.ToString("yyyy年M月d日")}至{ReportEnd.ToString("yyyy年M月d日")}") : ReportEnd.ToString("yyyy年M月d日"));
public DateTime ReportNow { get; set; }
public string ReportDateRange
{
get
{
var startDate = ReportStart;
if (startDate == DateTime.MinValue)
{
return $"{ReportEnd:yyyy/MM/dd}";
}
return $"{startDate:yyyy/MM/dd}-{ReportEnd:yyyy/MM/dd}";
}
}
public string BiaoTou { get; set; }
public string BiaoWei { get; set; }
/// <summary>
/// 用于Excel导出模板(交易明细)
/// </summary>
public IEnumerable<string> BiaoTouLines { get; set; }
/// <summary>
/// 用于Excel导出模板(交易明细)
/// </summary>
public IEnumerable<string> BiaoWeiLines { get; set; }
public string LuoKuan { get; set; }
public string Today => DateTime.Now.ToString("yyyy年M月d日");
/// <summary>
/// 导出文件输出文件夹路径
/// </summary>
public string OutputFolder { get; set; }
public List<TradeFlowMoreDetails> TradeFlowListAll { get; set; }
public TradeFlowMoreSum TradeFlowListSum { get; set; }
}
public class TradeFlowMoreDetails
{
public int id { get; set; }
public string TradeNumber { get; set; }
/// <summary>
/// 交易编号
/// </summary>
public string BuySell { get; set; }
/// <summary>
/// 标的代码
/// </summary>
public string UnderlyingCode { get; set; }
/// <summary>
/// 交易日期
/// </summary>
public DateTime? TradeDate { get; set; }
/// <summary>
/// 到期日期
/// </summary>
public DateTime? ExerciseDate { get; set; }
public string TradeDateString
{
get
{
return TradeDate?.ToString("yyyy/MM/dd");
}
}
public string ExerciseString
{
get
{
return ExerciseDate?.ToString("yyyy/MM/dd");
}
}
/// <summary>
/// 标的价格
/// </summary>
public double Price { get; set; }
public string PriceString
{
get
{
return Price.ToString("0.000000");
}
}
/// <summary>
/// 份额
/// </summary>
public double Notional { get; set; }
public string NotionalString
{
get
{
return (double.TryParse(Notional.ToString(), out double c) == true ? c.ToString() : 0.ToString());
}
}
/// <summary>
/// 利率
/// </summary>
public double? AnnualRate { get; set; }
public string AnnualRateString
{
get
{
return AnnualRate?.ToString("0.0000");
}
}
/// <summary>
/// 汇率
/// </summary>
public double? CurrencyRate { get; set; }
public string CurrencyRateString
{
get
{
return BuySell == "开仓" ? "--" : CurrencyRate?.ToString("0.0000");
}
}
/// <summary>
/// 平仓日期
/// </summary>
public DateTime? UnwindDate { get; set; }
public string UnwindDateString
{
get
{
return BuySell == "开仓" ? "--" : UnwindDate?.ToString("yyyy/MM/dd");
}
}
/// <summary>
/// 平仓价格
/// </summary>
public double? UnwindPrice { get; set; }
public string UnwindPriceString
{
get
{
return BuySell == "开仓" ? "--" : UnwindPrice?.ToString("0.000000");
}
}
/// <summary>
/// 平仓数量
/// </summary>
public double? UnwindNotional { get; set; }
public string UnwindNotionalString
{
get
{
return BuySell == "开仓" ? "--" : (int.TryParse(UnwindNotional?.ToString(), out int c) == true ? c.ToString() : 0.ToString());
}
}
/// <summary>
/// 浮动收益
/// </summary>
public double? FloatIncome { get; set; }
public string FloatIncomeString
{
get
{
return BuySell == "开仓" ? "--" : FloatIncome?.ToString("0.00");
}
}
/// <summary>
/// 固定收益
/// </summary>
public double? FixedIncome { get; set; }
public string FixedIncomeString
{
get
{
return BuySell == "开仓" ? "--" : FixedIncome?.ToString("0.00");
}
}
/// <summary>
/// 平仓总额
/// </summary>
public double? Amount { get; set; }
public string AmountString
{
get
{
return BuySell == "开仓" ? "--" : Amount?.ToString("0.00");
}
}
public string TradeType { get; set; }
public double StockEqvNotional { get; set; }
public string StockEqvNotionalString
{
get
{
return StockEqvNotional.ToString("0.00");
}
}
public string PayType
{
get
{
if (TradeNumber.Contains("W"))
{
return AnnualRate > 0 ? "商品互换\r\n收固定付浮动" : "商品互换\r\n付固定收浮动";
}
else if (TradeNumber.Contains("S"))
{
return AnnualRate > 0 ? "权益互换\r\n收固定付浮动" : "权益互换\r\n付固定收浮动";
}
else if (TradeNumber.Contains("F"))
{
return AnnualRate > 0 ? "仓单互换\r\n收固定付浮动" : "仓单互换\r\n付固定收浮动";
}
else
{
return AnnualRate > 0 ? "收固定付浮动" : "付固定收浮动";
}
}
}
public int? TradeId { get; set; }
public int? TradeCashId { get; set; }
/// <summary>
/// 手续费
/// </summary>
public double TotalFee { get; set; }
public string LongShort { get; set; }
/// <summary>
/// 排序规则时间
/// </summary>
public DateTime? OrderbyDate { get; set; }
public string OrderbyNumber { get; set; }
}
public class TradeFlowMoreSum
{
public double FloatIncomeSum { get; set; }
public double FixedIncomeSum { get; set; }
public double AmountSum { get; set; }
}
}