2635 lines
141 KiB
C#
2635 lines
141 KiB
C#
using Org.BouncyCastle.Ocsp;
|
|
using System.Diagnostics.Contracts;
|
|
using YLErp.Commons;
|
|
using YLErp.Configuration;
|
|
using YLErp.CustomizedBizLogic;
|
|
using YLErp.DBModels.Consts;
|
|
using YLErp.Enums;
|
|
using YLErp.Model;
|
|
using YLErp.Model.Enum;
|
|
using YLErp.Modules.AppModule;
|
|
using YLErp.Modules.ClientModule;
|
|
using YLErp.Modules.ReportModule;
|
|
using YLErp.Modules.TradeDalModule;
|
|
using YLErp.Modules.TradeModule;
|
|
using YLErp.Modules.TradeModule.DealModule;
|
|
using YLErp.Modules.TradeModule.DocGenerateModule;
|
|
using YLErp.Modules.UnderlyingModule;
|
|
using YLErp.MsOffice;
|
|
using YLErp.Office;
|
|
|
|
namespace YLErp.Web.Controllers
|
|
{
|
|
public class TradeConfirmBookController : BaseController
|
|
{
|
|
private static readonly IYcLogger logger = LogFactory.GetLogger<TradeConfirmBookController>();
|
|
|
|
private static readonly object createConfirmContractLock = new object();
|
|
|
|
readonly IViewRenderService _viewRenderer;
|
|
|
|
public TradeConfirmBookController(IViewRenderService viewRenderer)
|
|
{
|
|
_viewRenderer = viewRenderer;
|
|
}
|
|
|
|
// GET
|
|
[MyAuthorize("结算管理-交易确认书")]
|
|
public ActionResult Index()
|
|
{
|
|
ViewBag.ValueDate = valuedateBLL.ValueDate.ToString("yyyy-MM-dd");
|
|
if (GlobalConfig.SelectConfirmationBookTemplate)
|
|
{
|
|
try
|
|
{
|
|
if (string.IsNullOrWhiteSpace(GlobalConfig.PluginFolder))
|
|
{ throw new Exception("未找到插件路径"); }
|
|
var dirPath = Path.Combine(GlobalConfig.PluginFolder, "App_Docs", ContractTypeEnum.Trade);
|
|
if (!Directory.Exists(dirPath))
|
|
{
|
|
Directory.CreateDirectory(dirPath);
|
|
}
|
|
var paths = Directory.GetFiles(dirPath, "*.docx");
|
|
for (var i = 0; i < paths.Length; i++)
|
|
{
|
|
paths[i] = Path.GetFileName(paths[i]);
|
|
}
|
|
ViewBag.TemplateNames = paths;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
LogFactory.GetLogger("SelectConfirmationBookTemplate").Error(ex);
|
|
}
|
|
}
|
|
return View();
|
|
}
|
|
|
|
// GET - 期权交易确认书页面
|
|
[MyAuthorize("结算管理-交易确认书-期权")]
|
|
public ActionResult IndexOption()
|
|
{
|
|
ViewBag.ValueDate = valuedateBLL.ValueDate.ToString("yyyy-MM-dd");
|
|
if (GlobalConfig.SelectConfirmationBookTemplate)
|
|
{
|
|
try
|
|
{
|
|
if (string.IsNullOrWhiteSpace(GlobalConfig.PluginFolder))
|
|
{ throw new Exception("未找到插件路径"); }
|
|
var dirPath = Path.Combine(GlobalConfig.PluginFolder, "App_Docs", ContractTypeEnum.Trade);
|
|
if (!Directory.Exists(dirPath))
|
|
{
|
|
Directory.CreateDirectory(dirPath);
|
|
}
|
|
var paths = Directory.GetFiles(dirPath, "*.docx");
|
|
for (var i = 0; i < paths.Length; i++)
|
|
{
|
|
paths[i] = Path.GetFileName(paths[i]);
|
|
}
|
|
ViewBag.TemplateNames = paths;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
LogFactory.GetLogger("SelectConfirmationBookTemplate").Error(ex);
|
|
}
|
|
}
|
|
return View("~/Views/TradeConfirmBookOption/Index.cshtml");
|
|
}
|
|
|
|
public JsonResult ToPdf(string enid)
|
|
{
|
|
var intid = DataProtectHelper.DecryptInt(enid);
|
|
var trade = new TradeDalService(CurUser).GetTradeOrEodTrade(new[] { intid }, valuedateBLL.ValueDate).FirstOrDefault();
|
|
if (trade == null)
|
|
{
|
|
return JsonError("数据无效");
|
|
}
|
|
tradeBLL.SetFieldsByTradeType(trade);
|
|
return JsonError("申万定制功能,当前已不支持");
|
|
}
|
|
|
|
public ActionResult ConfirmBookListByClient()
|
|
{
|
|
return View();
|
|
}
|
|
|
|
public JsonResult clientConfirmQuery(ClientConfirmBookListReq req)
|
|
{
|
|
var result = new TradeContractGenerateService(CurUser).GetConfirmBookListByClient(req);
|
|
return Json(result);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 期权确认书查询(排除收益互换)
|
|
/// </summary>
|
|
public JsonResult OptionQuery(TradeReq req)
|
|
{
|
|
req.AssetIdList = AssetUnitModel.IntersectAssetUnits(req.AssetIdGroupList, req.AssetIdList).ToList();
|
|
req.UserAssets = CurUser.GetAssetUnitIds();
|
|
req.UserClients = CurUser.GetClientIdsByCurUser(CurUser.交易管理_查看所有交易);
|
|
req.CurUserTradeIds = CurUser.GetTradeIdsByCurUser();
|
|
// 排除收益互换
|
|
req.NotInTradeTypes = new List<string> { "收益互换" };
|
|
var sList = new tradeBLL().SearchListForTradeConfirm(req);
|
|
var rowList = sList.rows;
|
|
// 增加交易确认书编号
|
|
if (rowList != null && rowList.Any())
|
|
{
|
|
var tradeIds = rowList.Select(x => x.id).ToList();
|
|
var tradeContractCodeList = (from tradeContractR in yldb.trade_contract_r
|
|
join tradeContractDoc in (from tradeContractDocTemp in yldb.trade_contract_document where ContractTypeEnum.Trade == tradeContractDocTemp.Type select tradeContractDocTemp)
|
|
on tradeContractR.ContractCode equals tradeContractDoc.Code into tradeContractDoc1
|
|
from tradeContractDoc2 in tradeContractDoc1.DefaultIfEmpty()
|
|
where tradeIds.Contains(tradeContractR.TradeId) && ContractTypeEnum.Trade == tradeContractR.Type && tradeContractR.Type == tradeContractDoc2.Type && tradeContractR.IsValid
|
|
select new
|
|
{
|
|
tradeContractR.id,
|
|
tradeContractR.TradeId,
|
|
tradeContractR.ContractCode,
|
|
tradeContractR.send_email_result,
|
|
tradeContractDoc = tradeContractDoc2
|
|
}).ToList();
|
|
|
|
// 查询OA结果
|
|
var oaResults = yldb.tradeContractOaResult
|
|
.Where(x => tradeIds.Contains(x.trade_id) && x.is_valid)
|
|
.ToList();
|
|
|
|
foreach (var trade in rowList)
|
|
{
|
|
if (trade.TradeType == "合成价差期权")
|
|
{
|
|
trade.SyntheticUnderlyingTipsInfo = synthetic_underlyingBLL.GetUnderlyingTipsInfo(trade.UnderlyingCode);
|
|
}
|
|
var tradeContractinfo = tradeContractCodeList.FirstOrDefault(t => t.TradeId == trade.id);
|
|
trade.MetaDic["send_email_result"] = "";
|
|
if (tradeContractinfo != null)
|
|
{
|
|
trade.ContractCode = tradeContractinfo.ContractCode;
|
|
if (null != tradeContractinfo.tradeContractDoc)
|
|
{
|
|
trade.MetaDic["ContractEncryptId"] = tradeContractinfo.tradeContractDoc.EncryptId;
|
|
trade.MetaDic["ContractRId"] = tradeContractinfo.id.ToString();
|
|
trade.MetaDic["ContractDocUrl"] = tradeContractinfo.tradeContractDoc.RelativePath;
|
|
trade.MetaDic["HasGeneratedConfirmBook"] = "True";
|
|
trade.MetaDic["send_email_result"] = tradeContractinfo.send_email_result;
|
|
trade.MetaDic["ContractStatus"] = tradeContractinfo.tradeContractDoc.Status;
|
|
trade.MetaDic["StampDocumentFileName"] = tradeContractinfo.tradeContractDoc.StampDocumentFileName;
|
|
trade.MetaDic["SourceType"] = tradeContractinfo.tradeContractDoc.SourceType?.ToString() ?? "1";
|
|
}
|
|
else
|
|
{
|
|
trade.MetaDic["ContractEncryptId"] = "";
|
|
trade.MetaDic["ContractRId"] = tradeContractinfo.id.ToString();
|
|
trade.MetaDic["HasGeneratedConfirmBook"] = "False";
|
|
trade.MetaDic["SourceType"] = "";
|
|
}
|
|
}
|
|
else
|
|
{
|
|
trade.MetaDic["ContractEncryptId"] = "";
|
|
trade.MetaDic["ContractRId"] = "";
|
|
trade.MetaDic["HasGeneratedConfirmBook"] = "False";
|
|
}
|
|
|
|
// 设置OA状态
|
|
var oa = oaResults.FirstOrDefault(x => x.trade_id == trade.id);
|
|
trade.MetaDic["OAStatus"] = oa?.status ?? "";
|
|
trade.MetaDic["OAURL"] = oa?.oa_url ?? "";
|
|
trade.MetaDic["OAMessage"] = oa?.oa_msg ?? "";
|
|
}
|
|
}
|
|
return Json(sList);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 互换确认书查询(只查询收益互换)
|
|
/// </summary>
|
|
public JsonResult SwapQuery(TradeReq req)
|
|
{
|
|
req.AssetIdList = AssetUnitModel.IntersectAssetUnits(req.AssetIdGroupList, req.AssetIdList).ToList();
|
|
req.UserAssets = CurUser.GetAssetUnitIds();
|
|
req.UserClients = CurUser.GetClientIdsByCurUser(CurUser.交易管理_查看所有交易);
|
|
req.CurUserTradeIds = CurUser.GetTradeIdsByCurUser();
|
|
// 只查询收益互换
|
|
req.TradeTypes = "收益互换";
|
|
var sList = new tradeBLL().SearchListForTradeConfirm(req);
|
|
var rowList = sList.rows;
|
|
// 增加交易确认书编号
|
|
if (rowList != null && rowList.Any())
|
|
{
|
|
var tradeIds = rowList.Select(x => x.id).ToList();
|
|
var tradeContractCodeList = (from tradeContractR in yldb.trade_contract_r
|
|
join tradeContractDoc in (from tradeContractDocTemp in yldb.trade_contract_document where ContractTypeEnum.Trade == tradeContractDocTemp.Type select tradeContractDocTemp)
|
|
on tradeContractR.ContractCode equals tradeContractDoc.Code into tradeContractDoc1
|
|
from tradeContractDoc2 in tradeContractDoc1.DefaultIfEmpty()
|
|
where tradeIds.Contains(tradeContractR.TradeId) && ContractTypeEnum.Trade == tradeContractR.Type && tradeContractR.Type == tradeContractDoc2.Type && tradeContractR.IsValid
|
|
select new
|
|
{
|
|
tradeContractR.id,
|
|
tradeContractR.TradeId,
|
|
tradeContractR.ContractCode,
|
|
tradeContractR.send_email_result,
|
|
tradeContractDoc = tradeContractDoc2
|
|
}).ToList();
|
|
|
|
// 查询OA结果
|
|
var oaResults = yldb.tradeContractOaResult
|
|
.Where(x => tradeIds.Contains(x.trade_id) && x.is_valid)
|
|
.ToList();
|
|
|
|
foreach (var trade in rowList)
|
|
{
|
|
if (trade.TradeType == "合成价差期权")
|
|
{
|
|
trade.SyntheticUnderlyingTipsInfo = synthetic_underlyingBLL.GetUnderlyingTipsInfo(trade.UnderlyingCode);
|
|
}
|
|
var tradeContractinfo = tradeContractCodeList.FirstOrDefault(t => t.TradeId == trade.id);
|
|
trade.MetaDic["send_email_result"] = "";
|
|
if (tradeContractinfo != null)
|
|
{
|
|
trade.ContractCode = tradeContractinfo.ContractCode;
|
|
if (null != tradeContractinfo.tradeContractDoc)
|
|
{
|
|
trade.MetaDic["ContractEncryptId"] = tradeContractinfo.tradeContractDoc.EncryptId;
|
|
trade.MetaDic["ContractRId"] = tradeContractinfo.id.ToString();
|
|
trade.MetaDic["ContractDocUrl"] = tradeContractinfo.tradeContractDoc.RelativePath;
|
|
trade.MetaDic["HasGeneratedConfirmBook"] = "True";
|
|
trade.MetaDic["send_email_result"] = tradeContractinfo.send_email_result;
|
|
trade.MetaDic["ContractStatus"] = tradeContractinfo.tradeContractDoc.Status;
|
|
trade.MetaDic["StampDocumentFileName"] = tradeContractinfo.tradeContractDoc.StampDocumentFileName;
|
|
trade.MetaDic["SourceType"] = tradeContractinfo.tradeContractDoc.SourceType?.ToString() ?? "1";
|
|
}
|
|
else
|
|
{
|
|
trade.MetaDic["ContractEncryptId"] = "";
|
|
trade.MetaDic["ContractRId"] = tradeContractinfo.id.ToString();
|
|
trade.MetaDic["HasGeneratedConfirmBook"] = "False";
|
|
trade.MetaDic["SourceType"] = "";
|
|
}
|
|
}
|
|
else
|
|
{
|
|
trade.MetaDic["ContractEncryptId"] = "";
|
|
trade.MetaDic["ContractRId"] = "";
|
|
trade.MetaDic["HasGeneratedConfirmBook"] = "False";
|
|
}
|
|
|
|
// 设置OA状态
|
|
var oa = oaResults.FirstOrDefault(x => x.trade_id == trade.id);
|
|
trade.MetaDic["OAStatus"] = oa?.status ?? "";
|
|
trade.MetaDic["OAURL"] = oa?.oa_url ?? "";
|
|
trade.MetaDic["OAMessage"] = oa?.oa_msg ?? "";
|
|
}
|
|
}
|
|
return Json(sList);
|
|
}
|
|
|
|
public async Task<ActionResult> SentMail(string enid, List<string> reciver)
|
|
{
|
|
var result = await DoSendMailSywg(enid, reciver);
|
|
switch (result)
|
|
{
|
|
case EmailTradeConfirmResultType.Succeed:
|
|
return JsonSuccess("发送成功");
|
|
case EmailTradeConfirmResultType.TradeQueryFailed:
|
|
return JsonError("查询该交易失败");
|
|
case EmailTradeConfirmResultType.NoEmailSetting:
|
|
return JsonError("未设置邮箱,无法发送");
|
|
case EmailTradeConfirmResultType.EmailSentFailed:
|
|
return JsonError("发送失败");
|
|
case EmailTradeConfirmResultType.NotGenerated:
|
|
return JsonError("请先生成交易确认书");
|
|
case EmailTradeConfirmResultType.Other:
|
|
default:
|
|
return JsonError("发送邮件未知错误");
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 发送OA
|
|
/// </summary>
|
|
/// <param name="id">交易ID</param>
|
|
/// <returns></returns>
|
|
[HttpPost]
|
|
public async Task<JsonResult> SendOA(int id)
|
|
{
|
|
try
|
|
{
|
|
var oaService = new TradeOAService(CurUser);
|
|
var result = await oaService.ProcessSingleOAAsync(id);
|
|
|
|
return result.Success ? JsonSuccess(result.Message) : JsonError(result.Message);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
logger.Error($"提交OA失败: {ex.Message}", ex);
|
|
return JsonError($"提交OA失败: {ex.Message}");
|
|
}
|
|
}
|
|
|
|
private async Task<EmailTradeConfirmResultType> DoSendMailSywg(string tradeId, List<string> reciver,bool needDecryption = true)
|
|
{
|
|
try
|
|
{
|
|
var intid = needDecryption ? DataProtectHelper.DecryptInt(tradeId) : int.Parse(tradeId);
|
|
//trade trade = yldb.trade.Find(intid);
|
|
var trade = new TradeDalService(CurUser).GetTradeOrEodTrade(new[] { intid }, valuedateBLL.ValueDate, true).FirstOrDefault();
|
|
if (trade == null)
|
|
{
|
|
return EmailTradeConfirmResultType.TradeQueryFailed;
|
|
}
|
|
var valueDate = valuedateBLL.ValueDate;
|
|
var tcr = yldb.trade_contract_r.Where(t => t.Type == ContractTypeEnum.Trade && t.IsValid).FirstOrDefault(x => x.TradeId == intid);
|
|
if (tcr == null) // generate contract first
|
|
{
|
|
return EmailTradeConfirmResultType.NotGenerated;
|
|
}
|
|
var tcdQuery = yldb.trade_contract_document.AsNoTracking().AsQueryable();
|
|
|
|
var tcd = tcdQuery.FirstOrDefault(x => x.Code == tcr.ContractCode && x.Type == tcr.Type);
|
|
if (tcd == null)
|
|
{
|
|
return EmailTradeConfirmResultType.NotGenerated;
|
|
}
|
|
var emailType = "交易确认书";
|
|
|
|
var filePath = Path.ChangeExtension(tcd.AbsolutePath, "pdf");
|
|
if (PS.Config.ErpElement.ConfirmBookStampStatus)
|
|
{
|
|
if (!tcd.AbsoluteStampPath.IsNullOrWhiteSpace())
|
|
{
|
|
var stampTemplate = new EmailTemplateService(CurUser).GetData("交易确认书(用印)");
|
|
if (!string.IsNullOrEmpty(stampTemplate?.BodyTemplate))
|
|
{
|
|
emailType = "交易确认书(用印)";
|
|
}
|
|
filePath = tcd.AbsoluteStampPath;
|
|
}
|
|
}
|
|
if (!System.IO.File.Exists(filePath))
|
|
{
|
|
return EmailTradeConfirmResultType.NotGenerated;
|
|
}
|
|
var getUnderlyingInstrumentType = new Func<int, string>((underlyingId) =>
|
|
{
|
|
return DataCacheProvider.GetUnderlyingDataSource().GetData(underlyingId).UnderlyingInstrumentType;
|
|
});
|
|
var tradeListHtml = "";
|
|
var client = DataCacheProvider.GetClientDataSource().GetData(trade.ClientId);
|
|
var parentdatas = DataCacheProvider.GetClientDataSource().GetData(client.ParentId);
|
|
if (parentdatas != null && client.IsDocShowParentName == 1)
|
|
{
|
|
trade.ClientName = parentdatas.Name;
|
|
}
|
|
var instrumentTypeArr = new List<string>() { ConsGlobal.InstrumentType.Stock, ConsGlobal.InstrumentType.StockIF };
|
|
if (PS.Config.Is国泰君安 && instrumentTypeArr.Contains(getUnderlyingInstrumentType(trade.UnderlyingId)))
|
|
{
|
|
var cacheResult = Server.RazorEngine.Handler.Cache.RetrieveTemplate("Statics/views/TradeListMail");
|
|
if (cacheResult.Success)
|
|
{
|
|
var templatePage = cacheResult.Template.TemplatePageFactory();
|
|
tradeListHtml = await Server.RazorEngine.RenderTemplateAsync(templatePage, new[] { trade });
|
|
}
|
|
else
|
|
{
|
|
var tradeListHtmlViewPath = Server.MapPath("~/Statics/views/TradeListMail.cshtml");
|
|
using (var reader = new StreamReader(tradeListHtmlViewPath))
|
|
{
|
|
var templateContent = reader.ReadToEnd();
|
|
tradeListHtml = await Server.RazorEngine.CompileRenderStringAsync("Statics/views/TradeListMail", templateContent, new[] { trade });
|
|
}
|
|
}
|
|
//tradeListHtml = await _viewRenderer.RenderToStringAsync("Statics/views/TradeListMail", new[] { trade });
|
|
}
|
|
var mailInfo = new EmailTemplateService(CurUser).GenerateMailInfo(emailType, new MailInfoRequestModel
|
|
{
|
|
ClientName = client?.Name,
|
|
TradeDate = trade.TradeDate?.ToString("yyyy-MM-dd"),
|
|
DocNumber = tcd.Code,
|
|
TradeList = tradeListHtml
|
|
}) ?? new MailInfoResultModel
|
|
{
|
|
Body = string.Empty,
|
|
Title = trade.TradeDate?.ToString("yyyy-MM-dd") + " 交易确认书"
|
|
};
|
|
|
|
// 要向该客户的所有订阅了邮件通知的人员发送邮件
|
|
var emails = ClientDataQueryService.GetClientEmails(client.id, false, reciver);
|
|
if (!emails.Any())
|
|
{
|
|
return EmailTradeConfirmResultType.NoEmailSetting;
|
|
}
|
|
|
|
foreach (var email in emails)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(email))
|
|
{
|
|
logger.Info($"发送{tcr.ContractCode}确认书给{trade.ClientName}的关联客户中有邮箱为空的");
|
|
return EmailTradeConfirmResultType.NoEmailSetting;
|
|
}
|
|
}
|
|
var sendMail = EmailHelper.SendMailOfTradeConfirmBook(string.Join(";", emails), new[] { filePath },
|
|
mailInfo.Title, mailInfo.Body, mailInfo.IsBodyHtml);
|
|
if (!string.IsNullOrWhiteSpace(sendMail))
|
|
{
|
|
logger.Info($"发送{tcr.ContractCode}确认书给{trade.ClientName}的关联客户邮箱失败,失败信息是{sendMail}");
|
|
return EmailTradeConfirmResultType.EmailSentFailed;
|
|
}
|
|
|
|
//发送成功记录发送次数
|
|
trade.SentMailCount = (trade.SentMailCount != null) ? (trade.SentMailCount + 1) : 1;
|
|
yldb.SaveChanges();
|
|
return EmailTradeConfirmResultType.Succeed;
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
logger.Error(e.ToString(), e);
|
|
return EmailTradeConfirmResultType.Other;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 批量下载交易确认书
|
|
/// </summary>
|
|
public JsonResult BatchDownContracts(TradeReq req)
|
|
{
|
|
try
|
|
{
|
|
var tradeIdList = req.TradeIdList;
|
|
if (!tradeIdList.Any())
|
|
{
|
|
throw new InvalidOperationException($"未找到要下载确认书的交易!");
|
|
}
|
|
|
|
var contracts = (from d in yldb.trade_contract_document
|
|
join r in (from aa in yldb.trade_contract_r where aa.Type == ContractTypeEnum.Trade && tradeIdList.Contains(aa.TradeId) && aa.IsValid select aa)
|
|
on d.Code equals r.ContractCode
|
|
select d).ToList();
|
|
|
|
var Paths = new List<string>();
|
|
var mainPath = "";
|
|
foreach (var tcd in contracts)
|
|
{
|
|
var filePath = tcd.AbsolutePath;
|
|
if (string.IsNullOrWhiteSpace(mainPath))
|
|
{
|
|
mainPath = System.IO.Path.GetDirectoryName(filePath);
|
|
}
|
|
if (PS.Config.ErpElement.ConfirmBookStampStatus)
|
|
{
|
|
if (!tcd.AbsoluteStampPath.IsNullOrWhiteSpace())
|
|
{
|
|
filePath = tcd.AbsoluteStampPath;
|
|
if (!System.IO.File.Exists(filePath))
|
|
{
|
|
logger.Info($"已用印交易确认书{filePath}不存在");
|
|
throw new InvalidOperationException($"已用印交易确认书文件不存在");
|
|
}
|
|
}
|
|
}
|
|
if (!System.IO.File.Exists(filePath))
|
|
{
|
|
logger.Info($"交易确认书{filePath}不存在");
|
|
throw new InvalidOperationException($"交易确认书文件({filePath})不存在");
|
|
}
|
|
Paths.Add(filePath);
|
|
}
|
|
|
|
if (!string.IsNullOrWhiteSpace(mainPath))
|
|
{
|
|
var finalFile = mainPath + $"\\{DateTime.Now:yyyyMMdd}交易确认书批量下载.zip";
|
|
var rootPath = Server.MapPath("/");
|
|
var releativePath = "\\" + finalFile.Remove(0, rootPath.Length).Replace("\\", "/");
|
|
ZipHelper.ZipFilesWithLevel(Paths, finalFile, 0);
|
|
return JsonSuccess("下载成功", releativePath);
|
|
}
|
|
else
|
|
{
|
|
return JsonError("下载失败,没有找到生成的确认书记录");
|
|
}
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
logger.Error(e.ToString(), e);
|
|
return JsonError($"下载失败: {e.Message}");
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 批量发送交易确认书
|
|
/// </summary>
|
|
public async Task<ActionResult> BatchMailContracts(TradeReq req)
|
|
{
|
|
try
|
|
{
|
|
//var valueDate = valuedateBLL.ValueDate;
|
|
var bll = new tradeBLL();
|
|
req.LoginUserId = CurUser.UserId;
|
|
if (req.TradeTypes == null)
|
|
{
|
|
var types = DbContextFactory.GetYLDbContext().Structure_Info.Select(o => o.StructureName);
|
|
var TradeTypes = ConsTrade.TradeTypesForOtcOptions.Union(types).ToList();
|
|
TradeTypes.Add("收益互换");
|
|
TradeTypes.Add("远期");
|
|
TradeTypes.Add("掉期");
|
|
req.TradeTypes = string.Join(",", TradeTypes);
|
|
}
|
|
req.UserAssets = CurUser.GetAssetUnitIds();
|
|
req.UserClients = CurUser.GetClientIdsByCurUser(CurUser.交易管理_查看所有交易);
|
|
req.CurUserTradeIds = CurUser.GetTradeIdsByCurUser();
|
|
var query = bll.CreateValueDateQuery(req, false, false);
|
|
var tradeIdList = query.Select(t => t.id).ToList();
|
|
|
|
if (!tradeIdList.Any())
|
|
{
|
|
throw new InvalidOperationException($"未找到要发送确认书的交易!");
|
|
}
|
|
|
|
var clientTradeDict = query.ToLookup(t => t.ClientId);
|
|
//客户信息
|
|
var clientIds = clientTradeDict.Select(t => t.Key).ToList();
|
|
//var clientList = yldb.client.Where(t => clientIds.Contains(t.id)).ToList();
|
|
|
|
//var today = valuedateBLL.ValueDate;
|
|
var contracts = (from d in yldb.trade_contract_document
|
|
join r in (from aa in yldb.trade_contract_r where aa.Type == ContractTypeEnum.Trade && tradeIdList.Contains(aa.TradeId) && aa.IsValid select aa)
|
|
on d.Code equals r.ContractCode
|
|
where d.Type == r.Type
|
|
select new { dcd = d, tcr = r }).ToList();
|
|
|
|
if (req.TradeIdList.Count > 0 && contracts.Count != req.TradeIdList.Count)
|
|
{
|
|
throw new InvalidOperationException($"请勾选已生成过确认书的交易!");
|
|
}
|
|
var tempalte = new EmailTemplateService(CurUser).GetData("交易确认书");
|
|
var stampTemplate = new EmailTemplateService(CurUser).GetData("交易确认书(用印)");
|
|
EmailTemplate useTemplate;
|
|
var error = new List<string>();
|
|
var errorClient = new List<string>();
|
|
var successClient = new List<string>();
|
|
foreach (var item in clientTradeDict)
|
|
{
|
|
useTemplate = tempalte;
|
|
var tempTradeIds = item.Select(t => t.id).ToList();
|
|
var tempContractsDict = contracts.Where(t => tempTradeIds.Contains(t.tcr.TradeId)).Select(t => new { t.dcd, t.tcr.TradeId, t.tcr.TradeCashId }).Distinct().ToLookup(t => t.dcd.ValueDate);
|
|
|
|
foreach (var tempItem in tempContractsDict)
|
|
{
|
|
var tempContracts = tempItem.Select(O => O.dcd).ToList();
|
|
var tradeidlist = tempItem.Select(c => c.TradeId).ToList();
|
|
if (tempContracts.Count > 0)
|
|
{
|
|
var client = DataCacheProvider.GetClientDataSource().GetData(item.Key);
|
|
if (client == null)
|
|
{
|
|
errorClient.Add(client?.Name ?? "未知");
|
|
error.Add($"未找到客户ID为[{item.Key}]的客户信息");
|
|
continue;
|
|
}
|
|
var emails = ClientDataQueryService.GetClientEmails(item.Key, true, req.receiver);
|
|
if (!emails.Any())
|
|
{
|
|
errorClient.Add(client.Name);
|
|
error.Add($"客户 {client.Name} 未设置有效的联系人邮件地址!");
|
|
continue;
|
|
}
|
|
var canSend = true;
|
|
foreach (var t in emails)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(t))
|
|
{
|
|
errorClient.Add(client.Name);
|
|
error.Add($"客户 {client.Name} 的联系人未设置邮件地址!");
|
|
canSend = false;
|
|
continue;
|
|
}
|
|
}
|
|
if (!canSend)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
//附件
|
|
var Paths = new HashSet<string>();
|
|
tempContracts.ForEach(tcd =>
|
|
{
|
|
var filePath = Path.ChangeExtension(tcd.AbsolutePath, "pdf");
|
|
if (PS.Config.ErpElement.ConfirmBookStampStatus)
|
|
{
|
|
if (!tcd.AbsoluteStampPath.IsNullOrWhiteSpace())
|
|
{
|
|
if (!string.IsNullOrEmpty(stampTemplate?.BodyTemplate))
|
|
{
|
|
useTemplate = stampTemplate;
|
|
}
|
|
filePath = tcd.AbsoluteStampPath;
|
|
if (!System.IO.File.Exists(filePath))
|
|
{
|
|
logger.Info($"已用印交易确认书{filePath}不存在");
|
|
errorClient.Add(client.Name);
|
|
error.Add($"已用印交易确认书文件不存在");
|
|
canSend = false;
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
if (!System.IO.File.Exists(filePath))
|
|
{
|
|
logger.Info($"交易确认书{filePath}不存在");
|
|
errorClient.Add(client.Name);
|
|
error.Add($"交易确认书文件不存在");
|
|
canSend = false;
|
|
return;
|
|
}
|
|
Paths.Add(filePath);
|
|
});
|
|
if (!canSend)
|
|
{
|
|
continue;
|
|
};
|
|
var getUnderlyingInstrumentType = new Func<int, string>((underlyingId) =>
|
|
{
|
|
return DataCacheProvider.GetUnderlyingDataSource().GetData(underlyingId).UnderlyingInstrumentType;
|
|
});
|
|
var tradeListHtml = "";
|
|
var instrumentTypeArr = new List<string>() { ConsGlobal.InstrumentType.Stock, ConsGlobal.InstrumentType.StockIF };
|
|
IEnumerable<trade> tradelist = query.Where(C => tradeidlist.Contains(C.id)).ToList();
|
|
var clientall = DataCacheProvider.GetClientDataSource().AsQueryable();
|
|
foreach (var trade in tradelist)
|
|
{
|
|
var clientnow = DataCacheProvider.GetClientDataSource().GetData(trade.ClientId); ;
|
|
var parentdata = clientall.Where(c => c.id == clientnow.ParentId).FirstOrDefault();
|
|
if (parentdata != null && clientnow.IsDocShowParentName == 1)
|
|
{
|
|
trade.ClientName = parentdata.Name;
|
|
}
|
|
}
|
|
tradeBLL.SetFieldsByTradeType(tradelist);
|
|
if (PS.Config.Is国泰君安 && tradelist.Any(c => instrumentTypeArr.Contains(getUnderlyingInstrumentType(c.UnderlyingId))))
|
|
{
|
|
if (tradelist.Where(x => x.IsGroup > 0).Any())
|
|
{
|
|
var count = tradelist.GroupBy(O => O.IsGroup).Count();
|
|
if (count > 1)
|
|
{
|
|
error.Add("不应勾选多个非黑盒标的的交易");
|
|
errorClient.Add(client.Name);
|
|
continue;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
var count =
|
|
tradelist.GroupBy(O => new { UnderlyingInstrumentType = instrumentTypeArr.Contains(getUnderlyingInstrumentType(O.UnderlyingId)) ? 1 : 0 }).Count();
|
|
if (count > 1)
|
|
{
|
|
error.Add("不应勾选多个非股票(含股指期货)标的的交易");
|
|
errorClient.Add(client.Name);
|
|
continue;
|
|
}
|
|
}
|
|
var cacheResult = Server.RazorEngine.Handler.Cache.RetrieveTemplate("Statics/views/TradeListMail");
|
|
if (cacheResult.Success)
|
|
{
|
|
var templatePage = cacheResult.Template.TemplatePageFactory();
|
|
tradeListHtml = await Server.RazorEngine.RenderTemplateAsync(templatePage, tradelist);
|
|
}
|
|
else
|
|
{
|
|
var tradeListHtmlViewPath = Server.MapPath("~/Statics/views/TradeListMail.cshtml");
|
|
using (var reader = new StreamReader(tradeListHtmlViewPath))
|
|
{
|
|
var templateContent = reader.ReadToEnd();
|
|
tradeListHtml = await Server.RazorEngine.CompileRenderStringAsync("Statics/views/TradeListMail", templateContent, tradelist);
|
|
}
|
|
}
|
|
//tradeListHtml = await _viewRenderer.RenderToStringAsync("Statics/views/TradeListMail", tradelist);
|
|
}
|
|
//组织邮件主体
|
|
var mailInfo = EmailTemplateService.GenerateMailInfo(useTemplate, new MailInfoRequestModel
|
|
{
|
|
ClientName = client.Name,
|
|
TradeDate = tempItem.Key?.ToString("yyyy-MM-dd"),
|
|
TradeList = tradeListHtml,
|
|
DocNumber = tempContracts.Count > 0 ? tempContracts[0].Code : string.Empty
|
|
}) ?? new MailInfoResultModel
|
|
{
|
|
Body = string.Empty,
|
|
Title = "交易确认书 " + tempItem.Key?.ToString("yyyy-MM-dd")
|
|
};
|
|
|
|
var sendMail = EmailHelper.SendMailOfTradeConfirmBook(string.Join(";", emails), Paths.ToArray(),
|
|
mailInfo.Title, mailInfo.Body, mailInfo.IsBodyHtml);
|
|
if (!string.IsNullOrWhiteSpace(sendMail))
|
|
{
|
|
errorClient.Add(client.Name);
|
|
error.Add($"邮件发送失败:{sendMail}");
|
|
continue;
|
|
}
|
|
if (!successClient.Contains(client.Name))
|
|
{
|
|
successClient.Add(client.Name);
|
|
}
|
|
}
|
|
//var trades = yldb.trade.Where(t => tempTradeIds.Contains(t.id)).ToArray();
|
|
var trades = new TradeDalService(CurUser).GetTradeOrEodTrade(tempTradeIds, valuedateBLL.ValueDate, true);
|
|
foreach (var trade in trades)
|
|
{
|
|
trade.SentMailCount = (trade.SentMailCount != null) ? (trade.SentMailCount + 1) : 1;
|
|
}
|
|
//发送成功记录发送次数
|
|
yldb.SaveChanges();
|
|
}
|
|
}
|
|
if (error.Count > 0)
|
|
{
|
|
var errorMsg = $"错误 -- {string.Join(",", errorClient.ToArray())}发送报告时出错,{string.Join(",", error.ToArray())}。";
|
|
var successMsg = "";
|
|
if (successClient.Count > 0)
|
|
{
|
|
successMsg = $"成功 -- {string.Join(",", successClient.ToArray())}发送报告成功。";
|
|
}
|
|
|
|
throw new ServiceException("提示!" + errorMsg + successMsg);
|
|
}
|
|
return JsonSuccess("发送成功");
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
logger.Error(e.ToString(), e);
|
|
return JsonError($"发送失败: {e.Message}");
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 将上传确认书做成页面
|
|
/// </summary>
|
|
public ActionResult confirmBookUpload(string Id, string SendMailId = "")
|
|
{
|
|
//如果都是数字,进行一次编码
|
|
if (Id.All(char.IsDigit))
|
|
{
|
|
Id = DataProtectHelper.Encrypt(int.Parse(Id));
|
|
}
|
|
if (!string.IsNullOrWhiteSpace(SendMailId) && SendMailId.All(char.IsDigit))
|
|
{
|
|
SendMailId = DataProtectHelper.Encrypt(int.Parse(SendMailId));
|
|
}
|
|
ViewBag.Id = Id;
|
|
ViewBag.SendMailId = SendMailId;
|
|
return View();
|
|
}
|
|
/// <summary>
|
|
/// 将上传确认书做成页面
|
|
/// </summary>
|
|
public ActionResult confirmBookUploadNew(int tradeId = 0)
|
|
{
|
|
ViewBag.TradeId = tradeId;
|
|
return View();
|
|
}
|
|
|
|
private string CreateTradeConfirmation(trade trade, ServiceRepresentativeConfig spc)
|
|
{
|
|
if (spc == null)
|
|
{
|
|
throw new InvalidOperationException("未找到服务商信息");
|
|
}
|
|
|
|
string outputFileName;
|
|
//有限使用交易表中填写的交易确认书版本号
|
|
var contractVersion = string.IsNullOrWhiteSpace(trade.ContractVersion) ? TradeContractBLL.GetTradeConfirmContractVersion(spc, trade.BuySell, trade.UnderlyingInstrumentType) : trade.ContractVersion;
|
|
if (PS.Config.Company == CompanyEnum.申万)
|
|
{
|
|
if (contractVersion == null)
|
|
{
|
|
throw new InvalidOperationException("协议版本号不能为空,请到服务商配置相关信息");
|
|
}
|
|
|
|
if (contractVersion.StartsWith("B") && EnumTradeBuySell.Buy.Equals(trade.BuySell))
|
|
{
|
|
contractVersion = $"A{contractVersion.Substring(1)}";
|
|
}
|
|
if (contractVersion.EndsWith("T"))
|
|
{
|
|
contractVersion = contractVersion.Substring(0, contractVersion.Length - 1);
|
|
}
|
|
if (contractVersion.EndsWith("Z"))
|
|
{
|
|
contractVersion = contractVersion.Substring(0, contractVersion.Length - 1);
|
|
}
|
|
}
|
|
|
|
trade.ContractVersion = contractVersion;
|
|
//记录交易为单笔生成
|
|
trade.IsSingleContract = EnumSingleContract.Single;
|
|
|
|
if (string.IsNullOrEmpty(contractVersion))
|
|
{
|
|
throw new InvalidOperationException("未指定交易确认书版本");
|
|
}
|
|
|
|
var template = yldb.files_template.FirstOrDefault(x => x.Code == contractVersion);
|
|
if (template == null || string.IsNullOrWhiteSpace(template.FileName))
|
|
{
|
|
throw new InvalidOperationException($"未找到模板 {contractVersion}");
|
|
}
|
|
var templateDir = Server.MapPath("/App_Docs");
|
|
if (!string.IsNullOrWhiteSpace(template.Paths))
|
|
{
|
|
templateDir = Path.Combine(templateDir, template.Paths);
|
|
}
|
|
var templateFilePath = Path.Combine(templateDir, template.FileName);
|
|
|
|
if (!System.IO.File.Exists(templateFilePath))
|
|
{
|
|
throw new InvalidOperationException($"模板文件{contractVersion}不存在");
|
|
}
|
|
|
|
var broker = DataCacheProvider.GetClientDataSource().AsQueryable()
|
|
.FirstOrDefault(x => x.Name == PS.Config.CompanyFullName);
|
|
var client = DataCacheProvider.GetClientDataSource().GetData(trade.ClientId);
|
|
if (broker == null || client == null)
|
|
{
|
|
throw new InvalidOperationException("未找到客户信息");
|
|
}
|
|
|
|
var tradeContractMode = new TradeContractModeUtils(broker, client, trade.BuySell);
|
|
|
|
var contact1 = ClientDataQueryService.GetClientDuty(tradeContractMode.FirstParty.id);
|
|
var contact2 = ClientDataQueryService.GetClientDuty(tradeContractMode.SecondParty.id);
|
|
var contactClient = ClientDataQueryService.GetClientDuty(client.id);
|
|
if (contact1 == null || contact2 == null)
|
|
{
|
|
//throw new InvalidOperationException("未找到客户联系人信息");
|
|
}
|
|
|
|
var clientDb = DbContextFactory.GetClientDbContext(CurUser);
|
|
var bankcard1 = clientDb.bankcard.FirstOrDefault(x => x.ApprovalOrder < 1 && x.ClientId == tradeContractMode.FirstParty.id);
|
|
var bankcard2 = clientDb.bankcard.FirstOrDefault(x => x.ApprovalOrder < 1 && x.ClientId == tradeContractMode.SecondParty.id);
|
|
var bankcardClient = clientDb.bankcard.FirstOrDefault(x => x.ApprovalOrder < 1 && x.ClientId == client.id);
|
|
if (bankcard1 == null || bankcard2 == null)
|
|
{
|
|
throw new InvalidOperationException("未找到银行卡信息");
|
|
}
|
|
|
|
//初始预付金默认填写 预付金比率0.15
|
|
var marginRation = valuedateBLL.SystemDate.MarginRatio ?? 0.15;
|
|
|
|
var modelDict = new Dictionary<string, object>();
|
|
var eqvNotional = trade.UnderlyingInstrumentType == "Stock" ? trade.StockEqvNotional : (trade.SpotPrice * trade.Notional);
|
|
//标的信息
|
|
var underlyingManager = DataCacheProvider.GetUnderlyingDataSource().GetData(trade.UnderlyingCode);
|
|
if (underlyingManager == null)
|
|
{
|
|
throw new InvalidOperationException($"标的[{trade.UnderlyingCode}]信息未找到!");
|
|
}
|
|
var tradeUnit = ConsGlobal.InstrumentType.Stock.Equals(trade.UnderlyingInstrumentType) ? "元/股" : underlyingManager.TradeUnitString;
|
|
var quoteUnit = underlyingManager.QuoteUnitString;
|
|
var strikePrice = (trade.ActualStrike ?? 0.0).ToString("F2");
|
|
var initialSpotPrice = trade.SpotPrice.HasValue ? trade.SpotPrice.Value.ToString("F2") : "";
|
|
var isAmerican = ConsGlobal.ExerciseMode.IsAmerican(trade.ExerciseMode);
|
|
var model = new ContractModel
|
|
{
|
|
TradeType = trade.TradeType == "自定义交易" || trade.TradeType == "结构化交易" ? trade.TradeType : (trade.ExerciseModeCn + trade.TradeType.Replace("期权", "") + trade.OptionType),
|
|
ExerciseType = trade.TradeType == "亚式期权" ? "亚式" : (isAmerican ? "美式" : "欧式"),
|
|
Notional = trade.Notional.ToString("F2"),
|
|
TradeAmount = trade.TradeAmount.ToString("F2"),
|
|
TradeQuantity = (trade.Notional / underlyingManager.CountRatio).ToString("F2"),
|
|
Underlying = $"{underlyingManager.UnderlyingName}({trade.UnderlyingCode})",
|
|
Principle = trade.StockEqvNotional.ToString("F2"),
|
|
InitialSpotPrice = initialSpotPrice,
|
|
Strike = trade.IsMoneynessOptionData ? $"{trade.Strike * 100}%" : $"{trade.Strike}",
|
|
StrikePrice = strikePrice,
|
|
PremiumRate = $"{OtcFormatHelper.FormatValue(((trade.PremiumRate ?? ((eqvNotional ?? 0) == 0 ? 0 : ((trade.TradePrice ?? 0.0) / eqvNotional))) * 100) ?? 0, 4)}%",
|
|
Premium = (trade.TradePrice ?? 0.0).ToString("F2"),
|
|
PremiumSingle = (trade.TradeSinglePrice ?? 0.0).ToString("F3"),
|
|
StartDate = trade.StartDate.HasValue ? trade.StartDate.Value.ToString("yyyy年M月d日") : "",
|
|
ExerciseDate = trade.ExerciseDate.HasValue ? trade.ExerciseDate.Value.ToString("yyyy年M月d日") : "",
|
|
PremiumPayDate = trade.PremiumPayDate.HasValue ? trade.PremiumPayDate.Value.ToString("yyyy年M月d日") : "",
|
|
TradeUnit = tradeUnit,
|
|
QuoteUnit = quoteUnit,
|
|
Market = underlyingManager.MarketName,
|
|
TradeDate = trade.TradeDate.HasValue ? trade.TradeDate.Value.ToString("yyyy年M月d日") : "",
|
|
Remark1 = trade.ExerciseMode == "American" ? (trade.TradeType == "亚式期权" && trade.trade_asian_option.StrikeType == "Floating" ? (trade.CallPut == "Call" ? $"(期末价格 - 浮动行权价) * {trade.Notional.ToString("F2")}" : $"(浮动行权价 - 期末价格 ) * {trade.Notional.ToString("F2")}") : (trade.CallPut == "Call" ? $"(期末价格 - {strikePrice}) * {trade.Notional.ToString("F2")}" : $"({strikePrice} - 期末价格 ) * {trade.Notional.ToString("F2")}")) : "欧式期权不适用",
|
|
Remark2 = trade.TradeType == "亚式期权" && trade.trade_asian_option.StrikeType == "Floating" ? (trade.CallPut == "Call" ? $"({(trade.ExerciseDate.HasValue ? trade.ExerciseDate.Value.ToString("yyyy年M月d日") : "")}{trade.UnderlyingCode}合约收盘价 - 浮动行权价) * {trade.Notional.ToString("F2")}" : $"(浮动行权价 - {(trade.ExerciseDate.HasValue ? trade.ExerciseDate.Value.ToString("yyyy年M月d日") : "")}{trade.UnderlyingCode}合约收盘价 ) * {trade.Notional.ToString("F2")}") : (trade.CallPut == "Call" ? $"({(trade.ExerciseDate.HasValue ? trade.ExerciseDate.Value.ToString("yyyy年M月d日") : "")}{trade.UnderlyingCode}合约收盘价 - {strikePrice}) * {trade.Notional.ToString("F2")}" : $"({strikePrice} - {(trade.ExerciseDate.HasValue ? trade.ExerciseDate.Value.ToString("yyyy年M月d日") : "")}{trade.UnderlyingCode}合约收盘价 ) * {trade.Notional.ToString("F2")}"),
|
|
CallPut = trade.OptionType,
|
|
BuySell = trade.BuySell == "买入" ? "卖出" : "买入",
|
|
|
|
TotalPrinciple = trade.StockEqvNotional.ToString("F2"),
|
|
TotalPremium = (trade.TradePrice ?? 0.0).ToString("F2"),
|
|
|
|
FPCompanyName = tradeContractMode.FirstParty.Name,
|
|
FPAddress = tradeContractMode.FirstParty.PostalAddress,
|
|
FPTel = contact1?.PhoneNumber ?? string.Empty,
|
|
FPFax = contact1?.Fax ?? string.Empty,
|
|
FPName = bankcard1.ClientName,
|
|
FPBankCard = bankcard1.Card,
|
|
FPBankName = bankcard1.Bank,
|
|
FPLinkman = contact1?.ContactName ?? string.Empty,
|
|
FPEmail = contact1?.Email ?? string.Empty,
|
|
SPCompanyName = tradeContractMode.SecondParty.Name,
|
|
SPAddress = tradeContractMode.SecondParty.PostalAddress,
|
|
SPTel = contact2?.PhoneNumber ?? string.Empty,
|
|
SPFax = contact2?.Fax ?? string.Empty,
|
|
SPName = bankcard2.ClientName,
|
|
SPBankCard = bankcard2.Card,
|
|
SPBankName = bankcard2.Bank,
|
|
SPLinkman = contact2?.ContactName ?? string.Empty,
|
|
SPEmail = contact2?.Email ?? string.Empty,
|
|
ClientCompanyName = client.Name,
|
|
ClientAddress = client.PostalAddress,
|
|
ClientTel = contactClient?.PhoneNumber ?? string.Empty,
|
|
ClientFax = contactClient?.Fax ?? string.Empty,
|
|
ClientName = bankcardClient.ClientName,
|
|
ClientBankCard = bankcardClient.Card,
|
|
ClientBankName = bankcardClient.Bank,
|
|
ClientLinkman = contactClient?.ContactName ?? string.Empty,
|
|
ClientEmail = contactClient?.Email ?? string.Empty,
|
|
|
|
ContractVersion = contractVersion,
|
|
|
|
//欧式美式行权说明处理
|
|
ExerciseDateDesc = isAmerican ? "期权买方在生效日和到期日之前任一交易日北京时间 14:40 前要求期权卖方行权的日期。" : "期权买方仅能在到期日收盘后向期权卖方申请行权。",
|
|
ExerciseLabel1 = isAmerican ? "(1)提前行权:" : "行权说明:",
|
|
ExerciseLabel2 = isAmerican ? "(2)到期行权:" : "",
|
|
ExerciseDesc1 = isAmerican ? "卖方应按照买方提前行权时标的商品交易所公布的标的合约最新价作为结算价(St)支付行权收益给买方。 " : "如买方申请行权,卖方应按照到期日标的商品交易所公布的标的合约收盘价作为结算价(St)支付行权收益给买方。",
|
|
ExerciseDesc2 = isAmerican ? "卖方应按照到期日标的商品交易所公布的标的合约收盘价作为结算价(St)支付行权收益给买方。" : "",
|
|
|
|
ValueDate = trade.TradeDate.Value.ToString("yyyy年M月d日"),
|
|
OptionPremium = string.Format("{0:N2}", trade.TradePrice ?? 0.0),
|
|
//todo 预付金比率可配
|
|
InitialMargin = string.Format("{0:N2}", trade.BuySell == "买入" ? (trade.StockEqvNotional) * marginRation : 0),
|
|
};
|
|
|
|
var items = new List<ContractModel>();
|
|
|
|
if (trade.TradeType == "结构化交易" && PS.Config.Is申万)
|
|
{
|
|
//var subTrades = yldb.trade.Where(x => x.ParentTradeId == trade.id).ToList();
|
|
var subTrades = new TradeDalService(CurUser).GetTradeOrEodTrade(new[] { trade.id }, valuedateBLL.ValueDate);
|
|
subTrades.ForEach(x =>
|
|
{
|
|
var subStrikePrice = (x.ActualStrike ?? 0.0).ToString("F2");
|
|
items.Add(new ContractModel()
|
|
{
|
|
TradeType = x.ExerciseModeCn + x.OptionType + "期权",
|
|
ExerciseType = x.TradeType == "亚式期权" ? "亚式" : (ConsGlobal.ExerciseMode.IsAmerican(x.ExerciseMode) ? "美式" : "欧式"),
|
|
Notional = x.Notional.ToString("F2"),
|
|
TradeAmount = x.TradeAmount.ToString("F2"),
|
|
TradeQuantity = (x.Notional / underlyingManager.CountRatio).ToString("F2"),
|
|
Underlying = $"{x.UnderlyingAssetName}({x.UnderlyingCode})",
|
|
UnderlyingCode = x.UnderlyingCode,
|
|
UnderlyingName = x.UnderlyingAssetName,
|
|
Principle = x.StockEqvNotional.ToString("F2"),
|
|
InitialSpotPrice = initialSpotPrice,
|
|
Strike = x.IsMoneynessOptionData ? $"{x.Strike * 100}%" : $"{x.Strike}",
|
|
StrikePrice = subStrikePrice,
|
|
PremiumRate = $"{OtcFormatHelper.FormatValue(((x.PremiumRate ?? ((eqvNotional ?? 0) == 0 ? 0 : ((x.TradePrice ?? 0.0) / eqvNotional))) * 100) ?? 0, 4)}%",
|
|
Premium = $"{x.TradePrice.Value.ToString("F2")}",
|
|
PremiumSingle = $"{(x.TradeSinglePrice ?? 0.0).ToString("F3")}",
|
|
StartDate = x.StartDate.HasValue ? x.StartDate.Value.ToString("yyyy年M月d日") : "",
|
|
ExerciseDate = x.ExerciseDate.HasValue ? x.ExerciseDate.Value.ToString("yyyy年M月d日") : "",
|
|
PremiumPayDate = x.PremiumPayDate.HasValue ? x.PremiumPayDate.Value.ToString("yyyy年M月d日") : "",
|
|
TradeCode = x.TradeNumber,
|
|
TradeNumber = x.TradeNumber,
|
|
TradeUnit = tradeUnit,
|
|
QuoteUnit = quoteUnit,
|
|
Market = underlyingManager.MarketName,
|
|
TradeDate = x.TradeDate.HasValue ? x.TradeDate.Value.ToString("yyyy年M月d日") : "",
|
|
Remark1 = x.ExerciseMode == "American" ? (x.TradeType == "亚式期权" && x.trade_asian_option.StrikeType == "Floating" ? (x.CallPut == "Call" ? $"(期末价格 - 浮动行权价) * {x.Notional.ToString("F2")}" : $"(浮动行权价 - 期末价格 ) * {x.Notional.ToString("F2")}") : (x.CallPut == "Call" ? $"(期末价格 - {subStrikePrice}) * {x.Notional.ToString("F2")}" : $"({subStrikePrice} - 期末价格 ) * {x.Notional.ToString("F2")}")) : "欧式期权不适用",
|
|
Remark2 = x.TradeType == "亚式期权" && x.trade_asian_option.StrikeType == "Floating" ? (x.CallPut == "Call" ? $"({(x.ExerciseDate.HasValue ? x.ExerciseDate.Value.ToString("yyyy年M月d日") : "")}{x.UnderlyingCode}合约收盘价 - 浮动行权价) * {x.Notional.ToString("F2")}" : $"(浮动行权价 - {(x.ExerciseDate.HasValue ? x.ExerciseDate.Value.ToString("yyyy年M月d日") : "")}{x.UnderlyingCode}合约收盘价 ) * {x.Notional.ToString("F2")}") : (x.CallPut == "Call" ? $"({(x.ExerciseDate.HasValue ? x.ExerciseDate.Value.ToString("yyyy年M月d日") : "")}{x.UnderlyingCode}合约收盘价 - {subStrikePrice}) * {x.Notional.ToString("F2")}" : $"({subStrikePrice} - {(x.ExerciseDate.HasValue ? x.ExerciseDate.Value.ToString("yyyy年M月d日") : "")}{x.UnderlyingCode}合约收盘价 ) * {x.Notional.ToString("F2")}"),
|
|
CallPut = x.OptionType,
|
|
BuySell = x.BuySell == "买入" ? "卖出" : "买入"
|
|
});
|
|
});
|
|
}
|
|
else
|
|
{
|
|
items.Add(new ContractModel
|
|
{
|
|
TradeType = trade.TradeType == "自定义交易" ? trade.TradeType : trade.ExerciseModeCn + trade.OptionType + "期权",
|
|
ExerciseType = trade.TradeType == "亚式期权" ? "亚式" : (isAmerican ? "美式" : "欧式"),
|
|
Notional = trade.Notional.ToString("F2"),
|
|
TradeAmount = trade.TradeAmount.ToString("F2"),
|
|
TradeQuantity = (trade.Notional / underlyingManager.CountRatio).ToString("F2"),
|
|
Underlying = $"{trade.UnderlyingAssetName}({trade.UnderlyingCode})",
|
|
UnderlyingCode = trade.UnderlyingCode,
|
|
UnderlyingName = trade.UnderlyingAssetName,
|
|
Principle = trade.StockEqvNotional.ToString("F2"),
|
|
InitialSpotPrice = initialSpotPrice,
|
|
Strike = trade.IsMoneynessOptionData ? $"{trade.Strike * 100}%" : $"{trade.Strike}",
|
|
StrikePrice = strikePrice,
|
|
PremiumRate = $"{OtcFormatHelper.FormatValue(((trade.PremiumRate ?? ((eqvNotional ?? 0) == 0 ? 0 : ((trade.TradePrice ?? 0.0) / eqvNotional))) * 100) ?? 0, 4)}%",
|
|
Premium = $"{trade.TradePrice.Value.ToString("F2")}",
|
|
PremiumSingle = $"{(trade.TradeSinglePrice ?? 0.0).ToString("F3")}",
|
|
StartDate = trade.StartDate.HasValue ? trade.StartDate.Value.ToString("yyyy年M月d日") : "",
|
|
ExerciseDate = trade.ExerciseDate.HasValue ? trade.ExerciseDate.Value.ToString("yyyy年M月d日") : "",
|
|
PremiumPayDate = trade.PremiumPayDate.HasValue ? trade.PremiumPayDate.Value.ToString("yyyy年M月d日") : "",
|
|
TradeCode = trade.TradeNumber,
|
|
TradeNumber = trade.TradeNumber,
|
|
TradeUnit = tradeUnit,
|
|
QuoteUnit = quoteUnit,
|
|
Market = underlyingManager.MarketName,
|
|
TradeDate = trade.TradeDate.HasValue ? trade.TradeDate.Value.ToString("yyyy年M月d日") : "",
|
|
Remark1 = trade.ExerciseMode == "American" ? (trade.TradeType == "亚式期权" && trade.trade_asian_option.StrikeType == "Floating" ? (trade.CallPut == "Call" ? $"(期末价格 - 浮动行权价) * {trade.Notional.ToString("F2")}" : $"(浮动行权价 - 期末价格 ) * {trade.Notional.ToString("F2")}") : (trade.CallPut == "Call" ? $"(期末价格 - {strikePrice}) * {trade.Notional.ToString("F2")}" : $"({strikePrice} - 期末价格 ) * {trade.Notional.ToString("F2")}")) : "欧式期权不适用",
|
|
Remark2 = trade.TradeType == "亚式期权" && trade.trade_asian_option.StrikeType == "Floating" ? (trade.CallPut == "Call" ? $"({(trade.ExerciseDate.HasValue ? trade.ExerciseDate.Value.ToString("yyyy年M月d日") : "")}{trade.UnderlyingCode}合约收盘价 - 浮动行权价) * {trade.Notional.ToString("F2")}" : $"(浮动行权价 - {(trade.ExerciseDate.HasValue ? trade.ExerciseDate.Value.ToString("yyyy年M月d日") : "")}{trade.UnderlyingCode}合约收盘价 ) * {trade.Notional.ToString("F2")}") : (trade.CallPut == "Call" ? $"({(trade.ExerciseDate.HasValue ? trade.ExerciseDate.Value.ToString("yyyy年M月d日") : "")}{trade.UnderlyingCode}合约收盘价 - {strikePrice}) * {trade.Notional.ToString("F2")}" : $"({strikePrice} - {(trade.ExerciseDate.HasValue ? trade.ExerciseDate.Value.ToString("yyyy年M月d日") : "")}{trade.UnderlyingCode}合约收盘价 ) * {trade.Notional.ToString("F2")}"),
|
|
CallPut = trade.OptionType,
|
|
BuySell = trade.BuySell == "买入" ? "卖出" : "买入"
|
|
});
|
|
}
|
|
|
|
if (string.IsNullOrEmpty(trade.TradeNumber) || trade.TradeNumber.EndsWith(")"))
|
|
{
|
|
var newNumber = 0;
|
|
var lastNumberTrade = yldb.trade.Where(x => x.TradeNumber.StartsWith("OTC-C") && x.ParentTradeId == 0).OrderByDescending(x => x.TradeNumber).FirstOrDefault();
|
|
if (lastNumberTrade == null)
|
|
{
|
|
newNumber = 1;
|
|
}
|
|
else
|
|
{
|
|
newNumber = int.Parse(lastNumberTrade.TradeNumber.Replace("OTC-C", "")) + 1;
|
|
}
|
|
if (newNumber <= 99999)
|
|
{
|
|
var tradeCode = "OTC-C" + newNumber.ToString("D5");
|
|
trade.TradeNumber = tradeCode;
|
|
trade.ContractCode = tradeCode;
|
|
}
|
|
else
|
|
{
|
|
throw new Exception("最大交易编号" + (newNumber - 1) + ",超出了限制规则99999,生成交易编号失败");
|
|
}
|
|
|
|
//如果是结构化交易,子交易的tradeNumber也需要重新赋值
|
|
var tradesChild = yldb.trade.Where(x => x.ParentTradeId == trade.id);
|
|
var index = 0;
|
|
foreach (var subTrade in tradesChild)
|
|
{
|
|
index++;
|
|
subTrade.TradeNumber = BizLogicSingleton.Instance.GenerateSubTradeNumberBeforeConfirm(subTrade, trade, index, yldb);
|
|
}
|
|
}
|
|
|
|
model.TradeList = items;
|
|
model.ContractCode = trade.TradeNumber;
|
|
modelDict["主页"] = model;
|
|
modelDict["附页"] = model;
|
|
|
|
outputFileName = $"{client.Name}_{trade.TradeNumber}_{contractVersion}.xlsx";
|
|
var valueDate = trade.TradeDate ?? valuedateBLL.ValueDate;
|
|
var outputPath = Path.Combine(templateDir, valueDate.ToString("yyyyMMdd")).ToString();
|
|
var outPath = $"/{template.Paths.Replace("\\", "/")}/{valueDate.ToString("yyyyMMdd")}";
|
|
var rightAlignedText = $"交易确认书编号:{trade.TradeNumber}";
|
|
var UseRightAligned = Server.UseRightAligned;
|
|
if (!UseRightAligned)
|
|
{
|
|
rightAlignedText = null;
|
|
}
|
|
if (PS.Config.Is申万)
|
|
{
|
|
//void generateExcelCallback(ExcelWorksheets sheets)
|
|
//{
|
|
// foreach (var sheet in sheets)
|
|
// {
|
|
// if (sheet.Name == "主页")
|
|
// {
|
|
// if (model.TradeList.Count == 2)
|
|
// {
|
|
// sheet.Cells[16, 12, 17, 12].Merge = true;
|
|
// sheet.Cells[16, 13, 17, 13].Merge = true;
|
|
// }
|
|
// }
|
|
// }
|
|
//};
|
|
outputFileName = $"{trade.TradeNumber}.xlsx";
|
|
ExcelTemplate.GeneratePDFFromExeclTemplate(templateDir.ToString(), template.FileName, modelDict, outputPath, outputFileName, RightAlignedText: rightAlignedText, needLandscape: true);
|
|
}
|
|
else
|
|
{
|
|
ExcelTemplate.GeneratePDFFromExeclTemplate(templateDir.ToString(), template.FileName, modelDict, outputPath, outputFileName, RightAlignedText: rightAlignedText);
|
|
}
|
|
#region --- Add trade_contract_document and trade_contract_r records
|
|
|
|
var contractRecord = yldb.trade_contract_document.FirstOrDefault(x => x.Code == trade.TradeNumber && x.Type == ContractTypeEnum.Trade);
|
|
if (contractRecord == null)
|
|
{
|
|
contractRecord = new trade_contract_document();
|
|
yldb.trade_contract_document.Add(contractRecord);
|
|
}
|
|
contractRecord.Code = trade.TradeNumber;
|
|
contractRecord.ValueDate = valueDate;
|
|
if (trade.BuySell == "买入")
|
|
{
|
|
contractRecord.BuyerId = broker.id;
|
|
contractRecord.BuyerName = broker.Name;
|
|
contractRecord.SellerId = client.id;
|
|
contractRecord.SellerName = client.Name;
|
|
}
|
|
else
|
|
{
|
|
contractRecord.BuyerId = client.id;
|
|
contractRecord.BuyerName = client.Name;
|
|
contractRecord.SellerId = broker.id;
|
|
contractRecord.SellerName = broker.Name;
|
|
}
|
|
contractRecord.ContractVersion = contractVersion;
|
|
contractRecord.FileType = FileTypeEnum.Pdf;
|
|
contractRecord.Status = ContractStatusEnum.Draft;
|
|
contractRecord.SourceType = 1; // 系统生成
|
|
contractRecord.Paths = outPath.ToString();
|
|
contractRecord.FileName = outputFileName.Replace(".xlsx", ".pdf");
|
|
contractRecord.Type = ContractTypeEnum.Trade;
|
|
contractRecord.OptId = CurUser.UserId;
|
|
contractRecord.OptName = CurUser.UserName;
|
|
contractRecord.OptDate = DateTime.Now;
|
|
|
|
var contractTradeRelation = yldb.trade_contract_r.Where(t => t.Type == ContractTypeEnum.Trade && t.IsValid).FirstOrDefault(x => x.TradeId == trade.id);
|
|
if (contractTradeRelation == null)
|
|
{
|
|
contractTradeRelation = new trade_contract_r();
|
|
yldb.trade_contract_r.Add(contractTradeRelation);
|
|
}
|
|
|
|
contractTradeRelation.TradeId = trade.id;
|
|
contractTradeRelation.TradeNumber = trade.TradeNumber;
|
|
contractTradeRelation.ContractCode = trade.TradeNumber;
|
|
contractTradeRelation.OptId = CurUser.UserId;
|
|
contractTradeRelation.OptName = CurUser.UserName;
|
|
contractTradeRelation.OptDate = DateTime.Now;
|
|
contractTradeRelation.Type = ContractTypeEnum.Trade;
|
|
contractTradeRelation.IsValid = true;
|
|
|
|
//将HasGeneratedConfirmBook设置为1
|
|
//var td = yldb.trade.Find(trade.id);
|
|
//var childTds = yldb.trade.Where(x => x.ParentTradeId == trade.id);
|
|
var service = new TradeDalService(CurUser);
|
|
var td = service.GetTradeOrEodTrade(new[] { trade.id }, valueDate, true).FirstOrDefault();
|
|
var childTds = service.GetStructTradeFromTradeOrEodTrade(new[] { trade.id }, valueDate, true);
|
|
//if (td != null)
|
|
//{
|
|
// td.HasGeneratedConfirmBook = 1;l
|
|
// foreach (var child in childTds)
|
|
// {
|
|
// child.HasGeneratedConfirmBook = 1;
|
|
// }
|
|
//}
|
|
|
|
var clientCashInCashOuts = yldb.ClientCashInCashOut.Where(x => x.TradeId == trade.id).ToList();
|
|
clientCashInCashOuts.ForEach(x => x.TradeNumber = trade.TradeNumber);
|
|
|
|
yldb.SaveChanges();
|
|
#endregion --- Add trade_contract_document and trade_contract_r records
|
|
|
|
return $"{outPath}/{outputFileName.Replace(".xlsx", ".pdf")}";
|
|
}
|
|
|
|
/// <summary>
|
|
/// 生成交易确认书
|
|
/// </summary>
|
|
public JsonResult GJGenerateConfirmBook(List<int> tradeIds, string docType, int? userId, string userName, DateTime? startDate, DateTime? endDate)
|
|
{
|
|
if (docType?.ToLower() == "doc")
|
|
{
|
|
docType = "DOCX";
|
|
}
|
|
docType = docType.ToLower();
|
|
var user = new OptUserInfo(userId ?? UserId, userName.TrimToNull() ?? UserName, OptUserFrom.WebUI);
|
|
if (new TradeContractGenerateService(user).GJGenerateConfirmBook(tradeIds, docType, out var errors, out var files, startDate, endDate))
|
|
{
|
|
return JsonSuccess(PS.GetErpConfig().IsAutoSealAndUploadFiles ? "生成成功,用印等待中..." :"生成成功", files);
|
|
}
|
|
|
|
return JsonError(string.Join("\r\n", errors.AsEnumerable()), files);
|
|
}
|
|
|
|
private string CreateBatchTradeConfirmation(List<trade> trades, string contractVersion, ServiceRepresentativeConfig spc, Client client1, Client client2, DateTime valueDate, string tradeCodePrefix = null, string underlyingTypeStr = "")
|
|
{
|
|
string outputFileName;
|
|
//if (string.IsNullOrEmpty(spc.ContractVersion))
|
|
//{
|
|
// throw new InvalidOperationException("未指定交易确认书版本");
|
|
//}
|
|
|
|
if (trades.Count == 0)
|
|
{
|
|
throw new InvalidOperationException("交易笔数不能为0");
|
|
}
|
|
|
|
var template = yldb.files_template.FirstOrDefault(x => x.Code == contractVersion);
|
|
if (template == null || string.IsNullOrWhiteSpace(template.FileName))
|
|
{
|
|
throw new InvalidOperationException($"未找到模板 {contractVersion}");
|
|
}
|
|
var templateDir = Server.MapPath("/App_Docs");
|
|
var outPath = $"/App_Docs";
|
|
if (!string.IsNullOrWhiteSpace(template.Paths))
|
|
{
|
|
outPath = $"/App_Docs/{template.Paths}";
|
|
templateDir = Path.Combine(templateDir, template.Paths);
|
|
}
|
|
var templateFilePath = Path.Combine(templateDir, template.FileName);
|
|
|
|
if (!System.IO.File.Exists(templateFilePath))
|
|
{
|
|
throw new InvalidOperationException($"模板文件{contractVersion}不存在");
|
|
}
|
|
|
|
|
|
if (client1 == null || client2 == null)
|
|
{
|
|
throw new InvalidOperationException("未找到客户信息");
|
|
}
|
|
var client = client2;// the client used to generate trade code
|
|
if (trades[0].BuySell == "买入")
|
|
{
|
|
client = client1;
|
|
}
|
|
var contact1 = ClientDataQueryService.GetClientDuty(client1.id);
|
|
var contact2 = ClientDataQueryService.GetClientDuty(client2.id);
|
|
var contactClient = ClientDataQueryService.GetClientDuty(client.id);
|
|
if (contact1 == null || contact2 == null)
|
|
{
|
|
//throw new InvalidOperationException("未找到客户联系人信息");
|
|
}
|
|
var clientDb = DbContextFactory.GetClientDbContext(CurUser);
|
|
var bankcard1 = clientDb.bankcard.FirstOrDefault(x => x.ApprovalOrder < 1 && x.ClientId == client1.id);
|
|
var bankcard2 = clientDb.bankcard.FirstOrDefault(x => x.ApprovalOrder < 1 && x.ClientId == client2.id);
|
|
var bankcardClient = clientDb.bankcard.FirstOrDefault(x => x.ApprovalOrder < 1 && x.ClientId == client.id);
|
|
if (bankcard1 == null || bankcard2 == null)
|
|
{
|
|
throw new InvalidOperationException("未找到银行卡信息");
|
|
}
|
|
|
|
var modelDict = new Dictionary<string, object>();
|
|
var isAmerican = ConsGlobal.ExerciseMode.IsAmerican(trades[0].ExerciseMode);
|
|
|
|
var model = new ContractModel
|
|
{
|
|
StartDate = trades[0].StartDate.HasValue ? trades[0].StartDate.Value.ToString("yyyy年M月d日") : "",
|
|
ExerciseDate = trades[0].ExerciseDate.HasValue ? trades[0].ExerciseDate.Value.ToString("yyyy年M月d日") : "",
|
|
ValueDate = trades[0].TradeDate.HasValue ? trades[0].TradeDate.Value.ToString("yyyy年M月d日") : "",
|
|
ExerciseType = trades[0].TradeType == "亚式期权" ? "亚式" : (ConsGlobal.ExerciseMode.IsAmerican(trades[0].ExerciseMode) ? "美式" : "欧式"),
|
|
OptionPremium = "0",
|
|
InitialMargin = "0",
|
|
|
|
FPCompanyName = client1.Name,
|
|
FPAddress = client1.PostalAddress,
|
|
FPTel = contact1?.PhoneNumber ?? string.Empty,
|
|
FPFax = contact1?.Fax ?? string.Empty,
|
|
FPLinkman = contact1?.ContactName ?? string.Empty,
|
|
FPName = bankcard1.ClientName,
|
|
FPBankCard = bankcard1.Card,
|
|
FPBankName = bankcard1.Bank,
|
|
SPCompanyName = client2.Name,
|
|
SPAddress = client2.PostalAddress,
|
|
SPTel = contact2?.PhoneNumber ?? string.Empty,
|
|
SPFax = contact2?.Fax ?? string.Empty,
|
|
SPLinkman = contact2?.ContactName ?? string.Empty,
|
|
SPName = bankcard2.ClientName,
|
|
SPBankCard = bankcard2.Card,
|
|
SPBankName = bankcard2.Bank,
|
|
FPEmail = contact1?.Email ?? string.Empty,
|
|
SPEmail = contact2?.Email ?? string.Empty,
|
|
|
|
ClientCompanyName = client.Name,
|
|
ClientAddress = client.PostalAddress,
|
|
ClientTel = contactClient?.PhoneNumber ?? string.Empty,
|
|
ClientFax = contactClient?.Fax ?? string.Empty,
|
|
ClientName = bankcardClient.ClientName,
|
|
ClientBankCard = bankcardClient.Card,
|
|
ClientBankName = bankcardClient.Bank,
|
|
ClientLinkman = contactClient?.ContactName ?? string.Empty,
|
|
ClientEmail = contactClient?.Email ?? string.Empty,
|
|
|
|
ContractVersion = contractVersion,
|
|
|
|
//欧式美式行权说明处理
|
|
ExerciseDateDesc = isAmerican ? "期权买方在生效日和到期日之前任一交易日北京时间 14:40 前要求期权卖方行权的日期。" : "期权买方仅能在到期日收盘后向期权卖方申请行权。",
|
|
ExerciseLabel1 = isAmerican ? "(1)提前行权:" : "行权说明:",
|
|
ExerciseLabel2 = isAmerican ? "(2)到期行权:" : "",
|
|
ExerciseDesc1 = isAmerican ? "卖方应按照买方提前行权时标的商品交易所公布的标的合约最新价作为结算价(St)支付行权收益给买方。 " : "如买方申请行权,卖方应按照到期日标的商品交易所公布的标的合约收盘价作为结算价(St)支付行权收益给买方。",
|
|
ExerciseDesc2 = isAmerican ? "卖方应按照到期日标的商品交易所公布的标的合约收盘价作为结算价(St)支付行权收益给买方。" : "",
|
|
};
|
|
|
|
//如果客户买入的交易则添加期权费字段
|
|
//var buyTrades = trades.Where(t => t.BuySell == "卖出");
|
|
//if (buyTrades.Any()) {
|
|
model.OptionPremium = string.Format("{0:N2}", trades.Sum(t => t.TradePrice ?? 0));
|
|
//}
|
|
if (trades[0].TradeType == "亚式期权")
|
|
{
|
|
if (trades[0].trade_asian_option == null || trades[0].trade_asian_option.id == 0)
|
|
{
|
|
var tradeId = trades[0].id;
|
|
trades[0].trade_asian_option = yldb.trade_asian_option.FirstOrDefault(x => x.TradeId == tradeId);
|
|
}
|
|
|
|
model.SettlementInfo = "在结算价格采价期间所有交易日的标的资产的收盘价的算数平均数\r\n 结算价格采价期间:自" + ((trades[0].trade_asian_option?.AveragingPeriodStartDate) ?? trades[0].TradeDate)?.ToString("yyyy年MM月dd日") + "(含)至" + trades[0].ExerciseDate?.ToString("yyyy年MM月dd日") + "(含)";
|
|
}
|
|
else
|
|
{
|
|
model.SettlementInfo = "买方主动行权以行权时标的资产市价结算,到期自动行权以14:57~15:00均价结算。";
|
|
}
|
|
//初始预付金默认填写 预付金比率0.15
|
|
var marginRation = valuedateBLL.SystemDate.MarginRatio ?? 0.15;
|
|
var sellTrades = trades.Where(t => t.BuySell == "买入");
|
|
if (sellTrades.Any())
|
|
{
|
|
model.InitialMargin = string.Format("{0:N2}", sellTrades.Sum(t => t.StockEqvNotional) * marginRation);
|
|
}
|
|
|
|
var tradesWithCode = trades.Where(x => !string.IsNullOrEmpty(x.TradeNumber)).ToList();
|
|
var tradesWithoutCode = trades.Where(x => string.IsNullOrEmpty(x.TradeNumber)).ToList();
|
|
|
|
//默认如果传入交易确认书合约编号则是用传入的 否则根据规则生成
|
|
if (tradeCodePrefix == null)
|
|
{
|
|
if (tradesWithCode.Count() > 0)
|
|
{
|
|
tradeCodePrefix = BizLogicSingleton.Instance.GetTradeContractPrefix(tradesWithCode[0].TradeNumber);
|
|
}
|
|
else
|
|
{
|
|
client.CurrentContractNo = (client.CurrentContractNo ?? 0) + 1;
|
|
var contractNumber = ToStringFillUpZero(client.CurrentContractNo.Value, spc.ContractNoLength ?? 3);
|
|
tradeCodePrefix = $"{client.Code}{contractNumber}";
|
|
}
|
|
}
|
|
|
|
//var contractSubNoStyle = client.ContractSubNoStyle;
|
|
//if (string.IsNullOrEmpty(contractSubNoStyle))
|
|
//{
|
|
// contractSubNoStyle = "YYYYMMDD-000"; // TODO: support contractSubNoStyle
|
|
//}
|
|
|
|
outputFileName = $"{client1.Name}-{client2.Name}-{valueDate.ToString("yyyyMMdd")}-{underlyingTypeStr}-{tradeCodePrefix}.xlsx";
|
|
|
|
var outputPath = Path.Combine(templateDir, valueDate.ToString("yyyyMMdd")).ToString();
|
|
outPath = $"{outPath}/{valueDate.ToString("yyyyMMdd")}";
|
|
var items = new List<ContractModel>(trades.Count);
|
|
var TotalPremium = 0.0;
|
|
var TotalPrinciple = 0.0;
|
|
for (var i = 0; i < tradesWithCode.Count; i++)
|
|
{
|
|
var trade = tradesWithCode[i];
|
|
var eqvNotional = trade.UnderlyingInstrumentType == "Stock" ? trade.StockEqvNotional : (trade.SpotPrice * trade.Notional);
|
|
|
|
var um = DataCacheProvider.GetUnderlyingDataSource().GetData(trade.UnderlyingId);
|
|
var tradeUnit = "";
|
|
var quoteUnit = "";
|
|
if (um.UnderlyingType == "组合标的")
|
|
{
|
|
var dto = new UnderlyingDalService(CurUser).GetSyntheticUnderlyingByName(um.UnderlyingCode);
|
|
tradeUnit = ConsGlobal.InstrumentType.Stock.Equals(trade.UnderlyingInstrumentType) ? "元/股" : (dto.ContractSize == null ? "" : (dto.ContractSize ?? 0).ToString());
|
|
quoteUnit = "份";
|
|
}
|
|
else
|
|
{
|
|
tradeUnit = ConsGlobal.InstrumentType.Stock.Equals(trade.UnderlyingInstrumentType) ? "元/股" : ("元(人民币)/" + um.TradeUnitString);
|
|
quoteUnit = um.QuoteUnitString;
|
|
}
|
|
var strikePrice = (trade.ActualStrike ?? 0.0).ToString("F2");
|
|
var initialSpotPrice = trade.SpotPrice.HasValue ? trade.SpotPrice.Value.ToString("F2") : "";
|
|
|
|
items.Add(new ContractModel
|
|
{
|
|
TradeType = trade.TradeType == "自定义交易" || trade.TradeType == "结构化交易" ? trade.TradeType : (trade.ExerciseModeCn + trade.TradeType.Replace("期权", "") + trade.OptionType),
|
|
ExerciseType = trade.TradeType == "亚式期权" ? "亚式" : (ConsGlobal.ExerciseMode.IsAmerican(trade.ExerciseMode) ? "美式" : "欧式"),
|
|
Notional = trade.Notional.ToString("F2"),
|
|
TradeAmount = trade.TradeAmount.ToString("F2"),
|
|
TradeQuantity = (trade.Notional / um.CountRatio).ToString("F2"),
|
|
Underlying = $"{trade.UnderlyingAssetName}({trade.UnderlyingCode})",
|
|
UnderlyingCode = trade.UnderlyingCode,
|
|
UnderlyingName = trade.UnderlyingAssetName,
|
|
Principle = trade.StockEqvNotional.ToString("F2"),
|
|
InitialSpotPrice = initialSpotPrice,
|
|
Strike = trade.IsMoneynessOptionData ? $"{trade.Strike * 100}%" : $"{trade.Strike}",
|
|
StrikePrice = strikePrice,
|
|
PremiumRate = $"{OtcFormatHelper.FormatValue(((trade.PremiumRate ?? ((eqvNotional ?? 0) == 0 ? 0 : ((trade.TradePrice ?? 0.0) / eqvNotional))) * 100) ?? 0, 4)}%",
|
|
Premium = (trade.TradePrice ?? 0.0).ToString("F2"),
|
|
PremiumSingle = (trade.TradeSinglePrice ?? 0.0).ToString("F3"),
|
|
StartDate = trade.StartDate.HasValue ? trade.StartDate.Value.ToString("yyyy年M月d日") : "",
|
|
ExerciseDate = trade.ExerciseDate.HasValue ? trade.ExerciseDate.Value.ToString("yyyy年M月d日") : "",
|
|
PremiumPayDate = trade.PremiumPayDate.HasValue ? trade.PremiumPayDate.Value.ToString("yyyy年M月d日") : "",
|
|
TradeCode = trade.TradeNumber,
|
|
TradeNumber = trade.TradeNumber,
|
|
TradeUnit = tradeUnit,
|
|
QuoteUnit = quoteUnit,
|
|
Market = um == null ? "" : um.MarketName,
|
|
TradeDate = trade.TradeDate.HasValue ? trade.TradeDate.Value.ToString("yyyy年M月d日") : "",
|
|
Remark1 = trade.ExerciseMode == "American" ? (trade.TradeType == "亚式期权" && trade.trade_asian_option.StrikeType == "Floating" ? (trade.CallPut == "Call" ? $"(期末价格 - 浮动行权价) * {trade.Notional.ToString("F2")}" : $"(浮动行权价 - 期末价格 ) * {trade.Notional.ToString("F2")}") : (trade.CallPut == "Call" ? $"(期末价格 - {strikePrice}) * {trade.Notional.ToString("F2")}" : $"({strikePrice} - 期末价格 ) * {trade.Notional.ToString("F2")}")) : "欧式期权不适用",
|
|
Remark2 = trade.TradeType == "亚式期权" && trade.trade_asian_option.StrikeType == "Floating" ? (trade.CallPut == "Call" ? $"({(trade.ExerciseDate.HasValue ? trade.ExerciseDate.Value.ToString("yyyy年M月d日") : "")}{trade.UnderlyingCode}合约收盘价 - 浮动行权价) * {trade.Notional.ToString("F2")}" : $"(浮动行权价 - {(trade.ExerciseDate.HasValue ? trade.ExerciseDate.Value.ToString("yyyy年M月d日") : "")}{trade.UnderlyingCode}合约收盘价 ) * {trade.Notional.ToString("F2")}") : (trade.CallPut == "Call" ? $"({(trade.ExerciseDate.HasValue ? trade.ExerciseDate.Value.ToString("yyyy年M月d日") : "")}{trade.UnderlyingCode}合约收盘价 - {strikePrice}) * {trade.Notional.ToString("F2")}" : $"({strikePrice} - {(trade.ExerciseDate.HasValue ? trade.ExerciseDate.Value.ToString("yyyy年M月d日") : "")}{trade.UnderlyingCode}合约收盘价 ) * {trade.Notional.ToString("F2")}"),
|
|
CallPut = trade.OptionType,
|
|
BuySell = trade.BuySell == "买入" ? "卖出" : "买入"
|
|
});
|
|
TotalPremium += trade.TradePrice ?? 0.0;
|
|
TotalPrinciple += trade.StockEqvNotional;
|
|
}
|
|
for (var i = 0; i < tradesWithoutCode.Count; i++)
|
|
{
|
|
var subCode = ToStringFillUpZero(tradesWithCode.Count() + i + 1, 3);
|
|
//var tradeCode = $"{tradeCodePrefix}({valueDate.ToString("yyyyMMdd")}-{subCode})";
|
|
//var tradeCode = $"{valueDate.ToString("yyyyMMdd")}-{subCode}";
|
|
var trade = tradesWithoutCode[i];
|
|
var tradeCode = GenerateTradeNumber(tradeCodePrefix, client, valueDate, i + 1, trades, trade.UnderlyingInstrumentType, trade.BuySell, out subCode);
|
|
var eqvNotional = trade.UnderlyingInstrumentType == "Stock" ? trade.StockEqvNotional : (trade.SpotPrice * trade.Notional);
|
|
|
|
var um = DataCacheProvider.GetUnderlyingDataSource().GetData(trade.UnderlyingId);
|
|
var tradeUnit = ConsGlobal.InstrumentType.Stock.Equals(trade.UnderlyingInstrumentType) ? "元/股" : ("元(人民币)/" + um.TradeUnitString);
|
|
var quoteUnit = um.QuoteUnitString;
|
|
var strikePrice = (trade.ActualStrike ?? 0.0).ToString("F2");
|
|
var initialSpotPrice = trade.SpotPrice.HasValue ? trade.SpotPrice.Value.ToString("F2") : "";
|
|
|
|
items.Add(new ContractModel
|
|
{
|
|
TradeType = trade.ExerciseModeCn + trade.OptionType + "期权",
|
|
ExerciseType = trade.TradeType == "亚式期权" ? "亚式" : (ConsGlobal.ExerciseMode.IsAmerican(trade.ExerciseMode) ? "美式" : "欧式"),
|
|
Notional = trade.Notional.ToString("F2"),
|
|
TradeAmount = trade.TradeAmount.ToString("F2"),
|
|
TradeQuantity = (trade.Notional / um.CountRatio).ToString("F2"),
|
|
Underlying = $"{trade.UnderlyingAssetName}({trade.UnderlyingCode})",
|
|
UnderlyingCode = trade.UnderlyingCode,
|
|
UnderlyingName = trade.UnderlyingAssetName,
|
|
Principle = trade.StockEqvNotional.ToString("F2"),
|
|
InitialSpotPrice = initialSpotPrice,
|
|
Strike = trade.IsMoneynessOptionData ? $"{trade.Strike * 100}%" : $"{trade.Strike}",
|
|
StrikePrice = strikePrice,
|
|
PremiumRate = $"{OtcFormatHelper.FormatValue(((trade.PremiumRate ?? ((eqvNotional ?? 0) == 0 ? 0 : ((trade.TradePrice ?? 0.0) / eqvNotional))) * 100) ?? 0, 4)}%",
|
|
Premium = (trade.TradePrice ?? 0.0).ToString("F2"),
|
|
PremiumSingle = (trade.TradeSinglePrice ?? 0.0).ToString("F3"),
|
|
StartDate = trade.StartDate.HasValue ? trade.StartDate.Value.ToString("yyyy年M月d日") : "",
|
|
ExerciseDate = trade.ExerciseDate.HasValue ? trade.ExerciseDate.Value.ToString("yyyy年M月d日") : "",
|
|
PremiumPayDate = trade.PremiumPayDate.HasValue ? trade.PremiumPayDate.Value.ToString("yyyy年M月d日") : "",
|
|
TradeCode = $"{valueDate.ToString("yyyyMMdd")}-{subCode}",
|
|
TradeNumber = tradeCode,
|
|
TradeUnit = tradeUnit,
|
|
QuoteUnit = quoteUnit,
|
|
Market = um == null ? "" : um.MarketName,
|
|
TradeDate = trade.TradeDate.HasValue ? trade.TradeDate.Value.ToString("yyyy年M月d日") : "",
|
|
Remark1 = trade.ExerciseMode == "American" ? (trade.TradeType == "亚式期权" && trade.trade_asian_option.StrikeType == "Floating" ? (trade.CallPut == "Call" ? $"(期末价格 - 浮动行权价) * {trade.Notional.ToString("F2")}" : $"(浮动行权价 - 期末价格 ) * {trade.Notional.ToString("F2")}") : (trade.CallPut == "Call" ? $"(期末价格 - {strikePrice}) * {trade.Notional.ToString("F2")}" : $"({strikePrice} - 期末价格 ) * {trade.Notional.ToString("F2")}")) : "欧式期权不适用",
|
|
Remark2 = trade.TradeType == "亚式期权" && trade.trade_asian_option.StrikeType == "Floating" ? (trade.CallPut == "Call" ? $"({(trade.ExerciseDate.HasValue ? trade.ExerciseDate.Value.ToString("yyyy年M月d日") : "")}{trade.UnderlyingCode}合约收盘价 - 浮动行权价) * {trade.Notional.ToString("F2")}" : $"(浮动行权价 - {(trade.ExerciseDate.HasValue ? trade.ExerciseDate.Value.ToString("yyyy年M月d日") : "")}{trade.UnderlyingCode}合约收盘价 ) * {trade.Notional.ToString("F2")}") : (trade.CallPut == "Call" ? $"({(trade.ExerciseDate.HasValue ? trade.ExerciseDate.Value.ToString("yyyy年M月d日") : "")}{trade.UnderlyingCode}合约收盘价 - {strikePrice}) * {trade.Notional.ToString("F2")}" : $"({strikePrice} - {(trade.ExerciseDate.HasValue ? trade.ExerciseDate.Value.ToString("yyyy年M月d日") : "")}{trade.UnderlyingCode}合约收盘价 ) * {trade.Notional.ToString("F2")}"),
|
|
CallPut = trade.OptionType,
|
|
BuySell = trade.BuySell == "买入" ? "卖出" : "买入",
|
|
});
|
|
trade.TradeNumber = tradeCode;
|
|
trade.ContractVersion = contractVersion;
|
|
TotalPremium += trade.TradePrice ?? 0.0;
|
|
TotalPrinciple += trade.StockEqvNotional;
|
|
}
|
|
model.TotalPrinciple = TotalPrinciple.ToString("F2");
|
|
model.TotalPremium = TotalPremium.ToString("F2");
|
|
model.TradeList = items;
|
|
model.ContractCode = tradeCodePrefix;
|
|
modelDict["主页"] = model;
|
|
modelDict["附页"] = model;
|
|
modelDict["批量附页信息"] = new { Items = items };
|
|
var rightAlignedText = $"交易确认书编号:{tradeCodePrefix}";
|
|
var UseRightAligned = Server.UseRightAligned;
|
|
if (!UseRightAligned)
|
|
{
|
|
rightAlignedText = null;
|
|
}
|
|
if (PS.Config.Is申万)
|
|
{
|
|
//void generateExcelCallback(ExcelWorksheets sheets)
|
|
//{
|
|
// foreach (var sheet in sheets)
|
|
// {
|
|
// if (sheet.Name == "主页")
|
|
// {
|
|
// if (model.TradeList.Count == 2)
|
|
// {
|
|
// sheet.Cells[16, 12, 17, 12].Merge = true;
|
|
// sheet.Cells[16, 13, 17, 13].Merge = true;
|
|
// }
|
|
// }
|
|
// }
|
|
//};
|
|
outputFileName = $"{trades[0].TradeNumber}.xlsx";
|
|
ExcelTemplate.GeneratePDFFromExeclTemplate(templateDir.ToString(), template.FileName, modelDict, outputPath, outputFileName, RightAlignedText: rightAlignedText, needLandscape: true);
|
|
}
|
|
else
|
|
{
|
|
ExcelTemplate.GeneratePDFFromExeclTemplate(templateDir.ToString(), template.FileName, modelDict, outputPath, outputFileName, RightAlignedText: rightAlignedText);
|
|
}
|
|
|
|
#region --- Add trade_contract_document and trade_contract_r records
|
|
var contractRecord = yldb.trade_contract_document.FirstOrDefault(x => x.Code == tradeCodePrefix && x.Type == ContractTypeEnum.Trade);
|
|
if (contractRecord == null)
|
|
{
|
|
contractRecord = new trade_contract_document();
|
|
yldb.trade_contract_document.Add(contractRecord);
|
|
}
|
|
contractRecord.Code = tradeCodePrefix;
|
|
contractRecord.ValueDate = valueDate;
|
|
contractRecord.BuyerId = client2.id;
|
|
contractRecord.BuyerName = client2.Name;
|
|
contractRecord.SellerId = client1.id;
|
|
contractRecord.SellerName = client1.Name;
|
|
contractRecord.ContractVersion = contractVersion;
|
|
contractRecord.FileType = FileTypeEnum.Pdf;
|
|
contractRecord.Status = ContractStatusEnum.Draft;
|
|
contractRecord.SourceType = 1; // 系统生成
|
|
contractRecord.Paths = Path.Combine(DocumentPathConvert.ConvertToUrlPath(outPath), outputFileName.Replace(".xlsx", ".pdf"));
|
|
contractRecord.FileName = outputFileName.Replace(".xlsx", ".pdf");
|
|
contractRecord.Type = ContractTypeEnum.Trade;
|
|
contractRecord.OptId = CurUser.UserId;
|
|
contractRecord.OptName = CurUser.UserName;
|
|
contractRecord.OptDate = DateTime.Now;
|
|
|
|
var tradeIds = trades.Select(x => x.id).ToList();
|
|
//var childs = yldb.trade.Where(x => tradeIds.Contains(x.ParentTradeId ?? 0));
|
|
var service = new TradeDalService(CurUser);
|
|
var childs = service.GetStructTradeFromTradeOrEodTrade(tradeIds, valueDate, true);
|
|
foreach (var trade in trades)
|
|
{
|
|
var contractTradeRelation = yldb.trade_contract_r.Where(t => t.Type == ContractTypeEnum.Trade && t.IsValid).FirstOrDefault(x => x.TradeId == trade.id);
|
|
if (contractTradeRelation == null)
|
|
{
|
|
contractTradeRelation = new trade_contract_r();
|
|
yldb.trade_contract_r.Add(contractTradeRelation);
|
|
}
|
|
contractTradeRelation.TradeId = trade.id;
|
|
contractTradeRelation.TradeNumber = trade.TradeNumber;
|
|
contractTradeRelation.ContractCode = tradeCodePrefix;
|
|
contractTradeRelation.OptId = CurUser.UserId;
|
|
contractTradeRelation.OptName = CurUser.UserName;
|
|
contractTradeRelation.OptDate = DateTime.Now;
|
|
contractTradeRelation.Type = ContractTypeEnum.Trade;
|
|
contractTradeRelation.IsValid = true;
|
|
//var td = service.GetTradeOrEodTrade(new[] { trade.id }, valueDate, true).FirstOrDefault();
|
|
//var childTds = childs.Where(x => x.ParentTradeId == trade.id);
|
|
//if (td != null)
|
|
//{
|
|
// td.HasGeneratedConfirmBook = 1;
|
|
// foreach (var child in childTds)
|
|
// {
|
|
// child.HasGeneratedConfirmBook = 1;
|
|
// }
|
|
//}
|
|
}
|
|
yldb.SaveChanges();
|
|
#endregion --- Add trade_contract_document and trade_contract_r records
|
|
return $"{outPath}/{outputFileName.Replace(".xlsx", ".pdf")}";
|
|
}
|
|
private void CreateContracts(List<int> ids, List<trade_contract_r> tradeContractRList, string sellerContractVersion, string buyerContractVersion, KeyValuePair<string, List<trade>> dict, Tuple<int, string> pair, List<string> contractFiles, Client broker, Client client, DateTime date, ServiceRepresentativeConfig spc0)
|
|
{
|
|
if (ids.Count == 0) { return; }
|
|
//交易的确认书List
|
|
var tempTradeContractList = tradeContractRList.Where(t => ids.Contains(t.TradeId) && !string.IsNullOrEmpty(t.ContractCode)).ToList();
|
|
//交易合约书code list
|
|
var tradeContractCodes = tempTradeContractList.Select(t => t.ContractCode).Distinct().ToList();
|
|
var tradeHasTrades = tempTradeContractList.Select(t => t.TradeId).Distinct().ToList();
|
|
//处理所有已生成交易确认书的交易重新生成时保持交易确认书编号不变
|
|
if (tempTradeContractList.Count > 0)
|
|
{
|
|
var row = 0;
|
|
for (var j = 0; j < tradeContractCodes.Count; j++)
|
|
{
|
|
var item = tradeContractCodes[j];
|
|
var tempIds = tradeContractRList.Where(t => t.ContractCode == item).Select(t => t.TradeId).ToList();
|
|
if (tempIds.Count == 0)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
var contractTrade = dict.Value.Where(x => x.ClientId == pair.Item1 && x.BuySell == pair.Item2 && tempIds.Contains(x.id)).ToList();
|
|
//默认
|
|
if (row == 0)
|
|
{
|
|
row++;
|
|
//没有交易编号的生成
|
|
var tradeTemp = dict.Value.Where(x => x.ClientId == pair.Item1 && x.BuySell == pair.Item2 && !tradeHasTrades.Contains(x.id)).ToList();
|
|
contractTrade.AddRange(tradeTemp);
|
|
}
|
|
|
|
|
|
|
|
if (!sellerContractVersion.EndsWith("T") && !sellerContractVersion.EndsWith("BH")) // 非批量
|
|
{
|
|
foreach (var x in contractTrade)
|
|
{
|
|
contractFiles.Add(CreateTradeConfirmation(x, spc0));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
var tradeContractMode = new TradeContractModeUtils(broker, client, pair.Item2);
|
|
if ("卖出".Equals(pair.Item2) && contractTrade.Count > 0)
|
|
{
|
|
contractFiles.Add(CreateBatchTradeConfirmation(contractTrade, buyerContractVersion, spc0, tradeContractMode.FirstParty, tradeContractMode.SecondParty, date, item, dict.Key));
|
|
}
|
|
else if ("买入".Equals(pair.Item2) && contractTrade.Count > 0)
|
|
{
|
|
contractFiles.Add(CreateBatchTradeConfirmation(contractTrade, sellerContractVersion, spc0, tradeContractMode.FirstParty, tradeContractMode.SecondParty, date, item, dict.Key));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//没有交易编号的生成
|
|
var tradeTemp = dict.Value.Where(x => x.ClientId == pair.Item1 && x.BuySell == pair.Item2 && !tradeHasTrades.Contains(x.id)).ToList();
|
|
if (!sellerContractVersion.EndsWith("T") && !sellerContractVersion.EndsWith("BH")) // 非批量
|
|
{
|
|
foreach (var x in tradeTemp)
|
|
{
|
|
contractFiles.Add(CreateTradeConfirmation(x, spc0));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
var tradeContractMode = new TradeContractModeUtils(broker, client, pair.Item2);
|
|
//剔除已经单独生成交易确认书的交易
|
|
tradeTemp = tradeTemp.Where(t => !"是".Equals(t.IsSingleContract)).ToList();
|
|
var tradeCodePrefix = "";
|
|
if (PS.Config.Is渤海 && tradeTemp[0].TradeType == "亚式期权")
|
|
{
|
|
if (string.IsNullOrWhiteSpace(tradeTemp[0].TradeNumber))
|
|
{
|
|
tradeCodePrefix = GenerateTradeNumber(tradeCodePrefix, client, date, 1, tradeTemp, tradeTemp[0].UnderlyingInstrumentType, tradeTemp[0].BuySell, out _);
|
|
}
|
|
else
|
|
{
|
|
tradeCodePrefix = tradeTemp[0].TradeNumber;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
tradeCodePrefix = GetTradeContractNumber(broker, client, date, pair.Item2, dict.Key);
|
|
}
|
|
if ("卖出".Equals(pair.Item2) && tradeTemp.Count > 0)
|
|
{
|
|
//var tradeCodePrefix = $"{broker.Code}{date.ToString("yyyyMMdd")}-{client.id}B";
|
|
contractFiles.Add(CreateBatchTradeConfirmation(tradeTemp, buyerContractVersion, spc0, tradeContractMode.FirstParty, tradeContractMode.SecondParty, date, tradeCodePrefix, underlyingTypeStr: dict.Key));
|
|
}
|
|
else if ("买入".Equals(pair.Item2) && tradeTemp.Count > 0)
|
|
{
|
|
//var tradeCodePrefix = $"{broker.Code}{date:yyyyMMdd}-{client.id}S";
|
|
contractFiles.Add(CreateBatchTradeConfirmation(tradeTemp, sellerContractVersion, spc0, tradeContractMode.FirstParty, tradeContractMode.SecondParty, date, tradeCodePrefix, underlyingTypeStr: dict.Key));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public JsonResult BatchCreateContracts(DateTime? TradeDateStart, DateTime? TradeDateEnd, string ClientIds, string TradeIds)
|
|
{
|
|
try
|
|
{
|
|
lock (createConfirmContractLock)
|
|
{
|
|
if (!TradeDateStart.HasValue)
|
|
{
|
|
TradeDateStart = valuedateBLL.ValueDate;
|
|
}
|
|
|
|
if (!TradeDateEnd.HasValue)
|
|
{
|
|
TradeDateEnd = valuedateBLL.ValueDate;
|
|
}
|
|
|
|
var contractFiles = new List<string>();
|
|
|
|
string[] errors = null;
|
|
|
|
switch (PS.Config.Company)
|
|
{
|
|
case CompanyEnum.瑞达:
|
|
RDBatchGenerateContracts(contractFiles, ClientIds, TradeIds, out errors);
|
|
break;
|
|
case CompanyEnum.海通:
|
|
HTBatchGenerateContracts(contractFiles, ClientIds, TradeIds, out errors);
|
|
break;
|
|
case CompanyEnum.格林大华:
|
|
GLDHBatchGenerateContracts(contractFiles, ClientIds, TradeIds, TradeDateStart, TradeDateEnd, out errors);
|
|
break;
|
|
default:
|
|
DefaultBatchGenerateContracts(contractFiles, ClientIds, TradeIds, TradeDateStart, TradeDateEnd, out errors);
|
|
break;
|
|
}
|
|
|
|
if (errors != null && errors.Any())
|
|
{
|
|
return JsonError(string.Join("\r\n", errors.AsEnumerable()), contractFiles);
|
|
}
|
|
return Json($"成功生成以下交易确认书: {string.Join("\n", contractFiles)}");
|
|
}
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
logger.Error(e.StackTrace);
|
|
return JsonError($"生成交易确认书时出错: {e.Message}");
|
|
}
|
|
|
|
}
|
|
|
|
/// <summary>
|
|
/// 瑞达批量处理
|
|
/// </summary>
|
|
private void RDBatchGenerateContracts(List<string> contractFiles, string ClientIds, string TradeIds, out string[] errors)
|
|
{
|
|
errors = null;
|
|
if (string.IsNullOrWhiteSpace(TradeIds))
|
|
{ throw new ArgumentException("请勾选交易"); }
|
|
List<int> tids = new List<int>();
|
|
TradeIds?.Split(',')?.ToList()?.ForEach(g =>
|
|
{
|
|
var tid = Convert.ToInt32(g.Trim());
|
|
tids.Add(tid);
|
|
});
|
|
|
|
var tradeTypeArr = new List<string>() { "远期", "亚式期权" };
|
|
var query =
|
|
from t in yldb.trade
|
|
where
|
|
tids.Contains(t.id)
|
|
select new
|
|
{
|
|
t.id,
|
|
t.ClientId,
|
|
t.TradeDate,
|
|
tradeType = tradeTypeArr.Contains(t.TradeType) ? t.TradeType : "Normal",
|
|
IsSW = t.StructureType == "掉期" ? "0" : "1"
|
|
};
|
|
if (!query.Any())
|
|
{
|
|
throw new ArgumentException("请勾选交易");
|
|
}
|
|
if (!ClientIds.IsNullOrWhiteSpace())
|
|
{
|
|
var ids = ClientIds.Split(',');
|
|
query = query.Where(O => ids.Contains(O.ClientId + ""));
|
|
}
|
|
var clientTradeDict =
|
|
query.AsEnumerable().GroupBy(O => O.ClientId + " " + O.TradeDate + " " + O.tradeType + " " + O.IsSW)
|
|
.ToDictionary(K => K.Key, V => V.Select(O => O.id).ToList());
|
|
foreach (var trades in clientTradeDict)
|
|
{
|
|
var results =
|
|
new BatchConfirmationGenerateService(CurUser).Generate(trades.Value, "PDF");
|
|
errors = results.Where(n => !string.IsNullOrWhiteSpace(n.ErrorMessage)).Select(n => n.ErrorMessage).ToArray();
|
|
contractFiles = results.Where(n => !string.IsNullOrWhiteSpace(n.OutputFilePath)).Select(n => n.OutputFilePath).ToList();
|
|
if (errors.Any())
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 海通批量生成
|
|
/// </summary>
|
|
private void HTBatchGenerateContracts(List<string> contractFiles, string ClientIds, string TradeIds, out string[] errors)
|
|
{
|
|
errors = null;
|
|
if (string.IsNullOrWhiteSpace(TradeIds))
|
|
{ throw new ArgumentException("请勾选交易"); }
|
|
var tids = TradeIds.Split(',').ToList();
|
|
var intTids = new List<int>();
|
|
tids.ForEach(g => intTids.Add(Convert.ToInt32(g)));
|
|
|
|
var query =
|
|
from t in yldb.trade
|
|
where
|
|
intTids.Contains(t.id)
|
|
select new { t.id, t.ClientId };
|
|
if (!query.Any())
|
|
{
|
|
throw new ArgumentException("请勾选交易");
|
|
}
|
|
if (!ClientIds.IsNullOrWhiteSpace())
|
|
{
|
|
var ids = ClientIds.Split(',');
|
|
query = query.Where(O => ids.Contains(O.ClientId + ""));
|
|
}
|
|
var clientTradeDict =
|
|
query.AsEnumerable().GroupBy(O => O.ClientId)
|
|
.ToDictionary(K => K.Key, V => V.Select(O => O.id).ToList());
|
|
foreach (var trades in clientTradeDict)
|
|
{
|
|
var results =
|
|
new BatchConfirmationGenerateService(CurUser).Generate(trades.Value, "PDF");
|
|
errors = results.Where(n => !string.IsNullOrWhiteSpace(n.ErrorMessage)).Select(n => n.ErrorMessage).ToArray();
|
|
contractFiles = results.Where(n => !string.IsNullOrWhiteSpace(n.OutputFilePath)).Select(n => n.OutputFilePath).ToList();
|
|
if (errors.Any())
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 格林大华
|
|
/// </summary>
|
|
private void GLDHBatchGenerateContracts(List<string> contractFiles, string ClientIds, string TradeIds, DateTime? TradeDateStart, DateTime? TradeDateEnd, out string[] errors)
|
|
{
|
|
errors = null;
|
|
//需要生成交易确认书的状态
|
|
var NeedGenTradeStatus = new List<string> { ConsTrade.确认成交, ConsTrade.已执行, ConsTrade.已到期, ConsTrade.已平仓, ConsTrade.平仓待复核, ConsTrade.提前终止拒绝, ConsTrade.行权待复核 };
|
|
//渠道商信息
|
|
var broker = DataCacheProvider.GetClientDataSource().AsQueryable().FirstOrDefault(x => x.Name == PS.Config.CompanyFullName);
|
|
|
|
//渠道服务商 配置信息
|
|
var spc0 = ServicerePresentativeConfigService.GetData(0);
|
|
if (spc0 == null)
|
|
{
|
|
throw new InvalidOperationException("未找到服务商信息");
|
|
}
|
|
|
|
if (broker == null)
|
|
{
|
|
errors = new string[1] { "渠道交易渠道商字段[BrokerClientName]未配置" };
|
|
return;
|
|
}
|
|
//查询所有待生成交易确认书的场外期权交易
|
|
var query = yldb.trade.Where(t => NeedGenTradeStatus.Contains(t.TradeStatus)
|
|
&& t.ValidState != "InValid" && t.ClientId > 0
|
|
&& ConsTrade.TradeTypesForOtcOptions.Contains(t.TradeType));
|
|
if (string.IsNullOrWhiteSpace(TradeIds))
|
|
{
|
|
query = query.Where(t => t.TradeDate >= TradeDateStart && t.TradeDate <= TradeDateEnd);
|
|
if (!string.IsNullOrWhiteSpace(ClientIds))
|
|
{
|
|
var clientIdList = (ClientIds + "").Split(","[0]).Select(c => Convert.ToInt32(c)).ToList();
|
|
query = query.Where(t => clientIdList.Contains(t.ClientId));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
var tradeIdList = TradeIds.Split(',').Select(t => Convert.ToInt32(t)).ToList();
|
|
query = query.Where(t => tradeIdList.Contains(t.id));
|
|
}
|
|
|
|
|
|
//获取生成日期区间
|
|
var allTradeList = query.ToList();
|
|
TradeDateStart = allTradeList.Min(t => t.TradeDate);
|
|
TradeDateEnd = allTradeList.Max(t => t.TradeDate);
|
|
|
|
if (allTradeList.Count == 0)
|
|
{
|
|
errors = new string[1] { "当前选择的[客户][交易日区间]条件下未找到可生成交易确认书的交易!" };
|
|
return;
|
|
}
|
|
|
|
//AppManager.TryResolve(out IBatchTradeConfirmationGenerator batchTradeConfirmationGenerator);
|
|
//IBatchTradeDocGeneratorContext context = new BatchTradeDocGeneratorContext("Pdf", CurUser.UserId, CurUser.UserName, broker, spc0, valuedateBLL.SystemDate, Server.MapPath("/App_Docs"));
|
|
//batchTradeConfirmationGenerator.Initialize(context);
|
|
|
|
var tradeIds = allTradeList.Select(t => t.id).ToList();
|
|
//当日交易对应的所有对应关系
|
|
var tradeContractRList = yldb.trade_contract_r.Where(t => tradeIds.Contains(t.TradeId) && t.Type == ContractTypeEnum.Trade && t.IsValid).ToList();
|
|
|
|
var tempEnum = (TradeConfirmContractMode)Enum.Parse(typeof(TradeConfirmContractMode), string.IsNullOrEmpty(valuedateBLL.SystemDate.TradeContractDocMode) ? "单笔模式" : valuedateBLL.SystemDate.TradeContractDocMode);
|
|
var tempGroupList = new List<TradeConfirmContractGroupModel>();
|
|
switch (tempEnum)
|
|
{
|
|
case TradeConfirmContractMode.单笔模式:
|
|
foreach (var trade in allTradeList)
|
|
{
|
|
contractFiles.Add(CreateTradeConfirmation(trade, spc0));
|
|
}
|
|
break;
|
|
case TradeConfirmContractMode.单客户同日:
|
|
tempGroupList = allTradeList.Select(t => Tuple.Create(t.ClientId, t.TradeDate.Value)).Distinct().Select(t => new TradeConfirmContractGroupModel { ClientId = t.Item1, ValueDate = t.Item2 }).OrderBy(t => t.ValueDate).ToList();
|
|
break;
|
|
case TradeConfirmContractMode.单客户同日同类型:
|
|
tempGroupList = allTradeList.Select(t => Tuple.Create(t.ClientId, t.TradeDate.Value, t.UnderlyingInstrumentType)).Distinct().Select(t => new TradeConfirmContractGroupModel { ClientId = t.Item1, ValueDate = t.Item2, UnderlyingType = t.Item3 }).OrderBy(t => t.ValueDate).ThenBy(t => t.ClientId).ThenBy(t => t.UnderlyingType).ToList();
|
|
break;
|
|
case TradeConfirmContractMode.单客户同日同类型同方向:
|
|
tempGroupList = allTradeList.Select(t => Tuple.Create(t.ClientId, t.TradeDate.Value, t.UnderlyingInstrumentType, t.BuySell)).Distinct().Select(t => new TradeConfirmContractGroupModel { ClientId = t.Item1, ValueDate = t.Item2, UnderlyingType = t.Item3, BuySell = t.Item4 }).OrderBy(t => t.ValueDate).ThenBy(t => t.ClientId).ThenBy(t => t.UnderlyingType).ToList();
|
|
break;
|
|
//case TradeConfirmContractMode.申银万国模式:
|
|
// break;
|
|
default:
|
|
break;
|
|
}
|
|
//分组生成确认书
|
|
foreach (var item in tempGroupList)
|
|
{
|
|
//客户信息
|
|
var client = DataCacheProvider.GetClientDataSource().GetData(item.ClientId);
|
|
if (client == null)
|
|
{
|
|
throw new InvalidOperationException($"找不到id为{item.ClientId}的客户");
|
|
}
|
|
//当前条件生成交易确认书的交易列表
|
|
var tempQuery = allTradeList.Where(t => t.TradeDate == item.ValueDate && t.ClientId == item.ClientId);
|
|
if (!string.IsNullOrEmpty(item.UnderlyingType))
|
|
{
|
|
tempQuery = tempQuery.Where(t => t.UnderlyingInstrumentType == item.UnderlyingType);
|
|
}
|
|
if (!string.IsNullOrEmpty(item.BuySell))
|
|
{
|
|
tempQuery = tempQuery.Where(t => t.BuySell == item.BuySell);
|
|
}
|
|
var tempTradeList = tempQuery.ToList();
|
|
|
|
|
|
var contractVersion = spc0.StockBuyContractVersion;
|
|
if ("STO".Equals(item.UnderlyingTypeShort))
|
|
{
|
|
contractVersion = "买入".Equals(item.BuySell) ? spc0.StockSellContractVersion : spc0.StockBuyContractVersion;
|
|
}
|
|
else
|
|
{
|
|
contractVersion = "买入".Equals(item.BuySell) ? spc0.FutureSellContractVersion : spc0.FutureBuyContractVersion;
|
|
}
|
|
if (string.IsNullOrEmpty(contractVersion))
|
|
{
|
|
throw new InvalidOperationException($"未为渠道商设置商品期货期权交易确认书版本");
|
|
}
|
|
|
|
var tradeContractMode = new TradeContractModeUtils(broker, client, item.BuySell);
|
|
|
|
//当前客户当前买卖方向所有交易
|
|
var tempTradeIds = tempTradeList.Select(t => t.id).ToList();
|
|
//交易的确认书List
|
|
var tempTradeContractList = tradeContractRList.Where(t => tempTradeIds.Contains(t.TradeId) && !string.IsNullOrEmpty(t.ContractCode)).ToList();
|
|
//交易合约书code list
|
|
var tradeContractCodes = tempTradeContractList.Select(t => t.ContractCode).Distinct().ToList();
|
|
var tradeHasTrades = tempTradeContractList.Select(t => t.TradeId).Distinct().ToList();
|
|
|
|
//处理所有已生成交易确认书的交易重新生成时保持交易确认书编号不变
|
|
if (tempTradeContractList.Count > 0)
|
|
{
|
|
var row = 0;
|
|
for (var j = 0; j < tradeContractCodes.Count; j++)
|
|
{
|
|
var ContractCode = tradeContractCodes[j];
|
|
var tempIds = tradeContractRList.Where(t => t.ContractCode == ContractCode).Select(t => t.TradeId).ToList();
|
|
if (tempIds.Count == 0)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
var contractTrade = tempTradeList.Where(x => tempIds.Contains(x.id)).ToList();
|
|
//默认
|
|
if (row == 0)
|
|
{
|
|
row++;
|
|
//没有交易编号的生成
|
|
var tradeTemp = tempTradeList.Where(x => !tradeHasTrades.Contains(x.id)).ToList();
|
|
contractTrade.AddRange(tradeTemp);
|
|
}
|
|
contractFiles.Add(CreateBatchTradeConfirmation(contractTrade, contractVersion, spc0, tradeContractMode.FirstParty, tradeContractMode.SecondParty, item.ValueDate, ContractCode, item.UnderlyingTypeShort));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//剔除已经单独生成交易确认书的交易
|
|
var tradeTemp = tempTradeList.Where(t => !"是".Equals(t.IsSingleContract)).ToList();
|
|
var tradeCodePrefix = GetTradeContractNumber(broker, client, item.ValueDate, item.BuySell, item.UnderlyingTypeShort);
|
|
contractFiles.Add(CreateBatchTradeConfirmation(tradeTemp, contractVersion, spc0, tradeContractMode.FirstParty, tradeContractMode.SecondParty, item.ValueDate, tradeCodePrefix, underlyingTypeStr: item.UnderlyingTypeShort));
|
|
}
|
|
}
|
|
}
|
|
private void DefaultBatchGenerateContracts(List<string> contractFiles, string ClientIds, string TradeIds, DateTime? TradeDateStart, DateTime? TradeDateEnd, out string[] errors)
|
|
{
|
|
errors = null;
|
|
var buySellList = new List<string> { "卖出", "买入" };
|
|
var NeedGenTradeStatus = new List<string> { ConsTrade.确认成交, ConsTrade.已执行, ConsTrade.已到期, ConsTrade.已平仓, ConsTrade.平仓待复核, ConsTrade.提前终止拒绝, ConsTrade.行权待复核 };
|
|
//渠道商信息
|
|
var broker = DataCacheProvider.GetClientDataSource().AsQueryable().FirstOrDefault(x => x.Name == PS.Config.CompanyFullName);
|
|
|
|
if (broker == null)
|
|
{
|
|
errors = new string[1] { "渠道交易渠道商字段[BrokerClientName]未配置" };
|
|
return;
|
|
}
|
|
var tradeTypes = new List<string>(ConsTrade.TradeTypesForOtcOptions);
|
|
if (PS.Config.Is渤海)
|
|
{
|
|
tradeTypes.Add("远期");
|
|
}
|
|
var query = yldb.trade.Where(t => buySellList.Contains(t.BuySell)
|
|
&& NeedGenTradeStatus.Contains(t.TradeStatus)
|
|
&& t.ClientId > 0
|
|
&& tradeTypes.Contains(t.TradeType)
|
|
);
|
|
|
|
if (string.IsNullOrWhiteSpace(TradeIds))
|
|
{
|
|
query = query.Where(t => t.TradeDate >= TradeDateStart && t.TradeDate <= TradeDateEnd);
|
|
if (!string.IsNullOrWhiteSpace(ClientIds))
|
|
{
|
|
var clientIdList = (ClientIds + "").Split(","[0]).Select(c => Convert.ToInt32(c)).ToList();
|
|
query = query.Where(t => clientIdList.Contains(t.ClientId));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
var tradeIdList = TradeIds.Split(',').Select(t => Convert.ToInt32(t)).ToList();
|
|
query = query.Where(t => tradeIdList.Contains(t.id));
|
|
}
|
|
var tdIds = query.Select(l => l.id).ToList();
|
|
if (PS.Config.Company == CompanyEnum.国信金阳)
|
|
{
|
|
if (!new TradeContractGenerateService(CurUser).GXJY_CorrespondingConfirmationTemplate(tdIds, out string Msg))
|
|
{
|
|
throw new ServiceException(Msg);
|
|
}
|
|
}
|
|
var allTradeList = query.ToList();
|
|
TradeDateStart = allTradeList.Min(t => t.TradeDate);
|
|
TradeDateEnd = allTradeList.Max(t => t.TradeDate);
|
|
|
|
if (allTradeList.Count == 0)
|
|
{
|
|
errors = new string[1] { "当前选择的[客户][交易日区间]条件下未找到可生成交易确认书的交易!" };
|
|
return;
|
|
}
|
|
//生成日期区间
|
|
for (var date = TradeDateStart.Value; DateTime.Compare(TradeDateEnd.Value, date) >= 0; date = date.AddDays(1))
|
|
{
|
|
//当日所有交易
|
|
var tradeList = allTradeList.Where(t => t.TradeDate == date).ToList();
|
|
|
|
if (tradeList.Count == 0)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
var tradeIds = tradeList.Select(t => t.id).ToList();
|
|
|
|
//客户存在的买卖方向
|
|
var clientBuySell = tradeList.Select(t => Tuple.Create(t.ClientId, t.BuySell)).Distinct().ToList();
|
|
|
|
//当日交易对应的所有对应关系
|
|
var tradeContractRList = yldb.trade_contract_r.Where(t => tradeIds.Contains(t.TradeId) && t.Type == ContractTypeEnum.Trade && t.IsValid).ToList();
|
|
|
|
//渠道服务商
|
|
var spc0 = ServicerePresentativeConfigService.GetData(0);
|
|
if (spc0 == null)
|
|
{
|
|
throw new InvalidOperationException("未找到服务商信息");
|
|
}
|
|
var forwardTradeList = new List<trade>();
|
|
if (PS.Config.Is渤海)
|
|
{
|
|
forwardTradeList = tradeList.Where(t => t.TradeType == "远期").ToList();
|
|
tradeList = tradeList.Where(t => t.TradeType != "远期").ToList();
|
|
|
|
//渤海远期
|
|
if (forwardTradeList.Any())
|
|
{
|
|
if (string.IsNullOrEmpty(spc0.ForwardBuyContractVersion))
|
|
{
|
|
throw new InvalidOperationException($"未为渠道商设置商品期货期权交易确认书版本");
|
|
}
|
|
forwardTradeList.ForEach(a =>
|
|
{
|
|
var tradeContract = tradeContractRList.Where(t => !string.IsNullOrEmpty(t.ContractCode) && t.TradeId == a.id).FirstOrDefault();
|
|
var client = DataCacheProvider.GetClientDataSource().GetData(a.ClientId);
|
|
contractFiles.Add(BHRSForwardGenerateContract(a, broker, client, date, tradeContract, spc0.ForwardBuyContractVersion));
|
|
});
|
|
}
|
|
}
|
|
//买卖方向
|
|
for (var i = 0; i < clientBuySell.Count; i++)
|
|
{
|
|
var pair = clientBuySell[i];
|
|
|
|
var client = DataCacheProvider.GetClientDataSource().GetData(pair.Item1);
|
|
if (client == null)
|
|
{
|
|
throw new InvalidOperationException($"找不到id为{pair.Item1}的客户");
|
|
}
|
|
//股票期权交易
|
|
var stockTrades = tradeList.Where(x => x.ClientId == pair.Item1 && x.BuySell == pair.Item2 && x.UnderlyingInstrumentType == "Stock").ToList();
|
|
//商品期货期权
|
|
var futureTrades = tradeList.Where(x => x.ClientId == pair.Item1 && x.BuySell == pair.Item2 && x.UnderlyingInstrumentType != "Stock").ToList();
|
|
|
|
var tradeDict = new Dictionary<string, List<trade>>
|
|
{
|
|
["STO"] = stockTrades,
|
|
["FUT"] = futureTrades
|
|
};
|
|
//标的类型
|
|
foreach (var dict in tradeDict)
|
|
{
|
|
if (dict.Value == null || dict.Value.Count == 0)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
var sellerContractVersion = spc0.FutureSellContractVersion;
|
|
var buyerContractVersion = spc0.FutureBuyContractVersion;
|
|
|
|
if ("STO".Equals(dict.Key))
|
|
{
|
|
sellerContractVersion = spc0.StockSellContractVersion;
|
|
buyerContractVersion = spc0.StockBuyContractVersion;
|
|
if (string.IsNullOrEmpty(sellerContractVersion))
|
|
{
|
|
throw new InvalidOperationException($"未为渠道商设置个股期权交易确认书版本");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (string.IsNullOrEmpty(sellerContractVersion))
|
|
{
|
|
throw new InvalidOperationException($"未为渠道商设置商品期货期权交易确认书版本");
|
|
}
|
|
}
|
|
//当前客户当前买卖方向非亚式期权的所有交易
|
|
var tempTradeIds = dict.Value.Where(x => x.ClientId == pair.Item1 && x.BuySell == pair.Item2 && x.TradeType != "亚式期权").Select(t => t.id).ToList();
|
|
if (tempTradeIds.Count > 0)
|
|
{
|
|
var tDict = new KeyValuePair<string, List<trade>>(dict.Key, dict.Value.Where(O => O.TradeType != "亚式期权").ToList());
|
|
CreateContracts(tempTradeIds, tradeContractRList, sellerContractVersion, buyerContractVersion, tDict, pair, contractFiles, broker, client, date, spc0);
|
|
}
|
|
//当前客户当前买卖方向亚式期权的所有交易
|
|
dict.Value.RemoveAll(x => x.ClientId == pair.Item1 && x.BuySell == pair.Item2 && x.TradeType != "亚式期权");
|
|
tempTradeIds = dict.Value.Where(x => x.ClientId == pair.Item1 && x.BuySell == pair.Item2 && x.TradeType == "亚式期权").Select(t => t.id).ToList();
|
|
if (tempTradeIds.Count > 0)
|
|
{
|
|
foreach (var tId in tempTradeIds)
|
|
{
|
|
var tDict = new KeyValuePair<string, List<trade>>(dict.Key, dict.Value.Where(O => O.id == tId).ToList());
|
|
CreateContracts(new List<int> { tId }, tradeContractRList, sellerContractVersion, buyerContractVersion, tDict, pair, contractFiles, broker, client, date, spc0);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#region 渤海远期交易确认书
|
|
/// <summary>
|
|
/// 生成渤海远期交易确认书
|
|
/// </summary>
|
|
/// <param name="t"></param>
|
|
/// <param name="firstParty"></param>
|
|
/// <param name="client"></param>
|
|
/// <param name="date"></param>
|
|
/// <param name="tradeContract"></param>
|
|
/// <param name="templateFilePath"></param>
|
|
private string BHRSForwardGenerateContract(trade t, Client firstParty, Client client, DateTime date, trade_contract_r tradeContract, string contractVersion)
|
|
{
|
|
var settleBillService = new SettleBillService(CurUser);
|
|
|
|
string contractCode = string.IsNullOrEmpty(tradeContract?.ContractCode) ? settleBillService.BHRSForwardGenerateContractCode(date, "FW") : tradeContract.ContractCode;
|
|
|
|
if (string.IsNullOrEmpty(t.TradeNumber))
|
|
{
|
|
var subCode = "";
|
|
t.TradeNumber = GenerateTradeNumber(contractCode, client, date, 1, null, t.UnderlyingInstrumentType, t.BuySell, out subCode);
|
|
//查询出单条交易编号
|
|
var db = DbContextFactory.GetYLDbContext();
|
|
var trade = db.trade.Where(O => O.id == t.id).FirstOrDefault();
|
|
trade.TradeNumber = t.TradeNumber;
|
|
db.SaveChanges();
|
|
}
|
|
|
|
var template = yldb.files_template.Where(a => contractVersion == a.Code).FirstOrDefault();
|
|
string templateDir = Server.MapPath("/App_Docs");
|
|
string outPath = @"\App_Docs";
|
|
if (!string.IsNullOrEmpty(template.Paths))
|
|
{
|
|
templateDir = Path.Combine(templateDir, template.Paths);
|
|
outPath = Path.Combine(outPath, template.Paths, $"{date:yyyyMMdd}");
|
|
}
|
|
|
|
//渤海远期交易确认书模板 App_Docs\SYWG\远期商品期货交易确认书.docx
|
|
var templateFilePath = Path.Combine(templateDir, template.FileName);
|
|
if (!System.IO.File.Exists(templateFilePath))
|
|
{
|
|
throw new InvalidOperationException($"请设置渤海远期交易确认书模板地址");
|
|
}
|
|
string outFileName = $"{firstParty.Name}-{client.Name}-{date.ToString("yyyyMMdd")}-FW-{contractCode}.pdf";
|
|
string outFilePath = Path.Combine(outPath, outFileName);
|
|
|
|
var um = DataCacheProvider.GetUnderlyingDataSource().GetData(t.UnderlyingId);
|
|
string marketName = um.MarketName;
|
|
var marketInfo = DataCacheProvider.GetMarketDataSource().AsQueryable().Where(a => a.MarketName == marketName).FirstOrDefault();
|
|
var tradeUnit = "";
|
|
if (um.UnderlyingType == "组合标的")
|
|
{
|
|
var dto = new UnderlyingDalService(CurUser).GetSyntheticUnderlyingByName(um.UnderlyingCode);
|
|
tradeUnit = ConsGlobal.InstrumentType.Stock.Equals(t.UnderlyingInstrumentType) ? "元/股" : (dto.ContractSize == null ? "" : (dto.ContractSize ?? 0).ToString());
|
|
}
|
|
else
|
|
{
|
|
tradeUnit = ConsGlobal.InstrumentType.Stock.Equals(t.UnderlyingInstrumentType) ? "元/股" : ("元/" + um.TradeUnitString);
|
|
}
|
|
|
|
var dic = new Dictionary<string, object>();
|
|
dic["{{确认书编号}}"] = contractCode;
|
|
dic["{{乙方公司}}"] = client.Name;
|
|
dic["{{乙方地址}}"] = client.PostalAddress;
|
|
dic["{{交易编号}}"] = t.TradeNumber;
|
|
dic["{{开仓日期}}"] = t.TradeDate?.ToString("yyyy/MM/dd");
|
|
dic["{{交易标的}}"] = t.UnderlyingCode + "." + marketInfo?.ExchangeNo;
|
|
dic["{{合约类型}}"] = t.TradeType;
|
|
dic["{{交易方向}}"] = settleBillService.ToCallPut(t.CallPut, t.BuySell, t.TradeType);
|
|
dic["{{名义本金}}"] = t.OriginalStockEqvNotional?.ToString("F2") + " 元";
|
|
dic["{{期初价格}}"] = (t.SpotPrice.HasValue ? t.SpotPrice.Value.ToString("F2") : "0") + tradeUnit;
|
|
dic["{{数量}}"] = t.OriginalNotional / um.CountRatio;
|
|
dic["{{到期日}}"] = t.ExerciseDate.Value.ToString("yyyy/MM/dd");
|
|
dic["{{制表日期}}"] = date.ToString("yyyy年MM月dd日");
|
|
|
|
MsWordTempalteHelper.GenerateFromTemplate(templateFilePath, dic, Server.MapPath(outFilePath));
|
|
|
|
settleBillService.SaveTradeContract(t, null, contractCode, date, firstParty, client, contractVersion, outFilePath, outFileName, true);
|
|
|
|
return outFilePath;
|
|
}
|
|
|
|
#endregion
|
|
|
|
/// <summary>
|
|
/// 获取交易确认书编码
|
|
/// </summary>
|
|
private string GetTradeContractNumber(Client broker, Client client, DateTime date, string buySell, string underlyingType, bool IsSingle = false, string TradeType = null)
|
|
{
|
|
switch (PS.Config.Company)
|
|
{
|
|
case CompanyEnum.格林大华:
|
|
switch (buySell)
|
|
{
|
|
case "买入":
|
|
return $"{client.Code}-{date:yyMMdd}-{(IsSingle ? "M" : ("STO".Equals(underlyingType) ? "F" : "B"))}";
|
|
case "卖出":
|
|
return $"{client.Code}-{date:yyMMdd}-{(IsSingle ? "M" : ("STO".Equals(underlyingType) ? "E" : "A"))}";
|
|
default:
|
|
return "";
|
|
}
|
|
default:
|
|
return $"{broker.Code}{date:yyyyMMdd}{underlyingType}-{client.id}{("买入".Equals(buySell) ? "S" : "B")}";
|
|
}
|
|
}
|
|
|
|
private string ToStringFillUpZero(int number, int length)
|
|
{
|
|
var result = number.ToString();
|
|
var prefix = "";
|
|
for (var i = 0; i < length - result.Length; i++)
|
|
{
|
|
prefix += "0";
|
|
}
|
|
result = prefix + result;
|
|
return result;
|
|
}
|
|
|
|
private string GenerateTradeNumber(string tradeCodePrefix, Client client, DateTime valueDate, int number, List<trade> tradeList, string UnderlyingType, string BuySell, out string subCode)
|
|
{
|
|
subCode = ToStringFillUpZero(number, 3);
|
|
|
|
if (PS.Config.Company == CompanyEnum.渤海)
|
|
{
|
|
var numberPrefix = $"{client.Code}-{valueDate:yyyyMMdd}{(UnderlyingType == "Stock" ? "STO" : "FUT")}-";
|
|
var numberSuffix = (BuySell == "买入" ? "B" : "S");
|
|
var tradeNumberList =
|
|
yldb.trade
|
|
.Where(O => O.ValidState != "InValid" && O.TradeNumber.StartsWith(numberPrefix))
|
|
.OrderBy(O => O.id).Select(O => O.TradeNumber)
|
|
.ToList();
|
|
if (tradeList != null)
|
|
{
|
|
tradeNumberList.AddRange(tradeList
|
|
.Where(O => !string.IsNullOrWhiteSpace(O.TradeNumber))
|
|
.Select(O => O.TradeNumber).ToList());
|
|
}
|
|
|
|
var tradeNumber = "";
|
|
do
|
|
{
|
|
tradeNumber = $"{numberPrefix}{number:000}{numberSuffix}";
|
|
number++;
|
|
} while (tradeNumberList.Contains(tradeNumber));
|
|
return tradeNumber;
|
|
}
|
|
else
|
|
{
|
|
var tradeCode = $"{tradeCodePrefix}({valueDate:yyyyMMdd}-{subCode})";
|
|
if (tradeList.Any(t => tradeCode.Equals(t.TradeNumber) && t.UnderlyingInstrumentType == UnderlyingType && t.BuySell == BuySell))
|
|
{
|
|
number++;
|
|
return GenerateTradeNumber(tradeCodePrefix, client, valueDate, number, tradeList, UnderlyingType, BuySell, out subCode);
|
|
}
|
|
else
|
|
{
|
|
return tradeCode;
|
|
}
|
|
}
|
|
}
|
|
|
|
private Dictionary<string, string> AddStockDictionary(Dictionary<string, string> dic)
|
|
{
|
|
dic.Add("{{乙方名称}}", "");
|
|
dic.Add("{{合同编号}}", "");//table
|
|
dic.Add("{{账户信息乙方}}", "");
|
|
dic.Add("{{联系方式乙方}}", "");
|
|
dic.Add("{{联系方式乙方联系人}}", "");
|
|
dic.Add("{{联系方式乙方电话}}", "");
|
|
dic.Add("{{联系方式乙方电子邮件}}", "");
|
|
dic.Add("{{账户信息乙方户名}}", "");
|
|
dic.Add("{{账户信息乙方账号}}", "");
|
|
dic.Add("{{账户信息乙方开户行}}", "");
|
|
dic.Add("{{交易日年部分}}", "");
|
|
dic.Add("{{交易日月部分}}", "");
|
|
dic.Add("{{交易日日部分}}", "");
|
|
dic.Add("{{交易日}}", "");
|
|
dic.Add("{{名义本金}}", "");//table
|
|
dic.Add("{{证券名称}}", "");//table
|
|
dic.Add("{{证券代码}}", "");//table
|
|
dic.Add("{{计划期限}}", "");//table
|
|
dic.Add("{{起始日}}", "");//table
|
|
dic.Add("{{到期日}}", "");//table
|
|
dic.Add("{{结算日}}", "");//table
|
|
dic.Add("{{期初价格}}", "");//table
|
|
dic.Add("{{权利金}}", "");//table
|
|
dic.Add("{{期权类型}}", "");//table
|
|
dic.Add("{{执行价格}}", "");//table
|
|
dic.Add("{{权利金%}}", "");//table
|
|
dic.Add("{{行权手续费}}", ""); //table
|
|
return dic;
|
|
}
|
|
|
|
static readonly object locker = new object();
|
|
|
|
/// <summary>
|
|
/// 生成交易确认书
|
|
/// </summary>
|
|
/// <param name="clientIds">客户编号</param>
|
|
/// <param name="docType">确认书文件类型</param>
|
|
/// <param name="startDate">持仓日期区间-开始日期</param>
|
|
/// <param name="endDate">持仓日期区间-结束日期</param>
|
|
/// <param name="tradeType">
|
|
/// 交易类型
|
|
/// <para>1:互换交易</para>
|
|
/// <para>2:期权交易</para>
|
|
/// </param>
|
|
/// <returns></returns>
|
|
public JsonResult GetSingleGenerateConfirmBook(int[] clientIds, string docType, DateTime startDate, DateTime endDate, int tradeType,List<int> sealResults)
|
|
{
|
|
string[] tradeTypes = null;
|
|
switch (tradeType)
|
|
{
|
|
case 2:
|
|
tradeTypes = ConsTrade.AllTradeTypes.Except(ConsTrade.TradeTypesForHedge).Except(new[] { "收益互换" }).ToArray();
|
|
break;
|
|
case 1:
|
|
default:
|
|
tradeTypes = new[] { "收益互换" };
|
|
break;
|
|
}
|
|
|
|
var results = new TransactionGenerateService(CurUser).Generate(clientIds, docType, startDate, endDate, tradeTypes,sealResults);
|
|
|
|
var errors = results.Where(n => !string.IsNullOrWhiteSpace(n.ErrorMessage)).Select(n => n.ErrorMessage).ToArray();
|
|
var outfiles = results.Where(n => !string.IsNullOrWhiteSpace(n.OutputFilePath)).Select(n => n.OutputFilePath).ToList();
|
|
|
|
if (errors != null && errors.Any())
|
|
{
|
|
return JsonError(string.Join("\r\n", errors), outfiles);
|
|
}
|
|
else
|
|
{
|
|
return JsonSuccess(PS.GetErpConfig().IsAutoSealAndUploadFiles && PS.GetErpConfig().IsAutoSealAfterGeneratedBook? "生成成功,用印等待中..." : "生成成功", outfiles);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 判断文件是否存在
|
|
/// </summary>
|
|
/// <param name="filePath"></param>
|
|
/// <returns></returns>
|
|
public JsonResult ExistFile(string filePath)
|
|
{
|
|
var exist = false;
|
|
try
|
|
{
|
|
filePath = Server.MapPath(filePath);
|
|
exist = System.IO.File.Exists(filePath);
|
|
}
|
|
catch
|
|
{
|
|
}
|
|
return JsonSuccess("", exist);
|
|
}
|
|
}
|
|
|
|
public class ContractModel // model for 交易确认书模板
|
|
{
|
|
public ContractModel()
|
|
{
|
|
FPCompanyName = "";
|
|
FPAddress = "";
|
|
FPTel = "";
|
|
FPFax = "";
|
|
FPName = "";
|
|
FPBankCard = "";
|
|
FPBankName = "";
|
|
FPLinkman = "";
|
|
SPCompanyName = "";
|
|
SPAddress = "";
|
|
SPTel = "";
|
|
SPFax = "";
|
|
SPName = "";
|
|
SPBankCard = "";
|
|
SPBankName = "";
|
|
SPLinkman = "";
|
|
ClientCompanyName = "";
|
|
ClientAddress = "";
|
|
ClientTel = "";
|
|
ClientFax = "";
|
|
ClientName = "";
|
|
ClientBankCard = "";
|
|
ClientBankName = "";
|
|
ClientLinkman = "";
|
|
OptionPremium = "";
|
|
InitialMargin = "";
|
|
TradeType = "";
|
|
Principle = "";
|
|
InitialSpotPrice = "";
|
|
Strike = "";
|
|
StrikePrice = "";
|
|
PremiumRate = "";
|
|
Premium = "";
|
|
Underlying = "";
|
|
StartDate = "";
|
|
ExerciseDate = "";
|
|
PremiumPayDate = "";
|
|
ContractVersion = "";
|
|
ValueDate = "";
|
|
ContractCode = "";
|
|
TradeCode = "";
|
|
TradeNumber = "";
|
|
UnderlyingCode = "";
|
|
UnderlyingName = "";
|
|
ExerciseType = "";
|
|
Notional = "";
|
|
TradeUnit = "";
|
|
QuoteUnit = "";
|
|
Market = "";
|
|
TradeDate = "";
|
|
Remark1 = "";
|
|
CallPut = "";
|
|
BuySell = "";
|
|
CallPutBuy = "";
|
|
StockEqvNotional = "";
|
|
TradeList = new List<ContractModel>();
|
|
}
|
|
|
|
public string FPCompanyName { get; set; }
|
|
public string FPAddress { get; set; }
|
|
public string FPTel { get; set; }
|
|
public string FPFax { get; set; }
|
|
public string FPName { get; set; }
|
|
public string FPBankCard { get; set; }
|
|
public string FPBankName { get; set; }
|
|
public string FPLinkman { get; set; }
|
|
public string FPEmail { get; set; }
|
|
|
|
public string SPCompanyName { get; set; }
|
|
public string SPAddress { get; set; }
|
|
public string SPTel { get; set; }
|
|
public string SPFax { get; set; }
|
|
public string SPName { get; set; }
|
|
public string SPBankCard { get; set; }
|
|
public string SPBankName { get; set; }
|
|
public string SPLinkman { get; set; }
|
|
public string SPEmail { get; set; }
|
|
|
|
public string ClientCompanyName { get; set; }
|
|
public string ClientAddress { get; set; }
|
|
public string ClientTel { get; set; }
|
|
public string ClientFax { get; set; }
|
|
public string ClientName { get; set; }
|
|
public string ClientBankCard { get; set; }
|
|
public string ClientBankName { get; set; }
|
|
public string ClientLinkman { get; set; }
|
|
public string ClientEmail { get; set; }
|
|
|
|
public string PayDate { get; set; }//渤海使用支付日
|
|
//期权费
|
|
public string OptionPremium { get; set; }
|
|
//初始预付金
|
|
public string InitialMargin { get; set; }
|
|
|
|
public string TradeType { get; set; }
|
|
public string TradeType2 { get; set; }
|
|
public string ExerciseType { get; set; }
|
|
public string Notional { get; set; }
|
|
public string TradeAmount { get; set; }
|
|
|
|
public string TradeQuantity { get; set; }
|
|
|
|
public string Principle { get; set; }
|
|
public string InitialSpotPrice { get; set; }
|
|
public string Strike { get; set; }
|
|
public string StrikePrice { get; set; }
|
|
public string PremiumRate { get; set; }
|
|
public string Premium { get; set; }
|
|
public string PremiumSingle { get; set; }
|
|
public string Underlying { get; set; }
|
|
public string StartDate { get; set; }
|
|
public string ExerciseDate { get; set; }
|
|
public string PremiumPayDate { get; set; }
|
|
public string ContractVersion { get; set; }
|
|
public string Formula { get { return "{(S-K)/S0,0}"; } }
|
|
public string ValueDate { get; set; }
|
|
public string ContractCode { get; set; }
|
|
public string TradeCode { get; set; }
|
|
public string TradeNumber { get; set; }
|
|
public string UnderlyingCode { get; set; }
|
|
public string UnderlyingName { get; set; }
|
|
public string TradeUnit { get; set; }
|
|
public string QuoteUnit { get; set; }
|
|
public string Market { get; set; }
|
|
public string ExchangeNo { get; set; }
|
|
public string TradeDate { get; set; }
|
|
public string Remark1 { get; set; }
|
|
public string Remark2 { get; set; }
|
|
public string CallPut { get; set; }
|
|
public string BuySell { get; set; }
|
|
public string CallPutBuy { get; set; }
|
|
|
|
public string StockEqvNotional { get; set; }
|
|
public string TotalPremium { get; set; }
|
|
public string TotalPrinciple { get; set; }
|
|
|
|
public string ExerciseDateDesc { get; set; }
|
|
public string ExerciseLabel1 { get; set; }
|
|
public string ExerciseDesc1 { get; set; }
|
|
public string ExerciseLabel2 { get; set; }
|
|
public string ExerciseDesc2 { get; set; }
|
|
|
|
public string SettlementInfo { get; set; }
|
|
|
|
public List<ContractModel> TradeList { get; set; }
|
|
}
|
|
|
|
public class TradeContractModeUtils
|
|
{
|
|
public Client FirstParty { get; set; }
|
|
public Client SecondParty { get; set; }
|
|
|
|
public TradeContractModeUtils(Client broker, Client client, string BuySell)
|
|
{
|
|
//交易确认书甲乙方模式
|
|
var TradeContractMode = valuedateBLL.SystemDate.TradeContractMode;
|
|
|
|
switch (TradeContractMode)
|
|
{
|
|
case valuedate.TradeContractModeSellerForFirst:
|
|
if ("买入".Equals(BuySell))
|
|
{
|
|
FirstParty = client;
|
|
SecondParty = broker;
|
|
}
|
|
else
|
|
{
|
|
FirstParty = broker;
|
|
SecondParty = client;
|
|
}
|
|
break;
|
|
case valuedate.TradeContractModeBuyerForFirst:
|
|
if ("买入".Equals(BuySell))
|
|
{
|
|
FirstParty = broker;
|
|
SecondParty = client;
|
|
}
|
|
else
|
|
{
|
|
FirstParty = client;
|
|
SecondParty = broker;
|
|
}
|
|
break;
|
|
case valuedate.TradeContractModeBrokerForFirst:
|
|
default:
|
|
FirstParty = broker;
|
|
SecondParty = client;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
public enum TradeConfirmContractMode
|
|
{
|
|
单笔模式,
|
|
单客户同日,
|
|
单客户同日同类型,
|
|
单客户同日同类型同方向
|
|
}
|
|
|
|
public class TradeConfirmContractGroupModel
|
|
{
|
|
public int ClientId { get; set; }
|
|
public DateTime ValueDate { get; set; }
|
|
public string UnderlyingType { get; set; }
|
|
public string BuySell { get; set; }
|
|
|
|
public string UnderlyingTypeShort
|
|
{
|
|
get
|
|
{
|
|
return UnderlyingType == "Stock" ? "STO" : "FUT";
|
|
}
|
|
}
|
|
}
|
|
}
|