475 lines
21 KiB
C#
475 lines
21 KiB
C#
using System.Text;
|
|
using System.Text.RegularExpressions;
|
|
using OfficeOpenXml;
|
|
using YLErp.BLL;
|
|
using YLErp.BLL.EodSettlement;
|
|
using YLErp.Enums;
|
|
using YLErp.Helpers;
|
|
using YLErp.Model;
|
|
using YLErp.Modules.ClientModule;
|
|
using YLErp.Modules.DataCacheModule;
|
|
using YLErp.Modules.ReportModule.SettlementReportModule;
|
|
using YLErp.Modules.TradeModule.QueryModule;
|
|
using YLErp.Office;
|
|
using YLErp.QdpModule;
|
|
|
|
//using OfficeOpenXml.Style;
|
|
//using YLErp.BLL;
|
|
//using YLErp.Configuration;
|
|
//using YLErp.Modules.EodModule;
|
|
//using YLErp.QdpModule;
|
|
|
|
namespace YLErp.Modules.ReportModule
|
|
{
|
|
/// <summary>
|
|
/// 结算报告服务
|
|
/// </summary>
|
|
public class SettlementReportFotGTService : YLBaseService
|
|
{
|
|
public SettlementReportFotGTService(OptUserInfo userInfo) : base(userInfo)
|
|
{
|
|
}
|
|
|
|
/// <summary>
|
|
/// from:trade_spancontroller.GetReportData
|
|
/// </summary>
|
|
public ClientDingShiReport_GT GetReportData(DingShiReportEmail emailData, IEnumerable<int> userAssetUnits, string template = "")
|
|
{
|
|
var report = new ClientDingShiReport_GT() { ReportFrom = emailData.From, ReportEnd = emailData.To };
|
|
report.client = DataCacheProvider.GetClientDataSource().GetData(emailData.ClientId);
|
|
report.CurUserName = emailData.CurUserName;
|
|
|
|
if (emailData.SendContent.Contains("账户状况"))
|
|
{
|
|
var clientBalance = ClientBalanceUtility.GetClientBanlances(new List<int> { emailData.ClientId }, emailData.From, emailData.To, IsClientBalanceGap: false, IsGetOuterMarginGap: false, ParentFlag: emailData.ParentFlag).FirstOrDefault();
|
|
|
|
report.reportModel = new ReportModel_GT()
|
|
{
|
|
ClientName = report.client.Name,
|
|
ReportDate = report.ReportEnd,
|
|
|
|
LastDayRemainFund = clientBalance?.LastDayRemainFund ?? 0,
|
|
CashInChange = clientBalance?.InFund ?? 0,
|
|
CashOutChange = clientBalance?.OutFund ?? 0,
|
|
WinLoss = clientBalance?.WinLoss ?? 0,
|
|
ToEndBalance = clientBalance?.ToEndBalance ?? 0,
|
|
ToDayRemainFund = clientBalance?.AmountFund ?? 0,
|
|
|
|
WorstCastClientPayable = clientBalance?.MinusPayableMarginTotal ?? 0,
|
|
EodPremium = clientBalance?.EodPremium ?? 0,
|
|
OptionPremiumAndSwapSum = clientBalance?.OptionPremiumAndSwapSum ?? 0,
|
|
AvailableFund = clientBalance?.AvailableAmount ?? 0,
|
|
Credit = clientBalance?.TotalCredit ?? 0,
|
|
DesirableFund = clientBalance?.DesirableFund ?? 0,
|
|
|
|
WinLossSum = clientBalance?.WinLossSum ?? 0,
|
|
PositionPnl =((PS.Config.IsPVRounded ? clientBalance?.RoundedPositionPnl : clientBalance?.PositionPnl ) ?? 0),
|
|
AmountFundWithPositionPnl = clientBalance?.AmountFundWithPositionPnl ?? 0,
|
|
};
|
|
}
|
|
|
|
if (emailData.SendContent.Contains("持仓明细"))
|
|
{
|
|
var spanReq = new TradeSpanReq { ClientId = emailData.ClientId, ValueDate = emailData.To, ParentFlag = emailData.ParentFlag };
|
|
report.eodPositions = clientTradePositionQueryList(spanReq, userAssetUnits);
|
|
}
|
|
|
|
if (emailData.SendContent.Contains("历史交易"))
|
|
{
|
|
var treq = new TradeReq() { ClientId = emailData.ClientId, ValueDateStart = emailData.From, ValueDateEnd = emailData.To, ParentFlag = emailData.ParentFlag };
|
|
report.unwindTrades = SearchHistoryListOnly(treq, true);
|
|
}
|
|
|
|
//txt报告特殊处理用到
|
|
var desc = DBCacheManager.Single.GetStr(CacheTable.DingShiDesc, template: template);
|
|
if (string.IsNullOrWhiteSpace(desc))
|
|
{
|
|
desc = DBCacheManager.Single.GetStr(CacheTable.DingShiDesc);
|
|
}
|
|
var descList = Regex.Split(desc, "</p>", RegexOptions.IgnoreCase).Where(x => !string.IsNullOrWhiteSpace(x)).ToList();
|
|
var newDescList = new List<string>();
|
|
descList.ForEach(x =>
|
|
{
|
|
x = Regex.Replace(x, "<[^>]+>", "");
|
|
x = Regex.Replace(x, "&[^;]+;", "");
|
|
newDescList.Add(x);
|
|
});
|
|
report.downloadFilePath = emailData.DownloadFilePath;
|
|
if (string.IsNullOrWhiteSpace(emailData.Title))
|
|
{
|
|
emailData.Title = DBCacheManager.Single.GetStr(CacheTable.ClientBalanceReportTiltle, template: template);
|
|
}
|
|
report.Title = ReplaceWildcard(emailData.Title, report);
|
|
return report;
|
|
}
|
|
public string ReplaceWildcard(string input, ClientDingShiReport_GT report)
|
|
{
|
|
if (!string.IsNullOrEmpty(input))
|
|
{
|
|
input = Regex.Replace(input, @"\{\{(.*?)\}\}", m =>
|
|
{
|
|
switch (m.Groups[1].Value)
|
|
{
|
|
case "客户名称": return report.client.Name;
|
|
case "客户编号": return report.client.Number;
|
|
case "追保金额": return report.reportModel.WorstCastClientPayable.ToString("0.00");
|
|
case "大写追保金额": return NumberHelper.CmycurD(report.reportModel.WorstCastClientPayable);
|
|
case "支付截止时间":
|
|
return QdpCalendarHelper.GetNonHoliday(DateTime.Now < DateTime.Now.Date.AddHours(9).AddMinutes(30) ? DateTime.Now : DateTime.Now.AddDays(1)).ToString("yyyy年MM月dd日") + "上午9:30";
|
|
case "发送日期": return DateTime.Now.ToString("yyyy-MM-dd");
|
|
case "起始日期": return report.ReportFrom.ToString("yyyy-MM-dd");
|
|
case "结束日期": return report.ReportEnd.ToString("yyyy-MM-dd");
|
|
case "开户行":
|
|
if (report.ClientBank.Any())
|
|
{
|
|
var Bank = new StringBuilder();
|
|
report.ClientBank.ForEach(x =>
|
|
{
|
|
Bank.Append(x.Bank).Append(",");
|
|
});
|
|
return Bank.ToString().Substring(0, Bank.ToString().Length - 1);
|
|
}
|
|
return string.Empty;
|
|
case "户名":
|
|
if (report.ClientBank.Any())
|
|
{
|
|
var ClientName = new StringBuilder();
|
|
report.ClientBank.ForEach(x =>
|
|
{
|
|
ClientName.Append(x.ClientName).Append(",");
|
|
});
|
|
return ClientName.ToString().Substring(0, ClientName.ToString().Length - 1);
|
|
}
|
|
return string.Empty;
|
|
case "账号":
|
|
if (report.ClientBank.Any())
|
|
{
|
|
var Card = new StringBuilder();
|
|
report.ClientBank.ForEach(x =>
|
|
{
|
|
Card.Append(x.Card).Append(",");
|
|
});
|
|
return Card.ToString().Substring(0, Card.ToString().Length - 1);
|
|
}
|
|
return string.Empty;
|
|
default: return string.Empty;
|
|
}
|
|
});
|
|
}
|
|
return input;
|
|
}
|
|
|
|
public string GenerateFileEntry(ClientDingShiReport_GT report, string type)
|
|
{
|
|
var tempFolder = OtcAppContext.MapPath("~/App_Docs/Temp/结算报告");
|
|
var targetPath = string.IsNullOrEmpty(report.downloadFilePath) ? Path.Combine(tempFolder, report.ReportEnd.ToString("yyyyMMdd")) : report.downloadFilePath;
|
|
if (!Directory.Exists(targetPath))
|
|
{
|
|
Directory.CreateDirectory(targetPath);
|
|
}
|
|
var clientName = report.client.Name;
|
|
var fileName = $"结算报告_{clientName}_{report.ReportEnd:yyyy-MM-dd}";
|
|
var targetFileName = Path.Combine(targetPath, $"{fileName}.xlsx");
|
|
|
|
var modelDict = new Dictionary<string, object>();
|
|
if (report.reportModel != null)
|
|
{
|
|
modelDict.Add("客户权益信息", report.reportModel);
|
|
}
|
|
|
|
var positionSheetModels = new PositionSheetModels();
|
|
if (report.eodPositions != null)
|
|
{
|
|
modelDict.Add("客户持仓明细", report.eodPositions);
|
|
}
|
|
|
|
var historySheetModels = new HistorySheetModels();
|
|
if (report.unwindTrades != null)
|
|
{
|
|
modelDict.Add("到期平仓明细", report.unwindTrades);
|
|
}
|
|
|
|
var sourcePath = OtcAppContext.MapPath("~/App_Docs/导出模板");
|
|
var sourceFileName = Path.Combine(sourcePath, "结算报告模板_国投安信场外期权.xlsx");
|
|
var pdffile = ExcelTemplate.GeneratePDFFromExeclTemplate(sourcePath, sourceFileName, modelDict, targetPath, targetFileName
|
|
, shouldDeleteSheet: true, needToPdf: false, callback: new GenerateExcelCallback(this)
|
|
{
|
|
report = report
|
|
}.Callback);
|
|
|
|
string path = Path.Combine(targetPath, targetFileName);
|
|
|
|
//if (type == "PDF")
|
|
//{
|
|
// path = GeneratePDFReport(path);
|
|
//}
|
|
|
|
return path;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 没引用
|
|
/// </summary>
|
|
/// <param name="excelPath"></param>
|
|
/// <returns></returns>
|
|
//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))
|
|
// {
|
|
// MsOfficeHelper.ConvertExcelToPDF(excelfilepath2, pdfFilePath);
|
|
// }
|
|
// else
|
|
// {
|
|
// WordHelper.ConvertToFormat(wordfilepath, pdfFilePath, Microsoft.Office.Interop.Word.WdExportFormat.wdExportFormatPDF);
|
|
// }
|
|
// return pdfFilePath;
|
|
//}
|
|
|
|
class GenerateExcelCallback : YLBaseService
|
|
{
|
|
public ClientDingShiReport_GT report;
|
|
|
|
public GenerateExcelCallback(YLBaseService baseService) : base(baseService)
|
|
{
|
|
|
|
}
|
|
|
|
public void Callback(ExcelWorksheets sheets)
|
|
{ }
|
|
}
|
|
|
|
public (EmailTradeConfirmResultType status, string message) SendSettlementReports(DingShiReportEmail emailData, ClientDingShiReport_GT report, string template, bool IsSkipCheckMarginCall = false, List<string> recevier = null)
|
|
{
|
|
string message = null;
|
|
var attachFiles = new List<string>();
|
|
var IsNeedMarginCall = false;
|
|
if (!IsSkipCheckMarginCall)
|
|
{
|
|
IsNeedMarginCall = CheckIsNeedMarginCall(report.client, emailData.PayableFund > 0 ? emailData.PayableFund : report.reportModel.WorstCastClientPayable);
|
|
}
|
|
|
|
emailData.FileTypes.ForEach(type =>
|
|
{
|
|
if (type.@checked)
|
|
{
|
|
var filepath = GenerateFileEntry(report, type.type);
|
|
if (!string.IsNullOrEmpty(filepath))
|
|
{
|
|
attachFiles.Add(filepath);
|
|
}
|
|
}
|
|
});
|
|
|
|
// 要向该客户的所有订阅了邮件通知的人员发送邮件
|
|
var emails = ClientDataQueryService.GetClientEmails(report.client.id, false, recevier);
|
|
var status = EmailTradeConfirmResultType.Succeed;
|
|
if (emails.All(o => string.IsNullOrWhiteSpace(o)))
|
|
{
|
|
status = EmailTradeConfirmResultType.NoEmailSetting;
|
|
}
|
|
else
|
|
{
|
|
emails = emails.Where(o => !string.IsNullOrWhiteSpace(o));
|
|
|
|
var title = string.Empty;
|
|
var detail = string.Empty;
|
|
if (IsNeedMarginCall)
|
|
{
|
|
title = $"【追保通知】{report.Title}";
|
|
detail = emailData.MarginDetail;
|
|
detail = ReplaceWildcard(detail, report);
|
|
}
|
|
else
|
|
{
|
|
title = report.Title;
|
|
detail = emailData.Detail;
|
|
}
|
|
var mailFrom = DBCacheManager.Single.GetStr(CacheTable.TradeMarketSendUser, template);
|
|
if (string.IsNullOrWhiteSpace(mailFrom))
|
|
{
|
|
mailFrom = DBCacheManager.Single.GetStr(CacheTable.TradeMarketSendUser);
|
|
}
|
|
|
|
message = EmailHelper.SendMail(string.Join(";", emails), title, detail, true, attachFiles, emailData.CCEmail, mailFrom);
|
|
|
|
if (!string.IsNullOrEmpty(message))
|
|
{
|
|
status = EmailTradeConfirmResultType.EmailSentFailed;
|
|
}
|
|
|
|
}
|
|
return (status, message);
|
|
}
|
|
|
|
public bool CheckIsNeedMarginCall(int ClientId, DateTime start, DateTime end, double payableFund = -1, bool IsGap = false, bool IsOuter = false, bool ParentFlag = false)
|
|
{
|
|
var client = DataCacheProvider.GetClientDataSource().GetData(ClientId);
|
|
var clientBalance = ClientBalanceUtility.GetClientBanlances(new List<int> { ClientId }, start, end, IsGap, IsOuter, ParentFlag).FirstOrDefault();
|
|
return CheckIsNeedMarginCall(client, payableFund > 0 ? payableFund : clientBalance?.MinusPayableMarginTotal ?? 0);
|
|
}
|
|
|
|
private bool CheckIsNeedMarginCall(Client client, double payableFund)
|
|
{
|
|
var SamePeerMarginCallStarting = valuedateBLL.SystemDate.SamePeerMarginCallPoint;
|
|
if (client.SamePeer == 0 && payableFund > SamePeerMarginCallStarting)
|
|
{
|
|
return true;
|
|
}
|
|
if (client.SamePeer == 1 && payableFund > 1)
|
|
{
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
//from:trade_spancontroller.clientTradePositionQueryList
|
|
private List<EodPositionReportModel_GT> clientTradePositionQueryList(TradeSpanReq req, IEnumerable<int> userAssetUnits)
|
|
{
|
|
if (req.ClientId == null || req.ValueDate == null)
|
|
{
|
|
return new List<EodPositionReportModel_GT>(0);
|
|
}
|
|
|
|
var positionList = new ClientPositionQueryService(this).SearchPositionListAll(req, userAssetUnits);
|
|
var underlying = DataCacheProvider.GetUnderlyingDataSource();
|
|
|
|
int i = 1;
|
|
var result = positionList.Select(x =>
|
|
{
|
|
var model = new EodPositionReportModel_GT()
|
|
{
|
|
id = i++,
|
|
trade = x.trade,
|
|
ValueDate = x.ValueDate ?? DateTime.Today
|
|
};
|
|
|
|
model.ExerciseMode = x.trade.ExerciseMode == "European" ? "欧式" : "美式";
|
|
model.BuySell = x.trade.BuySell == "买入" ? "卖出" : "买入";
|
|
|
|
var isMoneyness = x.trade.IsMoneynessOption == "是";
|
|
model.Strike = x.trade.Strike.OtcFormatUmPrice(isMoneyness);
|
|
model.Strike2 = "\\";
|
|
model.Strike3 = "\\";
|
|
|
|
switch (model.trade.TradeType)
|
|
{
|
|
case "双鲨期权":
|
|
model.Strike2 = x.trade.trade_double_sharkfin_option.StrikeHigh.OtcFormatUmPrice(isMoneyness);
|
|
break;
|
|
case "凤凰期权":
|
|
model.Strike2 = x.trade.trade_autocall.SpreadStrike1.OtcFormatUmPrice(isMoneyness);
|
|
model.Strike3 = x.trade.trade_autocall.SpreadStrike.OtcFormatUmPrice(isMoneyness);
|
|
break;
|
|
case "雪球期权":
|
|
{
|
|
|
|
switch (x.trade.trade_snowball.KOPayoffType)
|
|
{
|
|
case KOPayoffTypeEnum.ToOption:
|
|
model.Strike2 = x.trade.trade_snowball.SpreadStrikeAtKO1.OtcFormatUmPrice(isMoneyness);
|
|
break;
|
|
case KOPayoffTypeEnum.ToSpreadOption:
|
|
model.Strike2 = x.trade.trade_snowball.SpreadStrikeAtKO.OtcFormatUmPrice(isMoneyness);
|
|
model.Strike3 = x.trade.trade_snowball.SpreadStrikeAtKO1.OtcFormatUmPrice(isMoneyness);
|
|
break;
|
|
}
|
|
switch (x.trade.trade_snowball.KIPayoffType)
|
|
{
|
|
case KIPayoffTypeEnum.ToPutOption:
|
|
case KIPayoffTypeEnum.ToCallOption:
|
|
model.Strike2 = x.trade.trade_snowball.SpreadStrikeAtMaturity1.OtcFormatUmPrice(isMoneyness);
|
|
break;
|
|
case KIPayoffTypeEnum.ToPutSpreadOption:
|
|
case KIPayoffTypeEnum.ToCallSpreadOption:
|
|
model.Strike2 = x.trade.trade_snowball.SpreadStrikeAtMaturity.OtcFormatUmPrice(isMoneyness);
|
|
model.Strike3 = x.trade.trade_snowball.SpreadStrikeAtMaturity1.OtcFormatUmPrice(isMoneyness);
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
var un = underlying.GetData(model.trade.UnderlyingCode);
|
|
if (un != null && un.IsCommodity())
|
|
{
|
|
model.UnderlyingCode = un.MarketCode == null || un.MarketCode == "" ? un.UnderlyingCode : un.UnderlyingCode + "." + un.MarketCode;
|
|
}
|
|
else
|
|
{
|
|
model.UnderlyingCode = model.trade.UnderlyingCode;
|
|
}
|
|
|
|
model.UnderlyingPrice = x.UnderlyingPrice;
|
|
model.CurrentPrice = Math.Abs(x.CurrentPrice ?? 0);
|
|
model.TradeSinglePrice = Math.Abs( x.TradeSinglePrice ?? 0);
|
|
model.TradePrice = Math.Abs(x.TradePrice ?? 0);
|
|
model.CurrentPriceSum = Math.Abs((x.CurrentPrice ?? 0) * x.trade.Notional);
|
|
|
|
model.Pnl = PS.Config.IsPVRounded ? x.RoundedPnl : x.Pnl;
|
|
model.Margin = x.Margin;
|
|
|
|
return model;
|
|
}).ToList();
|
|
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 查询所有历史交易数据
|
|
/// </summary>
|
|
private static List<UnwindTradeModel_GT> SearchHistoryListOnly(TradeReq req, bool isFromTradeMarketReport = false)
|
|
{
|
|
var historyList = new TradeHistoryQueryService(OptUserInfo.SystemUser)
|
|
.SearchHistoryListOnly(req, isFromTradeMarketReport);
|
|
|
|
var underlying = DataCacheProvider.GetUnderlyingDataSource();
|
|
|
|
int i = 1;
|
|
var sList = historyList.Select(x =>
|
|
{
|
|
var model = new UnwindTradeModel_GT()
|
|
{
|
|
id = i++,
|
|
trade = x.trade,
|
|
tc = x.trade_cash,
|
|
};
|
|
model.ExerciseMode = x.trade.ExerciseMode == "European" ? "欧式" : "美式";
|
|
model.BuySell = x.trade.BuySell == "买入" ? "卖出" : "买入";
|
|
|
|
var un = underlying.GetData(model.trade.UnderlyingCode);
|
|
if (un != null && un.IsCommodity())
|
|
{
|
|
model.UnderlyingCode = un.MarketCode == null || un.MarketCode == "" ? un.UnderlyingCode : un.UnderlyingCode + "." + un.MarketCode;
|
|
}
|
|
else
|
|
{
|
|
model.UnderlyingCode = model.trade.UnderlyingCode;
|
|
}
|
|
|
|
model.TradeSinglePrice = Math.Abs(x.trade.TradeSinglePrice ?? 0);
|
|
model.TradePrice = Math.Abs(x.TradePrice ?? 0);
|
|
model.UnwindPrice = Math.Abs(x.trade_cash.UnwindPrice ?? 0);
|
|
model.Amount = Math.Abs(x.trade_cash.Amount);
|
|
model.WinLoss = x.WinLoss;
|
|
|
|
return model;
|
|
}).ToList();
|
|
|
|
return sList;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
|