从山证v2.3.0拷贝
This commit is contained in:
@@ -0,0 +1,559 @@
|
||||
using YLErp.BLL;
|
||||
using YLErp.DBModels.Consts;
|
||||
using YLErp.Model;
|
||||
using YLErp.Models;
|
||||
using YLErp.Modules.ClientModule;
|
||||
using YLErp.Modules.TradeDalModule;
|
||||
using YLErp.MsOffice;
|
||||
using YLErp.Office.Converters;
|
||||
using YLErp.Plugins.TradeDocGenerator.Abstracts;
|
||||
|
||||
namespace YLErp.Modules.TradeModule.DocGenerateModule
|
||||
{
|
||||
/// <summary>
|
||||
/// 生成交易确认书
|
||||
/// </summary>
|
||||
public class BatchConfirmationGenerateService : YLBaseService
|
||||
{
|
||||
public BatchConfirmationGenerateService(OptUserInfo userInfo) : base(userInfo)
|
||||
{
|
||||
}
|
||||
|
||||
public BatchConfirmationGenerateService(YLBaseService baseService) : base(baseService)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 生成交易确认书
|
||||
/// </summary>
|
||||
public IEnumerable<TradeDocGenerateResult> Generate(IEnumerable<int> tradeIds, string docType, DateTime? startDate = null, DateTime? endDate = null)
|
||||
{
|
||||
if (tradeIds == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(tradeIds));
|
||||
}
|
||||
|
||||
if (docType == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(docType));
|
||||
}
|
||||
|
||||
//----------------------------------
|
||||
// 获取当日行权 平仓 到期的有效交易
|
||||
//----------------------------------
|
||||
var statusList = new List<string>() {
|
||||
ConsTrade.确认成交
|
||||
};
|
||||
if (GlobalConfig.EnableGenerateOnTradeClosed)
|
||||
{
|
||||
statusList.Add(ConsTrade.已到期);
|
||||
statusList.Add(ConsTrade.已平仓);
|
||||
statusList.Add(ConsTrade.已执行);
|
||||
}
|
||||
var service = new TradeDalService(this);
|
||||
//var tradeQuery = service
|
||||
// .GetTradeOrEodTrade(tradeIds, ValueDate, true)
|
||||
// .Where(O =>
|
||||
// statusList.Contains(O.TradeStatus)
|
||||
// && (O.ParentTradeId == null || O.ParentTradeId < 1)
|
||||
// && O.ClientId != null);
|
||||
|
||||
//var tradeQuery = from trad in DbContext.trade
|
||||
// where tradeIds.Contains(trad.id)
|
||||
// && statusList.Contains(trad.TradeStatus)
|
||||
// && trad.ValidState != "InValid" && trad.ClientId != null
|
||||
// && (trad.ParentTradeId == null || trad.ParentTradeId < 1)
|
||||
// select trad;
|
||||
|
||||
//----------------------------------
|
||||
// 交易现金交割记录
|
||||
//----------------------------------
|
||||
var allTrades = service.GetTradeOrEodTradeOfTidASid(tradeIds, SystemValueDate);
|
||||
|
||||
//只选中一笔子交易,按一笔子交易生成确认书
|
||||
if (PS.Config.Is润和)
|
||||
{
|
||||
allTrades.RemoveAll(x => x.ParentTradeId != 0 && !tradeIds.Contains(x.id));
|
||||
}
|
||||
|
||||
//收益互换剔除子交易
|
||||
if (allTrades.Any(t => t.TradeType == "收益互换"))
|
||||
{
|
||||
allTrades.RemoveAll(t => t.TradeType == "收益互换" && t.ParentTradeId != 0 && !tradeIds.Contains(t.id));
|
||||
}
|
||||
|
||||
//处理黑盒分组
|
||||
var ids = allTrades.Where(x => x.IsGroup == 1 && x.TradeType != "收益互换").Select(x => x.id);
|
||||
var BackTradelist = new TradeDalService(this).GetTradeOrEodTradeOfTidAPid(ids, SystemValueDate, false, false).Where(c => c.TradeType != "结构化交易");
|
||||
allTrades.AddRange(BackTradelist);
|
||||
|
||||
if (PS.Config.Is国泰君安)//历史数据的雪球都只有看跌会选择错模板
|
||||
{
|
||||
var snowids = allTrades.Where(x => x.TradeType == "雪球期权").Select(x => x.id);
|
||||
var tradeoptype = DbContext.trade.Where(x => snowids.Contains(x.id) && x.TradeType == "雪球期权").Select(x => new { x.id, x.OptionType }).ToList();
|
||||
allTrades.ForEach(x =>
|
||||
{
|
||||
if (x.TradeType == "雪球期权")
|
||||
{
|
||||
x.OptionType = tradeoptype.Where(o => o.id == x.id).FirstOrDefault().OptionType;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
var tradeDic = allTrades.Where(O =>
|
||||
statusList.Contains(O.TradeStatus)
|
||||
&& O.ClientId != 0
|
||||
&& O.ParentTradeId == 0)
|
||||
.ToDictionary(n => n.id, n => new trade_contract_group { trade = n });
|
||||
tradeIds = allTrades.Select(O => O.id);
|
||||
|
||||
var cashQuery = from tradeCash in DbContext.trade_cash
|
||||
where tradeIds.Contains(tradeCash.TradeId) && tradeCash.ValidState != ConsGlobal.InValid && !tradeCash.IsDeleted
|
||||
&& tradeCash.Action == ClientCashInCashOut.系统操作_期权费
|
||||
select tradeCash;
|
||||
var cashDatas = cashQuery.ToDictionary(K => K.TradeId, V => V);
|
||||
if (tradeDic.Count < 1 || cashDatas.Count < 1)
|
||||
{
|
||||
throw new ServiceException("没有已确认的记录信息!");
|
||||
}
|
||||
trade_cash cash = null;
|
||||
foreach (var item in tradeDic.Values)
|
||||
{
|
||||
if (item.trade.TradeType == "结构化交易")
|
||||
{
|
||||
//item.trade.SubTrades = DbContext.trade.Where(O => O.ParentTradeId == item.trade.id).ToList();
|
||||
item.trade.SubTrades = allTrades.Where(O => O.ParentTradeId == item.trade.id).ToList();
|
||||
var cashTig = new List<string>();
|
||||
foreach (var t in item.trade.SubTrades)
|
||||
{
|
||||
if (cashDatas.TryGetValue(t.id, out cash))
|
||||
{
|
||||
t.trade_cash = cash;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception("子交易未确认成交");
|
||||
}
|
||||
}
|
||||
if (cashDatas.TryGetValue(item.trade.id, out cash))
|
||||
{
|
||||
item.trade_cash = cash;
|
||||
item.trade.trade_cash = cash;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (item.trade.TradeType == "累计期权")
|
||||
{
|
||||
new OptionTradeActionRestoreService(this).RestoreTradeDataToSpecialDay(item.trade, item.trade.TradeDate.Value);
|
||||
}
|
||||
|
||||
if (cashDatas.TryGetValue(item.trade.id, out cash))
|
||||
{
|
||||
item.trade_cash = cash;
|
||||
item.trade.trade_cash = cash;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------
|
||||
// 生成交易确认书
|
||||
//----------------------------------
|
||||
|
||||
var resultList = new List<TradeDocGenerateResult>();
|
||||
|
||||
AppManager.TryResolve(out ITradeConfirmationGenerator generatorV2);
|
||||
|
||||
var tradeContractGroupTradeIds = tradeDic.Values.Select(x => x.trade.id).ToList();
|
||||
//var childs = DbContext.trade.Where(x => tradeContractGroupTradeIds.Contains(x.ParentTradeId ?? 0));
|
||||
//var childs = service.GetStructTradeFromTradeOrEodTrade(tradeContractGroupTradeIds, ValueDate);
|
||||
if (generatorV2 != null)
|
||||
{
|
||||
var result = GenerateSingleV2(
|
||||
generatorV2,
|
||||
tradeDic.Values.Select(O => O.trade).ToList(),
|
||||
tradeDic.Values.Select(O => (O.trade.trade_cash?.id) ?? 0).ToList(),
|
||||
docType,
|
||||
startDate,
|
||||
endDate);
|
||||
|
||||
resultList.Add(result);
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var item in tradeDic)
|
||||
{
|
||||
resultList.Add(GenerateSingleV1(item.Value, docType));
|
||||
}
|
||||
}
|
||||
if (generatorV2 == null)
|
||||
{
|
||||
DbContext.SaveChanges();
|
||||
}
|
||||
|
||||
return resultList;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
private TradeDocGenerateResult GenerateSingleV2(ITradeConfirmationGenerator generator, List<trade> trades, List<int> tradeCashIds, string docType = "DOCX", DateTime? startDate = null, DateTime? endDate = null)
|
||||
{
|
||||
try
|
||||
{
|
||||
var context = new ConfirmationGenerateContext(tradeCashIds, trades, ContractTypeEnum.Trade, OptUser, startDate, endDate);
|
||||
generator.Initialize(docType, context);
|
||||
return generator.GenerateDocument();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogFactory.GetLogger("GenerateSingleV2").Error(ex);
|
||||
|
||||
return new TradeDocGenerateResult(trades)
|
||||
{
|
||||
ErrorMessage = ex.Message
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
private TradeDocGenerateResult GenerateSingleV1(trade_contract_group contractGroup, string docType = "DOCX")
|
||||
{
|
||||
if (contractGroup == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(contractGroup));
|
||||
}
|
||||
|
||||
var contractBLL = new TradeContractBLL(this);
|
||||
var trade = contractGroup.trade;
|
||||
tradeBLL.SetFieldsByTradeType(trade);
|
||||
var needAddData = true;
|
||||
|
||||
#region 如果之前交易确认书已经生成过,则直接返回
|
||||
|
||||
var confirmDoc = contractBLL.GetContractDoc(trade.id, ContractTypeEnum.Trade);
|
||||
if (confirmDoc != null)
|
||||
{
|
||||
if (File.Exists(confirmDoc.AbsolutePath))
|
||||
{
|
||||
if (docType == "PDF")
|
||||
{
|
||||
var pdfPath = confirmDoc.AbsolutePath.Replace(".docx", ".pdf");
|
||||
if (!File.Exists(pdfPath))
|
||||
{
|
||||
OfficeFileConverter.ConvertDocxToPDF(confirmDoc.AbsolutePath, pdfPath);
|
||||
}
|
||||
|
||||
return new TradeDocGenerateResult(trade)
|
||||
{
|
||||
//OutputFilePath = $"/App_Docs/GTJA/{confirmDoc.FileName.Replace(".doc", ".pdf")}"
|
||||
OutputFilePath = YLErp.Helpers.PathHelper.PhysicalPathToWebPath(pdfPath, OtcAppContext.RootPath)
|
||||
};
|
||||
}
|
||||
|
||||
return new TradeDocGenerateResult(trade)
|
||||
{
|
||||
//OutputFilePath = $"/App_Docs/GTJA/{confirmDoc.FileName}"
|
||||
OutputFilePath = YLErp.Helpers.PathHelper.PhysicalPathToWebPath(confirmDoc.AbsolutePath, OtcAppContext.RootPath)
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
needAddData = false;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
var isGJBuyer = trade.BuySell == "买入";
|
||||
|
||||
var underlying = underlying_managerBLL.GetByCode(trade.UnderlyingCode);
|
||||
if (underlying == null)
|
||||
{
|
||||
return new TradeDocGenerateResult(trade)
|
||||
{
|
||||
ErrorMessage = $"标的资产{trade.UnderlyingCode}信息未找到"
|
||||
};
|
||||
}
|
||||
|
||||
var client = DataCacheProvider.GetClientDataSource().GetData(trade.ClientId);
|
||||
if (client == null)
|
||||
{
|
||||
return new TradeDocGenerateResult(trade)
|
||||
{
|
||||
ErrorMessage = $"客户{trade.ClientId}信息未找到"
|
||||
};
|
||||
}
|
||||
|
||||
var dic = new Dictionary<string, object>
|
||||
{
|
||||
["{{乙方名称}}"] = client.Name
|
||||
};
|
||||
|
||||
if (isGJBuyer)
|
||||
{
|
||||
dic["{{甲方方向}}"] = "买方";
|
||||
dic["{{乙方方向}}"] = "卖方";
|
||||
}
|
||||
else
|
||||
{
|
||||
dic["{{甲方方向}}"] = "卖方";
|
||||
dic["{{乙方方向}}"] = "买方";
|
||||
}
|
||||
|
||||
|
||||
dic["{{交易日}}"] = trade.TradeDate?.ToString("yyyy年M月d日");
|
||||
if (trade.TradeType == "香草期权" || trade.TradeType == "亚式期权")
|
||||
{
|
||||
dic["{{生效日}}"] = trade.TradeDate?.ToString("yyyy年M月d日");
|
||||
}
|
||||
else
|
||||
{
|
||||
dic["{{生效日}}"] = trade.StartDate?.ToString("yyyy年M月d日");
|
||||
}
|
||||
if (trade.TradeType == "亚式期权")
|
||||
{
|
||||
dic["{{均价起算日}}"] = trade.trade_asian_option.AveragingPeriodStartDate?.ToString("yyyy年M月d日");
|
||||
dic["{{奇异结构}}"] = $"{trade.trade_asian_option.StrikeTypeCn}的{trade.trade_asian_option.PayoffTypeCn}亚式";
|
||||
}
|
||||
dic["{{到期日}}"] = trade.ExerciseDate?.ToString("yyyy年M月d日");
|
||||
dic["{{行权日}}"] = "到期日";
|
||||
|
||||
dic["{{自动行权}}"] = "到期实值自动行权";
|
||||
|
||||
//商品标的
|
||||
|
||||
if (trade.TradeType == "合成价差期权")
|
||||
{
|
||||
dic["{{商品标的名称}}"] = synthetic_underlyingBLL.GetUnderlyingTipsInfo(trade.UnderlyingCode);
|
||||
}
|
||||
else
|
||||
{
|
||||
dic["{{商品标的名称}}"] = trade.UnderlyingCode;
|
||||
}
|
||||
|
||||
var strUnit = underlying.TradeUnitString;
|
||||
var notional = trade.Notional;
|
||||
|
||||
dic["{{报价单位}}"] = strUnit;
|
||||
dic["{{商品标的数量}}"] = $"{notional}{strUnit}";
|
||||
dic["{{商品标的交易所}}"] = underlying.MarketName;
|
||||
|
||||
//价格
|
||||
if (trade.ActualStrike != null)
|
||||
{
|
||||
if (trade.IsMoneynessOption == "是")
|
||||
{
|
||||
dic["{{执行价格}}"] = (trade.Strike ?? 0).OtcFormatUmPrice(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
dic["{{执行价格}}"] = $"{trade.ActualStrike?.OtcFormatUmPrice()}元/{strUnit}";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
dic["{{执行价格}}"] = "不适用";
|
||||
}
|
||||
|
||||
var tradeType = trade.TradeType == "香草期权" ? "普通" : (trade.TradeType == "结构化交易" ? trade.StructureType : trade.TradeType.Replace("期权", ""));
|
||||
dic["{{期权类型}}"] = $"{trade.ExerciseModeCn}{tradeType}{trade.OptionType}期权";
|
||||
|
||||
dic["{{期权费}}"] = $"{(trade.TradePrice ?? 0).OtcFormatMoney(grouping: false)}元";
|
||||
dic["{{协议编号}}"] = client.Remark;
|
||||
|
||||
dic["{{期权价格}}"] = $"{(trade.TradeSinglePrice ?? 0).OtcFormat(OtcFormatFlag.tradeSinglePrice)}元/{strUnit}";
|
||||
dic["{{支付时间}}"] = trade.PremiumPayDate != null ? "提前终止/到期时支付" : "已支付";
|
||||
|
||||
dic["{{期权方向}}"] = $"甲方{trade.BuySell}";
|
||||
dic["{{名义本金}}"] = trade.StockEqvNotional.OtcFormat(OtcFormatFlag.StockEqvNotional);
|
||||
dic["{{期初价格}}"] = (trade.SpotPrice ?? 0).OtcFormatUmPrice();
|
||||
dic["{{期权费率}}"] = ((trade.PremiumRate ?? ((trade.TradePrice ?? 0) / trade.OriginalStockEqvNotional.Value)) * 100).OtcFormatFlex(2);
|
||||
|
||||
var settlementType = "价格";
|
||||
if (trade.SettlementType == SettlementTypeEnum.SettlePrice)
|
||||
{
|
||||
settlementType = "结算价";
|
||||
}
|
||||
else if (trade.SettlementType == SettlementTypeEnum.ClosePrice)
|
||||
{
|
||||
settlementType = "收盘价";
|
||||
}
|
||||
|
||||
if (trade.ExerciseMode == "American")
|
||||
{
|
||||
dic["{{美式期权结算价}}"] = $"所属交易所公布的标的合约可成交的最新价";
|
||||
dic["{{欧式期权结算价}}"] = $"美式期权不适用";
|
||||
}
|
||||
else
|
||||
{
|
||||
dic["{{美式期权结算价}}"] = $"欧式期权不适用";
|
||||
dic["{{欧式期权结算价}}"] = $"所属交易所在到期日收盘后公布的标的合约{settlementType}";
|
||||
}
|
||||
|
||||
if (trade.UnderlyingInstrumentType != "CommodityFutures")
|
||||
{
|
||||
dic["{{证券名称}}"] = underlying.UnderlyingName;
|
||||
dic["{{证券代码}}"] = underlying.UnderlyingCode;
|
||||
|
||||
dic["{{账户信息乙方}}"] = client.Name;
|
||||
dic["{{联系方式乙方}}"] = client.Name;
|
||||
dic["{{联系方式乙方联系人}}"] = client.Name;
|
||||
dic["{{联系方式乙方电话}}"] = client.Phone;
|
||||
dic["{{联系方式乙方电子邮件}}"] = client.Email;
|
||||
|
||||
var bankcard = ClientDataQueryService.GetBankCard(trade.ClientId);
|
||||
if (bankcard != null)
|
||||
{
|
||||
dic["{{账户信息乙方户名}}"] = bankcard.ClientName;
|
||||
dic["{{账户信息乙方账号}}"] = bankcard.Card;
|
||||
dic["{{账户信息乙方开户行}}"] = bankcard.Bank;
|
||||
}
|
||||
|
||||
dic["{{期权方向}}"] = $"甲方{trade.BuySell}";
|
||||
dic["{{名义本金}}"] = trade.StockEqvNotional.OtcFormat(OtcFormatFlag.StockEqvNotional);
|
||||
}
|
||||
|
||||
if (trade.OptionType == "看涨")
|
||||
{
|
||||
if (trade.ExerciseMode == "American")
|
||||
{
|
||||
dic["{{美式期权结算金额}}"] =
|
||||
$"(行权时{trade.UnderlyingCode}合约可成交最新价 - {trade.ActualStrike.OtcFormatUmPrice()})× {notional.OtcFormatNotional()}";
|
||||
dic["{{欧式期权结算金额}}"] = $"美式期权不适用";
|
||||
}
|
||||
else
|
||||
{
|
||||
dic["{{美式期权结算金额}}"] = $"欧式期权不适用";
|
||||
dic["{{欧式期权结算金额}}"] =
|
||||
$"({trade.ExerciseDate?.ToString("yyyy年M月d日")}{trade.UnderlyingCode}合约{settlementType} - {trade.ActualStrike.OtcFormatUmPrice()})× {notional.OtcFormatNotional()}";
|
||||
}
|
||||
}
|
||||
else if (trade.OptionType == "看跌")
|
||||
{
|
||||
if (trade.ExerciseMode == "American")
|
||||
{
|
||||
dic["{{美式期权结算金额}}"] =
|
||||
$"({trade.ActualStrike.OtcFormatUmPrice()} - 行权时{trade.UnderlyingCode}合约可成交最新价)× {notional.OtcFormatNotional()}";
|
||||
dic["{{欧式期权结算金额}}"] = $"美式期权不适用";
|
||||
}
|
||||
else
|
||||
{
|
||||
dic["{{美式期权结算金额}}"] = $"欧式期权不适用";
|
||||
dic["{{欧式期权结算金额}}"] =
|
||||
$"({trade.ActualStrike.OtcFormatUmPrice()} - {trade.ExerciseDate?.ToString("yyyy年M月d日")}{trade.UnderlyingCode}合约{settlementType})× {notional.OtcFormatNotional()}";
|
||||
}
|
||||
}
|
||||
|
||||
//合同编号
|
||||
string contractNo;
|
||||
string outPutFileName;
|
||||
if (confirmDoc != null)
|
||||
{
|
||||
contractNo = confirmDoc.Code;
|
||||
outPutFileName = confirmDoc.FileName;
|
||||
}
|
||||
else
|
||||
{
|
||||
var contractIndex = contractBLL.GetContractNo("GTJA");
|
||||
if (PS.Config.CompanyID == "中财资本")
|
||||
{
|
||||
contractNo = $"{trade.TradeNumber}";
|
||||
}
|
||||
else
|
||||
{
|
||||
contractNo = $"{client.Number}C{contractIndex}";
|
||||
}
|
||||
outPutFileName = $"{client.Name}交易确认书C{contractIndex}.docx";
|
||||
}
|
||||
dic["{{合同编号}}"] = contractNo;
|
||||
dic["{{结算方式}}"] = "人民币现金结算";
|
||||
dic["{{补充}}"] = "补充";
|
||||
|
||||
try
|
||||
{
|
||||
var templateDir = OtcAppContext.MapPath("~/App_Docs/GTJA");
|
||||
var templatePath = OtcAppContext.MapPath("~/App_Docs/导出模板/交易确认书模板.docx");
|
||||
if (trade.TradeType == "亚式期权")
|
||||
{
|
||||
templatePath = OtcAppContext.MapPath("~/App_Docs/导出模板/交易确认书(亚式期权)模板.docx");
|
||||
}
|
||||
|
||||
if (trade.IsUsePremiumRate != null && trade.IsUsePremiumRate.Value)
|
||||
{
|
||||
templatePath = OtcAppContext.MapPath("~/App_Docs/导出模板/交易确认书(名义本金)模板.docx");
|
||||
}
|
||||
|
||||
LogFactory.GetLogger("交易确认书").Info("交易确认书:" + outPutFileName);
|
||||
|
||||
var outPutFilePath = Path.Combine(templateDir, outPutFileName);
|
||||
|
||||
MsWordTempalteHelper.GenerateFromTemplate(templatePath, dic, outPutFilePath);
|
||||
|
||||
if (docType == "PDF" && !outPutFilePath.EndsWith(".pdf", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
OfficeFileConverter.ConvertDocxToPDF(outPutFilePath, outPutFilePath.Replace(".docx", ".pdf"));
|
||||
}
|
||||
|
||||
//更新操作时间
|
||||
var now = DateTime.Now;
|
||||
File.SetLastAccessTime(outPutFilePath, now);
|
||||
|
||||
#region --- Add trade_contract_document and trade_contract_r records
|
||||
|
||||
if (needAddData)
|
||||
{
|
||||
contractBLL.DeleteConfirmBook(trade.id, null);
|
||||
|
||||
var nowDate = DateTime.Now;
|
||||
|
||||
var contractRecord = new trade_contract_document();
|
||||
DbContext.trade_contract_document.Add(contractRecord);
|
||||
contractRecord.Code = dic["{{合同编号}}"].ToString();
|
||||
contractRecord.ValueDate = valuedateBLL.ValueDate;
|
||||
contractRecord.BuyerId = isGJBuyer ? 0 : trade.ClientId;
|
||||
contractRecord.BuyerName = isGJBuyer ? PS.Config.CompanyFullName : trade.ClientName;
|
||||
contractRecord.SellerId = isGJBuyer ? trade.ClientId : 0;
|
||||
contractRecord.SellerName = isGJBuyer ? trade.ClientName : PS.Config.CompanyFullName;
|
||||
contractRecord.FileType = FileTypeEnum.Word;
|
||||
contractRecord.Status = ContractStatusEnum.Draft;
|
||||
contractRecord.Paths = $"App_Docs\\GTJA\\{outPutFileName}";
|
||||
contractRecord.FileName = outPutFileName;
|
||||
contractRecord.Type = ContractTypeEnum.Trade;
|
||||
contractRecord.OptId = UserId;
|
||||
contractRecord.OptName = UserName;
|
||||
contractRecord.OptDate = nowDate;
|
||||
|
||||
var contractTradeRelation = new trade_contract_r();
|
||||
DbContext.trade_contract_r.Add(contractTradeRelation);
|
||||
contractTradeRelation.TradeId = trade.id;
|
||||
contractTradeRelation.TradeNumber = trade.TradeNumber;
|
||||
contractTradeRelation.ContractCode = contractRecord.Code;
|
||||
contractTradeRelation.Type = ContractTypeEnum.Trade;
|
||||
contractTradeRelation.OptId = UserId;
|
||||
contractTradeRelation.OptName = UserName;
|
||||
contractTradeRelation.OptDate = nowDate;
|
||||
contractTradeRelation.TradeCashId = contractGroup.trade_cash == null ? 0 : contractGroup.trade_cash.id;
|
||||
contractTradeRelation.IsValid = true;
|
||||
|
||||
DbContext.SaveChanges();
|
||||
}
|
||||
|
||||
#endregion --- Add trade_contract_document and trade_contract_r records
|
||||
|
||||
return new TradeDocGenerateResult(trade)
|
||||
{
|
||||
OutputFilePath = $"/App_Docs/GTJA/{(docType == "PDF" ? outPutFileName.Replace(".docx", ".pdf") : outPutFileName)}"
|
||||
};
|
||||
}
|
||||
|
||||
catch (Exception e)
|
||||
{
|
||||
LogFactory.GetLogger<ConfirmationGenerateService>().Error("GenerateSingleConfirmBook出错", e);
|
||||
return new TradeDocGenerateResult(trade) { ErrorMessage = e.Message };
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,474 @@
|
||||
using System.Text.RegularExpressions;
|
||||
using YLErp.BLL;
|
||||
using YLErp.BLL.MarginCalculation;
|
||||
using YLErp.DBModels.Consts;
|
||||
using YLErp.DBModels.Converts;
|
||||
using YLErp.Model;
|
||||
using YLErp.Models;
|
||||
using YLErp.Modules.DataProviderModule;
|
||||
using YLErp.Modules.TradeDalModule;
|
||||
using YLErp.MsOffice;
|
||||
using YLErp.Office.Converters;
|
||||
using YLErp.Plugins.TradeDocGenerator.Abstracts;
|
||||
|
||||
namespace YLErp.Modules.TradeModule.DocGenerateModule
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public class BatchSettlementBillGenerateService : YLBaseService
|
||||
{
|
||||
public BatchSettlementBillGenerateService(OptUserInfo userInfo) : base(userInfo)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 生成结算确认书
|
||||
/// </summary>
|
||||
public IEnumerable<TradeDocGenerateResult> Generate(IEnumerable<int> tradeCashIds, IEnumerable<int> tradeIds, string docType, int userId, string userName)
|
||||
{
|
||||
if (tradeCashIds != null && tradeCashIds.Any())
|
||||
{
|
||||
tradeIds = DbContext.trade_cash.Where(x => tradeCashIds.Contains(x.id) && !x.IsDeleted).Select(x => x.TradeId).Distinct();
|
||||
}
|
||||
if (tradeIds == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(tradeIds));
|
||||
}
|
||||
if (docType == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(docType));
|
||||
}
|
||||
|
||||
//当前交易日
|
||||
var valueDate = valuedateBLL.ValueDate;
|
||||
var tradeStatus = new string[] { ConsTrade.已到期, ConsTrade.已执行 };
|
||||
var tradeCashStatus = new string[] { ClientCashInCashOut.系统操作_行权费 };
|
||||
|
||||
//----------------------------------
|
||||
// 获取当日行权 平仓 到期的有效交易
|
||||
//----------------------------------
|
||||
var service = new TradeDalService(this);
|
||||
var tradeQuery = service
|
||||
.GetTradeOrEodTrade(tradeIds, valueDate)
|
||||
.Where(O =>
|
||||
tradeStatus.Contains(O.TradeStatus)
|
||||
&& O.UnWindDate <= valueDate
|
||||
&& O.ClientId != 0);
|
||||
//var tradeQuery = from trade in Table
|
||||
// where tradeIds.Contains(trade.id)
|
||||
// && tradeStatus.Contains(trade.TradeStatus) && trade.ValidState != "InValid"
|
||||
// && trade.UnWindDate <= valueDate && trade.ClientId != null
|
||||
// select trade;
|
||||
|
||||
var tradeDic = tradeQuery.ToDictionary(n => n.id, n => new trade_contract_group { trade = n });
|
||||
if (tradeDic.Count < 1)
|
||||
{
|
||||
throw new ServiceException("当日没有要结算的记录信息!");
|
||||
}
|
||||
|
||||
tradeIds = tradeDic.Keys.ToArray();
|
||||
var parentTradeIds = tradeDic.Values.Where(O => O.trade != null && O.trade.ParentTradeId != 0).ToDictionary(K => K.trade.id, V => V.trade.ParentTradeId);
|
||||
var parentTrades = service
|
||||
.GetTradeOrEodTrade(parentTradeIds.Values, valueDate)
|
||||
.Where(O =>
|
||||
tradeStatus.Contains(O.TradeStatus)
|
||||
&& O.UnWindDate <= valueDate
|
||||
&& O.ClientId != 0)
|
||||
.ToDictionary(K => K.id, V => V);
|
||||
//var parentTrades = (from trade in Table
|
||||
// where parentTradeIds.Values.Contains(trade.id)
|
||||
// && tradeStatus.Contains(trade.TradeStatus)
|
||||
// && trade.ValidState != "InValid"
|
||||
// && trade.UnWindDate <= valueDate
|
||||
// && trade.ClientId != null
|
||||
// select trade).ToDictionary(K => K.id, V => V);
|
||||
|
||||
//----------------------------------
|
||||
// 交易确认书数据
|
||||
//----------------------------------
|
||||
var tcrQuery = from aa in DbContext.trade_contract_r
|
||||
where (tradeIds.Contains(aa.TradeId)
|
||||
|| parentTradeIds.Values.Contains(aa.TradeId))
|
||||
&& aa.Type == ContractTypeEnum.Trade && aa.IsValid
|
||||
select aa;
|
||||
var tcrDatas = tcrQuery.ToDictionary(K => K.TradeId, V => V);
|
||||
foreach (var data in tradeDic)
|
||||
{
|
||||
var id = data.Key;
|
||||
if (data.Value.trade.ParentTradeId != 0)
|
||||
{ id = data.Value.trade.ParentTradeId; }
|
||||
if (tcrDatas.TryGetValue(id, out var tcr))
|
||||
{ data.Value.ConfirmContractR = tcr; }
|
||||
}
|
||||
|
||||
//----------------------------------
|
||||
// 交易现金交割记录
|
||||
//----------------------------------
|
||||
var cashQuery = from tradeCash in DbContext.trade_cash
|
||||
where tradeIds.Contains(tradeCash.TradeId) &&
|
||||
tradeCash.ValidState != ConsGlobal.InValid && !tradeCash.IsDeleted
|
||||
&& tradeCashStatus.Contains(tradeCash.Action)
|
||||
&& tradeCash.ExerciseWay == TradeCashExerciseWayEnum.到期行权
|
||||
select tradeCash;
|
||||
var cashDatas = cashQuery.ToDictionary(K => K.TradeId, V => V);
|
||||
foreach (var data in cashDatas)
|
||||
{
|
||||
if (tradeDic.TryGetValue(data.Value.TradeId, out var group))
|
||||
{
|
||||
if (parentTradeIds.ContainsKey(data.Value.TradeId))
|
||||
{
|
||||
var id = parentTradeIds[data.Value.TradeId];
|
||||
//var subTrades = (from t in DbContext.trade where t.ParentTradeId == id select t).GroupBy(O => O.TradeStatus).ToDictionary(K => K.Key, V => V.ToList());
|
||||
var subTrades = service.GetStructTradeFromTradeOrEodTrade(new[] { id }, valueDate).GroupBy(O => O.TradeStatus).ToDictionary(K => K.Key, V => V.ToList());
|
||||
tradeIds = subTrades.First().Value.Select(O => O.id).ToArray();
|
||||
var cashes = cashQuery.GroupBy(O => new { O.ValueDate, O.Action, O.ExerciseWay, O.Notional, O.UnwindNotional }).ToDictionary(K => K.Key, V => V.ToList());
|
||||
if (subTrades.Count == 1 && cashes.Count == 1)
|
||||
{
|
||||
subTrades.First().Value.ForEach(O => O.trade_cash = cashes.First().Value.First(B => B.TradeId == O.id));
|
||||
group.trade = parentTrades[group.trade.ParentTradeId];
|
||||
group.trade.SubTrades = subTrades.First().Value;
|
||||
}
|
||||
}
|
||||
group.trade.trade_cash = data.Value;
|
||||
group.trade_cash = data.Value;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//----------------------------------
|
||||
// 生成交易结算书
|
||||
//----------------------------------
|
||||
var resultList = new List<TradeDocGenerateResult>();
|
||||
AppManager.TryResolve(out ITradeSettleBillGenerator generatorV2);
|
||||
|
||||
//客户编号列表
|
||||
foreach (var tradeContractGroup in tradeDic.Values)
|
||||
{
|
||||
if ((tradeContractGroup.trade.TradeType != "结构化交易" && tradeContractGroup.trade.TradeStatus == ConsTrade.已执行 && tradeContractGroup.trade_cash == null)
|
||||
|| (tradeContractGroup.trade.TradeType == "结构化交易" && tradeContractGroup.trade.IsGroup == 0 && tradeContractGroup.trade.SubTrades.Any(O => O.trade_cash == null)))
|
||||
{
|
||||
resultList.Add(new TradeDocGenerateResult(tradeContractGroup.trade)
|
||||
{
|
||||
ErrorMessage = "缺少现金交割记录"
|
||||
});
|
||||
}
|
||||
}
|
||||
if (generatorV2 != null)
|
||||
{
|
||||
var result = GenerateSingleV2(generatorV2, tradeDic.Values.Select(O => O.trade).ToList(), tradeCashIds, docType);
|
||||
resultList.Add(result);
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var item in tradeDic)
|
||||
{
|
||||
resultList.Add(GenerateSingleV1(item.Value, OptUser.UserId, OptUser.UserName, docType));
|
||||
}
|
||||
}
|
||||
|
||||
return resultList;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
internal TradeDocGenerateResult GenerateSingleV2(ITradeSettleBillGenerator generator, List<trade> trades, IEnumerable<int> tradeCashIds, string docType = "DOCX", DateTime? startDate = null, DateTime? endDate = null)
|
||||
{
|
||||
try
|
||||
{
|
||||
var context = new SettlementBillGenerateContext(
|
||||
tradeCashIds,
|
||||
trades,
|
||||
ContractTypeEnum.Clearing, OptUser, startDate, endDate);
|
||||
generator.Initialize(docType, context);
|
||||
return generator.GenerateDocument();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogFactory.GetLogger<BatchSettlementBillGenerateService>().Error("GenerateSingleV2", ex);
|
||||
|
||||
return new TradeDocGenerateResult(trades)
|
||||
{
|
||||
Exception = ex,
|
||||
ErrorMessage = "出错:" + ex.Message
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
internal TradeDocGenerateResult GenerateSingleV1(trade_contract_group contractGroup, int userId, string userName, string docType = "DOCX")
|
||||
{
|
||||
if (contractGroup == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(contractGroup));
|
||||
}
|
||||
|
||||
var contractBLL = new TradeContractBLL(this);
|
||||
var dic = new Dictionary<string, object>();
|
||||
var trade = contractGroup.trade;
|
||||
var tradeCash = contractGroup.trade_cash;
|
||||
var tradeContractR = contractGroup.ConfirmContractR;
|
||||
if (tradeContractR == null)
|
||||
{
|
||||
throw new Exception(contractGroup.trade.TradeNumber + "该笔交易未生成交易确认书");
|
||||
}
|
||||
var needAddData = true;
|
||||
|
||||
#region 如果到期结算单已经生成过,则直接返回
|
||||
var settlementDoc = contractBLL.GetContractDoc(trade.id, ContractTypeEnum.Clearing);
|
||||
if (settlementDoc != null)
|
||||
{
|
||||
if (File.Exists(settlementDoc.AbsolutePath))
|
||||
{
|
||||
if (docType == "PDF")
|
||||
{
|
||||
var pdfPath = settlementDoc.AbsolutePath.Replace(".docx", ".pdf");
|
||||
if (!File.Exists(pdfPath))
|
||||
{
|
||||
OfficeFileConverter.ConvertDocxToPDF(settlementDoc.AbsolutePath, pdfPath);
|
||||
}
|
||||
return new TradeDocGenerateResult(trade)
|
||||
{
|
||||
OutputFilePath = $"../App_Docs/GTJA/{settlementDoc.FileName.Replace(".docx", ".pdf")}"
|
||||
};
|
||||
}
|
||||
|
||||
return new TradeDocGenerateResult(trade)
|
||||
{
|
||||
OutputFilePath = $"../App_Docs/GTJA/{settlementDoc.FileName}"
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
needAddData = false;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
var underlying = DataCacheProvider.GetUnderlyingDataSource().GetData(trade.UnderlyingCode); ;
|
||||
if (underlying == null)
|
||||
{
|
||||
return new TradeDocGenerateResult(trade)
|
||||
{
|
||||
ErrorMessage = $"标的资产{trade.UnderlyingCode}信息未找到"
|
||||
};
|
||||
}
|
||||
var client = DataCacheProvider.GetClientDataSource().GetData(trade.ClientId);
|
||||
var Parentdata = DataCacheProvider.GetClientDataSource().GetData(client.ParentId);
|
||||
if (client == null)
|
||||
{
|
||||
return new TradeDocGenerateResult(trade)
|
||||
{
|
||||
ErrorMessage = $"客户(id:{trade.ClientId})信息未找到"
|
||||
};
|
||||
}
|
||||
if (Parentdata == null)
|
||||
{
|
||||
dic["{{客户名称}}"] = $"{trade.ClientName ?? ""}";
|
||||
}
|
||||
else
|
||||
{
|
||||
dic["{{客户名称}}"] = $"{(Parentdata.IsDocShowParentName == 1 ? client.Name : trade.ClientName ?? "")}";
|
||||
}
|
||||
dic["{{交易方向}}"] = $"贵司{BuySellConvert.GetClientBuySell(contractGroup.trade.BuySell)}";
|
||||
|
||||
var tradeType = trade.TradeType == "香草期权" ? "普通" : (trade.TradeType == "结构化交易" ? trade.StructureType : trade.TradeType.Replace("期权", ""));
|
||||
dic["{{期权类型}}"] = $"{trade.ExerciseModeCn}{tradeType}{trade.OptionType}期权";
|
||||
dic["{{到期日}}"] = trade.ExerciseDate?.ToString("yyyy年M月d日");
|
||||
dic["{{交易日}}"] = trade.TradeDate?.ToString("yyyy年M月d日");
|
||||
dic["{{合约到期日}}"] = trade.MaturityDate?.ToString("yyyy年M月d日");
|
||||
|
||||
var variety = VarietyBLL.GetAllvarietyModel().FirstOrDefault(x => x.id == underlying.UnderlyingTypeId);
|
||||
if (trade.TradeType == "合成价差期权")
|
||||
{
|
||||
dic["{{商品标的名称}}"] = synthetic_underlyingBLL.GetUnderlyingTipsInfo(trade.UnderlyingCode);
|
||||
}
|
||||
else
|
||||
{
|
||||
//合约代码和名称需要调整
|
||||
var UnderlyingCode = underlying.UnderlyingCode;
|
||||
if (Regex.IsMatch(UnderlyingCode, "^[a-zA-Z]+00"))
|
||||
{
|
||||
UnderlyingCode = UnderlyingCode.TrimEnd('0');
|
||||
}
|
||||
UnderlyingCode += "." + underlying.MarketCode;
|
||||
dic["{{商品标的名称}}"] = PS.Config.Is东兴 ? UnderlyingCode : trade.UnderlyingCode;
|
||||
}
|
||||
|
||||
var strUnit = variety.QuoteUnitSingle;
|
||||
var tradeNotional = trade.Notional;
|
||||
var tradeOriginalNotional = (trade.OriginalNotional ?? 0);
|
||||
|
||||
dic["{{商品标的数量}}"] = $"{tradeOriginalNotional.OtcFormatNotional()}{strUnit}";
|
||||
dic["{{支付时间}}"] = "买方终止 / 到期时支付";
|
||||
//期末价格
|
||||
var endPrice = underlying.Price ?? 0;
|
||||
//交割金额
|
||||
double tradeCashAmount = 0;
|
||||
double notional = 0;
|
||||
if (tradeCash != null)
|
||||
{
|
||||
endPrice = tradeCash.FinalPrice ?? 0;
|
||||
tradeCashAmount = tradeCash.Amount;
|
||||
notional = tradeCash.Action == "系统操作-行权费" ? tradeCash.Notional : tradeCash.UnwindNotional ?? 0;
|
||||
}
|
||||
|
||||
dic["{{执行价格}}"] = $"{(trade.ActualStrike ?? 0).OtcFormatUmPrice()}元/{strUnit}";
|
||||
dic["{{期初价格}}"] = $"{(trade.SpotPrice ?? 0).OtcFormatUmPrice()}元/{strUnit}";
|
||||
dic["{{期权价格}}"] = $"{(trade.TradeSinglePrice ?? 0).OtcFormatMoney(grouping: false)}元/{strUnit}";
|
||||
dic["{{期权费率}}"] = $"{trade.PremiumRate?.OtcFormat(OtcFormatFlag.premiumRateP)}";
|
||||
dic["{{期初名义本金}}"] = $"{(trade.OriginalStockEqvNotional ?? 0).OtcFormat(OtcFormatFlag.StockEqvNotional)}元";
|
||||
dic["{{期末名义本金}}"] = $"{trade.StockEqvNotional.OtcFormat(OtcFormatFlag.StockEqvNotional)}元";
|
||||
dic["{{期末价格}}"] = $"{endPrice.OtcFormatUmPrice()}元/{strUnit}";
|
||||
dic["{{期权收益}}"] = $"{Math.Abs(tradeCashAmount / tradeNotional).OtcFormatFlex(2, 4)}元/{strUnit}";
|
||||
dic["{{期末数量}}"] = $"{tradeNotional.OtcFormatNotional()}{strUnit}";
|
||||
dic["{{期权费}}"] = $"{(trade.TradePrice ?? 0).OtcFormatMoney(grouping: false)}元";
|
||||
dic["{{结算价}}"] = $"{Math.Abs(tradeCashAmount).OtcFormatMoney()}元";
|
||||
dic["{{终止日}}"] = trade.UnWindDate?.ToString("yyyy年M月d日");
|
||||
var req = new RunMarginCalculationReq(UserInfo)
|
||||
{
|
||||
tradeList = new List<trade> { trade },
|
||||
settleDate = trade.UnWindDate.Value,
|
||||
PriceProvider = new SinglePriceProvider(trade.UnderlyingCode, endPrice)
|
||||
};
|
||||
if (trade.IsGroup == 1)
|
||||
{
|
||||
req.tradeList = DbContext.trade.Where(x => x.ParentTradeId == trade.id).ToList();
|
||||
}
|
||||
var tradeSpans = MarginDefault.RunMarginCalculation(req);
|
||||
if (tradeSpans?.Count > 0)
|
||||
{
|
||||
var margin = trade.IsGroup == 1 ? tradeSpans.Sum(x => x.WorstCastClientPayable ?? 0) : (tradeSpans[0].WorstCastClientPayable ?? 0);
|
||||
dic["{{预付金}}"] = $"{Math.Abs(margin).OtcFormatMoney()}元";
|
||||
}
|
||||
else
|
||||
{
|
||||
dic["{{预付金}}"] = "0元";
|
||||
}
|
||||
dic["{{结算价格}}"] = dic["{{期权收益}}"];
|
||||
|
||||
var isGJBuyer = trade.BuySell == "买入";
|
||||
double incomes;
|
||||
if (isGJBuyer)
|
||||
{
|
||||
incomes = tradeCashAmount - (notional * trade.TradeSinglePrice) ?? 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
incomes = tradeCashAmount + (notional * trade.TradeSinglePrice) ?? 0;
|
||||
}
|
||||
dic["{{结算净额}}"] = $"{Math.Abs(incomes).OtcFormatMoney()}元";
|
||||
dic["{{结算方式}}"] = incomes > 0 ? "贵司向我司支付结算净额" : "我司向贵司支付结算净额";
|
||||
dic["{{到期盈亏}}"] = $"{Math.Abs(incomes).OtcFormatMoney(grouping: false)}元";
|
||||
|
||||
//东兴结算净额处理逻辑(卖价差期权)
|
||||
dic["{{客户结算净额}}"] = $"{(Math.Abs(tradeCashAmount) - (notional * trade.TradeSinglePrice))?.OtcFormatMoney()}元"; ;
|
||||
dic["{{机构结算净额}}"] = $"{((notional * trade.TradeSinglePrice) - Math.Abs(tradeCashAmount))?.OtcFormatMoney()}元"; ;
|
||||
|
||||
//合同编号
|
||||
string contractNo;
|
||||
string outPutFileName;
|
||||
if (settlementDoc != null)
|
||||
{
|
||||
contractNo = settlementDoc.Code;
|
||||
outPutFileName = settlementDoc.FileName;
|
||||
}
|
||||
else
|
||||
{
|
||||
var contractIndex = contractBLL.GetContractNo("GTJASettlement");
|
||||
if (PS.Config.CompanyID == "中财资本")
|
||||
{
|
||||
contractNo = $"{trade.TradeNumber}S";
|
||||
}
|
||||
else
|
||||
{
|
||||
contractNo = $"{client.Number}C{contractIndex}S";
|
||||
}
|
||||
outPutFileName = $"{client.Name}到期结算单C{contractIndex}S.docx";
|
||||
}
|
||||
dic["{{合同编号}}"] = contractNo;
|
||||
dic["{{合同时间}}"] = $"{DateTime.Now.ToString("yyyy年M月d日")}";
|
||||
dic["{{确认书编号}}"] = tradeContractR.ContractCode;
|
||||
|
||||
try
|
||||
{
|
||||
var templateDir = OtcAppContext.MapPath("~/App_Docs/GTJA");
|
||||
var templatePath = OtcAppContext.MapPath("~/App_Docs/导出模板/到期结算单模板.docx");
|
||||
if (trade.IsUsePremiumRate != null && trade.IsUsePremiumRate.Value)
|
||||
{
|
||||
templatePath = OtcAppContext.MapPath("~/App_Docs/导出模板/到期结算单(名义本金)模板.docx");
|
||||
}
|
||||
|
||||
var outPutFilePath = Path.Combine(templateDir, outPutFileName);
|
||||
|
||||
MsWordTempalteHelper.GenerateFromTemplate(templatePath, dic, outPutFilePath);
|
||||
|
||||
if (docType == "PDF" && !outPutFilePath.EndsWith(".pdf", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
OfficeFileConverter.ConvertDocxToPDF(outPutFilePath, outPutFilePath.Replace(".docx", ".pdf"));
|
||||
}
|
||||
|
||||
//更新操作时间
|
||||
var now = DateTime.Now;
|
||||
File.SetLastAccessTime(outPutFilePath, now);
|
||||
|
||||
#region --- Add trade_contract_document and trade_contract_r records
|
||||
|
||||
if (needAddData)
|
||||
{
|
||||
var nowDate = DateTime.Now;
|
||||
var contractRecord = new trade_contract_document();
|
||||
DbContext.trade_contract_document.Add(contractRecord);
|
||||
contractRecord.Code = settlementDoc != null ? settlementDoc.Code : dic["{{合同编号}}"].ToString();
|
||||
contractRecord.ValueDate = valuedateBLL.ValueDate;
|
||||
contractRecord.BuyerId = isGJBuyer ? 0 : trade.ClientId;
|
||||
contractRecord.BuyerName = isGJBuyer ? PS.Config.CompanyFullName : trade.ClientName;
|
||||
contractRecord.SellerId = isGJBuyer ? trade.ClientId : 0;
|
||||
contractRecord.SellerName = isGJBuyer ? trade.ClientName : PS.Config.CompanyFullName;
|
||||
contractRecord.FileType = FileTypeEnum.Word;
|
||||
contractRecord.Status = ContractStatusEnum.Draft;
|
||||
contractRecord.Paths = $"App_Docs\\GTJA\\{outPutFileName}";
|
||||
contractRecord.FileName = outPutFileName;
|
||||
contractRecord.Type = ContractTypeEnum.Clearing;
|
||||
contractRecord.OptId = userId;
|
||||
contractRecord.OptName = userName;
|
||||
contractRecord.OptDate = nowDate;
|
||||
|
||||
var contractTradeRelation = new trade_contract_r();
|
||||
DbContext.trade_contract_r.Add(contractTradeRelation);
|
||||
contractTradeRelation.TradeId = trade.id;
|
||||
contractTradeRelation.TradeNumber = trade.TradeNumber;
|
||||
contractTradeRelation.ContractCode = contractRecord.Code;
|
||||
contractTradeRelation.TradeClearCode = contractRecord.Code;
|
||||
contractTradeRelation.Type = ContractTypeEnum.Clearing;
|
||||
contractTradeRelation.OptId = userId;
|
||||
contractTradeRelation.OptName = userName;
|
||||
contractTradeRelation.OptDate = nowDate;
|
||||
contractTradeRelation.TradeCashId = tradeCash.id;
|
||||
contractTradeRelation.IsValid = true;
|
||||
|
||||
DbContext.SaveChanges();
|
||||
}
|
||||
|
||||
#endregion --- Add trade_contract_document and trade_contract_r records
|
||||
|
||||
return new TradeDocGenerateResult(trade)
|
||||
{
|
||||
OutputFilePath = $"../App_Docs/GTJA/{(docType == "PDF" ? outPutFileName.Replace(".docx", ".pdf") : outPutFileName)}"
|
||||
};
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogFactory.GetLogger<SettlementBillGenerateService>().Error("GenerateSingleSettleBill出错", ex);
|
||||
return new TradeDocGenerateResult(trade)
|
||||
{
|
||||
ErrorMessage = "出错:" + ex.Message
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
using YLErp.DBModels.Consts;
|
||||
using YLErp.Modules.TradeDalModule;
|
||||
using YLErp.Plugins.TradeDocGenerator.Abstracts;
|
||||
|
||||
namespace YLErp.Modules.TradeModule.DocGenerateModule
|
||||
{
|
||||
public class BatchTradeDocGeneratorContext : YLBaseService, IBatchTradeDocGeneratorContext
|
||||
{
|
||||
public string ContractType { get; set; }
|
||||
|
||||
public Client Broker { get; set; }
|
||||
|
||||
public ServiceRepresentativeConfig Spc0 { get; set; }
|
||||
|
||||
public valuedate Valuedate { get; set; }
|
||||
|
||||
public string TemplateDir { get; set; }
|
||||
|
||||
public BatchTradeDocGeneratorContext(string contractType, OptUserInfo userInfo, Client broker, ServiceRepresentativeConfig spc0, valuedate valuedate, string templateDir)
|
||||
: base(userInfo)
|
||||
{
|
||||
ContractType = contractType ?? throw new ArgumentNullException(nameof(contractType));
|
||||
Broker = broker;
|
||||
Spc0 = spc0;
|
||||
Valuedate = valuedate;
|
||||
TemplateDir = templateDir;
|
||||
}
|
||||
|
||||
public ITradeConfirmationGeneratotContext CreateContext(OtcTradeBase trade, int tradeCashId)
|
||||
{
|
||||
return new ConfirmationGenerateContext(tradeCashId, (trade)trade, ContractType, OptUser);
|
||||
}
|
||||
|
||||
public IEnumerable<trade_contract_r> GetContractRs(IEnumerable<int> tradeIds)
|
||||
{
|
||||
return DbContext.trade_contract_r.Where(t => tradeIds.Contains(t.TradeId) && t.Type == ContractTypeEnum.Trade && t.IsValid).ToList();
|
||||
}
|
||||
|
||||
public files_template GetFilesTemplate(string contractVersion)
|
||||
{
|
||||
return DbContext.files_template.FirstOrDefault(x => x.Code == contractVersion);
|
||||
}
|
||||
|
||||
public void SaveData(string fileName, string tradeCodePrefix, string outPath, string contractVersion, IList<OtcTradeBase> trades)
|
||||
{
|
||||
trade_contract_document contractRecord = DbContext.trade_contract_document.FirstOrDefault(x => x.Code == tradeCodePrefix && x.Type == ContractTypeEnum.Trade);
|
||||
if (contractRecord == null)
|
||||
{
|
||||
contractRecord = new trade_contract_document();
|
||||
DbContext.trade_contract_document.Add(contractRecord);
|
||||
}
|
||||
contractRecord.Code = tradeCodePrefix;
|
||||
contractRecord.ValueDate = Valuedate.ValueDate;
|
||||
contractRecord.BuyerId = trades[0].BuySell == "买入" ? Broker.id : trades[0].ClientId;
|
||||
contractRecord.BuyerName = trades[0].BuySell == "买入" ? Broker.Name : trades[0].ClientName;
|
||||
contractRecord.SellerId = trades[0].BuySell == "卖出" ? Broker.id : trades[0].ClientId;
|
||||
contractRecord.SellerName = trades[0].BuySell == "卖出" ? Broker.Name : trades[0].ClientName;
|
||||
contractRecord.ContractVersion = contractVersion;
|
||||
contractRecord.FileType = FileTypeEnum.Pdf;
|
||||
contractRecord.Status = ContractStatusEnum.Draft;
|
||||
contractRecord.Paths = outPath;
|
||||
contractRecord.FileName = outPath.Replace(".xlsx", ".pdf");
|
||||
contractRecord.Type = ContractTypeEnum.Trade;
|
||||
contractRecord.OptId = UserId;
|
||||
contractRecord.OptName = UserName;
|
||||
contractRecord.OptDate = DateTime.Now;
|
||||
|
||||
var tradeIds = trades.Select(x => x.id).ToList();
|
||||
//var childs = DbContext.trade.Where(x => tradeIds.Contains(x.ParentTradeId ?? 0));
|
||||
TradeDalService service = new TradeDalService(this);
|
||||
var childs = service.GetStructTradeFromTradeOrEodTrade(tradeIds, SystemValueDate, true);
|
||||
foreach (var trade in trades)
|
||||
{
|
||||
trade_contract_r contractTradeRelation = DbContext.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();
|
||||
DbContext.trade_contract_r.Add(contractTradeRelation);
|
||||
}
|
||||
contractTradeRelation.TradeId = trade.id;
|
||||
contractTradeRelation.TradeNumber = trade.TradeNumber;
|
||||
contractTradeRelation.ContractCode = tradeCodePrefix;
|
||||
contractTradeRelation.OptId = UserId;
|
||||
contractTradeRelation.OptName = UserName;
|
||||
contractTradeRelation.OptDate = DateTime.Now;
|
||||
contractTradeRelation.Type = ContractTypeEnum.Trade;
|
||||
contractTradeRelation.IsValid = true;
|
||||
//var td = DbContext.trade.Find(trade.id);
|
||||
//var td = service.GetTradeOrEodTrade(new[] { trade.id }, ValueDate, true).FirstOrDefault();
|
||||
//var childTds = childs.Where(x => x.ParentTradeId == td.id);
|
||||
//if (td != null)
|
||||
//{
|
||||
// td.HasGeneratedConfirmBook = 1;
|
||||
// foreach (var child in childTds)
|
||||
// {
|
||||
// child.HasGeneratedConfirmBook = 1;
|
||||
// }
|
||||
//}
|
||||
}
|
||||
DbContext.SaveChanges();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,464 @@
|
||||
using YLErp.BLL;
|
||||
using YLErp.BLL.MarginCalculation;
|
||||
using YLErp.DBModels.Consts;
|
||||
using YLErp.Model;
|
||||
using YLErp.Models;
|
||||
using YLErp.Modules.DataProviderModule;
|
||||
using YLErp.Modules.TradeDalModule;
|
||||
using YLErp.MsOffice;
|
||||
using YLErp.Office;
|
||||
using YLErp.Office.Converters;
|
||||
using YLErp.Plugins.TradeDocGenerator.Abstracts;
|
||||
|
||||
namespace YLErp.Modules.TradeModule.DocGenerateModule
|
||||
{
|
||||
public class BatchUnwindReportGenerateService : YLBaseService
|
||||
{
|
||||
public BatchUnwindReportGenerateService(OptUserInfo userInfo) : base(userInfo)
|
||||
{
|
||||
}
|
||||
|
||||
public BatchUnwindReportGenerateService(YLBaseService baseService) : base(baseService)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 生成结算确认书
|
||||
/// </summary>
|
||||
public IEnumerable<TradeDocGenerateResult> Generate(IEnumerable<UnwindReportInputModel> unwindReportInputModels, string docType, int userId, string userName)
|
||||
{
|
||||
if (unwindReportInputModels == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(unwindReportInputModels));
|
||||
}
|
||||
|
||||
if (docType == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(docType));
|
||||
}
|
||||
|
||||
//使用Action等于票息并且IsLastAction检索数据,逻辑是存在问题的,敲出平仓+票息是没问题的, 到期+票息应该会取出多条,需要梳理逻辑后调整
|
||||
|
||||
var tradeIds = unwindReportInputModels.Select(m => m.TradeId).ToHashSet();
|
||||
var tradeCashIds = unwindReportInputModels.Select(m => m.TradeCashId).ToHashSet();
|
||||
//当前交易日
|
||||
var valueDate = valuedateBLL.ValueDate;
|
||||
var tradeCashStatus = new string[] { ClientCashInCashOut.系统操作_行权费, ClientCashInCashOut.系统操作_平仓费 };
|
||||
|
||||
//----------------------------------
|
||||
// 获取当日行权 平仓 到期的有效交易
|
||||
//----------------------------------
|
||||
var service = new TradeDalService(this);
|
||||
var tradeQuery = service.GetTradeOrEodTrade(tradeIds, valueDate).AsEnumerable();
|
||||
|
||||
IEnumerable<trade_contract_group> query;
|
||||
|
||||
var tcPredicate = PredicateBuilder.Create<trade_cash>(tc => tc.ValidState != ConsGlobal.InValid
|
||||
&& !tc.IsDeleted && tradeCashIds.Contains(tc.id)
|
||||
&& (tradeCashStatus.Contains(tc.Action) && tc.ExerciseWay == TradeCashExerciseWayEnum.提前终止行权 || tc.Action == ClientCashInCashOut.系统操作_票息 && tc.IsLastAction));
|
||||
|
||||
if (PS.Config.TradeElement.IsSingleExecutionTemplate)
|
||||
{
|
||||
tradeQuery = tradeQuery.Where(O => O.ClientId > 0 && (O.TradeStatus == ConsTrade.已平仓 || O.UnWindNotional > 0));
|
||||
}
|
||||
else
|
||||
{
|
||||
tradeQuery = tradeQuery.Where(O => O.ClientId > 0
|
||||
&& (O.TradeStatus == ConsTrade.已平仓 || O.UnWindNotional > 0 || (O.TradeStatus == ConsTrade.已执行 && O.ExerciseMode == "American")));
|
||||
}
|
||||
|
||||
var tids2 = tradeQuery.Select(n => n.ParentTradeId > 0 ? n.ParentTradeId : n.id).ToHashSet();
|
||||
|
||||
var tcrQuery = from tcrConfirm in DbContext.trade_contract_r
|
||||
join contractDoc in DbContext.trade_contract_document.Where(aa => aa.Type == ContractTypeEnum.Clearing)
|
||||
on tcrConfirm.ContractCode equals contractDoc.Code into contractDocs
|
||||
from contractDoc in contractDocs.DefaultIfEmpty()
|
||||
where tids2.Contains(tcrConfirm.TradeId) && tcrConfirm.Type == ContractTypeEnum.Trade && tcrConfirm.IsValid
|
||||
select new { tcrConfirm.TradeId, tcrConfirm, contractDoc };
|
||||
|
||||
query = from trade in tradeQuery
|
||||
join tradeCash in DbContext.trade_cash.Where(tcPredicate) on trade.id equals tradeCash.TradeId
|
||||
join tcr in tcrQuery
|
||||
on new { id = trade.ParentTradeId > 0 ? trade.ParentTradeId : trade.id } equals new { id = tcr.TradeId } into tcr_t
|
||||
from tcr in tcr_t.DefaultIfEmpty()
|
||||
select new trade_contract_group
|
||||
{
|
||||
id = tradeCash.id,
|
||||
trade = trade,
|
||||
trade_cash = tradeCash,
|
||||
ConfirmContractR = tcr != null ? tcr.tcrConfirm : null,
|
||||
trade_contract_document = tcr != null ? tcr.contractDoc : null,
|
||||
UnwindVol = tradeCash.Action == ClientCashInCashOut.系统操作_平仓费 ? tradeCash.UnwindVol : null
|
||||
};
|
||||
|
||||
if (!query.Any())
|
||||
{
|
||||
throw new ServiceException("当日没有要结算的记录信息!");
|
||||
}
|
||||
|
||||
//----------------------------------
|
||||
// 生成交易结算书
|
||||
//----------------------------------
|
||||
var resultList = new List<TradeDocGenerateResult>();
|
||||
AppManager.TryResolve(out ITradeUnwindReportGenerator generatorV2);
|
||||
var groups = query.ToList();
|
||||
var tradeList = new List<trade>();
|
||||
var groupSet = groups.Select(n => n.trade.id + n.trade_cash.ExerciseWay).ToHashSet();
|
||||
foreach (var tradeContractGroup in groups)
|
||||
{
|
||||
if (tradeContractGroup.trade_cash.ExerciseWay == ClientCashInCashOut.系统操作_票息
|
||||
&& groupSet.Contains(tradeContractGroup.trade.id + TradeCashExerciseWayEnum.提前终止行权))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!GlobalConfig.DotFindBrotherTrade)
|
||||
{
|
||||
if (tradeContractGroup.trade.ParentTradeId != 0)
|
||||
{
|
||||
var structureTrades = service
|
||||
.GetTradeOrEodTradeOfTidAPid(new[] { tradeContractGroup.trade.ParentTradeId }, valueDate);
|
||||
//var structureTrades = (from trade in DbContext.trade
|
||||
// where (trade.id == tradeContractGroup.trade.ParentTradeId
|
||||
// || trade.ParentTradeId == tradeContractGroup.trade.ParentTradeId)
|
||||
// && trade.ValidState != "InValid"
|
||||
// select trade).ToList();
|
||||
var subTradeDict = structureTrades.Where(O => O.ParentTradeId == tradeContractGroup.trade.ParentTradeId).GroupBy(O => O.TradeStatus).ToDictionary(K => K.Key, V => V.ToList());
|
||||
if (subTradeDict.Count == 1)
|
||||
{
|
||||
var subTradeIds = subTradeDict.First().Value.Select(O => O.id).ToList();
|
||||
var tradeCashes = (from cash in DbContext.trade_cash
|
||||
where subTradeIds.Contains(cash.TradeId) && !cash.IsDeleted
|
||||
&& cash.Action == tradeContractGroup.trade_cash.Action
|
||||
&& cash.ValueDate == tradeContractGroup.trade_cash.ValueDate
|
||||
&& cash.ExerciseWay == tradeContractGroup.trade_cash.ExerciseWay
|
||||
&& cash.Notional == tradeContractGroup.trade_cash.Notional
|
||||
&& cash.UnwindNotional == tradeContractGroup.trade_cash.UnwindNotional
|
||||
select cash)
|
||||
.ToList();
|
||||
if (tradeCashes.Count == subTradeDict.First().Value.Count)
|
||||
{
|
||||
subTradeDict.First().Value.ForEach(O => O.trade_cash = tradeCashes.First(B => B.TradeId == O.id));
|
||||
tradeContractGroup.trade = structureTrades.Where(O => !subTradeIds.Contains(O.id)).First();
|
||||
tradeContractGroup.trade.SubTrades = structureTrades.Where(O => subTradeIds.Contains(O.id)).ToList();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
tradeContractGroup.trade.trade_cash = tradeContractGroup.trade_cash;
|
||||
//if (!YLErp.PS.Config.Is光大光子 && tradeContractGroup.ConfirmContractR == null)
|
||||
//{
|
||||
// resultList.Add(new TradeDocGenerateResult(tradeContractGroup.trade) {
|
||||
// ErrorMessage = "缺少交易确认书"
|
||||
// });
|
||||
//}
|
||||
//else
|
||||
if ((tradeContractGroup.trade.TradeType != "结构化交易" && tradeContractGroup.trade_cash == null)
|
||||
|| (tradeContractGroup.trade.TradeType == "结构化交易" && tradeContractGroup.trade.IsGroup == 0 && tradeContractGroup.trade.SubTrades.Any(O => O.trade_cash == null)))
|
||||
{
|
||||
resultList.Add(new TradeDocGenerateResult(tradeContractGroup.trade)
|
||||
{
|
||||
ErrorMessage = "缺少现金交割记录"
|
||||
});
|
||||
}
|
||||
tradeList.Add(tradeContractGroup.trade.Clone());
|
||||
}
|
||||
if (generatorV2 != null)
|
||||
{
|
||||
var result = GenerateSingleV2(generatorV2, tradeList, tradeCashIds, docType);
|
||||
resultList.Add(result);
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var item in groups)
|
||||
{
|
||||
resultList.Add(GenerateSingleV1(item, OptUser.UserId, OptUser.UserName, docType));
|
||||
}
|
||||
}
|
||||
|
||||
return resultList;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
protected TradeDocGenerateResult GenerateSingleV2(ITradeUnwindReportGenerator generator, List<trade> trades, IEnumerable<int> tradeCashIds, string docType = "DOCX", DateTime? startDate = null, DateTime? endDate = null)
|
||||
{
|
||||
try
|
||||
{
|
||||
var context = new UnwindReportGenerateContext(tradeCashIds, trades, ContractTypeEnum.UnWind, OptUser, startDate, endDate);
|
||||
generator.Initialize(docType, context);
|
||||
return generator.GenerateDocument();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogFactory.GetLogger<UnwindReportGenerateService>().Error("GenerateSingleV2", ex);
|
||||
return new TradeDocGenerateResult(trades)
|
||||
{
|
||||
Exception = ex,
|
||||
ErrorMessage = "出错:" + ex.Message
|
||||
};
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
protected TradeDocGenerateResult GenerateSingleV1(trade_contract_group contractGroup, int userId, string userName, string docType = "DOCX")
|
||||
{
|
||||
if (contractGroup == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(contractGroup));
|
||||
}
|
||||
|
||||
var contractBLL = new TradeContractBLL(this);
|
||||
var dic = new Dictionary<string, object>();
|
||||
var trade = contractGroup.trade;
|
||||
var tradeCash = contractGroup.trade_cash;
|
||||
var contractDoc = contractGroup.trade_contract_document;
|
||||
var needAddData = true;
|
||||
|
||||
#region 如果提前终止确认书已经生成过,则直接返回
|
||||
|
||||
var unWindDoc = contractBLL.GetContractDoc(trade.id, ContractTypeEnum.UnWind, tradeCash.id);
|
||||
if (unWindDoc != null)
|
||||
{
|
||||
if (File.Exists(unWindDoc.AbsolutePath))
|
||||
{
|
||||
if (docType == "PDF")
|
||||
{
|
||||
var pdfPath = unWindDoc.AbsolutePath.Replace(".docx", ".pdf");
|
||||
if (!File.Exists(pdfPath))
|
||||
{
|
||||
OfficeFileConverter.ConvertDocxToPDF(unWindDoc.AbsolutePath, pdfPath);
|
||||
}
|
||||
|
||||
return new TradeDocGenerateResult(trade)
|
||||
{
|
||||
OutputFilePath = $"../App_Docs/GTJA/{unWindDoc.FileName.Replace(".docx", ".pdf")}"
|
||||
};
|
||||
}
|
||||
|
||||
return new TradeDocGenerateResult(trade)
|
||||
{
|
||||
OutputFilePath = $"../App_Docs/GTJA/{unWindDoc.FileName}"
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
needAddData = false;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
var isGJBuyer = trade.BuySell == "买入";
|
||||
|
||||
var underlying = DataCacheProvider.GetUnderlyingDataSource().GetData(trade.UnderlyingCode);
|
||||
if (underlying == null)
|
||||
{
|
||||
return new TradeDocGenerateResult(trade)
|
||||
{
|
||||
ErrorMessage = $"标的资产{trade.UnderlyingCode}信息未找到"
|
||||
};
|
||||
}
|
||||
var client = DataCacheProvider.GetClientDataSource().GetData(trade.ClientId);
|
||||
if (client == null)
|
||||
{
|
||||
return new TradeDocGenerateResult(trade)
|
||||
{
|
||||
ErrorMessage = $"客户(id:{trade.ClientId})信息未找到"
|
||||
};
|
||||
}
|
||||
|
||||
dic["{{乙方名称}}"] = client.Name;
|
||||
|
||||
if (isGJBuyer)
|
||||
{
|
||||
dic["{{甲方方向}}"] = "买方";
|
||||
dic["{{乙方方向}}"] = "卖方";
|
||||
}
|
||||
else
|
||||
{
|
||||
dic["{{甲方方向}}"] = "卖方";
|
||||
dic["{{乙方方向}}"] = "买方";
|
||||
}
|
||||
|
||||
var tradeType = trade.TradeType == "香草期权" ? "普通" : (trade.TradeType == "结构化交易" ? trade.StructureType : trade.TradeType.Replace("期权", ""));
|
||||
dic["{{期权类型}}"] = $"{trade.ExerciseModeCn}{tradeType}{trade.OptionType}期权";
|
||||
|
||||
var variety = VarietyBLL.GetAllvarietyModel().FirstOrDefault(x => x.id == underlying.UnderlyingTypeId);
|
||||
if (trade.TradeType == "合成价差期权")
|
||||
{
|
||||
dic["{{商品标的名称}}"] = synthetic_underlyingBLL.GetUnderlyingTipsInfo(trade.UnderlyingCode);
|
||||
}
|
||||
else
|
||||
{
|
||||
dic["{{商品标的名称}}"] = trade.UnderlyingCode;
|
||||
}
|
||||
dic["{{交易日}}"] = trade.TradeDate?.ToString("yyyy年M月d日");
|
||||
dic["{{到期日}}"] = trade.ExerciseDate?.ToString("yyyy年M月d日");
|
||||
|
||||
var strUnit = variety.QuoteUnitSingle;
|
||||
var tradeNotional = trade.Notional;
|
||||
var tradeOriginalNotional = (trade.OriginalNotional ?? 0);
|
||||
var unWindCount = trade.TradeStatus == ConsTrade.已平仓 || (trade.UnWindNotional > 0 && tradeCash.UnwindNotional > 0) ? (tradeCash.UnwindNotional).Value : trade.Notional;
|
||||
var unWindCountPercent = (tradeCash.Action == ClientCashInCashOut.系统操作_平仓费 ? (tradeCash.UnwindPercentRate ?? 0) : (trade.Notional / trade.OriginalNotional) ?? 0).OtcFormatNotional(isPercent: true);
|
||||
var unWindPricePercent = (tradeCash.UnwindPricePercentRate ?? 0).OtcFormat(OtcFormatFlag.premiumRateP);
|
||||
|
||||
dic["{{执行价格}}"] = $"{(trade.ActualStrike ?? 0).OtcFormatUmPrice()}元/{strUnit}";
|
||||
dic["{{期权价格}}"] = $"{(trade.TradeSinglePrice ?? 0).OtcFormatMoney(grouping: false)}元/{strUnit}";
|
||||
dic["{{商品标的数量}}"] = $"{tradeOriginalNotional.OtcFormatNotional()}{strUnit}";
|
||||
dic["{{名义本金}}"] = $"{(trade.OriginalStockEqvNotional ?? 0).OtcFormat(OtcFormatFlag.StockEqvNotional)}";
|
||||
dic["{{期权费率}}"] = $"{(trade.PremiumRate ?? 0).OtcFormat(OtcFormatFlag.premiumRateP)}";
|
||||
dic["{{支付时间}}"] = "提前终止/到期时支付";
|
||||
dic["{{终止类型}}"] = tradeCash.Action == ClientCashInCashOut.系统操作_平仓费 ? "平仓" : "美式期权行权";
|
||||
dic["{{终止日}}"] = $"{trade.UnWindDate.Value:yyyy年M月d日}";
|
||||
dic["{{终止数量}}"] = trade.IsUsePremiumRate.HasValue && trade.IsUsePremiumRate.Value ? unWindCountPercent : $"{unWindCount.OtcFormatNotional()}{strUnit}";
|
||||
dic["{{标的终止日价格}}"] = $"{(tradeCash.FinalPrice ?? 0).OtcFormatUmPrice()}元/{strUnit}";
|
||||
|
||||
dic["{{期末价格}}"] = $"{(tradeCash.FinalPrice ?? 0).OtcFormatUmPrice()}元/{strUnit}";
|
||||
|
||||
var req = new RunMarginCalculationReq(UserInfo)
|
||||
{
|
||||
tradeList = new List<trade> { trade },
|
||||
settleDate = trade.UnWindDate.Value,
|
||||
PriceProvider = new SinglePriceProvider(trade.UnderlyingCode, tradeCash.FinalPrice ?? 0)
|
||||
};
|
||||
if (trade.IsGroup == 1)
|
||||
{
|
||||
req.tradeList = DbContext.trade.Where(x => x.ParentTradeId == trade.id).ToList();
|
||||
}
|
||||
var tradeSpans = MarginDefault.RunMarginCalculation(req);
|
||||
if (tradeSpans?.Count > 0)
|
||||
{
|
||||
var margin = trade.IsGroup == 1 ? tradeSpans.Sum(x => x.WorstCastClientPayable ?? 0) : (tradeSpans[0].WorstCastClientPayable ?? 0);
|
||||
dic["{{预付金}}"] = $"{Math.Abs(margin).OtcFormatMoney()}元";
|
||||
}
|
||||
else
|
||||
{
|
||||
dic["{{预付金}}"] = "0元";
|
||||
}
|
||||
|
||||
dic["{{期权平仓价格}}"] = tradeCash.Action == "系统操作-行权费" || tradeCash.UnwindType == "部分行权" ? "行权收益" : "期权平仓价格";
|
||||
dic["{{平仓价格}}"] = trade.IsUsePremiumRate == true && tradeCash.Action == "系统操作-平仓费" ? unWindPricePercent : $"{Math.Abs(tradeCash.UnwindPrice ?? 0).OtcFormatUmPrice()}元/{strUnit}";
|
||||
dic["{{提前终止款}}"] = $"{tradeCash.Amount.OtcFormatMoney()}元";
|
||||
dic["{{结算价格}}"] = dic["{{平仓价格}}"];
|
||||
|
||||
var premiumFee = trade.OriginalNotional > 0 ? (trade.TradePrice ?? 0) * unWindCount / trade.OriginalNotional.Value : 0;
|
||||
if (isGJBuyer)
|
||||
{
|
||||
var incomes = tradeCash.Amount - premiumFee;
|
||||
dic["{{结算净额}}"] = $"{Math.Abs(incomes).OtcFormatMoney()}元";
|
||||
dic["{{结算方式}}"] = incomes > 0 ? "卖方向买方支付结算净额" : "买方向卖方支付结算净额";
|
||||
dic["{{平仓盈亏}}"] = $"{Math.Abs(incomes).OtcFormatMoney(grouping: false)}元";
|
||||
}
|
||||
else
|
||||
{
|
||||
var incomes = tradeCash.Amount + premiumFee;
|
||||
dic["{{结算净额}}"] = $"{Math.Abs(incomes).OtcFormatMoney()}元";
|
||||
dic["{{结算方式}}"] = incomes > 0 ? "买方向卖方支付结算净额" : "卖方向买方支付结算净额";
|
||||
dic["{{平仓盈亏}}"] = $"{Math.Abs(incomes).OtcFormatMoney(grouping: false)}元";
|
||||
}
|
||||
//合同编号
|
||||
string contractNo;
|
||||
string outPutFileName;
|
||||
if (unWindDoc != null)
|
||||
{
|
||||
contractNo = unWindDoc.Code;
|
||||
outPutFileName = unWindDoc.FileName;
|
||||
}
|
||||
else
|
||||
{
|
||||
var contractIndex = contractBLL.GetContractNo("GTJAUnWind");
|
||||
if (PS.Config.CompanyID == "中财资本")
|
||||
{
|
||||
contractNo = $"{trade.TradeNumber} - 01";
|
||||
}
|
||||
else
|
||||
{
|
||||
contractNo = $"{client.Number}C{contractIndex} - 01";
|
||||
}
|
||||
outPutFileName = $"{client.Name}交易确认书C{contractIndex}-01.docx";
|
||||
}
|
||||
dic["{{合同编号}}"] = contractNo;
|
||||
dic["{{确认书编号}}"] = contractDoc == null ? "" : contractDoc.Code;
|
||||
dic["{{确认书时间}}"] = contractDoc == null ? "" : $"{contractDoc.ValueDate.Value:yyyy年M月d日}";
|
||||
|
||||
try
|
||||
{
|
||||
var templateDir = OtcAppContext.MapPath("~/App_Docs/GTJA");
|
||||
var templatePath = OtcAppContext.MapPath("~/App_Docs/导出模板/提前终止确认书模板.docx");
|
||||
if (trade.IsUsePremiumRate.HasValue && trade.IsUsePremiumRate.Value)
|
||||
{
|
||||
templatePath = OtcAppContext.MapPath("~/App_Docs/导出模板/提前终止确认书(名义本金)模板.docx");
|
||||
}
|
||||
|
||||
var outPutFilePath = Path.Combine(templateDir, outPutFileName);
|
||||
|
||||
MsWordTempalteHelper.GenerateFromTemplate(templatePath, dic, outPutFilePath);
|
||||
|
||||
if (docType == "PDF" && !outPutFilePath.EndsWith(".pdf", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
MsWordFormatConverter.ConvertToPDF(outPutFilePath, outPutFilePath.Replace(".docx", ".pdf"));
|
||||
}
|
||||
|
||||
//更新操作时间
|
||||
var now = DateTime.Now;
|
||||
System.IO.File.SetLastAccessTime(outPutFilePath, now);
|
||||
|
||||
#region --- Add trade_contract_document and trade_contract_r records
|
||||
|
||||
if (needAddData)
|
||||
{
|
||||
var nowDate = DateTime.Now;
|
||||
|
||||
var contractRecord = new trade_contract_document();
|
||||
DbContext.trade_contract_document.Add(contractRecord);
|
||||
contractRecord.Code = dic["{{合同编号}}"].ToString();
|
||||
contractRecord.ValueDate = valuedateBLL.ValueDate;
|
||||
contractRecord.BuyerId = isGJBuyer ? 0 : trade.ClientId;
|
||||
contractRecord.BuyerName = isGJBuyer ? PS.Config.CompanyFullName : trade.ClientName;
|
||||
contractRecord.SellerId = isGJBuyer ? trade.ClientId : 0;
|
||||
contractRecord.SellerName = isGJBuyer ? trade.ClientName : PS.Config.CompanyFullName;
|
||||
contractRecord.FileType = FileTypeEnum.Word;
|
||||
contractRecord.Status = ContractStatusEnum.Draft;
|
||||
contractRecord.Paths = $"App_Docs\\GTJA\\{outPutFileName}";
|
||||
contractRecord.FileName = outPutFileName;
|
||||
contractRecord.Type = ContractTypeEnum.UnWind;
|
||||
contractRecord.OptId = userId;
|
||||
contractRecord.OptName = userName;
|
||||
contractRecord.OptDate = nowDate;
|
||||
|
||||
var contractTradeRelation = new trade_contract_r();
|
||||
DbContext.trade_contract_r.Add(contractTradeRelation);
|
||||
contractTradeRelation.TradeCashId = tradeCash.id;
|
||||
contractTradeRelation.TradeId = trade.id;
|
||||
contractTradeRelation.TradeNumber = trade.TradeNumber;
|
||||
contractTradeRelation.ContractCode = contractRecord.Code;
|
||||
contractTradeRelation.TradeClearCode = contractRecord.Code;
|
||||
contractTradeRelation.Type = ContractTypeEnum.UnWind;
|
||||
contractTradeRelation.OptId = userId;
|
||||
contractTradeRelation.OptName = userName;
|
||||
contractTradeRelation.OptDate = nowDate;
|
||||
contractTradeRelation.IsValid = true;
|
||||
|
||||
DbContext.SaveChanges();
|
||||
}
|
||||
|
||||
#endregion --- Add trade_contract_document and trade_contract_r records
|
||||
|
||||
return new TradeDocGenerateResult(trade)
|
||||
{
|
||||
OutputFilePath = $"../App_Docs/GTJA/{(docType == "PDF" ? outPutFileName.Replace(".docx", ".pdf") : outPutFileName)}"
|
||||
};
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogFactory.GetLogger<UnwindReportGenerateService>().Error("GenerateSingleUnwindReport出错", ex);
|
||||
return new TradeDocGenerateResult(trade)
|
||||
{
|
||||
ErrorMessage = "出错:" + ex.Message
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,985 @@
|
||||
using NPOI.Util;
|
||||
using Org.BouncyCastle.Asn1.Ocsp;
|
||||
using System.Text;
|
||||
using YLErp.BLL;
|
||||
using YLErp.BLL.GenerateDocument;
|
||||
using YLErp.DBModels.Consts;
|
||||
using YLErp.Helpers;
|
||||
using YLErp.Model;
|
||||
using YLErp.Model.Enum;
|
||||
using YLErp.Models;
|
||||
using YLErp.Modules.TradeDalModule;
|
||||
using YLErp.MsOffice;
|
||||
using YLErp.Modules.TradeModule.DealModule;
|
||||
using YLErp.Office;
|
||||
using YLErp.Office.Converters;
|
||||
using YLErp.Plugins.TradeDocGenerator.Abstracts;
|
||||
|
||||
namespace YLErp.Modules.TradeModule.DocGenerateModule
|
||||
{
|
||||
/// <summary>
|
||||
/// 生成交易确认书
|
||||
/// </summary>
|
||||
public class ConfirmationGenerateService : YLBaseService
|
||||
{
|
||||
public ConfirmationGenerateService(OptUserInfo userInfo) : base(userInfo)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public ConfirmationGenerateService(YLBaseService baseService) : base(baseService)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 生成交易确认书
|
||||
/// </summary>
|
||||
public List<TradeDocGenerateResult> Generate(IEnumerable<int> tradeIds, string docType)
|
||||
{
|
||||
if (tradeIds == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(tradeIds));
|
||||
}
|
||||
|
||||
if (docType == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(docType));
|
||||
}
|
||||
|
||||
//----------------------------------
|
||||
// 获取当日行权 平仓 到期的有效交易
|
||||
//----------------------------------
|
||||
List<string> statusList = new List<string>() {
|
||||
ConsTrade.确认成交
|
||||
};
|
||||
if (GlobalConfig.EnableGenerateOnTradeClosed)
|
||||
{
|
||||
statusList.Add(ConsTrade.已到期);
|
||||
statusList.Add(ConsTrade.已平仓);
|
||||
statusList.Add(ConsTrade.已执行);
|
||||
}
|
||||
if (PS.Config.Is山西固收)
|
||||
{
|
||||
statusList.Add(ConsTrade.审批中);
|
||||
}
|
||||
TradeDalService service = new TradeDalService(this);
|
||||
|
||||
//var tradeQuery = from trad in DbContext.trade
|
||||
// where tradeIds.Contains(trad.id)
|
||||
// && statusList.Contains(trad.TradeStatus)
|
||||
// && trad.ValidState != "InValid" && trad.ClientId != null
|
||||
// && (trad.ParentTradeId == null || trad.ParentTradeId < 1)
|
||||
// select trad;
|
||||
|
||||
|
||||
//----------------------------------
|
||||
// 交易现金交割记录
|
||||
//----------------------------------
|
||||
List<trade> allTradeList = new List<trade>();
|
||||
if (PS.Config.Is山西固收)
|
||||
{
|
||||
allTradeList = DbContext.trade.Where(x=> tradeIds.Contains(x.id)).ToList();
|
||||
}
|
||||
else
|
||||
{
|
||||
allTradeList = service.GetTradeOrEodTradeOfTidASid(tradeIds, SystemValueDate);
|
||||
}
|
||||
if (allTradeList.Count < 1)
|
||||
{
|
||||
throw new ServiceException("没有已确认的记录信息!");
|
||||
}
|
||||
//只选中一笔子交易,按一笔子交易生成确认书
|
||||
if (PS.Config.Is光大光子 || PS.Config.Is兴业商贸)
|
||||
{
|
||||
allTradeList.RemoveAll(x => x.ParentTradeId != 0 && !tradeIds.Contains(x.id));
|
||||
}
|
||||
|
||||
var tradeDic = allTradeList.Where(O =>
|
||||
statusList.Contains(O.TradeStatus)
|
||||
&& O.ClientId != 0
|
||||
&& O.ParentTradeId == 0)
|
||||
.ToDictionary(n => n.id, n => new trade_contract_group { trade = n });
|
||||
if (PS.Config.Is长江)
|
||||
{
|
||||
foreach (var item in allTradeList)
|
||||
{
|
||||
if (item.ParentTradeId != 0)
|
||||
{
|
||||
if (item.StructureType != "牛市价差" && item.StructureType != "熊市价差")
|
||||
{
|
||||
if (tradeDic.ContainsKey(item.ParentTradeId))
|
||||
{
|
||||
tradeDic.Remove(item.ParentTradeId);
|
||||
}
|
||||
tradeDic.Add(item.id, new trade_contract_group { trade = item });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
var cashQuery = from trade in allTradeList
|
||||
join tradeCash in DbContext.trade_cash on trade.id equals tradeCash.TradeId
|
||||
where tradeCash.ValidState != ConsGlobal.InValid && !tradeCash.IsDeleted
|
||||
&& tradeCash.Action == ClientCashInCashOut.系统操作_期权费
|
||||
select tradeCash;
|
||||
var cashDatas = cashQuery.ToDictionary(K => K.TradeId, V => V);
|
||||
//var cashSwapQuery = from trade in allTradeList
|
||||
// join tradeCashSwap in DbContext.swap_event on trade.id equals tradeCashSwap.SwapTradeId
|
||||
// where tradeCashSwap.EventType == 9
|
||||
// select tradeCashSwap;
|
||||
//var cashSwapDatas = cashSwapQuery.ToDictionary(K => K.SwapTradeId, V => V);
|
||||
trade_cash cash = null;
|
||||
//swap_event cashSwap = null;
|
||||
foreach (var item in tradeDic.Values)
|
||||
{
|
||||
if (item.trade.TradeType == "结构化交易")
|
||||
{
|
||||
item.trade.SubTrades = allTradeList.Where(O => O.ParentTradeId == item.trade.id);
|
||||
List<string> cashTig = new List<string>();
|
||||
foreach (var t in item.trade.SubTrades)
|
||||
{
|
||||
if (cashDatas.TryGetValue(t.id, out cash))
|
||||
{
|
||||
t.trade_cash = cash;
|
||||
item.trade.trade_cash = cash;
|
||||
}
|
||||
}
|
||||
if (item.trade.IsGroup == 1)
|
||||
{
|
||||
item.trade.SubTrades = DbContext.trade.Where(O => O.ParentTradeId == item.trade.id).ToList();
|
||||
foreach (var t in item.trade.SubTrades)
|
||||
{
|
||||
t.trade_cash = DbContext.trade_cash.FirstOrDefault(l => l.TradeId == t.id);
|
||||
}
|
||||
if (cashDatas.TryGetValue(item.trade.id, out cash))
|
||||
{
|
||||
item.trade.trade_cash = cash;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (item.trade.TradeType == "累计期权")
|
||||
{
|
||||
new OptionTradeActionRestoreService(this).RestoreTradeDataToSpecialDay(item.trade, item.trade.TradeDate.Value);
|
||||
}
|
||||
|
||||
if (cashDatas.TryGetValue(item.trade.id, out cash))
|
||||
{
|
||||
item.trade_cash = cash;
|
||||
item.trade.trade_cash = cash;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------
|
||||
// 生成交易确认书
|
||||
//----------------------------------
|
||||
|
||||
var resultList = new List<TradeDocGenerateResult>();
|
||||
|
||||
AppManager.TryResolve(out ITradeConfirmationGenerator generatorV2);
|
||||
|
||||
if (generatorV2 == null && !PS.Config.UseOldGenerateBook)
|
||||
{
|
||||
var baseGenerate = BatchGenerateFactory.GetInstance(tradeIds, UserId, UserName, ContractTypeEnum.Trade, docType);
|
||||
var returnInfo = baseGenerate.GenerateBooks();
|
||||
var trad = new trade();
|
||||
resultList = returnInfo.Content.Select(n => new TradeDocGenerateResult(trad) { OutputFilePath = n }).ToList();
|
||||
if (!returnInfo.Success)
|
||||
{
|
||||
resultList.Add(new TradeDocGenerateResult(trad) { ErrorMessage = returnInfo.Msg });
|
||||
}
|
||||
return resultList;
|
||||
}
|
||||
|
||||
var tradeContractGroupTradeIds = tradeDic.Values.Select(x => x.trade.id).ToList();
|
||||
//var childs = DbContext.trade.Where(x => tradeContractGroupTradeIds.Contains(x.ParentTradeId ?? 0));
|
||||
var childs = service.GetStructTradeFromTradeOrEodTrade(tradeContractGroupTradeIds, SystemValueDate, true);
|
||||
foreach (var tradeContractGroup in tradeDic.Values)
|
||||
{
|
||||
if ((tradeContractGroup.trade.TradeType != "结构化交易" && tradeContractGroup.trade.TradeType != "收益互换" && tradeContractGroup.trade_cash == null)
|
||||
|| (tradeContractGroup.trade.TradeType == "结构化交易" && tradeContractGroup.trade.IsGroup == 0 && tradeContractGroup.trade.SubTrades.Any(O => O.trade_cash == null)))
|
||||
{
|
||||
resultList.Add(new TradeDocGenerateResult(tradeContractGroup.trade)
|
||||
{
|
||||
ErrorMessage = "缺少现金交割记录"
|
||||
});
|
||||
}
|
||||
//插件版本
|
||||
else if (generatorV2 != null)
|
||||
{
|
||||
var result = GenerateSingleV2(generatorV2, tradeContractGroup, docType);
|
||||
resultList.Add(result);
|
||||
}
|
||||
else
|
||||
{
|
||||
var result = GenerateSingleV1(tradeContractGroup, docType);
|
||||
resultList.Add(result);
|
||||
//if (!string.IsNullOrWhiteSpace(result.OutputFilePath))
|
||||
//{
|
||||
// tradeContractGroup.trade.HasGeneratedConfirmBook = 1;
|
||||
// var childTds = childs.Where(x => x.ParentTradeId == tradeContractGroup.trade.id);
|
||||
// foreach (var child in childTds)
|
||||
// {
|
||||
// child.HasGeneratedConfirmBook = 1;
|
||||
// }
|
||||
//}
|
||||
}
|
||||
}
|
||||
|
||||
if (generatorV2 == null)
|
||||
{
|
||||
DbContext.SaveChanges();
|
||||
}
|
||||
|
||||
return resultList;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
private TradeDocGenerateResult GenerateSingleV2(ITradeConfirmationGenerator generator, trade_contract_group tradeContractGroup, string docType = "DOCX")
|
||||
{
|
||||
try
|
||||
{
|
||||
//修改调用的构造方法
|
||||
List<trade> trades = new List<trade>() { tradeContractGroup.trade };
|
||||
List<int> ids = new List<int>();
|
||||
if (tradeContractGroup.trade != null && tradeContractGroup.trade.trade_cash != null)
|
||||
{
|
||||
ids.Add(tradeContractGroup.trade.trade_cash.id);
|
||||
}
|
||||
var context = new ConfirmationGenerateContext(
|
||||
ids,
|
||||
trades,
|
||||
ContractTypeEnum.Trade, OptUser, null, null);
|
||||
generator.Initialize(docType, context);
|
||||
return generator.GenerateDocument();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogFactory.GetLogger("GenerateSingleV2").Error(ex);
|
||||
|
||||
return new TradeDocGenerateResult(tradeContractGroup.trade)
|
||||
{
|
||||
ErrorMessage = ex.Message
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
private TradeDocGenerateResult GenerateSingleV1(trade_contract_group contractGroup, string docType = "DOCX")
|
||||
{
|
||||
if (contractGroup == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(contractGroup));
|
||||
}
|
||||
|
||||
var contractBLL = new TradeContractBLL(this);
|
||||
var trade = contractGroup.trade;
|
||||
tradeBLL.SetFieldsByTradeType(trade);
|
||||
var needAddData = true;
|
||||
|
||||
#region 如果之前交易确认书已经生成过,则直接返回
|
||||
|
||||
var confirmDoc = contractBLL.GetContractDoc(trade.id, ContractTypeEnum.Trade);
|
||||
if (confirmDoc != null)
|
||||
{
|
||||
if (File.Exists(confirmDoc.AbsolutePath))
|
||||
{
|
||||
if (docType == "PDF")
|
||||
{
|
||||
var pdfPath = confirmDoc.AbsolutePath.Replace(".docx", ".pdf");
|
||||
if (!File.Exists(pdfPath))
|
||||
{
|
||||
OfficeFileConverter.ConvertDocxToPDF(confirmDoc.AbsolutePath, pdfPath);
|
||||
}
|
||||
return new TradeDocGenerateResult(trade)
|
||||
{
|
||||
OutputFilePath = YLErp.Helpers.PathHelper.PhysicalPathToWebPath(pdfPath, OtcAppContext.RootPath)
|
||||
};
|
||||
}
|
||||
return new TradeDocGenerateResult(trade)
|
||||
{
|
||||
OutputFilePath = YLErp.Helpers.PathHelper.PhysicalPathToWebPath(confirmDoc.AbsolutePath.Replace(".pdf", ".docx"), OtcAppContext.RootPath)
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
needAddData = false;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
var isGJBuyer = trade.BuySell == "买入";
|
||||
|
||||
var underlying = underlying_managerBLL.GetByCode(trade.UnderlyingCode);
|
||||
if (underlying == null)
|
||||
{
|
||||
return new TradeDocGenerateResult(trade)
|
||||
{
|
||||
ErrorMessage = $"标的资产{trade.UnderlyingCode}信息未找到"
|
||||
};
|
||||
}
|
||||
|
||||
var client = DataCacheProvider.GetClientDataSource().GetData(trade.ClientId);
|
||||
|
||||
if (client == null)
|
||||
{
|
||||
return new TradeDocGenerateResult(trade)
|
||||
{
|
||||
ErrorMessage = $"客户{trade.ClientId}信息未找到"
|
||||
};
|
||||
}
|
||||
|
||||
var dic = new Dictionary<string, object>
|
||||
{
|
||||
["{{乙方名称}}"] = client.Name
|
||||
};
|
||||
|
||||
if (isGJBuyer)
|
||||
{
|
||||
dic["{{甲方方向}}"] = "买方";
|
||||
dic["{{乙方方向}}"] = "卖方";
|
||||
}
|
||||
else
|
||||
{
|
||||
dic["{{甲方方向}}"] = "卖方";
|
||||
dic["{{乙方方向}}"] = "买方";
|
||||
}
|
||||
|
||||
|
||||
dic["{{交易日}}"] = trade.TradeDate?.ToString("yyyy年M月d日");
|
||||
if (trade.TradeType == "香草期权" || trade.TradeType == "亚式期权")
|
||||
{
|
||||
dic["{{生效日}}"] = trade.TradeDate?.ToString("yyyy年M月d日");
|
||||
}
|
||||
else
|
||||
{
|
||||
dic["{{生效日}}"] = trade.StartDate?.ToString("yyyy年M月d日");
|
||||
}
|
||||
if (trade.TradeType == "亚式期权")
|
||||
{
|
||||
dic["{{均价起算日}}"] = trade.trade_asian_option.AveragingPeriodStartDate?.ToString("yyyy年M月d日");
|
||||
dic["{{奇异结构}}"] = $"{trade.trade_asian_option.StrikeTypeCn}的{trade.trade_asian_option.PayoffTypeCn}亚式";
|
||||
}
|
||||
dic["{{到期日}}"] = trade.ExerciseDate?.ToString("yyyy年M月d日");
|
||||
dic["{{行权日}}"] = "到期日";
|
||||
|
||||
dic["{{自动行权}}"] = "到期实值自动行权";
|
||||
|
||||
//商品标的
|
||||
|
||||
if (trade.TradeType == "合成价差期权")
|
||||
{
|
||||
dic["{{商品标的名称}}"] = synthetic_underlyingBLL.GetUnderlyingTipsInfo(trade.UnderlyingCode);
|
||||
}
|
||||
else
|
||||
{
|
||||
dic["{{商品标的名称}}"] = trade.UnderlyingCode;
|
||||
}
|
||||
|
||||
string strUnit = underlying.TradeUnitString;
|
||||
double notional = trade.Notional;
|
||||
|
||||
dic["{{报价单位}}"] = strUnit;
|
||||
dic["{{商品标的数量}}"] = $"{notional}{strUnit}";
|
||||
dic["{{商品标的交易所}}"] = underlying.MarketName;
|
||||
|
||||
//价格
|
||||
if (trade.ActualStrike != null)
|
||||
{
|
||||
if (trade.IsMoneynessOption == "是")
|
||||
{
|
||||
dic["{{执行价格}}"] = trade.Strike.OtcFormatUmPrice(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
dic["{{执行价格}}"] = $"{trade.ActualStrike.OtcFormatUmPrice()}元/{strUnit}";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
dic["{{执行价格}}"] = "不适用";
|
||||
}
|
||||
|
||||
var tradeType = trade.TradeType == "香草期权" ? "普通" : (trade.TradeType == "结构化交易" ? trade.StructureType : trade.TradeType.Replace("期权", ""));
|
||||
dic["{{期权类型}}"] = $"{trade.ExerciseModeCn}{tradeType}{trade.OptionType}期权";
|
||||
if (trade.TradeType == "远期")
|
||||
{
|
||||
dic["{{期权费}}"] = $"{(trade.TradePrice * (trade.BuySell == "卖出" ? -1 : 1) ?? 0).OtcFormatMoney(grouping: false)}元";
|
||||
}
|
||||
else
|
||||
{
|
||||
dic["{{期权费}}"] = $"{(trade.TradePrice ?? 0).OtcFormatMoney(grouping: false)}元";
|
||||
}
|
||||
|
||||
dic["{{协议编号}}"] = client.Remark;
|
||||
|
||||
dic["{{期权价格}}"] = $"{(trade.TradeSinglePrice ?? 0).OtcFormat(OtcFormatFlag.tradeSinglePrice)}元/{strUnit}";
|
||||
dic["{{支付时间}}"] = trade.PremiumPayDate != null ? "提前终止/到期时支付" : "已支付";
|
||||
|
||||
dic["{{期权方向}}"] = $"甲方{trade.BuySell}";
|
||||
dic["{{名义本金}}"] = trade.StockEqvNotional.OtcFormat(OtcFormatFlag.StockEqvNotional);
|
||||
dic["{{期初价格}}"] = trade.SpotPrice.OtcFormatUmPrice();
|
||||
dic["{{期权费率}}"] = ((trade.PremiumRate ?? ((trade.TradePrice ?? 0) / trade.StockEqvNotional)) * 100).OtcFormatFlex(2);
|
||||
|
||||
string settlementType = "价格";
|
||||
if (trade.SettlementType == SettlementTypeEnum.SettlePrice)
|
||||
{
|
||||
settlementType = "结算价";
|
||||
}
|
||||
else if (trade.SettlementType == SettlementTypeEnum.ClosePrice)
|
||||
{
|
||||
settlementType = "收盘价";
|
||||
}
|
||||
|
||||
if (trade.ExerciseMode == "American")
|
||||
{
|
||||
dic["{{美式期权结算价}}"] = $"所属交易所公布的标的合约可成交的最新价";
|
||||
dic["{{欧式期权结算价}}"] = $"美式期权不适用";
|
||||
}
|
||||
else
|
||||
{
|
||||
dic["{{美式期权结算价}}"] = $"欧式期权不适用";
|
||||
dic["{{欧式期权结算价}}"] = $"所属交易所在到期日收盘后公布的标的合约{settlementType}";
|
||||
}
|
||||
|
||||
if (trade.UnderlyingInstrumentType != "CommodityFutures")
|
||||
{
|
||||
dic["{{证券名称}}"] = underlying.UnderlyingName;
|
||||
dic["{{证券代码}}"] = underlying.UnderlyingCode;
|
||||
|
||||
dic["{{账户信息乙方}}"] = client.Name;
|
||||
dic["{{联系方式乙方}}"] = client.Name;
|
||||
dic["{{联系方式乙方联系人}}"] = client.Name;
|
||||
dic["{{联系方式乙方电话}}"] = client.Phone;
|
||||
dic["{{联系方式乙方电子邮件}}"] = client.Email;
|
||||
|
||||
var bankcard = DbContextFactory.GetClientDbContext(null).bankcard.FirstOrDefault(s => s.ApprovalOrder < 1 && s.ClientId == trade.ClientId && s.ValidState == "Valid");
|
||||
|
||||
if (bankcard != null)
|
||||
{
|
||||
dic["{{账户信息乙方户名}}"] = bankcard.ClientName;
|
||||
dic["{{账户信息乙方账号}}"] = bankcard.Card;
|
||||
dic["{{账户信息乙方开户行}}"] = bankcard.Bank;
|
||||
}
|
||||
|
||||
dic["{{期权方向}}"] = $"甲方{trade.BuySell}";
|
||||
dic["{{名义本金}}"] = trade.StockEqvNotional.OtcFormat(OtcFormatFlag.StockEqvNotional);
|
||||
}
|
||||
|
||||
if (trade.OptionType == "看涨")
|
||||
{
|
||||
if (trade.ExerciseMode == "American")
|
||||
{
|
||||
dic["{{美式期权结算金额}}"] =
|
||||
$"(行权时{trade.UnderlyingCode}合约可成交最新价 - {trade.ActualStrike.OtcFormatUmPrice()})× {notional.OtcFormatNotional()}";
|
||||
dic["{{欧式期权结算金额}}"] = $"美式期权不适用";
|
||||
}
|
||||
else
|
||||
{
|
||||
dic["{{美式期权结算金额}}"] = $"欧式期权不适用";
|
||||
dic["{{欧式期权结算金额}}"] =
|
||||
$"({trade.ExerciseDate?.ToString("yyyy年M月d日")}{trade.UnderlyingCode}合约{settlementType} - {trade.ActualStrike.OtcFormatUmPrice()})× {notional.OtcFormatNotional()}";
|
||||
}
|
||||
}
|
||||
else if (trade.OptionType == "看跌")
|
||||
{
|
||||
if (trade.ExerciseMode == "American")
|
||||
{
|
||||
dic["{{美式期权结算金额}}"] =
|
||||
$"({trade.ActualStrike.OtcFormatUmPrice()} - 行权时{trade.UnderlyingCode}合约可成交最新价)× {notional.OtcFormatNotional()}";
|
||||
dic["{{欧式期权结算金额}}"] = $"美式期权不适用";
|
||||
}
|
||||
else
|
||||
{
|
||||
dic["{{美式期权结算金额}}"] = $"欧式期权不适用";
|
||||
dic["{{欧式期权结算金额}}"] =
|
||||
$"({trade.ActualStrike.OtcFormatUmPrice()} - {trade.ExerciseDate?.ToString("yyyy年M月d日")}{trade.UnderlyingCode}合约{settlementType})× {notional.OtcFormatNotional()}";
|
||||
}
|
||||
}
|
||||
|
||||
//合同编号
|
||||
string contractNo;
|
||||
string outPutFileName;
|
||||
if (confirmDoc != null)
|
||||
{
|
||||
contractNo = confirmDoc.Code;
|
||||
outPutFileName = confirmDoc.FileName;
|
||||
}
|
||||
else
|
||||
{
|
||||
var contractIndex = contractBLL.GetContractNo("GTJA");
|
||||
if (PS.Config.CompanyID == "中财资本")
|
||||
{
|
||||
contractNo = $"{trade.TradeNumber}";
|
||||
}
|
||||
else
|
||||
{
|
||||
contractNo = $"{client.Number}C{contractIndex}";
|
||||
}
|
||||
outPutFileName = $"{client.Name}交易确认书C{contractIndex}.docx";
|
||||
}
|
||||
dic["{{合同编号}}"] = contractNo;
|
||||
dic["{{结算方式}}"] = "人民币现金结算";
|
||||
dic["{{补充}}"] = "补充";
|
||||
|
||||
try
|
||||
{
|
||||
var templateDir = OtcAppContext.MapPath("~/App_Docs/GTJA");
|
||||
var templatePath = OtcAppContext.MapPath("~/App_Docs/导出模板/交易确认书模板.docx");
|
||||
if (trade.TradeType == "亚式期权")
|
||||
{
|
||||
templatePath = OtcAppContext.MapPath("~/App_Docs/导出模板/交易确认书(亚式期权)模板.docx");
|
||||
}
|
||||
|
||||
if (trade.IsUsePremiumRate != null && trade.IsUsePremiumRate.Value)
|
||||
{
|
||||
templatePath = OtcAppContext.MapPath("~/App_Docs/导出模板/交易确认书(名义本金)模板.docx");
|
||||
}
|
||||
|
||||
LogFactory.GetLogger("交易确认书").Info("交易确认书:" + outPutFileName);
|
||||
|
||||
string outPutFilePath = Path.Combine(templateDir, outPutFileName);
|
||||
|
||||
MsWordTempalteHelper.GenerateFromTemplate(templatePath, dic, outPutFilePath);
|
||||
|
||||
if (docType == "PDF" && !outPutFilePath.EndsWith(".pdf", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
MsWordFormatConverter.ConvertToPDF(outPutFilePath, outPutFilePath.Replace(".docx", ".pdf"));
|
||||
}
|
||||
|
||||
//更新操作时间
|
||||
var now = DateTime.Now;
|
||||
File.SetLastAccessTime(outPutFilePath, now);
|
||||
|
||||
#region --- Add trade_contract_document and trade_contract_r records
|
||||
|
||||
if (needAddData)
|
||||
{
|
||||
contractBLL.DeleteConfirmBook(trade.id, null);
|
||||
|
||||
var nowDate = DateTime.Now;
|
||||
|
||||
var contractRecord = new trade_contract_document();
|
||||
DbContext.trade_contract_document.Add(contractRecord);
|
||||
contractRecord.Code = dic["{{合同编号}}"].ToString();
|
||||
contractRecord.ValueDate = valuedateBLL.ValueDate;
|
||||
contractRecord.BuyerId = isGJBuyer ? 0 : trade.ClientId;
|
||||
contractRecord.BuyerName = isGJBuyer ? PS.Config.CompanyFullName : trade.ClientName;
|
||||
contractRecord.SellerId = isGJBuyer ? trade.ClientId : 0;
|
||||
contractRecord.SellerName = isGJBuyer ? trade.ClientName : PS.Config.CompanyFullName;
|
||||
contractRecord.FileType = FileTypeEnum.Word;
|
||||
contractRecord.Status = ContractStatusEnum.Draft;
|
||||
contractRecord.Paths = $"App_Docs\\GTJA\\{outPutFileName}";
|
||||
contractRecord.FileName = outPutFileName;
|
||||
contractRecord.Type = ContractTypeEnum.Trade;
|
||||
contractRecord.ClientId = trade.ClientId;
|
||||
contractRecord.OptId = UserId;
|
||||
contractRecord.OptName = UserName;
|
||||
contractRecord.OptDate = nowDate;
|
||||
|
||||
var contractTradeRelation = new trade_contract_r();
|
||||
DbContext.trade_contract_r.Add(contractTradeRelation);
|
||||
contractTradeRelation.TradeId = trade.id;
|
||||
contractTradeRelation.TradeNumber = trade.TradeNumber;
|
||||
contractTradeRelation.ContractCode = contractRecord.Code;
|
||||
contractTradeRelation.Type = ContractTypeEnum.Trade;
|
||||
contractTradeRelation.OptId = UserId;
|
||||
contractTradeRelation.OptName = UserName;
|
||||
contractTradeRelation.OptDate = nowDate;
|
||||
contractTradeRelation.TradeCashId = contractGroup.trade_cash == null ? 0 : contractGroup.trade_cash.id;
|
||||
contractTradeRelation.IsValid = true;
|
||||
|
||||
DbContext.SaveChanges();
|
||||
}
|
||||
|
||||
#endregion --- Add trade_contract_document and trade_contract_r records
|
||||
|
||||
return new TradeDocGenerateResult(trade)
|
||||
{
|
||||
OutputFilePath = $"/App_Docs/GTJA/{(docType == "PDF" ? outPutFileName.Replace(".docx", ".pdf") : outPutFileName)}"
|
||||
};
|
||||
}
|
||||
|
||||
catch (Exception e)
|
||||
{
|
||||
LogFactory.GetLogger<ConfirmationGenerateService>().Error("GenerateSingleConfirmBook出错", e);
|
||||
return new TradeDocGenerateResult(trade) { ErrorMessage = e.Message };
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
public (bool, string, DateTime, string) UploadContractFile(string encryptId, string fileDescription, string ContractCode, bool OurpartySeal, bool CounterpartySeal, UploadFileModel uploadFileModel)
|
||||
{
|
||||
|
||||
try
|
||||
{
|
||||
var msg = "";
|
||||
#region 验证
|
||||
if (string.IsNullOrWhiteSpace(encryptId))
|
||||
{
|
||||
|
||||
return (false, "请传入id", DateTime.Now, "");
|
||||
}
|
||||
|
||||
var intid = DataProtectHelper.DecryptInt(encryptId);
|
||||
|
||||
var db = DbContextFactory.GetYLDbContext();
|
||||
|
||||
var contractDoc = db.trade_contract_document.Find(intid);
|
||||
var contractDocRArr = db.trade_contract_r.Where(O => O.ContractCode == contractDoc.Code && O.Type == contractDoc.Type && O.IsValid).ToArray();
|
||||
var contractDocR = contractDocRArr.FirstOrDefault();
|
||||
if (contractDoc == null || contractDocR == null)
|
||||
{
|
||||
return (false, "没有相关的确认书文档", DateTime.Now, "");
|
||||
}
|
||||
|
||||
var isExistCode = true;
|
||||
if (!string.IsNullOrWhiteSpace(ContractCode))
|
||||
{
|
||||
var Codes = new List<string>
|
||||
{
|
||||
ContractCode
|
||||
};
|
||||
|
||||
var oldDoc = db.trade_contract_document.Where(O => O.Code == ContractCode).FirstOrDefault();
|
||||
isExistCode = oldDoc != null ||
|
||||
(new TradeContractGenerateService(OptUser).GetExistsContractCode(Codes).Any());
|
||||
if (isExistCode)
|
||||
{
|
||||
if (!contractDoc.Code.Equals(ContractCode))
|
||||
{
|
||||
if (db.trade_contract_r.Where(O => O.ContractCode == ContractCode && O.IsValid).Any())
|
||||
{
|
||||
return (false, "合约编号已存在", DateTime.Now, "");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (oldDoc != null)
|
||||
{
|
||||
db.trade_contract_document.Remove(oldDoc);
|
||||
isExistCode = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
msg = "修改成功";
|
||||
}
|
||||
#endregion
|
||||
|
||||
//var files = Request.Form.Files;
|
||||
|
||||
if (uploadFileModel?.Length > 0)
|
||||
{
|
||||
//var file = files[0];
|
||||
|
||||
|
||||
|
||||
// var str = Encoding.UTF8.GetString(fileBytes);
|
||||
|
||||
|
||||
#region 验证
|
||||
if (PS.Config.ErpElement.SecuritiesEnvironment)
|
||||
{
|
||||
if (System.IO.Path.GetExtension(uploadFileModel.FileName).ToLower() != ".xlsx"
|
||||
&& System.IO.Path.GetExtension(uploadFileModel.FileName).ToLower() != ".xls"
|
||||
&& System.IO.Path.GetExtension(uploadFileModel.FileName).ToLower() != ".pdf"
|
||||
&& System.IO.Path.GetExtension(uploadFileModel.FileName).ToLower() != ".docx"
|
||||
&& System.IO.Path.GetExtension(uploadFileModel.FileName).ToLower() != ".doc")
|
||||
{
|
||||
return (false, "请上传PDF/Word/Excel格式的文件", DateTime.Now, "");
|
||||
}
|
||||
}
|
||||
if (PS.Config.ErpElement.SecuritiesEnvironment && uploadFileModel.Length > Modules.SuperviseReportModule.SAC.Model.ReportStatusModel.MaxAnnexLength)//小于30MB
|
||||
{
|
||||
return (false, "上传失败,单笔确认书文件大小不应超过30MB", DateTime.Now, "");
|
||||
}
|
||||
#endregion
|
||||
|
||||
var tradeNumber = "未知";
|
||||
if (contractDocR != null)
|
||||
{
|
||||
tradeNumber = contractDocR.TradeNumber;
|
||||
}
|
||||
var filePath = Path.Combine(OtcAppContext.AppDocsPath, "contractdoc", YLErp.PS.Config.Company.ToString(), tradeNumber);
|
||||
|
||||
if (!Directory.Exists(filePath))
|
||||
{
|
||||
Directory.CreateDirectory(filePath);
|
||||
}
|
||||
|
||||
#region 设置用印文件名
|
||||
|
||||
var stampFileFullName = Path.Combine(filePath, uploadFileModel.FileName);
|
||||
contractDoc.StampDocumentFileName = stampFileFullName.Replace(OtcAppContext.AppDocsPath, "/App_Docs").Replace("\\", "/");
|
||||
|
||||
#endregion
|
||||
|
||||
if (File.Exists(stampFileFullName))
|
||||
{
|
||||
File.Delete(stampFileFullName);
|
||||
}
|
||||
|
||||
using var fs = new FileStream(stampFileFullName, FileMode.Create, FileAccess.ReadWrite);
|
||||
|
||||
//using var fs = File.OpenWrite(filePath);
|
||||
|
||||
using var sr = uploadFileModel.OpenReadStream();
|
||||
|
||||
sr.Seek(0, SeekOrigin.Begin);
|
||||
var tempBytes = new byte[sr.Length];
|
||||
sr.Read(tempBytes, 0, tempBytes.Length);
|
||||
|
||||
////var tempstr = Encoding.UTF8.GetString(tempBytes);
|
||||
fs.Write(tempBytes, 0, tempBytes.Length);
|
||||
|
||||
sr.Close();
|
||||
|
||||
fs.Close();
|
||||
|
||||
|
||||
|
||||
//sr.CopyTo(fs);
|
||||
msg = msg.Length > 0 ? msg : "上传成功";
|
||||
}
|
||||
|
||||
#region 更新数据
|
||||
contractDoc.Comments = fileDescription;
|
||||
if (OurpartySeal && CounterpartySeal)
|
||||
{ contractDoc.Status = ContractStatusEnum.BothPartyStamped; }
|
||||
else if (OurpartySeal) { contractDoc.Status = ContractStatusEnum.OurPartyStamped; }
|
||||
else if (CounterpartySeal) { contractDoc.Status = ContractStatusEnum.CounterPartyStamped; }
|
||||
else { contractDoc.Status = ContractStatusEnum.Draft; }
|
||||
if (!isExistCode)//默认为存在,判断 要有修改的合约编号且修改后的编号不存在
|
||||
{
|
||||
//trade_meta
|
||||
var meta = db.TradeMeta.Where(O => (O.MetaKey == ConsTradeMetaKey.ContractCode || O.MetaKey.Contains("确认书")) && O.MetaValue == contractDoc.Code).FirstOrDefault();
|
||||
if (meta != null)
|
||||
{
|
||||
meta.MetaValue = ContractCode;
|
||||
}
|
||||
foreach (var docR in contractDocRArr)
|
||||
{
|
||||
docR.ContractCode = ContractCode;
|
||||
docR.OptDate = DateTime.Now;
|
||||
docR.OptId = OptUser.UserId;
|
||||
docR.OptName = OptUser.UserName;
|
||||
}
|
||||
contractDocR.ContractCode = ContractCode;
|
||||
contractDocR.TradeClearCode = ContractCode;
|
||||
contractDoc.OptDate = DateTime.Now;
|
||||
contractDoc.OptId = OptUser.UserId;
|
||||
contractDoc.OptName = OptUser.UserName;
|
||||
contractDoc.Code = ContractCode;
|
||||
}
|
||||
|
||||
new TradeConfirmService(OptUser, db).EditReportStatus(contractDocR.TradeId, true);
|
||||
db.SaveChanges();
|
||||
#endregion
|
||||
|
||||
return (true, msg, contractDoc.OptDate.Value, contractDoc.StampDocumentFileName);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogFactory.GetLogger("UploadContractFile").Error("UploadContractFile出错", ex);
|
||||
return (false, "操作出错", DateTime.Now, "");
|
||||
}
|
||||
}
|
||||
|
||||
public (bool, string, DateTime, string) UploadContractFileNew(string encryptId, UploadFileModel uploadFileModel)
|
||||
{
|
||||
|
||||
try
|
||||
{
|
||||
var msg = "";
|
||||
#region 验证
|
||||
if (string.IsNullOrWhiteSpace(encryptId))
|
||||
{
|
||||
|
||||
return (false, "请传入id", DateTime.Now, "");
|
||||
}
|
||||
|
||||
var intid = DataProtectHelper.DecryptInt(encryptId);
|
||||
|
||||
var db = DbContextFactory.GetYLDbContext();
|
||||
|
||||
var contractDoc = db.trade_contract_document.Find(intid);
|
||||
var contractDocRArr = db.trade_contract_r.Where(O => O.ContractCode == contractDoc.Code && O.Type == contractDoc.Type && O.IsValid).ToArray();
|
||||
var contractDocR = contractDocRArr.FirstOrDefault();
|
||||
if (contractDoc == null || contractDocR == null)
|
||||
{
|
||||
return (false, "没有相关的确认书文档", DateTime.Now, "");
|
||||
}
|
||||
#endregion
|
||||
|
||||
if (uploadFileModel?.Length > 0)
|
||||
{
|
||||
#region 验证
|
||||
if (PS.Config.ErpElement.SecuritiesEnvironment)
|
||||
{
|
||||
if (System.IO.Path.GetExtension(uploadFileModel.FileName).ToLower() != ".xlsx"
|
||||
&& System.IO.Path.GetExtension(uploadFileModel.FileName).ToLower() != ".xls"
|
||||
&& System.IO.Path.GetExtension(uploadFileModel.FileName).ToLower() != ".pdf"
|
||||
&& System.IO.Path.GetExtension(uploadFileModel.FileName).ToLower() != ".docx"
|
||||
&& System.IO.Path.GetExtension(uploadFileModel.FileName).ToLower() != ".doc")
|
||||
{
|
||||
return (false, "请上传PDF/Word/Excel格式的文件", DateTime.Now, "");
|
||||
}
|
||||
}
|
||||
if (PS.Config.ErpElement.SecuritiesEnvironment && uploadFileModel.Length > Modules.SuperviseReportModule.SAC.Model.ReportStatusModel.MaxAnnexLength)//小于30MB
|
||||
{
|
||||
return (false, "上传失败,单笔确认书文件大小不应超过30MB", DateTime.Now, "");
|
||||
}
|
||||
#endregion
|
||||
|
||||
var tradeNumber = "未知";
|
||||
if (contractDocR != null)
|
||||
{
|
||||
tradeNumber = contractDocR.TradeNumber;
|
||||
}
|
||||
var filePath = Path.Combine(OtcAppContext.AppDocsPath, "contractdoc", "output");
|
||||
|
||||
if (!Directory.Exists(filePath))
|
||||
{
|
||||
Directory.CreateDirectory(filePath);
|
||||
}
|
||||
|
||||
var stampFileFullName = Path.Combine(filePath, uploadFileModel.FileName);
|
||||
contractDoc.Paths = stampFileFullName.Replace(OtcAppContext.AppDocsPath, "/App_Docs").Replace("\\", "/");
|
||||
contractDoc.FileName = uploadFileModel.FileName;
|
||||
if (File.Exists(stampFileFullName))
|
||||
{
|
||||
File.Delete(stampFileFullName);
|
||||
}
|
||||
|
||||
using var fs = new FileStream(stampFileFullName, FileMode.Create, FileAccess.ReadWrite);
|
||||
|
||||
using var sr = uploadFileModel.OpenReadStream();
|
||||
|
||||
sr.Seek(0, SeekOrigin.Begin);
|
||||
var tempBytes = new byte[sr.Length];
|
||||
sr.Read(tempBytes, 0, tempBytes.Length);
|
||||
fs.Write(tempBytes, 0, tempBytes.Length);
|
||||
|
||||
sr.Close();
|
||||
|
||||
fs.Close();
|
||||
msg = msg.Length > 0 ? msg : "上传成功";
|
||||
}
|
||||
|
||||
#region 更新数据
|
||||
|
||||
new TradeConfirmService(OptUser, db).EditReportStatus(contractDocR.TradeId, true);
|
||||
db.SaveChanges();
|
||||
#endregion
|
||||
|
||||
return (true, msg, contractDoc.OptDate.Value, contractDoc.StampDocumentFileName);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogFactory.GetLogger("UploadContractFileNew").Error("UploadContractFileNew出错", ex);
|
||||
return (false, "操作出错", DateTime.Now, "");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public string GetSealErrMsg(string code)
|
||||
{
|
||||
var db = DbContextFactory.GetYLDbContext();
|
||||
|
||||
var errMsg = db.trade_contract_document.FirstOrDefault(x => x.Code == code && x.SealResult == 1);
|
||||
|
||||
return errMsg == null ? "" : errMsg.SealErrMsg;
|
||||
}
|
||||
|
||||
public bool IsSealWaiting(int tradeId)
|
||||
{
|
||||
var db = DbContextFactory.GetYLDbContext();
|
||||
|
||||
var code = db.trade_contract_r.FirstOrDefault(x => x.TradeId == tradeId)?.ContractCode;
|
||||
|
||||
var flag = code != null && db.trade_contract_document.Any(x => x.Code == code && x.SealResult == 3);
|
||||
|
||||
return flag;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 判断确认书是否生成过
|
||||
/// </summary>
|
||||
/// <param name="ids">trade_contract_r.id</param>
|
||||
/// <returns></returns>
|
||||
public bool IsContractGenerated(List<int> ids,List<string> types)
|
||||
{
|
||||
var db = DbContextFactory.GetYLDbContext();
|
||||
var flag = true;
|
||||
var tradeContractList = (from tradeContractR in db.trade_contract_r
|
||||
join tradeContractDoc in (from tradeContractDocTemp in db.trade_contract_document select tradeContractDocTemp)
|
||||
on tradeContractR.ContractCode equals tradeContractDoc.Code into tradeContractDoc1
|
||||
from tradeContractDoc2 in tradeContractDoc1.DefaultIfEmpty()
|
||||
where ids.Contains(tradeContractR.id) && types.Contains(tradeContractR.Type) && tradeContractR.IsValid
|
||||
select new
|
||||
{
|
||||
tradeContractR.id,
|
||||
tradeContractR.TradeId,
|
||||
tradeContractR.ContractCode,
|
||||
tradeContractDoc = tradeContractDoc2
|
||||
}).ToList();
|
||||
if (tradeContractList.Count == 0 || tradeContractList.Any(x => x.tradeContractDoc == null || string.IsNullOrWhiteSpace(x.tradeContractDoc.Paths)))
|
||||
{
|
||||
flag = false;
|
||||
return flag;
|
||||
}
|
||||
foreach (var item in tradeContractList)
|
||||
{
|
||||
var path = Path.ChangeExtension(item.tradeContractDoc.AbsolutePath, "pdf");
|
||||
if (!File.Exists(path))
|
||||
{
|
||||
flag = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return flag;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 批量用印
|
||||
/// </summary>
|
||||
/// <param name="ids">trade_contract_r.id</param>
|
||||
/// <param name="type"></param>
|
||||
public void SealContracts(List<int> ids,List<string> types)
|
||||
{
|
||||
var db = DbContextFactory.GetYLDbContext();
|
||||
var contract = (from tradeContractR in db.trade_contract_r
|
||||
join tradeContractDoc in (from tradeContractDocTemp in db.trade_contract_document
|
||||
select tradeContractDocTemp)
|
||||
on tradeContractR.ContractCode equals tradeContractDoc.Code into tradeContractDoc1
|
||||
from tradeContractDoc2 in tradeContractDoc1.DefaultIfEmpty()
|
||||
where ids.Contains(tradeContractR.id) && types.Contains(tradeContractR.Type) && tradeContractR.IsValid
|
||||
select new
|
||||
{
|
||||
tradeContractR.id,
|
||||
tradeContractR.TradeId,
|
||||
tradeContractR.ContractCode,
|
||||
tradeContractDoc = tradeContractDoc2
|
||||
}).ToList();
|
||||
foreach (var item in contract)
|
||||
{
|
||||
|
||||
if (item.tradeContractDoc != null)
|
||||
{
|
||||
GlobalConfig.SealHandler.RemoveQueue(item.TradeId);
|
||||
|
||||
GlobalConfig.SealHandler.AddQueue(item.tradeContractDoc, item.TradeId);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
+179
@@ -0,0 +1,179 @@
|
||||
using System.Data;
|
||||
using System.Text.RegularExpressions;
|
||||
using YLErp.BLL;
|
||||
using YLErp.BLL.MarginCalculation;
|
||||
using YLErp.DBModels.Consts;
|
||||
using YLErp.DBModels.Converts;
|
||||
using YLErp.Model;
|
||||
using YLErp.Models;
|
||||
using YLErp.Modules.DataProviderModule;
|
||||
using YLErp.Modules.TradeDalModule;
|
||||
using YLErp.Office;
|
||||
using YLErp.Plugins.TradeDocGenerator.Abstracts;
|
||||
|
||||
namespace YLErp.Modules.TradeModule.DocGenerateModule
|
||||
{
|
||||
/// <summary>
|
||||
/// 生成远期结算确认书
|
||||
/// </summary>
|
||||
public class ForwardSettlementBillGenerateService : YLBaseService
|
||||
{
|
||||
public ForwardSettlementBillGenerateService(OptUserInfo userInfo) : base(userInfo)
|
||||
{
|
||||
}
|
||||
|
||||
public ForwardSettlementBillGenerateService(YLBaseService baseService) : base(baseService)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取交易关联的标的
|
||||
/// </summary>
|
||||
public underlying_manager GetTradeUnderlying(string underlyingcode)
|
||||
{
|
||||
var _underlying = DbContext.underlying_manager.AsNoTracking().FirstOrDefault(x => x.UnderlyingCode == underlyingcode);
|
||||
return _underlying;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 生成结算确认书
|
||||
/// </summary>
|
||||
public List<TradeDocGenerateResult> Generate(IEnumerable<int> tradeCashIds, IEnumerable<int> tradeIds, string docType)
|
||||
{
|
||||
if (tradeCashIds != null && tradeCashIds.Any())
|
||||
{
|
||||
tradeIds = DbContext.trade_cash.Where(x => tradeCashIds.Contains(x.id) && !x.IsDeleted).Select(x => x.TradeId).Distinct();
|
||||
}
|
||||
if (tradeIds == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(tradeIds));
|
||||
}
|
||||
|
||||
if (docType == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(docType));
|
||||
}
|
||||
|
||||
//当前交易日
|
||||
var valueDate = valuedateBLL.ValueDate;
|
||||
|
||||
//----------------------------------
|
||||
// 获取当日行权 平仓 到期的有效交易
|
||||
//----------------------------------
|
||||
var service = new TradeDalService(this);
|
||||
var tradeQuery = service
|
||||
.GetTradeOrEodTrade(tradeIds, valueDate)
|
||||
.Where(O => O.TradeStatus== ConsTrade.已平仓
|
||||
&& O.UnWindDate <= valueDate
|
||||
&& O.ClientId != 0);
|
||||
var tradeDic = tradeQuery.ToDictionary(n => n.id, n => new trade_contract_group { trade = n });
|
||||
if (tradeDic.Count < 1)
|
||||
{
|
||||
throw new ServiceException("当日没有要结算的记录信息!");
|
||||
}
|
||||
|
||||
tradeIds = tradeDic.Keys.ToArray();
|
||||
//----------------------------------
|
||||
// 交易确认书数据
|
||||
//----------------------------------
|
||||
var tcrQuery = from aa in DbContext.trade_contract_r
|
||||
where tradeIds.Contains(aa.TradeId)
|
||||
&& aa.Type == ContractTypeEnum.Trade && aa.IsValid
|
||||
select aa;
|
||||
var tcrDatas = tcrQuery.ToDictionary(K => K.TradeId, V => V);
|
||||
foreach (var data in tradeDic)
|
||||
{
|
||||
var id = data.Key;
|
||||
if (tcrDatas.TryGetValue(id, out var tcr))
|
||||
{ data.Value.ConfirmContractR = tcr; }
|
||||
}
|
||||
|
||||
//----------------------------------
|
||||
// 交易现金交割记录
|
||||
//----------------------------------
|
||||
var tradeCashDict = new Dictionary<int, int>();
|
||||
|
||||
var cashQuery = from tradeCash in DbContext.trade_cash.AsNoTracking()
|
||||
where tradeIds.Contains(tradeCash.TradeId) &&
|
||||
tradeCash.ValidState != ConsGlobal.InValid && !tradeCash.IsDeleted
|
||||
&& tradeCash.IsLastAction
|
||||
&& tradeCash.ExerciseWay == TradeCashExerciseWayEnum.提前终止行权
|
||||
select tradeCash;
|
||||
//当一笔交易存在多条到期行权记录时,取的最后一条资金记录。 --时嬴政 2022年8月2日
|
||||
var cashDatas = cashQuery.AsEnumerable().GroupBy(O => O.TradeId).ToDictionary(K => K.Key, V => V.LastOrDefault());
|
||||
if (tradeCashIds != null && tradeCashIds.Count() > 0)
|
||||
{
|
||||
tradeCashDict = cashDatas.Where(O => tradeCashIds.Contains(O.Value.id)).Select(O => O).ToDictionary(K => K.Key, V => V.Value.id);
|
||||
}
|
||||
else
|
||||
{
|
||||
tradeCashDict = cashDatas.Select(O => O).ToDictionary(K => K.Key, V => V.Value.id);
|
||||
}
|
||||
|
||||
foreach (var data in cashDatas)
|
||||
{
|
||||
if (tradeDic.TryGetValue(data.Value.TradeId, out var group))
|
||||
{
|
||||
group.trade.trade_cash = data.Value;
|
||||
group.trade_cash = data.Value;
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------
|
||||
// 生成交易结算书
|
||||
//----------------------------------
|
||||
var resultList = new List<TradeDocGenerateResult>();
|
||||
AppManager.TryResolve(out ITradeSettleBillGenerator generatorV2);
|
||||
var cacheList = new List<string>();
|
||||
//客户编号列表
|
||||
foreach (var tradeContractGroup in tradeDic.Values)
|
||||
{
|
||||
if (tradeContractGroup.trade.TradeStatus != ConsTrade.已平仓 && tradeContractGroup.trade_cash == null)
|
||||
{
|
||||
resultList.Add(new TradeDocGenerateResult(tradeContractGroup.trade)
|
||||
{
|
||||
ErrorMessage = "缺少现金交割记录"
|
||||
});
|
||||
}
|
||||
else if (generatorV2 != null)
|
||||
{
|
||||
var key = $"{tradeContractGroup.trade.id}_{tradeContractGroup.trade_cash.Action}_{tradeContractGroup.trade_cash.Notional}_{tradeContractGroup.trade_cash.UnwindNotional}";
|
||||
//判断重复
|
||||
if (cacheList.Contains(key))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
cacheList.Add(key);
|
||||
var result = GenerateSingleV2(generatorV2, tradeContractGroup, tradeContractGroup.trade_cash.id, docType);
|
||||
resultList.Add(result);
|
||||
}
|
||||
}
|
||||
|
||||
return resultList;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
private TradeDocGenerateResult GenerateSingleV2(ITradeSettleBillGenerator generator, trade_contract_group tradeContractGroup, int tradeCashId, string docType = "DOCX")
|
||||
{
|
||||
try
|
||||
{
|
||||
var context = new SettlementBillGenerateContext(tradeCashId, tradeContractGroup.trade, ContractTypeEnum.Clearing, OptUser);
|
||||
|
||||
generator.Initialize(docType, context);
|
||||
return generator.GenerateDocument();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogFactory.GetLogger("GenerateSingleV2").Error(ex);
|
||||
|
||||
return new TradeDocGenerateResult(tradeContractGroup.trade)
|
||||
{
|
||||
Exception = ex,
|
||||
ErrorMessage = "出错:" + ex.Message
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
using YLErp.DBModels.Abstract;
|
||||
using YLErp.DBModels.Consts;
|
||||
using YLErp.Modules.DataProviderModule;
|
||||
using YLErp.Plugins.TradeDocGenerator.Abstracts;
|
||||
|
||||
namespace YLErp.Modules.TradeModule.DocGenerateModule
|
||||
{
|
||||
/// <summary>
|
||||
/// 交易结算生成上下文
|
||||
/// </summary>
|
||||
public class MarginReportGenerateContext : ConfirmationGenerateContext, ITradeMarginReportGeneratorContext
|
||||
{
|
||||
private readonly trade_span _tradeSpan;
|
||||
|
||||
public MarginReportGenerateContext(int tradeCashId, trade tradeObj, trade_span tradeSpan, string contractType, OptUserInfo userInfo)
|
||||
: base(tradeCashId, tradeObj, contractType, userInfo)
|
||||
{
|
||||
_tradeSpan = tradeSpan ?? throw new ArgumentNullException(nameof(tradeSpan));
|
||||
}
|
||||
|
||||
|
||||
//交易确认书对象
|
||||
trade_contract_document _contractDoc;
|
||||
double? _underlyingSettlePrice = null;
|
||||
|
||||
/// <summary>
|
||||
/// 获取交易确认书
|
||||
/// </summary>
|
||||
public ITradeContractDocument GetTradeContractDocument()
|
||||
{
|
||||
if (_contractDoc == null)
|
||||
{
|
||||
var db = DbContextFactory.GetYLDbContext();
|
||||
var query = from contractDoc in db.trade_contract_document
|
||||
join tcr in db.trade_contract_r on contractDoc.Code equals tcr.ContractCode
|
||||
where tcr.TradeId == Trade.id && contractDoc.Type == ContractTypeEnum.Trade && tcr.Type == ContractTypeEnum.Trade && tcr.IsValid
|
||||
select contractDoc;
|
||||
_contractDoc = query.FirstOrDefault();
|
||||
}
|
||||
|
||||
if (_contractDoc == null)
|
||||
{
|
||||
throw new ServiceException($"未找到交易确认书(交易ID:{Trade.id},交易编号:{Trade.TradeNumber})");
|
||||
}
|
||||
|
||||
return _contractDoc;
|
||||
}
|
||||
|
||||
public trade_span GetTradeSpan()
|
||||
{
|
||||
return _tradeSpan;
|
||||
}
|
||||
|
||||
public bool OnMarginReportGenerated()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
|
||||
public double GetUnderlyingSettlePrice()
|
||||
{
|
||||
if (_underlyingSettlePrice == null)
|
||||
{
|
||||
if (EodPriceQueryService.TryGetEodPrice(_tradeSpan.ValueDate, Trade.UnderlyingCode, out var eodPrice))
|
||||
{
|
||||
_underlyingSettlePrice = eodPrice.GetPrice(Trade.SettlementType);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ServiceException($"未找到交易{Trade.TradeNumber}对应标的{Trade.UnderlyingCode}的{Trade.GetSettlementTypeDesc()}");
|
||||
}
|
||||
}
|
||||
|
||||
return _underlyingSettlePrice.Value;
|
||||
}
|
||||
|
||||
public override DateTime SystemValueDate => _tradeSpan.ValueDate;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,142 @@
|
||||
using YLErp.DBModels.Consts;
|
||||
using YLErp.Model;
|
||||
using YLErp.Models;
|
||||
using YLErp.Modules.TradeDalModule;
|
||||
using YLErp.Plugins.TradeDocGenerator.Abstracts;
|
||||
|
||||
namespace YLErp.Modules.TradeModule.DocGenerateModule
|
||||
{
|
||||
/// <summary>
|
||||
/// 生成追保通知书
|
||||
/// </summary>
|
||||
public class MarginReportGenerateService : YLBaseService
|
||||
{
|
||||
public MarginReportGenerateService(OptUserInfo userInfo) : base(userInfo)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 生成追保通知书
|
||||
/// </summary>
|
||||
public IEnumerable<TradeDocGenerateResult> Generate(IEnumerable<int> tradeIds, DateTime? valueDate, string docType)
|
||||
{
|
||||
if (tradeIds == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(tradeIds));
|
||||
}
|
||||
|
||||
if (valueDate == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(valueDate));
|
||||
}
|
||||
|
||||
if (docType == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(docType));
|
||||
}
|
||||
|
||||
//----------------------------------
|
||||
// 获取有效交易
|
||||
//----------------------------------
|
||||
//var tradeQuery = from trade in Table
|
||||
// where tradeIds.Contains(trade.id) && trade.ValidState != "InValid"
|
||||
// select trade;
|
||||
var tradeQuery = new TradeDalService(this).GetTradeOrEodTrade(tradeIds, SystemValueDate);
|
||||
|
||||
var tradeDic = tradeQuery.ToDictionary(n => n.id, n => new trade_contract_group { trade = n });
|
||||
tradeIds = tradeDic.Keys.ToArray();
|
||||
if (tradeDic.Count < 1)
|
||||
{
|
||||
throw new ServiceException("当日没有要结算的记录信息!");
|
||||
}
|
||||
|
||||
//----------------------------------
|
||||
// 交易确认书数据
|
||||
//----------------------------------
|
||||
var tcrQuery = from aa in DbContext.trade_contract_r
|
||||
where tradeIds.Contains(aa.TradeId) && aa.Type == ContractTypeEnum.Trade && aa.IsValid
|
||||
select aa;
|
||||
var tcrDatas = tcrQuery.ToArray();
|
||||
foreach (var data in tcrDatas)
|
||||
{
|
||||
if (tradeDic.TryGetValue(data.TradeId, out var group))
|
||||
{
|
||||
group.ConfirmContractR = data;
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------
|
||||
// 交易预付金记录
|
||||
//----------------------------------
|
||||
var tradeSpanQuery = from tradeSpan in DbContext.trade_span
|
||||
where tradeIds.Contains(tradeSpan.TradeId) &&
|
||||
tradeSpan.ValueDate == valueDate
|
||||
select tradeSpan;
|
||||
var tradeSpans = tradeSpanQuery.ToArray();
|
||||
foreach (var data in tradeSpans)
|
||||
{
|
||||
if (tradeDic.TryGetValue(data.TradeId, out var group))
|
||||
{
|
||||
group.trade_span = data;
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------
|
||||
// 生成追保通知书
|
||||
//----------------------------------
|
||||
var resultList = new List<TradeDocGenerateResult>();
|
||||
AppManager.TryResolve(out ITradeMarginReportGenerator generator);
|
||||
|
||||
foreach (var tradeContractGroup in tradeDic.Values)
|
||||
{
|
||||
if (generator == null)
|
||||
{
|
||||
resultList.Add(new TradeDocGenerateResult(tradeContractGroup.trade)
|
||||
{
|
||||
ErrorMessage = "此类型报告尚未实现"
|
||||
});
|
||||
}
|
||||
else if (!YLErp.PS.Config.Is光大光子 && tradeContractGroup.ConfirmContractR == null)
|
||||
{
|
||||
resultList.Add(new TradeDocGenerateResult(tradeContractGroup.trade)
|
||||
{
|
||||
ErrorMessage = "缺少交易确认书"
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
var result = GenerateSingle(generator, tradeContractGroup, tradeContractGroup.trade_cash.id, docType);
|
||||
resultList.Add(result);
|
||||
}
|
||||
}
|
||||
|
||||
return resultList;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
private TradeDocGenerateResult GenerateSingle(ITradeMarginReportGenerator generator, trade_contract_group tradeContractGroup, int tradeCashId, string docType = "DOCX")
|
||||
{
|
||||
try
|
||||
{
|
||||
var context = new MarginReportGenerateContext(
|
||||
tradeCashId,
|
||||
tradeContractGroup.trade,
|
||||
tradeContractGroup.trade_span,
|
||||
ContractTypeEnum.Margin, OptUser);
|
||||
generator.Initialize(docType, context);
|
||||
return generator.GenerateDocument();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogFactory.GetLogger("MarginReportGenerateService").Error(ex);
|
||||
return new TradeDocGenerateResult(tradeContractGroup.trade)
|
||||
{
|
||||
Exception = ex,
|
||||
ErrorMessage = "出错:" + ex.Message
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,119 @@
|
||||
using YLErp.BLL;
|
||||
using YLErp.DBModels.Consts;
|
||||
using YLErp.Model;
|
||||
using YLErp.Models;
|
||||
using YLErp.Modules.TradeDalModule;
|
||||
using YLErp.Plugins.TradeDocGenerator.Abstracts;
|
||||
|
||||
namespace YLErp.Modules.TradeModule.DocGenerateModule
|
||||
{
|
||||
/// <summary>
|
||||
/// 根据传入的TradeCashIds生成文档,不检查TradeCash状态
|
||||
/// </summary>
|
||||
public class RDBatchEndBillGenerateService : BatchUnwindReportGenerateService
|
||||
{
|
||||
public RDBatchEndBillGenerateService(OptUserInfo userInfo) : base(userInfo)
|
||||
{
|
||||
|
||||
}
|
||||
public IEnumerable<TradeDocGenerateResult> Generate(IEnumerable<int> tradeCashIds, IEnumerable<int> tradeIds, string docType, int userId, string userName, DateTime? startDate = null, DateTime? endDate = null)
|
||||
{
|
||||
if (tradeCashIds != null && tradeCashIds.Any())
|
||||
{
|
||||
tradeIds = DbContext.trade_cash.Where(x => tradeCashIds.Contains(x.id) && !x.IsDeleted).Select(x => x.TradeId).Distinct();
|
||||
}
|
||||
if (tradeIds == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(tradeIds));
|
||||
}
|
||||
|
||||
if (docType == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(docType));
|
||||
}
|
||||
|
||||
var valueDate = valuedateBLL.ValueDate;
|
||||
var tradeCashStatus = new string[] { ClientCashInCashOut.系统操作_行权费, ClientCashInCashOut.系统操作_平仓费, ClientCashInCashOut.系统操作_互换, ClientCashInCashOut.系统操作_票息 };
|
||||
|
||||
//----------------------------------
|
||||
// 获取当日行权 平仓 到期的有效交易
|
||||
//----------------------------------
|
||||
TradeDalService service = new TradeDalService(this);
|
||||
var allTrade = service
|
||||
.GetTradeOrEodTrade(tradeIds, valueDate)
|
||||
.Where(O =>
|
||||
(O.UnWindDate <= valueDate || O.UnWindDate == null)
|
||||
&& O.ClientId != 0).ToList();
|
||||
|
||||
if (!allTrade.Any())
|
||||
{
|
||||
throw new ServiceException("当日没有要结算的记录信息!");
|
||||
}
|
||||
var tradeList = allTrade/*.Where(O => O.ParentTradeId == 0)*/;
|
||||
|
||||
tradeIds = allTrade.Select(O => O.id).ToArray();
|
||||
//var parentTradeIds = allTrade.Where(O => O.ParentTradeId != 0).Distinct().ToDictionary(K => K.id, V => V.ParentTradeId);
|
||||
//var parentTrades = service
|
||||
// .GetTradeOrEodTrade(parentTradeIds.Values, valueDate)
|
||||
// .Where(O =>
|
||||
// O.UnWindDate <= valueDate
|
||||
// && O.ClientId != 0);
|
||||
var tradeDic = tradeList./*Concat(parentTrades).*/ToDictionary(n => n.id, n => new trade_contract_group { trade = n });
|
||||
|
||||
//----------------------------------
|
||||
// 交易确认书数据
|
||||
//----------------------------------
|
||||
var tcrQuery = from aa in DbContext.trade_contract_r
|
||||
where (tradeIds.Contains(aa.TradeId) && aa.IsValid
|
||||
//|| parentTradeIds.Values.Contains(aa.TradeId)
|
||||
)
|
||||
&& aa.Type == ContractTypeEnum.Trade
|
||||
select aa;
|
||||
var tcrDatas = tcrQuery.ToDictionary(K => K.TradeId, V => V);
|
||||
foreach (var data in tradeDic)
|
||||
{
|
||||
int id = data.Key;
|
||||
if (data.Value.trade.ParentTradeId != 0)
|
||||
{ id = data.Value.trade.ParentTradeId; }
|
||||
if (tcrDatas.TryGetValue(id, out var tcr))
|
||||
{ data.Value.ConfirmContractR = tcr; }
|
||||
}
|
||||
|
||||
//----------------------------------
|
||||
// 找到TradeCashId对应的TradeCash
|
||||
//----------------------------------
|
||||
var cashQuery = from tradeCash in DbContext.trade_cash
|
||||
where tradeCashIds.Contains(tradeCash.id) &&
|
||||
tradeCash.ValidState != ConsGlobal.InValid && !tradeCash.IsDeleted
|
||||
&& tradeCashStatus.Contains(tradeCash.Action)
|
||||
select tradeCash;
|
||||
//var cashDatas = cashQuery.GroupBy(O => O.TradeId).ToDictionary(K => K.Key, V => V);
|
||||
List<trade> tradelist = new List<trade>();
|
||||
foreach (var data in cashQuery)
|
||||
{
|
||||
trade t = tradeDic[data.TradeId].trade.Clone();
|
||||
t.trade_cash = data;
|
||||
tradelist.Add(t);
|
||||
}
|
||||
|
||||
var resultList = new List<TradeDocGenerateResult>();
|
||||
|
||||
AppManager.TryResolve(out ITradeUnwindReportGenerator generatorV2);
|
||||
if (generatorV2 != null)
|
||||
{
|
||||
|
||||
var result = base.GenerateSingleV2(generatorV2, tradelist, tradeCashIds, docType, startDate, endDate);
|
||||
resultList.Add(result);
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var item in tradeDic)
|
||||
{
|
||||
resultList.Add(base.GenerateSingleV1(item.Value, OptUser.UserId, OptUser.UserName, docType));
|
||||
}
|
||||
}
|
||||
|
||||
return resultList;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,483 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using YLErp.Abstract;
|
||||
using YLErp.DBModels;
|
||||
using YLErp.DBModels.Abstract;
|
||||
using YLErp.Modules.TradeModule.DealModule;
|
||||
using System.Net.Http;
|
||||
using BaseOUDAL;
|
||||
using YLErp.Modules;
|
||||
using Qdp.Pricing.Base.Enums;
|
||||
using System.Threading.Channels;
|
||||
using YLErp.Model;
|
||||
using Org.BouncyCastle.Asn1.Ocsp;
|
||||
using YLErp.DBModels.Consts;
|
||||
using YLErp.Helpers;
|
||||
using Qdp.Pricing.Library.Base.Utilities;
|
||||
using YLErp.Modules.SuperviseReportModule.SAC.Service;
|
||||
using NPOI.POIFS.Crypt;
|
||||
using YLErp.Models;
|
||||
using static Microsoft.EntityFrameworkCore.DbLoggerCategory;
|
||||
using YLErp.Modules.ApiModule;
|
||||
using static ICSharpCode.SharpZipLib.Zip.ExtendedUnixData;
|
||||
using YLErp.Model.Enum;
|
||||
using Qdp.Foundation.Utilities;
|
||||
using static YLErp.ConsGlobal;
|
||||
using System.Net.Http.Headers;
|
||||
using NPOI.HPSF;
|
||||
using YieldChain.Security;
|
||||
|
||||
namespace YLErp.Modules.TradeModule.DocGenerateModule
|
||||
{
|
||||
/// <summary>
|
||||
/// 自动用印业务类
|
||||
/// </summary>
|
||||
public class SealTaskHandleService : YLBaseService, ISealTaskHandler
|
||||
{
|
||||
/// <summary>
|
||||
/// 用印队列
|
||||
/// </summary>
|
||||
private static readonly Queue<SealTask> ContractQueue = new Queue<SealTask>();
|
||||
private Thread _thread = null;
|
||||
private bool _runStatus = false;
|
||||
private readonly object _obj = new object();
|
||||
|
||||
private readonly IYcLogger _logger;
|
||||
|
||||
private HttpClientWrap _httpClient = null;
|
||||
|
||||
private HttpClientWrap httpClient
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_httpClient == null)
|
||||
{
|
||||
lock (this)
|
||||
{
|
||||
if (_httpClient == null)
|
||||
{
|
||||
_httpClient = new HttpClientWrap(PS.GetErpConfig().SealApi,60);
|
||||
}
|
||||
}
|
||||
}
|
||||
return _httpClient;
|
||||
}
|
||||
}
|
||||
|
||||
private OptUserInfo _systemUser = new OptUserInfo(0, "系统用印", OptUserFrom.System);
|
||||
|
||||
//private readonly string _sealApi = ;
|
||||
//private readonly IHttpClientFactory _httpClientFactory;
|
||||
|
||||
public SealTaskHandleService(OptUserInfo userInfo) : base(userInfo)
|
||||
{
|
||||
_logger = LogFactory.GetLogger("确认书用印");
|
||||
|
||||
|
||||
}
|
||||
|
||||
public void AddQueue(ITradeContractDocument confirmDoc, List<int> tradeIds)
|
||||
{
|
||||
|
||||
try
|
||||
{
|
||||
lock (_obj)
|
||||
{
|
||||
|
||||
UpdateTradeContractDocument(confirmDoc, (int)SealResultEnum.用印等待中, null);
|
||||
|
||||
_logger.Info("等待进入排队序列...");
|
||||
|
||||
tradeIds.ForEach(tId =>
|
||||
{
|
||||
SaveTradeAuditLog(tId, "", "开始排队", DateTime.Now);
|
||||
_logger.Info($"交易编号:{tId}开始排队,等待用印");
|
||||
});
|
||||
|
||||
StartSealTask(confirmDoc, tradeIds);
|
||||
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.Info($"排队失败,错误信息:{ex.Message}");
|
||||
}
|
||||
|
||||
//ExecuteSealTask();
|
||||
}
|
||||
|
||||
private void StartSealTask(ITradeContractDocument confirmDoc, List<int> tradeids)
|
||||
{
|
||||
var sealTask = new SealTask();
|
||||
sealTask.Document = confirmDoc;
|
||||
sealTask.TradeIds = tradeids;
|
||||
ContractQueue.Enqueue(sealTask);
|
||||
|
||||
if (!_runStatus)
|
||||
{
|
||||
_runStatus = true;
|
||||
_thread = new Thread(new ThreadStart(ExecuteSealTask));
|
||||
_thread.Start();
|
||||
_logger.Info($"线程成功开启");
|
||||
}
|
||||
}
|
||||
|
||||
public void AddQueue(ITradeContractDocument confirmDoc, int tradeId)
|
||||
{
|
||||
try
|
||||
{
|
||||
lock (_obj)
|
||||
{
|
||||
_logger.Info("等待进入排队序列...");
|
||||
UpdateTradeContractDocument(confirmDoc, (int)SealResultEnum.用印等待中, null);
|
||||
|
||||
SaveTradeAuditLog(tradeId, "", "开始排队", DateTime.Now);
|
||||
|
||||
StartSealTask(confirmDoc, new List<int>() { tradeId });
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.Info($"排队失败,错误信息:{ex.Message}");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void RemoveQueue(int tradeId)
|
||||
{
|
||||
lock (_obj)
|
||||
{
|
||||
for (int i = 0; i < ContractQueue.Count; i++)
|
||||
{
|
||||
var obj = ContractQueue.Dequeue();
|
||||
if (obj.TradeIds.Contains(tradeId))
|
||||
{
|
||||
obj.TradeIds.Remove(tradeId);
|
||||
}
|
||||
ContractQueue.Enqueue(obj);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async void ExecuteSealTask()
|
||||
{
|
||||
//SetLog(tradeIds,"开始用印");
|
||||
|
||||
while (true)
|
||||
{
|
||||
SealTask obj = null;
|
||||
lock (_obj)
|
||||
{
|
||||
if (!ContractQueue.TryPeek(out obj))
|
||||
{
|
||||
_runStatus = false;
|
||||
_logger.Info($"线程执行结束");
|
||||
break;
|
||||
}
|
||||
_logger.Info($"线程成功取到对象");
|
||||
}
|
||||
|
||||
//发送用印到接口
|
||||
var (success, result, fileBytesStr) = await UploadApiAsync(obj.Document, PS.GetErpConfig().SealKeyWord);
|
||||
lock (_obj)
|
||||
{
|
||||
ContractQueue.TryPeek(out var temp);
|
||||
//if (obj != temp)
|
||||
//{
|
||||
// continue;
|
||||
//}
|
||||
if (!success)
|
||||
{
|
||||
UpdateTradeContractDocument(obj.Document, (int)SealResultEnum.失败, result);
|
||||
}
|
||||
else
|
||||
{
|
||||
//上传
|
||||
var ms = new MemoryStream();
|
||||
if (!string.IsNullOrWhiteSpace(fileBytesStr))
|
||||
{
|
||||
|
||||
var fileBytes = Convert.FromBase64String(fileBytesStr);
|
||||
|
||||
ms.Write(fileBytes, 0, fileBytes.Length);
|
||||
|
||||
//OptUser.UserId = 0;
|
||||
|
||||
//OptUser.UserName = "系统用印";
|
||||
}
|
||||
|
||||
var (flag, msg, optDate,stampPath) = new ConfirmationGenerateService(_systemUser).UploadContractFile(obj.Document.EncryptId, obj.Document.Comments, obj.Document.Code, true, false, new UploadFileModel
|
||||
{
|
||||
Length = ms.Length,
|
||||
ContentType = "application/pdf",
|
||||
FileName = obj.Document.FileName,
|
||||
OpenReadStream = () => ms
|
||||
});
|
||||
|
||||
if (flag)
|
||||
{
|
||||
UpdateTradeContractDocument(obj.Document, (int)SealResultEnum.成功, result);
|
||||
}
|
||||
else
|
||||
{
|
||||
UpdateTradeContractDocument(obj.Document, (int)SealResultEnum.失败, msg);
|
||||
}
|
||||
|
||||
foreach (var tId in temp.TradeIds)
|
||||
{
|
||||
if (!success)
|
||||
{
|
||||
//记日志
|
||||
_logger.Error($"交易编号:{tId}用印失败:{result}");
|
||||
|
||||
SaveTradeAuditLog(tId, result, "用印失败", DateTime.Now);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (flag)
|
||||
{
|
||||
//记日志
|
||||
_logger.Info($"交易编号:{tId}用印文件上传成功");
|
||||
|
||||
SaveTradeAuditLog(tId, result, "用印成功", optDate);
|
||||
}
|
||||
else
|
||||
{
|
||||
//记日志
|
||||
_logger.Error($"交易编号:{tId}用印文件上传失败:{msg}");
|
||||
|
||||
SaveTradeAuditLog(tId, msg, "用印失败", optDate);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ContractQueue.Dequeue();
|
||||
|
||||
_logger.Info("用印结束");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="document"></param>
|
||||
/// <param name="keyword"></param>
|
||||
/// <returns>
|
||||
/// <para>1:用印是否成功</para>
|
||||
/// <para>2:用印接口返回信息</para>
|
||||
/// <para>3:用印文件base64字符串</para>
|
||||
/// </returns>
|
||||
public async Task<(bool, string, string)> UploadApiAsync(ITradeContractDocument document, string keyword)
|
||||
{
|
||||
var msg = "";
|
||||
try
|
||||
{
|
||||
_logger.Info("请求用印接口token");
|
||||
|
||||
|
||||
var res = await httpClient.PostMultipartFormDataAsync("es/v1/getToken", new Dictionary<string, HttpContent>
|
||||
{
|
||||
["appid"] = new StringContent("zqsy_api_yl"),
|
||||
["secretkey"] = new StringContent("8PyrLMVxT1=WzTmr")
|
||||
}, null);
|
||||
|
||||
var tokenModel = JsonHelper.Deserialize<ZQTokenApiResponseModel>(res);
|
||||
|
||||
var token = "";
|
||||
|
||||
if (tokenModel.success)
|
||||
{
|
||||
token = tokenModel.data.token;
|
||||
_logger.Info("请求用印接口token成功");
|
||||
}
|
||||
else
|
||||
{
|
||||
msg = "请求用印接口token失败";
|
||||
|
||||
return (false, msg, null);
|
||||
}
|
||||
|
||||
var path = Path.ChangeExtension(document.AbsolutePath, "pdf");
|
||||
using var fs = new FileStream(path, FileMode.Open, FileAccess.Read);
|
||||
|
||||
var fileBytes = new byte[fs.Length];
|
||||
|
||||
fs.Read(fileBytes, 0, fileBytes.Length);
|
||||
|
||||
//file = Encoding.UTF8.GetString(fileBytes);
|
||||
|
||||
|
||||
|
||||
var postData = new Dictionary<string, HttpContent>
|
||||
{
|
||||
["file"] = new ByteArrayContent(fileBytes)
|
||||
{
|
||||
Headers =
|
||||
{
|
||||
ContentDisposition = new ContentDispositionHeaderValue("form-data")
|
||||
{
|
||||
Name = "file",
|
||||
FileName = document.FileName,
|
||||
}
|
||||
}
|
||||
},
|
||||
["typeCode"] = new StringContent("MM")
|
||||
};
|
||||
|
||||
//if(!string.IsNullOrWhiteSpace(keyword))
|
||||
//{
|
||||
|
||||
|
||||
postData.Add("keywords", new StringContent(keyword));
|
||||
//}
|
||||
|
||||
|
||||
//res = _httpClient.PostJson("es/v1/sign", postData, req =>
|
||||
//{
|
||||
// var content = new MultipartFormDataContent();
|
||||
|
||||
// var boundary = string.Format("--{0}", DateTime.Now.Ticks.ToString("x"));
|
||||
|
||||
// content.Headers.Add("ContentType", $"multipart/form-data, boundary={boundary}");
|
||||
|
||||
// req.Content = content;
|
||||
// req.Headers.Add("token", token);
|
||||
//});
|
||||
|
||||
res = await httpClient.PostMultipartFormDataAsync("es/v1/sign", postData, req =>
|
||||
{
|
||||
req.Headers.Add("token", token);
|
||||
});
|
||||
|
||||
var sealModel = JsonHelper.Deserialize<ZQSealApiResponseModel>(res);
|
||||
|
||||
var fileBytesStr = "";
|
||||
|
||||
if (sealModel.success)
|
||||
{
|
||||
fileBytesStr = sealModel.data.fileByte;
|
||||
msg = sealModel.msg;
|
||||
}
|
||||
else
|
||||
{
|
||||
msg = sealModel.msg;
|
||||
|
||||
|
||||
return (false, msg, null);
|
||||
}
|
||||
|
||||
return (true, msg, fileBytesStr);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
msg = $"用印失败:{ex.Message}";
|
||||
|
||||
|
||||
return (false, msg, null);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public bool IsQueueExistsCode(string code)
|
||||
{
|
||||
return ContractQueue.Any(c => c.Document.Code == code);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 记日志
|
||||
/// </summary>
|
||||
/// <param name="log"></param>
|
||||
/// <returns></returns>
|
||||
public void SaveTradeAuditLog(int tradeId, string changes, string optType, DateTime optDate)
|
||||
{
|
||||
|
||||
|
||||
var tradeAuditLog = new TradeAuditLog
|
||||
{
|
||||
TradeId = tradeId,
|
||||
Changes = changes,
|
||||
DataType = "00",
|
||||
OptId = 0,
|
||||
OptName = "系统用印",
|
||||
OptDate = optDate,
|
||||
OptType = optType,
|
||||
AuditFlag = TradeAuditFlag.operation
|
||||
};
|
||||
try
|
||||
{
|
||||
using var db = DbContextFactory.GetYLDbContext();
|
||||
|
||||
db.TradeAuditLog.Add(tradeAuditLog);
|
||||
|
||||
db.SaveChanges();
|
||||
|
||||
|
||||
|
||||
_logger.Info($"交易编号:{tradeId},trade_audit_log保存成功");
|
||||
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.Error($"交易编号:{tradeId},trade_audit_log保存失败,错误信息:{ex.Message}");
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void UpdateTradeContractDocument(ITradeContractDocument document, int sealResult, string errMsg)
|
||||
{
|
||||
|
||||
try
|
||||
{
|
||||
using var db = DbContextFactory.GetYLDbContext();
|
||||
|
||||
var contractDocument = db.trade_contract_document.FirstOrDefault(x => x.Code == document.Code);
|
||||
|
||||
if (contractDocument != null)
|
||||
{
|
||||
contractDocument.SealResult = sealResult;
|
||||
|
||||
if (sealResult == 1)
|
||||
{
|
||||
contractDocument.SealErrMsg = errMsg;
|
||||
_logger.Info($"确认书编号{document.Code}trade_contract_document error message:{errMsg}");
|
||||
}else if (sealResult == 0)
|
||||
{
|
||||
contractDocument.OptDate = DateTime.Now;
|
||||
_logger.Info($"确认书编号{document.Code}trade_contract_document用印成功");
|
||||
}
|
||||
|
||||
db.SaveChanges();
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Info($"确认书编号{document.Code}trade_contract_document保存失败,错误信息:查不到相关数据");
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.Error($"确认书编号{document.Code}trade_contract_document保存失败,错误信息:{ex.Message}");
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
using YLErp.BLL.MarginCalculation;
|
||||
using YLErp.DBModels.Abstract;
|
||||
using YLErp.DBModels.Consts;
|
||||
using YLErp.Modules.CalculationModule;
|
||||
using YLErp.Modules.DataProviderModule;
|
||||
using YLErp.Plugins.TradeDocGenerator.Abstracts;
|
||||
|
||||
namespace YLErp.Modules.TradeModule.DocGenerateModule
|
||||
{
|
||||
/// <summary>
|
||||
/// 交易结算生成上下文
|
||||
/// </summary>
|
||||
public class SettlementBillGenerateContext : ConfirmationGenerateContext, ITradeSettleBillGeneratorContext
|
||||
{
|
||||
public SettlementBillGenerateContext(IEnumerable<int> tradeCashIds, IEnumerable<trade> trades, string contractType, OptUserInfo userInfo, DateTime? startDate, DateTime? endDate)
|
||||
: base(tradeCashIds, trades, contractType, userInfo, startDate, endDate) { }
|
||||
|
||||
public SettlementBillGenerateContext(int tradeCashId, trade tradeObj, string contractType, OptUserInfo userInfo)
|
||||
: base(tradeCashId, tradeObj, contractType, userInfo) { }
|
||||
|
||||
public SettlementBillGenerateContext(Client client, List<swap_flow_event> flowEvents, List<swap_flow_event> allFlowEvents, List<trade> trades, List<swap_position> swapPositions, string contractType, OptUserInfo userInfo)
|
||||
:base(client, flowEvents, allFlowEvents, trades, swapPositions, contractType, userInfo)
|
||||
{
|
||||
|
||||
}
|
||||
/// <summary>
|
||||
/// 获取预付金
|
||||
/// </summary>
|
||||
public double? GetMargin(double endPrice)
|
||||
{
|
||||
var req = new RunMarginCalculationReq(UserInfo)
|
||||
{
|
||||
tradeList = new List<trade> { (trade)Trade },
|
||||
settleDate = Trade.UnWindDate.Value,
|
||||
PriceProvider = new SinglePriceProvider(Trade.UnderlyingCode, endPrice)
|
||||
};
|
||||
var tradeSpans = MarginDefault.RunMarginCalculation(req);
|
||||
return tradeSpans?.FirstOrDefault()?.WorstCastClientPayable;
|
||||
}
|
||||
|
||||
//交易确认书对象
|
||||
trade_contract_document _contractDoc;
|
||||
|
||||
/// <summary>
|
||||
/// 获取交易确认书
|
||||
/// </summary>
|
||||
public ITradeContractDocument GetTradeContractDocument(int tradeId, string tradeNumber, bool throwException = true)
|
||||
{
|
||||
if (_contractDoc == null)
|
||||
{
|
||||
var db = DbContextFactory.GetYLDbContext();
|
||||
var query = from contractDoc in db.trade_contract_document
|
||||
join tcr in db.trade_contract_r on contractDoc.Code equals tcr.ContractCode
|
||||
where tcr.TradeId == tradeId && contractDoc.Type == ContractTypeEnum.Trade && tcr.Type == ContractTypeEnum.Trade && tcr.IsValid
|
||||
select contractDoc;
|
||||
_contractDoc = query.FirstOrDefault();
|
||||
}
|
||||
|
||||
if (_contractDoc == null && throwException)
|
||||
{
|
||||
throw new ServiceException($"未找到交易确认书(交易编号:{tradeNumber})");
|
||||
}
|
||||
|
||||
return _contractDoc;
|
||||
}
|
||||
|
||||
public bool OnSettlmentBillGenerated()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public double GetAverageSpotPrice(OtcTradeBase trade, trade_swap trade_swap)
|
||||
{
|
||||
var trades = (from td in DbContext.trade.Where(x => x.ClientId == trade.ClientId && x.UnderlyingCode == trade.UnderlyingCode && x.BuySell == trade.BuySell && x.TradeDate == trade.TradeDate && x.ValidState != "InValid")
|
||||
join swap in DbContext.trade_swap.Where(x => x.PayLongShort == trade_swap.PayLongShort && x.GetLongShort == trade_swap.GetLongShort)
|
||||
on td.id equals swap.TradeId
|
||||
select new { td, swap }).ToList();
|
||||
|
||||
var totalSpotPrice = 0.0;
|
||||
var totalNotional = 0.0;
|
||||
trades.ForEach(x =>
|
||||
{
|
||||
var tradeprice = x.swap.IsGetFloatingProfit ? (x.swap.PayTradePrice ?? 0) : (x.swap.GetTradePrice ?? 0);
|
||||
var notional = x.swap.IsGetFloatingProfit ? (x.swap.GetNotional ?? 0) : (x.swap.PayNotional ?? 0);
|
||||
var longshort = x.swap.IsGetFloatingProfit ? x.swap.GetLongShort : x.swap.PayLongShort;
|
||||
var spotprice = x.swap.IsGetFloatingProfit ? (x.swap.GetSpotPrice ?? 0) : (x.swap.PaySpotPrice ?? 0);
|
||||
var sigleprice = Math.Abs(tradeprice / notional);
|
||||
totalSpotPrice += (spotprice + (longshort == "空头" ? -1 : 1) * sigleprice) * notional;
|
||||
totalNotional += notional;
|
||||
});
|
||||
|
||||
return totalNotional > 0 ? totalSpotPrice / totalNotional : 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,559 @@
|
||||
using System.Data;
|
||||
using System.Text.RegularExpressions;
|
||||
using YLErp.BLL;
|
||||
using YLErp.BLL.MarginCalculation;
|
||||
using YLErp.DBModels.Consts;
|
||||
using YLErp.DBModels.Converts;
|
||||
using YLErp.Model;
|
||||
using YLErp.Models;
|
||||
using YLErp.Modules.DataProviderModule;
|
||||
using YLErp.Modules.TradeDalModule;
|
||||
using YLErp.MsOffice;
|
||||
using YLErp.Office;
|
||||
using YLErp.Office.Converters;
|
||||
using YLErp.Plugins.TradeDocGenerator.Abstracts;
|
||||
|
||||
namespace YLErp.Modules.TradeModule.DocGenerateModule
|
||||
{
|
||||
/// <summary>
|
||||
/// 生成结算确认书
|
||||
/// </summary>
|
||||
public class SettlementBillGenerateService : YLBaseService
|
||||
{
|
||||
public SettlementBillGenerateService(OptUserInfo userInfo) : base(userInfo)
|
||||
{
|
||||
}
|
||||
|
||||
public SettlementBillGenerateService(YLBaseService baseService) : base(baseService)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取交易关联的标的
|
||||
/// </summary>
|
||||
public underlying_manager GetTradeUnderlying(string underlyingcode)
|
||||
{
|
||||
var _underlying = DbContext.underlying_manager.AsNoTracking().FirstOrDefault(x => x.UnderlyingCode == underlyingcode);
|
||||
return _underlying;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 生成结算确认书
|
||||
/// </summary>
|
||||
public IEnumerable<TradeDocGenerateResult> Generate(IEnumerable<int> tradeCashIds, IEnumerable<int> tradeIds, string docType, int userId, string userName)
|
||||
{
|
||||
if (docType == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(docType));
|
||||
}
|
||||
|
||||
if (tradeCashIds != null && tradeCashIds.Any())
|
||||
{
|
||||
tradeIds = DbContext.trade_cash.Where(x => tradeCashIds.Contains(x.id) && !x.IsDeleted).Select(x => x.TradeId).Distinct();
|
||||
}
|
||||
|
||||
if (tradeIds == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(tradeIds));
|
||||
}
|
||||
|
||||
//当前交易日
|
||||
var valueDate = valuedateBLL.ValueDate;
|
||||
var tradeStatus = new string[] { ConsTrade.已到期, ConsTrade.已执行 };
|
||||
var tradeCashStatus = new string[] { ClientCashInCashOut.系统操作_行权费, ClientCashInCashOut.系统操作_平仓费, ClientCashInCashOut.系统操作_互换, ClientCashInCashOut.系统操作_票息 };
|
||||
|
||||
//----------------------------------
|
||||
// 获取当日行权 平仓 到期的有效交易
|
||||
//----------------------------------
|
||||
var service = new TradeDalService(this);
|
||||
var tradeQuery = service
|
||||
.GetTradeOrEodTrade(tradeIds, valueDate)
|
||||
.Where(O => tradeStatus.Contains(O.TradeStatus)
|
||||
&& O.UnWindDate <= valueDate
|
||||
&& O.ClientId != 0);
|
||||
|
||||
if (PS.Config.Is浙期)
|
||||
{//主要解决多腿交易,只勾选一腿时,将另一腿查出来一起生成;
|
||||
tradeQuery = service
|
||||
.GetTradeOrEodTradeOfTidASid(tradeIds, valueDate, useTradeDate: false)
|
||||
.Where(O => tradeStatus.Contains(O.TradeStatus)
|
||||
&& O.TradeType != "结构化交易"
|
||||
&& O.UnWindDate <= valueDate
|
||||
&& O.ClientId != 0);
|
||||
}
|
||||
var tradeDic = tradeQuery.ToDictionary(n => n.id, n => new trade_contract_group { trade = n });
|
||||
if (tradeDic.Count < 1)
|
||||
{
|
||||
throw new ServiceException("当日没有要结算的记录信息!");
|
||||
}
|
||||
|
||||
tradeIds = tradeDic.Keys.ToArray();
|
||||
var parentTradeIds = tradeDic.Values.Where(O => O.trade != null && O.trade.ParentTradeId != 0).ToDictionary(K => K.trade.id, V => V.trade.ParentTradeId);
|
||||
|
||||
if (PS.Config.Is长江)
|
||||
{
|
||||
parentTradeIds = tradeDic.Values.Where(O => O.trade != null && O.trade.ParentTradeId != 0 && (O.trade.StructureType == "牛市价差" || O.trade.StructureType == "熊市价差")).ToDictionary(K => K.trade.id, V => V.trade.ParentTradeId);
|
||||
}
|
||||
|
||||
var parentTrades = service
|
||||
.GetStructTradeFromTradeOrEodTrade(parentTradeIds.Values, valueDate)
|
||||
.Where(O =>
|
||||
tradeStatus.Contains(O.TradeStatus)
|
||||
&& O.UnWindDate <= valueDate
|
||||
&& O.ClientId != 0)
|
||||
.ToDictionary(K => K.id, V => V);
|
||||
|
||||
if (PS.Config.Is长江 && parentTrades.Count > 0)
|
||||
{
|
||||
tradeIds = parentTrades.Select(O => O.Key);
|
||||
}
|
||||
//----------------------------------
|
||||
// 交易确认书数据
|
||||
//----------------------------------
|
||||
var tcrQuery = from aa in DbContext.trade_contract_r
|
||||
where (tradeIds.Contains(aa.TradeId)
|
||||
|| parentTradeIds.Values.Contains(aa.TradeId))
|
||||
&& aa.Type == ContractTypeEnum.Trade && aa.IsValid
|
||||
select aa;
|
||||
var tcrDatas = tcrQuery.ToDictionary(K => K.TradeId, V => V);
|
||||
foreach (var data in tradeDic)
|
||||
{
|
||||
var id = data.Key;
|
||||
if (data.Value.trade.ParentTradeId != 0)
|
||||
{
|
||||
id = data.Value.trade.ParentTradeId;
|
||||
}
|
||||
if (tcrDatas.TryGetValue(id, out var tcr))
|
||||
{
|
||||
data.Value.ConfirmContractR = tcr;
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------
|
||||
// 交易现金交割记录
|
||||
//----------------------------------
|
||||
var cashQuery = from tradeCash in DbContext.trade_cash.AsNoTracking()
|
||||
where tradeIds.Contains(tradeCash.TradeId)
|
||||
&& tradeCash.ValidState != ConsGlobal.InValid && !tradeCash.IsDeleted
|
||||
&& tradeCash.IsLastAction
|
||||
//20230408:如果参数入值没问题的话,ExerciseWay应该是不需要的
|
||||
//20230408:东莞的黑箱雪球的tradeCash.ExerciseWay为null,故而把这行注释掉
|
||||
// tradeCash.ExerciseWay == TradeCashExerciseWayEnum.到期行权
|
||||
select tradeCash;
|
||||
|
||||
//当一笔交易存在多条到期行权记录时,取的最后一条资金记录。 --时嬴政 2022年8月2日
|
||||
var cashDatas = cashQuery.AsEnumerable().GroupBy(O => O.TradeId).ToDictionary(K => K.Key, V => V.LastOrDefault());
|
||||
|
||||
foreach (var data in cashDatas)
|
||||
{
|
||||
if (tradeDic.TryGetValue(data.Value.TradeId, out var group))
|
||||
{
|
||||
if (parentTradeIds.ContainsKey(data.Value.TradeId))
|
||||
{
|
||||
if (PS.Config.Is光大光子)//这个分支里的逻辑和下面那个长江应该没区别
|
||||
{
|
||||
var id = parentTradeIds[data.Value.TradeId];
|
||||
var allTradeList = service.GetTradeOrEodTradeOfTidAPid(new[] { id }, valueDate).GroupBy(O => O.TradeStatus).ToDictionary(K => K.Key, V => V.ToList());
|
||||
allTradeList.First().Value.RemoveAll(x => x.ParentTradeId != 0 && !tradeIds.Contains(x.id));
|
||||
var subTrades = allTradeList.First().Value.Where(x => x.ParentTradeId != 0).ToList();
|
||||
var subTradeIds = subTrades.Select(O => O.id);
|
||||
var cashes = cashQuery.Where(O => subTradeIds.Contains(O.TradeId)).AsEnumerable().GroupBy(O => new { O.ValueDate, O.Action, O.ExerciseWay, O.Notional, O.UnwindNotional }).ToDictionary(K => K.Key, V => V.ToList());
|
||||
if (subTrades.Count == cashes.First().Value.Count)
|
||||
{
|
||||
subTrades.ForEach(O => O.trade_cash = cashes.First().Value.First(B => B.TradeId == O.id));
|
||||
group.trade = allTradeList.First().Value.Where(O => O.id == id).First();
|
||||
group.trade.SubTrades = allTradeList.First().Value.Where(O => O.id != id).ToList();
|
||||
}
|
||||
}
|
||||
else if (PS.Config.Is长江 || PS.Config.Is浙期)
|
||||
{
|
||||
var id = parentTradeIds[data.Value.TradeId];
|
||||
//将已到期和已执行视为同一个状态;
|
||||
var allTradeList = service.GetTradeOrEodTradeOfTidAPid(new[] { id }, valueDate).GroupBy(O => (O.TradeStatus == "已执行" ? "已到期" : O.TradeStatus)).ToDictionary(K => K.Key, V => V.ToList());
|
||||
var subTrades = allTradeList.Values.Aggregate((X, Y) => { X.AddRange(Y); return X; }).Where(x => x.ParentTradeId != 0).ToList();
|
||||
var subTradeIds = subTrades.Select(O => O.id);
|
||||
var cashes = cashQuery.Where(O => subTradeIds.Contains(O.TradeId)).AsEnumerable().GroupBy(O => new { O.ValueDate, O.Action, O.ExerciseWay, O.Notional, O.UnwindNotional }).ToDictionary(K => K.Key, V => V.ToList());
|
||||
//忽略主交易状态;
|
||||
if (subTrades.GroupBy(O => (O.TradeStatus == "已执行" ? "已到期" : O.TradeStatus)).Count() == 1 && cashes.Count == 1)
|
||||
{
|
||||
subTrades.ForEach(O => O.trade_cash = cashes.First().Value.First(B => B.TradeId == O.id));
|
||||
group.trade = allTradeList.First().Value.Where(O => O.id == id).First();
|
||||
group.trade.SubTrades = subTrades;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var id = parentTradeIds[data.Value.TradeId];
|
||||
var subTrades = service.GetStructTradeFromTradeOrEodTrade(new[] { id }, valueDate).GroupBy(O => O.TradeStatus).ToDictionary(K => K.Key, V => V.ToList());
|
||||
tradeIds = subTrades.First().Value.Select(O => O.id).ToArray();
|
||||
var cashes = cashQuery.AsEnumerable().GroupBy(O => new { O.ValueDate, O.Action, O.ExerciseWay, O.Notional, O.UnwindNotional }).ToDictionary(K => K.Key, V => V.ToList());
|
||||
if (subTrades.Count == 1 && cashes.Count == 1)
|
||||
{
|
||||
subTrades.First().Value.ForEach(O => O.trade_cash = cashes.First().Value.First(B => B.TradeId == O.id));
|
||||
group.trade = parentTrades[group.trade.id];
|
||||
group.trade.SubTrades = subTrades.First().Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
group.trade.trade_cash = data.Value;
|
||||
group.trade_cash = data.Value;
|
||||
|
||||
if (group.trade.TradeType == "结构化交易")
|
||||
{
|
||||
if (group.trade.IsGroup == 1)
|
||||
{
|
||||
group.trade.SubTrades = DbContext.trade.Where(O => O.ParentTradeId == group.trade.id).ToList();
|
||||
foreach (var subtc in group.trade.SubTrades)
|
||||
{
|
||||
subtc.trade_cash = DbContext.trade_cash.FirstOrDefault(tc => tc.TradeId == subtc.id
|
||||
&& tc.ValidState != ConsGlobal.InValid && !tc.IsDeleted
|
||||
&& tc.IsLastAction);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------
|
||||
// 生成交易结算书
|
||||
//----------------------------------
|
||||
var resultList = new List<TradeDocGenerateResult>();
|
||||
AppManager.TryResolve(out ITradeSettleBillGenerator generatorV2);
|
||||
var checkDuplicateSet = new HashSet<string>();
|
||||
//客户编号列表
|
||||
foreach (var tradeContractGroup in tradeDic.Values)
|
||||
{
|
||||
var missingTradeCash = false;
|
||||
|
||||
if (tradeContractGroup.trade.TradeType != "结构化交易")
|
||||
{
|
||||
missingTradeCash = tradeContractGroup.trade_cash == null;
|
||||
}
|
||||
else if (tradeContractGroup.trade.IsGroup == 0)
|
||||
{
|
||||
missingTradeCash = tradeContractGroup.trade_cash == null || tradeContractGroup.trade.SubTrades.Any(O => O.trade_cash == null);
|
||||
}
|
||||
|
||||
if (missingTradeCash)
|
||||
{
|
||||
resultList.Add(new TradeDocGenerateResult(tradeContractGroup.trade)
|
||||
{
|
||||
ErrorMessage = "缺少现金交割记录"
|
||||
});
|
||||
}
|
||||
else if (generatorV2 != null)
|
||||
{
|
||||
var key = $"{tradeContractGroup.trade.id}_{tradeContractGroup.trade_cash.Action}_{tradeContractGroup.trade_cash.Notional}_{tradeContractGroup.trade_cash.UnwindNotional}";
|
||||
if (!checkDuplicateSet.Add(key)) //判断重复
|
||||
{
|
||||
continue;
|
||||
}
|
||||
var result = GenerateSingleV2(generatorV2, tradeContractGroup, tradeContractGroup.trade_cash.id, docType);
|
||||
if (PS.Config.Is方顿 && resultList.Any(x => x.OutputFilePath == result.OutputFilePath))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
resultList.Add(result);
|
||||
}
|
||||
else
|
||||
{
|
||||
var result = GenerateSingleV1(tradeContractGroup, userId, userName, docType);
|
||||
resultList.Add(result);
|
||||
}
|
||||
}
|
||||
|
||||
return resultList;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
private TradeDocGenerateResult GenerateSingleV2(ITradeSettleBillGenerator generator, trade_contract_group tradeContractGroup, int tradeCashId, string docType = "DOCX")
|
||||
{
|
||||
try
|
||||
{
|
||||
var context = new SettlementBillGenerateContext(tradeCashId, tradeContractGroup.trade, ContractTypeEnum.Clearing, OptUser);
|
||||
|
||||
generator.Initialize(docType, context);
|
||||
return generator.GenerateDocument();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogFactory.GetLogger("GenerateSingleV2").Error(ex);
|
||||
|
||||
return new TradeDocGenerateResult(tradeContractGroup.trade)
|
||||
{
|
||||
Exception = ex,
|
||||
ErrorMessage = "出错:" + ex.Message
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
private TradeDocGenerateResult GenerateSingleV1(trade_contract_group contractGroup, int userId, string userName, string docType = "DOCX")
|
||||
{
|
||||
if (contractGroup == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(contractGroup));
|
||||
}
|
||||
|
||||
var contractBLL = new TradeContractBLL(this);
|
||||
var dic = new Dictionary<string, object>();
|
||||
var trade = contractGroup.trade;
|
||||
var tradeCash = contractGroup.trade_cash;
|
||||
var tradeContractR = contractGroup.ConfirmContractR;
|
||||
if (tradeContractR == null)
|
||||
{
|
||||
throw new Exception(contractGroup.trade.TradeNumber + "该笔交易未生成交易确认书");
|
||||
}
|
||||
var needAddData = true;
|
||||
|
||||
#region 如果到期结算单已经生成过,则直接返回
|
||||
var settlementDoc = contractBLL.GetContractDoc(trade.id, ContractTypeEnum.Clearing);
|
||||
if (settlementDoc != null)
|
||||
{
|
||||
if (File.Exists(settlementDoc.AbsolutePath))
|
||||
{
|
||||
if (docType == "PDF")
|
||||
{
|
||||
var pdfPath = settlementDoc.AbsolutePath.Replace(".docx", ".pdf");
|
||||
if (!File.Exists(pdfPath))
|
||||
{
|
||||
OfficeFileConverter.ConvertDocxToPDF(settlementDoc.AbsolutePath, pdfPath);
|
||||
}
|
||||
return new TradeDocGenerateResult(trade)
|
||||
{
|
||||
OutputFilePath = $"../App_Docs/GTJA/{settlementDoc.FileName.Replace(".docx", ".pdf")}"
|
||||
};
|
||||
}
|
||||
|
||||
return new TradeDocGenerateResult(trade)
|
||||
{
|
||||
OutputFilePath = $"../App_Docs/GTJA/{settlementDoc.FileName}"
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
needAddData = false;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
var underlying = DataCacheProvider.GetUnderlyingDataSource().GetData(trade.UnderlyingCode);
|
||||
if (underlying == null)
|
||||
{
|
||||
return new TradeDocGenerateResult(trade)
|
||||
{
|
||||
ErrorMessage = $"标的资产{trade.UnderlyingCode}信息未找到"
|
||||
};
|
||||
}
|
||||
var client = DataCacheProvider.GetClientDataSource().GetData(trade.ClientId);
|
||||
if (client == null)
|
||||
{
|
||||
return new TradeDocGenerateResult(trade)
|
||||
{
|
||||
ErrorMessage = $"客户(id:{trade.ClientId})信息未找到"
|
||||
};
|
||||
}
|
||||
dic["{{客户名称}}"] = $"{trade.ClientName ?? ""}";
|
||||
dic["{{交易方向}}"] = $"贵司{BuySellConvert.GetClientBuySell(contractGroup.trade.BuySell)}";
|
||||
|
||||
var tradeType = trade.TradeType == "香草期权" ? "普通" : (trade.TradeType == "结构化交易" ? trade.StructureType : trade.TradeType.Replace("期权", ""));
|
||||
dic["{{期权类型}}"] = $"{trade.ExerciseModeCn}{tradeType}{trade.OptionType}期权";
|
||||
dic["{{到期日}}"] = trade.ExerciseDate?.ToString("yyyy年M月d日");
|
||||
dic["{{交易日}}"] = trade.TradeDate?.ToString("yyyy年M月d日");
|
||||
dic["{{合约到期日}}"] = trade.MaturityDate?.ToString("yyyy年M月d日");
|
||||
|
||||
var variety = VarietyBLL.GetAllvarietyModel().FirstOrDefault(x => x.id == underlying.UnderlyingTypeId);
|
||||
if (trade.TradeType == "合成价差期权")
|
||||
{
|
||||
dic["{{商品标的名称}}"] = synthetic_underlyingBLL.GetUnderlyingTipsInfo(trade.UnderlyingCode);
|
||||
}
|
||||
else
|
||||
{
|
||||
//合约代码和名称需要调整
|
||||
var UnderlyingCode = underlying.UnderlyingCode;
|
||||
if (Regex.IsMatch(UnderlyingCode, "^[a-zA-Z]+00"))
|
||||
{
|
||||
UnderlyingCode = UnderlyingCode.TrimEnd('0');
|
||||
}
|
||||
UnderlyingCode += "." + underlying.MarketCode;
|
||||
dic["{{商品标的名称}}"] = PS.Config.Is东兴 ? UnderlyingCode : trade.UnderlyingCode;
|
||||
}
|
||||
|
||||
var strUnit = variety.QuoteUnitSingle;
|
||||
var tradeNotional = trade.Notional;
|
||||
var tradeOriginalNotional = (trade.OriginalNotional ?? 0);
|
||||
|
||||
dic["{{商品标的数量}}"] = $"{tradeOriginalNotional.OtcFormatNotional()}{strUnit}";
|
||||
dic["{{支付时间}}"] = "买方终止 / 到期时支付";
|
||||
//期末价格
|
||||
var endPrice = underlying.Price ?? 0;
|
||||
//交割金额
|
||||
double tradeCashAmount = 0;
|
||||
double notional = 0;
|
||||
if (tradeCash != null)
|
||||
{
|
||||
endPrice = tradeCash.FinalPrice ?? 0;
|
||||
tradeCashAmount = tradeCash.Amount;
|
||||
notional = tradeCash.Action == "系统操作-行权费" ? tradeCash.Notional : tradeCash.UnwindNotional ?? 0;
|
||||
}
|
||||
|
||||
dic["{{执行价格}}"] = $"{(trade.ActualStrike ?? 0).OtcFormatUmPrice()}元/{strUnit}";
|
||||
dic["{{期初价格}}"] = $"{(trade.SpotPrice ?? 0).OtcFormatUmPrice()}元/{strUnit}";
|
||||
dic["{{期权价格}}"] = $"{(trade.TradeSinglePrice ?? 0).OtcFormatMoney(grouping: false)}元/{strUnit}";
|
||||
dic["{{期权费率}}"] = $"{trade.PremiumRate?.OtcFormat(OtcFormatFlag.premiumRateP)}";
|
||||
dic["{{期初名义本金}}"] = $"{(trade.OriginalStockEqvNotional ?? 0).OtcFormat(OtcFormatFlag.StockEqvNotional)}元";
|
||||
dic["{{期末名义本金}}"] = $"{trade.StockEqvNotional.OtcFormat(OtcFormatFlag.StockEqvNotional)}元";
|
||||
dic["{{期末价格}}"] = $"{endPrice.OtcFormatUmPrice()}元/{strUnit}";
|
||||
dic["{{期权收益}}"] = $"{Math.Abs(tradeCashAmount / tradeNotional).OtcFormatFlex(2, 4)}元/{strUnit}";
|
||||
dic["{{期末数量}}"] = $"{tradeNotional.OtcFormatNotional()}{strUnit}";
|
||||
dic["{{期权费}}"] = $"{(trade.TradePrice ?? 0).OtcFormatMoney(grouping: false)}元";
|
||||
dic["{{结算价}}"] = $"{Math.Abs(tradeCashAmount).OtcFormatMoney()}元";
|
||||
dic["{{终止日}}"] = trade.UnWindDate?.ToString("yyyy年M月d日");
|
||||
var req = new RunMarginCalculationReq(UserInfo)
|
||||
{
|
||||
tradeList = new List<trade> { trade },
|
||||
settleDate = trade.UnWindDate.Value,
|
||||
PriceProvider = new SinglePriceProvider(trade.UnderlyingCode, endPrice)
|
||||
};
|
||||
if (trade.IsGroup == 1)
|
||||
{
|
||||
req.tradeList = DbContext.trade.Where(x => x.ParentTradeId == trade.id).ToList();
|
||||
}
|
||||
var tradeSpans = MarginDefault.RunMarginCalculation(req);
|
||||
if (tradeSpans?.Count > 0)
|
||||
{
|
||||
var margin = trade.IsGroup == 1 ? tradeSpans.Sum(x => x.WorstCastClientPayable ?? 0) : (tradeSpans[0].WorstCastClientPayable ?? 0);
|
||||
dic["{{预付金}}"] = $"{Math.Abs(margin).OtcFormatMoney(grouping: false)}元";
|
||||
}
|
||||
else
|
||||
{
|
||||
dic["{{预付金}}"] = "0元";
|
||||
}
|
||||
dic["{{结算价格}}"] = dic["{{期权收益}}"];
|
||||
|
||||
var isGJBuyer = trade.BuySell == "买入";
|
||||
double incomes;
|
||||
if (isGJBuyer)
|
||||
{
|
||||
incomes = tradeCashAmount - (notional * trade.TradeSinglePrice) ?? 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
incomes = tradeCashAmount + (notional * trade.TradeSinglePrice) ?? 0;
|
||||
}
|
||||
dic["{{结算净额}}"] = $"{Math.Abs(incomes).OtcFormatMoney(grouping: false)}元";
|
||||
dic["{{结算方式}}"] = incomes > 0 ? "贵司向我司支付结算净额" : "我司向贵司支付结算净额";
|
||||
dic["{{到期盈亏}}"] = $"{Math.Abs(incomes).OtcFormatMoney(grouping: false)}元";
|
||||
|
||||
//东兴结算净额处理逻辑(卖价差期权)
|
||||
dic["{{客户结算净额}}"] = $"{(Math.Abs(tradeCashAmount) - (notional * trade.TradeSinglePrice))?.OtcFormatMoney(grouping: false)}元"; ;
|
||||
dic["{{机构结算净额}}"] = $"{((notional * trade.TradeSinglePrice) - Math.Abs(tradeCashAmount))?.OtcFormatMoney(grouping: false)}元"; ;
|
||||
|
||||
//合同编号
|
||||
string contractNo;
|
||||
string outPutFileName;
|
||||
if (settlementDoc != null)
|
||||
{
|
||||
contractNo = settlementDoc.Code;
|
||||
outPutFileName = settlementDoc.FileName;
|
||||
}
|
||||
else
|
||||
{
|
||||
var contractIndex = contractBLL.GetContractNo("GTJASettlement");
|
||||
if (PS.Config.CompanyID == "中财资本")
|
||||
{
|
||||
contractNo = $"{trade.TradeNumber}S";
|
||||
}
|
||||
else
|
||||
{
|
||||
contractNo = $"{client.Number}C{contractIndex}S";
|
||||
}
|
||||
outPutFileName = $"{client.Name}到期结算单C{contractIndex}S.docx";
|
||||
}
|
||||
dic["{{合同编号}}"] = contractNo;
|
||||
dic["{{合同时间}}"] = $"{DateTime.Now:yyyy年M月d日}";
|
||||
dic["{{确认书编号}}"] = tradeContractR.ContractCode;
|
||||
|
||||
try
|
||||
{
|
||||
|
||||
var templateDir = OtcAppContext.MapPath("~/App_Docs/GTJA");
|
||||
var templatePath = OtcAppContext.MapPath("~/App_Docs/导出模板/到期结算单模板.docx");
|
||||
if (trade.IsUsePremiumRate != null && trade.IsUsePremiumRate.Value)
|
||||
{
|
||||
templatePath = OtcAppContext.MapPath("~/App_Docs/导出模板/到期结算单(名义本金)模板.docx");
|
||||
}
|
||||
|
||||
var outPutFilePath = Path.Combine(templateDir, outPutFileName);
|
||||
|
||||
MsWordTempalteHelper.GenerateFromTemplate(templatePath, dic, outPutFilePath);
|
||||
|
||||
if (docType == "PDF" && !outPutFilePath.EndsWith(".pdf", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
MsWordFormatConverter.ConvertToPDF(outPutFilePath, outPutFilePath.Replace(".docx", ".pdf"));
|
||||
}
|
||||
|
||||
//更新操作时间
|
||||
var now = DateTime.Now;
|
||||
File.SetLastAccessTime(outPutFilePath, now);
|
||||
|
||||
#region --- Add trade_contract_document and trade_contract_r records
|
||||
|
||||
if (needAddData)
|
||||
{
|
||||
var nowDate = DateTime.Now;
|
||||
var contractRecord = new trade_contract_document();
|
||||
DbContext.trade_contract_document.Add(contractRecord);
|
||||
contractRecord.Code = settlementDoc != null ? settlementDoc.Code : dic["{{合同编号}}"].ToString();
|
||||
contractRecord.ValueDate = valuedateBLL.ValueDate;
|
||||
contractRecord.BuyerId = isGJBuyer ? 0 : trade.ClientId;
|
||||
contractRecord.BuyerName = isGJBuyer ? PS.Config.CompanyFullName : trade.ClientName;
|
||||
contractRecord.SellerId = isGJBuyer ? trade.ClientId : 0;
|
||||
contractRecord.SellerName = isGJBuyer ? trade.ClientName : PS.Config.CompanyFullName;
|
||||
contractRecord.FileType = FileTypeEnum.Word;
|
||||
contractRecord.Status = ContractStatusEnum.Draft;
|
||||
contractRecord.Paths = $"App_Docs\\GTJA\\{outPutFileName}";
|
||||
contractRecord.FileName = outPutFileName;
|
||||
contractRecord.Type = ContractTypeEnum.Clearing;
|
||||
contractRecord.OptId = userId;
|
||||
contractRecord.OptName = userName;
|
||||
contractRecord.OptDate = nowDate;
|
||||
|
||||
var contractTradeRelation = new trade_contract_r();
|
||||
DbContext.trade_contract_r.Add(contractTradeRelation);
|
||||
contractTradeRelation.TradeId = trade.id;
|
||||
contractTradeRelation.TradeNumber = trade.TradeNumber;
|
||||
contractTradeRelation.ContractCode = contractRecord.Code;
|
||||
contractTradeRelation.TradeClearCode = contractRecord.Code;
|
||||
contractTradeRelation.Type = ContractTypeEnum.Clearing;
|
||||
contractTradeRelation.OptId = userId;
|
||||
contractTradeRelation.OptName = userName;
|
||||
contractTradeRelation.OptDate = nowDate;
|
||||
contractTradeRelation.TradeCashId = tradeCash.id;
|
||||
contractTradeRelation.IsValid = true;
|
||||
|
||||
DbContext.SaveChanges();
|
||||
}
|
||||
|
||||
#endregion --- Add trade_contract_document and trade_contract_r records
|
||||
|
||||
return new TradeDocGenerateResult(trade)
|
||||
{
|
||||
OutputFilePath = $"/App_Docs/GTJA/{(docType == "PDF" ? outPutFileName.Replace(".docx", ".pdf") : outPutFileName)}"
|
||||
};
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogFactory.GetLogger<SettlementBillGenerateService>().Error("GenerateSingleSettleBill出错", ex);
|
||||
return new TradeDocGenerateResult(trade)
|
||||
{
|
||||
ErrorMessage = "出错:" + ex.Message
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,199 @@
|
||||
using NPOI.HPSF;
|
||||
using OfficeOpenXml;
|
||||
using Qdp.Pricing.Core.Modules;
|
||||
using Qdp.Pricing.Library.Base.Utilities;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using YLErp.BLL;
|
||||
using YLErp.Core.Helpers;
|
||||
using YLErp.DBModels;
|
||||
using YLErp.DBModels.Consts;
|
||||
using YLErp.Model;
|
||||
using YLErp.Models;
|
||||
using YLErp.Modules.TradeDalModule;
|
||||
using YLErp.Office;
|
||||
using YLErp.Plugins.TradeDocGenerator.Abstracts;
|
||||
using static YLErp.ConsGlobal;
|
||||
|
||||
namespace YLErp.Modules.TradeModule.DocGenerateModule
|
||||
{
|
||||
public class SwapSettlementBillGenerateService : YLBaseService
|
||||
{
|
||||
public SwapSettlementBillGenerateService(OptUserInfo userInfo) : base(userInfo)
|
||||
{
|
||||
}
|
||||
/// <summary>
|
||||
/// 生成结算确认书
|
||||
/// </summary>
|
||||
public IEnumerable<TradeDocGenerateResult> Generate(IEnumerable<long> flowEventIds, string docType, int userId, string userName)
|
||||
{
|
||||
if (docType == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(docType));
|
||||
}
|
||||
var flowEvents = DbContext.swap_flow_event.Where(l => flowEventIds.Contains(l.id)).ToList();
|
||||
var clientIds= flowEvents.Select(l => l.ClientId).ToList();
|
||||
var eventDates= flowEvents.Select(l => l.UnwindDate).ToList();
|
||||
var flowEventQuery = DbContext.swap_flow_event.Where(l => clientIds.Contains(l.ClientId) && eventDates.Contains(l.UnwindDate) && l.EventType == (int)SwapEventTypeEnum.平仓&&l.PositionType>0);
|
||||
var newFlowEvents =from se in flowEventQuery
|
||||
join s in DbContext.swap_event on se.EventId equals s.id
|
||||
where s.Invalid==false
|
||||
select se;
|
||||
var eventIds = newFlowEvents.Select(l => l.EventId).ToList();
|
||||
var tradeIds = newFlowEvents.Select(l => l.SwapTradeId).ToList();
|
||||
if (tradeIds.Count() == 0)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(tradeIds));
|
||||
}
|
||||
var trades = DbContext.trade.Where(x => tradeIds.Contains(x.id)).ToList();
|
||||
var swapPositions = DbContext.swap_position.Where(x => tradeIds.Contains(x.SwapTradeId) && !x.Invalid).ToList();
|
||||
var allFlowEvents = DbContext.swap_flow_event.Where(x => eventIds.Contains(x.EventId)).ToList();
|
||||
var tradeContracts = DbContext.trade_contract_r.Where(x=> tradeIds.Contains(x.TradeId)&&x.Type== ContractTypeEnum.Clearing&&x.IsValid).ToList();
|
||||
flowEvents = newFlowEvents.ToList();
|
||||
//----------------------------------
|
||||
// 交易确认书数据
|
||||
//----------------------------------
|
||||
var tcrQuery = from aa in DbContext.trade_contract_r
|
||||
where tradeIds.Contains(aa.TradeId)
|
||||
&& aa.Type == ContractTypeEnum.Trade && aa.IsValid
|
||||
select aa;
|
||||
var tcrDatas = tcrQuery.ToDictionary(K => K.TradeId, V => V);
|
||||
|
||||
//----------------------------------
|
||||
// 生成交易结算书
|
||||
//----------------------------------
|
||||
var resultList = new List<TradeDocGenerateResult>();
|
||||
AppManager.TryResolve(out ITradeSettleBillGenerator generatorV2);
|
||||
Dictionary<int, List<swap_flow_event>> noDMAFlows = new Dictionary<int, List<swap_flow_event>>();
|
||||
Dictionary<int, List<swap_flow_event>> DMAFlows = new Dictionary<int, List<swap_flow_event>>();
|
||||
List<trade_extend> extendList = null;
|
||||
if (flowEvents != null && flowEvents.Any())
|
||||
{
|
||||
var flowTradeIds = flowEvents.Where(p => p.PayDate == null || p.EventType != (int)SwapEventTypeEnum.平仓).Select(p => p.SwapTradeId).Distinct().ToList();
|
||||
if (flowTradeIds != null && flowTradeIds.Count > 0)
|
||||
{
|
||||
extendList = DbContext.trade_extend.AsNoTracking().Where(p => flowTradeIds.Contains(p.TradeId)).ToList();
|
||||
}
|
||||
}
|
||||
if (extendList == null)
|
||||
{
|
||||
extendList = new List<trade_extend>();
|
||||
}
|
||||
foreach (var flowEvent in flowEvents)
|
||||
{
|
||||
var contract = tradeContracts.FirstOrDefault(x=>x.SwapFlowEventId==flowEvent.id);
|
||||
if (contract!=null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
//重置payDate 解决系统除平仓外其余场景 payDate可能为空的情况
|
||||
if (flowEvent.PayDate == null || flowEvent.EventType != (int)SwapEventTypeEnum.平仓)
|
||||
{
|
||||
var extend = extendList.FirstOrDefault(p => p.TradeId == flowEvent.SwapTradeId);
|
||||
if (extend != null)
|
||||
{
|
||||
flowEvent.PayDate = flowEvent.UnwindDate.Value.AddDays(extend.ExtendObj.SettlementRules);
|
||||
}
|
||||
}
|
||||
var trade = trades.FirstOrDefault(x => x.id == flowEvent.SwapTradeId);
|
||||
if (trade == null)
|
||||
{
|
||||
throw new ServiceException("找不到交易");
|
||||
}
|
||||
if (trade.ValidState!=ConsGlobal.InValid)
|
||||
{
|
||||
if (trade.StructureType == "多空组合"||trade.StructureType== "定义文件型债券收益互换")
|
||||
{
|
||||
if (DMAFlows.ContainsKey(trade.ClientId))
|
||||
{
|
||||
DMAFlows[trade.ClientId].Add(flowEvent);
|
||||
}
|
||||
else
|
||||
{
|
||||
DMAFlows[trade.ClientId] = new List<swap_flow_event> { flowEvent };
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (noDMAFlows.ContainsKey(trade.ClientId))
|
||||
{
|
||||
noDMAFlows[trade.ClientId].Add(flowEvent);
|
||||
}
|
||||
else
|
||||
{
|
||||
noDMAFlows[trade.ClientId] = new List<swap_flow_event> { flowEvent };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
if (noDMAFlows.Count()==0&& DMAFlows.Count()==0)
|
||||
{
|
||||
throw new ServiceException("没有需要生成的确认书");
|
||||
}
|
||||
foreach (var item in noDMAFlows)
|
||||
{
|
||||
var noDMAResults = GenerateShanxiSwap(item.Key, item.Value, trades, swapPositions, allFlowEvents, generatorV2, docType);
|
||||
resultList.AddRange(noDMAResults);
|
||||
}
|
||||
foreach (var item in DMAFlows)
|
||||
{
|
||||
var DMAResults = GenerateShanxiSwap(item.Key, item.Value, trades, swapPositions, allFlowEvents, generatorV2, docType);
|
||||
resultList.AddRange(DMAResults);
|
||||
}
|
||||
return resultList;
|
||||
}
|
||||
|
||||
public void DelDoc(List<long> flowEventIds)
|
||||
{
|
||||
if (flowEventIds.Count==0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
var tradeContracts = DbContext.trade_contract_r.Where(x => flowEventIds.Contains(x.SwapFlowEventId??0) && x.Type == ContractTypeEnum.Clearing && x.IsValid).ToList();
|
||||
var contractCodes = tradeContracts.Select(s=>s.ContractCode).Distinct().ToList();
|
||||
tradeContracts= DbContext.trade_contract_r.Where(x => contractCodes.Contains(x.ContractCode)).ToList();
|
||||
var contractDocs = DbContext.trade_contract_document.Where(x => contractCodes.Contains(x.Code)).ToList();
|
||||
DbContext.trade_contract_document.RemoveRange(contractDocs);
|
||||
DbContext.trade_contract_r.RemoveRange(tradeContracts);
|
||||
DbContext.SaveChanges();
|
||||
}
|
||||
private List<TradeDocGenerateResult> GenerateShanxiSwap(int clientId, List<swap_flow_event> flowEvents, List<trade> trades, List<swap_position> swapPositions, List<swap_flow_event> allFlowEvents, ITradeSettleBillGenerator generator,string docType)
|
||||
{
|
||||
var client = DataCacheProvider.GetClientDataSource().GetData(clientId);
|
||||
if (client == null)
|
||||
{
|
||||
throw new ServiceException("未找到客户信息");
|
||||
}
|
||||
List<TradeDocGenerateResult> docGenerateResults = new List<TradeDocGenerateResult>();
|
||||
foreach (var flowEvent in flowEvents.GroupBy(x => x.UnwindDate))//每个客户没日只有一份结算确认书
|
||||
{
|
||||
var flowEventGroups = flowEvent.ToList();
|
||||
var tradeIds = flowEventGroups.Select(l => l.SwapTradeId).ToList();
|
||||
var _trades = trades.Where(x=> tradeIds.Contains(x.id)).ToList();
|
||||
try
|
||||
{
|
||||
var context = new SettlementBillGenerateContext(client, flowEventGroups, allFlowEvents, _trades, swapPositions, ContractTypeEnum.Clearing, OptUser);
|
||||
generator.Initialize(docType, context);
|
||||
var results= generator.GenerateDocuments();
|
||||
docGenerateResults.AddRange(results);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogFactory.GetLogger("GenerateSingleV2").Error(ex);
|
||||
return new List<TradeDocGenerateResult>() {new TradeDocGenerateResult(_trades)
|
||||
{
|
||||
Exception = ex,
|
||||
ErrorMessage = "出错:" + ex.Message
|
||||
} };
|
||||
}
|
||||
}
|
||||
|
||||
return docGenerateResults;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,151 @@
|
||||
using NPOI.SS.Formula.Functions;
|
||||
using Org.BouncyCastle.Ocsp;
|
||||
using System.Diagnostics;
|
||||
using YLErp.DBModels.Consts;
|
||||
using YLErp.Models;
|
||||
using YLErp.Plugins.TradeDocGenerator.Abstracts;
|
||||
|
||||
namespace YLErp.Modules.TradeModule.DocGenerateModule
|
||||
{
|
||||
public class TransactionGenerateService : BatchSettlementBillGenerateService
|
||||
{
|
||||
public TransactionGenerateService(OptUserInfo userInfo) : base(userInfo)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 生成确认书
|
||||
/// </summary>
|
||||
/// <param name="clientID">要生成确认书的客户Id</param>
|
||||
/// <param name="docType">生成的确认书文件类型</param>
|
||||
/// <param name="errors">错误信息</param>
|
||||
/// <param name="files">生成的确认书文件路径</param>
|
||||
/// <param name="startDate">持仓日期区间-开始日期</param>
|
||||
/// <param name="endDate">持仓日期区间-结束日期</param>
|
||||
/// <param name="TradeTypes">要包含的交易类型</param>
|
||||
/// <returns></returns>
|
||||
public IEnumerable<TradeDocGenerateResult> Generate(int[] clientIds, string docType, DateTime startDate, DateTime endDate, string[] TradeTypes, List<int> sealResults)
|
||||
{
|
||||
var idquery = from tc in DbContext.trade_cash
|
||||
join t in DbContext.trade
|
||||
on tc.TradeId equals t.id
|
||||
where t.TradeType == "累计期权"
|
||||
&& t.ValidState != ConsGlobal.InValid
|
||||
&& ConsTrade.TradeCompleteStatus.Contains(t.TradeStatus)
|
||||
&& tc.Action != "系统操作-期权费"
|
||||
&& tc.ValidState != ConsGlobal.InValid
|
||||
&& tc.IsDeleted != true
|
||||
group tc by tc.TradeId into g
|
||||
select new
|
||||
{
|
||||
Key = g.Key,
|
||||
list = g.ToList()
|
||||
};
|
||||
|
||||
var ids = idquery.ToList().Select(x => x.list.OrderByDescending(i => i.ValueDate).FirstOrDefault()).Where(t => t.ValueDate >= startDate
|
||||
&& t.ValueDate <= endDate).Select(x => x.id).ToList();
|
||||
|
||||
var tid2 = DbContext.trade.Where(x => x.TradeType == "累计期权" && x.ValidState != ConsGlobal.InValid && x.TradeDate >= startDate && x.TradeDate <= endDate).Select(x => x.id).ToList();
|
||||
var tcid2 = DbContext.trade_cash.Where(x => x.Action == "系统操作-期权费" && x.ValidState != ConsGlobal.InValid
|
||||
&& x.IsDeleted != true && tid2.Contains(x.TradeId)).AsEnumerable().GroupBy(x => x.TradeId).Select(x => x.FirstOrDefault().id).ToList();
|
||||
|
||||
var tcid = ids.Union(tcid2);
|
||||
|
||||
var query1 = (from tc in DbContext.trade_cash
|
||||
join t in DbContext.trade
|
||||
on tc.TradeId equals t.id
|
||||
where
|
||||
TradeTypes.Contains(t.TradeType)
|
||||
&& tcid.Contains(tc.id)
|
||||
select new { t, tc });
|
||||
|
||||
var query2 = (from tc in DbContext.trade_cash
|
||||
join t in DbContext.trade
|
||||
on tc.TradeId equals t.id
|
||||
where
|
||||
t.ValidState != ConsGlobal.InValid
|
||||
&& tc.ValidState != ConsGlobal.InValid
|
||||
&& tc.IsDeleted != true
|
||||
&& tc.ValueDate >= startDate
|
||||
&& tc.ValueDate <= endDate
|
||||
&& TradeTypes.Contains(t.TradeType)
|
||||
&& t.TradeType != "累计期权"
|
||||
select new { t, tc });
|
||||
|
||||
var dict = query1.Union(query2);
|
||||
|
||||
if (sealResults != null && sealResults.Count > 0)
|
||||
{
|
||||
var docQuery = from dic in dict
|
||||
join tcr in (from aa in DbContext.trade_contract_r
|
||||
where aa.Type == ContractTypeEnum.Clearing && aa.IsValid
|
||||
select aa) on dic.t.id equals tcr.TradeId into tcr1
|
||||
from tcr in tcr1.DefaultIfEmpty()
|
||||
join doc in DbContext.trade_contract_document
|
||||
on tcr.ContractCode equals doc.Code into tempDoc
|
||||
from doc in tempDoc.DefaultIfEmpty()
|
||||
select new
|
||||
{
|
||||
t = dic.t,
|
||||
tc = dic.tc,
|
||||
doc
|
||||
};
|
||||
|
||||
|
||||
|
||||
if (sealResults.Contains(2))
|
||||
{
|
||||
docQuery = docQuery.Where(t => sealResults.Contains((int)t.doc.SealResult) || t.doc.SealResult == null);
|
||||
}
|
||||
else
|
||||
{
|
||||
docQuery = docQuery.Where(t => sealResults.Contains((int)t.doc.SealResult));
|
||||
}
|
||||
|
||||
dict = docQuery.Select(d => new { d.t, d.tc });
|
||||
|
||||
}
|
||||
|
||||
|
||||
if (clientIds != null && clientIds.Any())
|
||||
{
|
||||
dict = dict.Where(x => clientIds.Contains(x.t.ClientId));
|
||||
}
|
||||
|
||||
var tradelist = dict.ToList();
|
||||
|
||||
foreach (var trade in tradelist)
|
||||
{
|
||||
if (trade.t != null && trade.tc != null && trade.t.TradeType == "累计期权" && trade.tc.Action != "系统操作-期权费")
|
||||
{
|
||||
trade.tc.UnwindNotional = trade.t.OriginalNotional;
|
||||
var amount = DbContext.trade_cash.Where(x => x.Action != "系统操作-期权费" && x.ValidState != ConsGlobal.InValid
|
||||
&& x.IsDeleted != true && trade.t.id == x.TradeId).Sum(x => x.Amount);
|
||||
trade.tc.Amount = amount;
|
||||
}
|
||||
}
|
||||
|
||||
var list = tradelist.Select(O => { O.t.trade_cash = O.tc.Clone(); return O.t.Clone(); }).GroupBy(O => new { O.trade_cash.ValueDate, O.ClientId })
|
||||
.ToDictionary(K => K.Key, V => V.ToList());
|
||||
|
||||
AppManager.TryResolve(out ITradeSettleBillGenerator generatorV2);
|
||||
var resultList = new List<TradeDocGenerateResult>();
|
||||
foreach (var item in list)
|
||||
{
|
||||
if (generatorV2 != null)
|
||||
{
|
||||
var tcIds = item.Value.Select(x => x.trade_cash.id).Distinct().ToList();
|
||||
var results = base.GenerateSingleV2(generatorV2, item.Value.ToList(), tcIds, docType, startDate, endDate);
|
||||
resultList.Add(results);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ServiceException("确认书插件不存在");
|
||||
}
|
||||
}
|
||||
|
||||
return resultList;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
using YLErp.DBModels.Abstract;
|
||||
using YLErp.DBModels.Consts;
|
||||
using YLErp.Plugins.TradeDocGenerator.Abstracts;
|
||||
|
||||
namespace YLErp.Modules.TradeModule.DocGenerateModule
|
||||
{
|
||||
/// <summary>
|
||||
/// 交易结算生成上下文
|
||||
/// </summary>
|
||||
public class UnwindReportGenerateContext : ConfirmationGenerateContext, ITradeUnwindReportGeneratorContext
|
||||
{
|
||||
public UnwindReportGenerateContext(IEnumerable<int> tradeCashIds, IEnumerable<trade> trades, string contractType, OptUserInfo userInfo, DateTime? startDate, DateTime? endDate)
|
||||
: base(tradeCashIds, trades, contractType, userInfo, startDate, endDate) { }
|
||||
|
||||
public UnwindReportGenerateContext(int tradeCashId, trade tradeObj, string contractType, OptUserInfo userInfo)
|
||||
: base(tradeCashId, tradeObj, contractType, userInfo)
|
||||
{ }
|
||||
|
||||
//交易确认书对象
|
||||
trade_contract_document _contractDoc;
|
||||
|
||||
/// <summary>
|
||||
/// 获取交易确认书
|
||||
/// </summary>
|
||||
public ITradeContractDocument GetTradeContractDocument(int tradeId, string tradeNumber, bool throwException = true)
|
||||
{
|
||||
if (_contractDoc == null)
|
||||
{
|
||||
var db = DbContextFactory.GetYLDbContext();
|
||||
var query = from contractDoc in db.trade_contract_document
|
||||
join tcr in db.trade_contract_r on contractDoc.Code equals tcr.ContractCode
|
||||
where tcr.TradeId == tradeId && contractDoc.Type == ContractTypeEnum.Trade && tcr.Type == ContractTypeEnum.Trade && tcr.IsValid
|
||||
select contractDoc;
|
||||
_contractDoc = query.FirstOrDefault();
|
||||
}
|
||||
|
||||
if (_contractDoc == null && throwException)
|
||||
{
|
||||
throw new ServiceException($"未找到交易确认书(交易编号:{tradeNumber})");
|
||||
}
|
||||
|
||||
return _contractDoc;
|
||||
}
|
||||
|
||||
|
||||
public bool OnUnwindReportGenerated()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,498 @@
|
||||
using YLErp.BLL;
|
||||
using YLErp.BLL.MarginCalculation;
|
||||
using YLErp.DBModels.Consts;
|
||||
using YLErp.Model;
|
||||
using YLErp.Models;
|
||||
using YLErp.Modules.DataProviderModule;
|
||||
using YLErp.Modules.TradeDalModule;
|
||||
using YLErp.MsOffice;
|
||||
using YLErp.Office;
|
||||
using YLErp.Office.Converters;
|
||||
using YLErp.Plugins.TradeDocGenerator.Abstracts;
|
||||
|
||||
namespace YLErp.Modules.TradeModule.DocGenerateModule
|
||||
{
|
||||
/// <summary>
|
||||
/// 生成结算确认书
|
||||
/// </summary>
|
||||
public class UnwindReportGenerateService : YLBaseService
|
||||
{
|
||||
public UnwindReportGenerateService(OptUserInfo userInfo) : base(userInfo)
|
||||
{
|
||||
}
|
||||
|
||||
public UnwindReportGenerateService(YLBaseService baseService) : base(baseService)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 生成结算确认书
|
||||
/// </summary>
|
||||
public IEnumerable<TradeDocGenerateResult> Generate(IEnumerable<UnwindReportInputModel> unwindReportInputModels, string docType)
|
||||
{
|
||||
if (unwindReportInputModels == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(unwindReportInputModels));
|
||||
}
|
||||
|
||||
if (docType == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(docType));
|
||||
}
|
||||
|
||||
var tradeIds = unwindReportInputModels.Select(m => m.TradeId).ToHashSet();
|
||||
var tradeCashIds = unwindReportInputModels.Select(m => m.TradeCashId).ToHashSet();
|
||||
//当前交易日
|
||||
var valueDate = valuedateBLL.ValueDate;
|
||||
var tradeCashStatus = new string[] { ClientCashInCashOut.系统操作_行权费, ClientCashInCashOut.系统操作_平仓费 };
|
||||
|
||||
//----------------------------------
|
||||
// 获取当日行权 平仓 到期的有效交易
|
||||
//----------------------------------
|
||||
var service = new TradeDalService(this);
|
||||
|
||||
IEnumerable<trade> tradeQuery;
|
||||
|
||||
if (PS.Config.TradeElement.IsSingleExecutionTemplate)
|
||||
{
|
||||
tradeQuery = service.GetTradeOrEodTrade(tradeIds, valueDate)
|
||||
.Where(O => (O.TradeStatus == ConsTrade.已平仓 || O.TradeType == "累计期权" || O.UnWindNotional > 0) && O.ClientId > 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
tradeQuery = service.GetTradeOrEodTrade(tradeIds, valueDate)
|
||||
.Where(O => (O.TradeStatus == ConsTrade.已平仓 || O.UnWindNotional > 0 || O.TradeType == "累计期权" || (O.TradeStatus == ConsTrade.已执行 && O.ExerciseMode == "American")) && O.ClientId > 0);
|
||||
}
|
||||
|
||||
if (PS.Config.Is长江)
|
||||
{
|
||||
foreach (var td in tradeQuery)
|
||||
{
|
||||
if (td.StructureType != "牛市价差" && td.StructureType != "熊市价差")
|
||||
{
|
||||
td.ParentTradeId = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//使用Action等于票息并且IsLastAction检索数据,逻辑是存在问题的,敲出平仓+票息是没问题的, 到期+票息应该会取出多条,需要梳理逻辑后调整
|
||||
|
||||
var tcPredicate = PredicateBuilder.Create<trade_cash>(tc =>
|
||||
tc.ValidState != ConsGlobal.InValid && !tc.IsDeleted && tradeCashIds.Contains(tc.id) && tradeIds.Contains(tc.TradeId)
|
||||
&& (tradeCashStatus.Contains(tc.Action) && tc.ExerciseWay == TradeCashExerciseWayEnum.提前终止行权 || tc.Action == ClientCashInCashOut.系统操作_票息 && tc.IsLastAction));
|
||||
|
||||
var tcQuery = DbContext.trade_cash.Where(tcPredicate);
|
||||
|
||||
var tids2 = tradeQuery.Select(n => n.ParentTradeId > 0 ? n.ParentTradeId : n.id).ToHashSet();
|
||||
|
||||
var trQuery = from cr in DbContext.trade_contract_r
|
||||
join cd in DbContext.trade_contract_document on cr.ContractCode equals cd.Code
|
||||
where cr.Type == ContractTypeEnum.Trade && cr.IsValid && (cd.Type == ContractTypeEnum.Clearing)
|
||||
&& tids2.Contains(cr.TradeId)
|
||||
select new { cr.TradeId, cr, cd };
|
||||
|
||||
var query = from td in tradeQuery
|
||||
join tc in tcQuery on td.id equals tc.TradeId
|
||||
join tr in trQuery on new { id = td.ParentTradeId > 0 ? td.ParentTradeId : td.id } equals new { id = tr.TradeId } into trs
|
||||
from tr in trs.DefaultIfEmpty()
|
||||
select new trade_contract_group
|
||||
{
|
||||
id = tc.id,
|
||||
trade = td,
|
||||
trade_cash = tc,
|
||||
ConfirmContractR = tr == null ? null : tr.cr,
|
||||
trade_contract_document = tr == null ? null : tr.cd,
|
||||
UnwindVol = tc.Action == ClientCashInCashOut.系统操作_平仓费 ? tc.UnwindVol : null
|
||||
};
|
||||
|
||||
var queryList = query.ToArray();
|
||||
|
||||
if (!queryList.Any())
|
||||
{
|
||||
throw new ServiceException("当日没有要结算的记录信息!");
|
||||
}
|
||||
|
||||
//----------------------------------
|
||||
// 生成交易结算书
|
||||
//----------------------------------
|
||||
var resultList = new List<TradeDocGenerateResult>();
|
||||
AppManager.TryResolve(out ITradeUnwindReportGenerator generatorV2);
|
||||
var querySet = queryList.Select(n => n.trade.id + n.trade_cash.ExerciseWay).ToHashSet();
|
||||
var cacheList = new List<string>();
|
||||
//客户编号列表
|
||||
foreach (var tradeContractGroup in queryList)
|
||||
{
|
||||
if (tradeContractGroup.trade_cash.ExerciseWay == ClientCashInCashOut.系统操作_票息
|
||||
&& querySet.Contains(tradeContractGroup.trade.id + TradeCashExerciseWayEnum.提前终止行权))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (tradeContractGroup.trade.ParentTradeId != 0)
|
||||
{
|
||||
var structureTrades = service.GetTradeOrEodTradeOfTidAPid(new[] { tradeContractGroup.trade.ParentTradeId }, valueDate);
|
||||
if (YLErp.PS.Config.Is光大光子 || YLErp.PS.Config.Is兴业商贸 || YLErp.PS.Config.Is方顿)
|
||||
{
|
||||
structureTrades.RemoveAll(x => x.ParentTradeId != 0 && !tradeIds.Contains(x.id));
|
||||
}
|
||||
var subTradeDict = structureTrades.Where(O => O.ParentTradeId == tradeContractGroup.trade.ParentTradeId).GroupBy(O => O.TradeStatus).ToDictionary(K => K.Key, V => V.ToList());
|
||||
if (subTradeDict.Count == 1)
|
||||
{
|
||||
var subTradeIds = subTradeDict.First().Value.Select(O => O.id).ToList();
|
||||
var tradeCashes = (from cash in DbContext.trade_cash
|
||||
where subTradeIds.Contains(cash.TradeId) && !cash.IsDeleted
|
||||
&& cash.Action == tradeContractGroup.trade_cash.Action
|
||||
&& cash.ValueDate == tradeContractGroup.trade_cash.ValueDate
|
||||
&& cash.ExerciseWay == tradeContractGroup.trade_cash.ExerciseWay
|
||||
&& cash.Notional == tradeContractGroup.trade_cash.Notional
|
||||
&& cash.UnwindNotional == tradeContractGroup.trade_cash.UnwindNotional
|
||||
select cash)
|
||||
.ToList();
|
||||
if (tradeCashes.Count == subTradeDict.First().Value.Count)
|
||||
{
|
||||
subTradeDict.First().Value.ForEach(O => O.trade_cash = tradeCashes.First(B => B.TradeId == O.id));
|
||||
tradeContractGroup.trade = structureTrades.Where(O => !subTradeIds.Contains(O.id)).First();
|
||||
tradeContractGroup.trade.SubTrades = structureTrades.Where(O => subTradeIds.Contains(O.id)).ToList();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (tradeContractGroup.trade.TradeType == "结构化交易")
|
||||
{
|
||||
if (tradeContractGroup.trade.IsGroup == 1)
|
||||
{
|
||||
tradeContractGroup.trade.SubTrades = DbContext.trade.Where(O => O.ParentTradeId == tradeContractGroup.trade.id).ToList();
|
||||
foreach (var subtc in tradeContractGroup.trade.SubTrades)
|
||||
{
|
||||
subtc.trade_cash = DbContext.trade_cash.FirstOrDefault(tc =>
|
||||
tc.ValidState != ConsGlobal.InValid && !tc.IsDeleted && tc.TradeId == subtc.id
|
||||
&& (tradeCashStatus.Contains(tc.Action) && tc.ExerciseWay == TradeCashExerciseWayEnum.提前终止行权 || tc.Action == ClientCashInCashOut.系统操作_票息 && tc.IsLastAction));
|
||||
}
|
||||
}
|
||||
}
|
||||
tradeContractGroup.trade.trade_cash = tradeContractGroup.trade_cash;
|
||||
|
||||
if ((tradeContractGroup.trade.TradeType != "结构化交易" && tradeContractGroup.trade_cash == null)
|
||||
|| (tradeContractGroup.trade.TradeType == "结构化交易" && tradeContractGroup.trade.IsGroup == 0 && tradeContractGroup.trade.SubTrades.Any(O => O.trade_cash == null)))
|
||||
{
|
||||
resultList.Add(new TradeDocGenerateResult(tradeContractGroup.trade)
|
||||
{
|
||||
ErrorMessage = "缺少现金交割记录"
|
||||
});
|
||||
}
|
||||
else if (generatorV2 != null)
|
||||
{
|
||||
var key = $"{tradeContractGroup.trade.id}_{tradeContractGroup.trade_cash.Action}_{tradeContractGroup.trade_cash.Notional}_{tradeContractGroup.trade_cash.UnwindNotional}";
|
||||
if (cacheList.Contains(key))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
cacheList.Add(key);
|
||||
if (PS.Config.Company == Configuration.CompanyEnum.兴业商贸 && !DbContext.trade_contract_r.Any(x => tradeContractGroup.trade.id == x.TradeId && x.Type == ContractTypeEnum.Trade && x.IsValid))
|
||||
{
|
||||
resultList.Add(new TradeDocGenerateResult(tradeContractGroup.trade)
|
||||
{
|
||||
ErrorMessage = "请先生成对应的交易确认书!"
|
||||
});
|
||||
}
|
||||
var result = GenerateSingleV2(generatorV2, tradeContractGroup, tradeContractGroup.trade_cash.id, docType);
|
||||
if (PS.Config.Is方顿)
|
||||
{
|
||||
if (resultList.Where(x => x.OutputFilePath == result.OutputFilePath).Count() > 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
resultList.Add(result);
|
||||
}
|
||||
else
|
||||
{
|
||||
var result = GenerateSingleV1(tradeContractGroup, docType);
|
||||
resultList.Add(result);
|
||||
}
|
||||
}
|
||||
|
||||
return resultList;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
private TradeDocGenerateResult GenerateSingleV2(ITradeUnwindReportGenerator generator, trade_contract_group tradeContractGroup, int tradeCashId, string docType = "DOCX")
|
||||
{
|
||||
try
|
||||
{
|
||||
var context = new UnwindReportGenerateContext(tradeCashId, tradeContractGroup.trade, ContractTypeEnum.UnWind, OptUser);
|
||||
generator.Initialize(docType, context);
|
||||
return generator.GenerateDocument();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogFactory.GetLogger<UnwindReportGenerateService>().Error("GenerateSingleV2", ex);
|
||||
|
||||
return new TradeDocGenerateResult(tradeContractGroup.trade)
|
||||
{
|
||||
ErrorMessage = "出错:" + ex.Message
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
private TradeDocGenerateResult GenerateSingleV1(trade_contract_group contractGroup, string docType = "DOCX")
|
||||
{
|
||||
if (contractGroup == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(contractGroup));
|
||||
}
|
||||
|
||||
var contractBLL = new TradeContractBLL(this);
|
||||
var dic = new Dictionary<string, object>();
|
||||
var trade = contractGroup.trade;
|
||||
var tradeCash = contractGroup.trade_cash;
|
||||
var contractDoc = contractGroup.trade_contract_document;
|
||||
var needAddData = true;
|
||||
|
||||
#region 如果提前终止确认书已经生成过,则直接返回
|
||||
|
||||
var unWindDoc = contractBLL.GetContractDoc(trade.id, ContractTypeEnum.UnWind, tradeCash.id);
|
||||
if (unWindDoc != null)
|
||||
{
|
||||
if (File.Exists(unWindDoc.AbsolutePath))
|
||||
{
|
||||
if (docType == "PDF")
|
||||
{
|
||||
var pdfPath = unWindDoc.AbsolutePath.Replace(".docx", ".pdf");
|
||||
if (!File.Exists(pdfPath))
|
||||
{
|
||||
OfficeFileConverter.ConvertDocxToPDF(unWindDoc.AbsolutePath, pdfPath);
|
||||
}
|
||||
|
||||
return new TradeDocGenerateResult(trade)
|
||||
{
|
||||
OutputFilePath = $"../App_Docs/GTJA/{unWindDoc.FileName.Replace(".docx", ".pdf")}"
|
||||
};
|
||||
}
|
||||
|
||||
return new TradeDocGenerateResult(trade)
|
||||
{
|
||||
OutputFilePath = $"../App_Docs/GTJA/{unWindDoc.FileName}"
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
needAddData = false;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
var isGJBuyer = trade.BuySell == "买入";
|
||||
|
||||
var underlying = DataCacheProvider.GetUnderlyingDataSource().GetData(trade.UnderlyingCode);
|
||||
if (underlying == null)
|
||||
{
|
||||
return new TradeDocGenerateResult(trade)
|
||||
{
|
||||
ErrorMessage = $"标的资产{trade.UnderlyingCode}信息未找到"
|
||||
};
|
||||
}
|
||||
var client = ClientModule.ClientDataQueryService.GetClient(trade.ClientId);
|
||||
if (client == null)
|
||||
{
|
||||
return new TradeDocGenerateResult(trade)
|
||||
{
|
||||
ErrorMessage = $"客户(id:{trade.ClientId})信息未找到"
|
||||
};
|
||||
}
|
||||
|
||||
dic["{{乙方名称}}"] = client.Name;
|
||||
|
||||
if (isGJBuyer)
|
||||
{
|
||||
dic["{{甲方方向}}"] = "买方";
|
||||
dic["{{乙方方向}}"] = "卖方";
|
||||
}
|
||||
else
|
||||
{
|
||||
dic["{{甲方方向}}"] = "卖方";
|
||||
dic["{{乙方方向}}"] = "买方";
|
||||
}
|
||||
|
||||
var tradeType = trade.TradeType == "香草期权" ? "普通" : (trade.TradeType == "结构化交易" ? trade.StructureType : trade.TradeType.Replace("期权", ""));
|
||||
dic["{{期权类型}}"] = $"{trade.ExerciseModeCn}{tradeType}{trade.OptionType}期权";
|
||||
|
||||
var variety = VarietyBLL.GetAllvarietyModel().FirstOrDefault(x => x.id == underlying.UnderlyingTypeId);
|
||||
if (trade.TradeType == "合成价差期权")
|
||||
{
|
||||
dic["{{商品标的名称}}"] = synthetic_underlyingBLL.GetUnderlyingTipsInfo(trade.UnderlyingCode);
|
||||
}
|
||||
else
|
||||
{
|
||||
dic["{{商品标的名称}}"] = trade.UnderlyingCode;
|
||||
}
|
||||
dic["{{交易日}}"] = trade.TradeDate?.ToString("yyyy年M月d日");
|
||||
dic["{{到期日}}"] = trade.ExerciseDate?.ToString("yyyy年M月d日");
|
||||
|
||||
var strUnit = variety.QuoteUnitSingle;
|
||||
var tradeNotional = trade.Notional;
|
||||
var tradeOriginalNotional = (trade.OriginalNotional ?? 0);
|
||||
var unWindCount = trade.TradeStatus == ConsTrade.已平仓 || (trade.UnWindNotional > 0 && tradeCash.UnwindNotional > 0) ? (tradeCash.UnwindNotional).Value : trade.Notional;
|
||||
var unWindCountPercent = (tradeCash.Action == ClientCashInCashOut.系统操作_平仓费 ? (tradeCash.UnwindPercentRate ?? 0) : (trade.Notional / trade.OriginalNotional) ?? 0).OtcFormatNotional(isPercent: true);
|
||||
var unWindPricePercent = (tradeCash.UnwindPricePercentRate ?? 0).OtcFormat(OtcFormatFlag.premiumRateP);
|
||||
|
||||
dic["{{执行价格}}"] = $"{(trade.ActualStrike ?? 0).OtcFormatUmPrice()}元/{strUnit}";
|
||||
dic["{{期权价格}}"] = $"{(trade.TradeSinglePrice ?? 0).OtcFormatMoney(grouping: false)}元/{strUnit}";
|
||||
dic["{{商品标的数量}}"] = $"{tradeOriginalNotional.OtcFormatNotional()}{strUnit}";
|
||||
dic["{{名义本金}}"] = $"{(trade.OriginalStockEqvNotional ?? 0).OtcFormat(OtcFormatFlag.StockEqvNotional)}";
|
||||
dic["{{期权费率}}"] = $"{(trade.PremiumRate ?? 0).OtcFormat(OtcFormatFlag.premiumRateP)}";
|
||||
dic["{{支付时间}}"] = "提前终止/到期时支付";
|
||||
dic["{{终止类型}}"] = tradeCash.Action == ClientCashInCashOut.系统操作_平仓费 ? "平仓" : "美式期权行权";
|
||||
dic["{{终止日}}"] = $"{tradeCash.ValueDate:yyyy年M月d日}";
|
||||
dic["{{终止数量}}"] = trade.IsUsePremiumRate.HasValue && trade.IsUsePremiumRate.Value ? unWindCountPercent : $"{unWindCount.OtcFormatNotional()}{strUnit}";
|
||||
dic["{{标的终止日价格}}"] = $"{(tradeCash.FinalPrice ?? 0).OtcFormatUmPrice()}元/{strUnit}";
|
||||
|
||||
dic["{{期末价格}}"] = $"{(tradeCash.FinalPrice ?? 0).OtcFormatUmPrice()}元/{strUnit}";
|
||||
|
||||
var req = new RunMarginCalculationReq(UserInfo)
|
||||
{
|
||||
tradeList = new List<trade> { trade },
|
||||
settleDate = tradeCash.ValueDate,
|
||||
PriceProvider = new SinglePriceProvider(trade.UnderlyingCode, tradeCash.FinalPrice ?? 0)
|
||||
};
|
||||
if (trade.IsGroup == 1)
|
||||
{
|
||||
req.tradeList = DbContext.trade.Where(x => x.ParentTradeId == trade.id).ToList();
|
||||
}
|
||||
var tradeSpans = MarginDefault.RunMarginCalculation(req);
|
||||
if (tradeSpans?.Count > 0)
|
||||
{
|
||||
var margin = trade.IsGroup == 1 ? tradeSpans.Sum(x => x.WorstCastClientPayable ?? 0) : (tradeSpans[0].WorstCastClientPayable ?? 0);
|
||||
dic["{{预付金}}"] = $"{Math.Abs(margin).OtcFormatMoney()}元";
|
||||
}
|
||||
else
|
||||
{
|
||||
dic["{{预付金}}"] = "0元";
|
||||
}
|
||||
|
||||
dic["{{期权平仓价格}}"] = tradeCash.Action == "系统操作-行权费" || tradeCash.UnwindType == "部分行权" ? "行权收益" : "期权平仓价格";
|
||||
dic["{{平仓价格}}"] = trade.IsUsePremiumRate == true && tradeCash.Action == "系统操作-平仓费" ? unWindPricePercent : $"{Math.Abs(tradeCash.UnwindPrice ?? 0).OtcFormatFlex(2, 4)}元/{strUnit}";
|
||||
dic["{{提前终止款}}"] = $"{tradeCash.Amount.OtcFormatMoney()}元";
|
||||
dic["{{结算价格}}"] = dic["{{平仓价格}}"];
|
||||
|
||||
var premiumFee = trade.OriginalNotional > 0 ? (trade.TradePrice ?? 0) * unWindCount / trade.OriginalNotional.Value : 0;
|
||||
if (isGJBuyer)
|
||||
{
|
||||
var incomes = tradeCash.Amount - premiumFee;
|
||||
dic["{{结算净额}}"] = $"{Math.Abs(incomes).OtcFormatMoney()}元";
|
||||
dic["{{结算方式}}"] = incomes > 0 ? "卖方向买方支付结算净额" : "买方向卖方支付结算净额";
|
||||
dic["{{平仓盈亏}}"] = $"{Math.Abs(incomes).OtcFormatMoney(grouping: false)}元";
|
||||
}
|
||||
else
|
||||
{
|
||||
var incomes = (tradeCash.Amount) + premiumFee;
|
||||
dic["{{结算净额}}"] = $"{Math.Abs(incomes).OtcFormatMoney()}元";
|
||||
dic["{{结算方式}}"] = incomes > 0 ? "买方向卖方支付结算净额" : "卖方向买方支付结算净额";
|
||||
dic["{{平仓盈亏}}"] = $"{Math.Abs(incomes).OtcFormatMoney(grouping: false)}元";
|
||||
}
|
||||
//合同编号
|
||||
string contractNo;
|
||||
string outPutFileName;
|
||||
if (unWindDoc != null)
|
||||
{
|
||||
contractNo = unWindDoc.Code;
|
||||
outPutFileName = unWindDoc.FileName;
|
||||
}
|
||||
else
|
||||
{
|
||||
var contractIndex = contractBLL.GetContractNo("GTJAUnWind");
|
||||
if (PS.Config.CompanyID == "中财资本")
|
||||
{
|
||||
contractNo = $"{trade.TradeNumber} - 01";
|
||||
}
|
||||
else
|
||||
{
|
||||
contractNo = $"{client.Number}C{contractIndex} - 01";
|
||||
}
|
||||
outPutFileName = $"{client.Name}交易确认书C{contractIndex}-01.docx";
|
||||
}
|
||||
dic["{{合同编号}}"] = contractNo;
|
||||
dic["{{确认书编号}}"] = contractDoc == null ? "" : contractDoc.Code;
|
||||
dic["{{确认书时间}}"] = contractDoc == null ? "" : $"{contractDoc.ValueDate.Value:yyyy年M月d日}";
|
||||
|
||||
try
|
||||
{
|
||||
var templateDir = OtcAppContext.MapPath("~/App_Docs/GTJA");
|
||||
var templatePath = OtcAppContext.MapPath("~/App_Docs/导出模板/提前终止确认书模板.doc");
|
||||
if (trade.IsUsePremiumRate.HasValue && trade.IsUsePremiumRate.Value)
|
||||
{
|
||||
templatePath = OtcAppContext.MapPath("~/App_Docs/导出模板/提前终止确认书(名义本金)模板.doc");
|
||||
}
|
||||
|
||||
var outPutFilePath = Path.Combine(templateDir, outPutFileName);
|
||||
|
||||
MsWordTempalteHelper.GenerateFromTemplate(templatePath, dic, outPutFilePath);
|
||||
|
||||
if (docType == "PDF" && !outPutFilePath.EndsWith(".pdf", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
MsWordFormatConverter.ConvertToPDF(outPutFilePath, outPutFilePath.Replace(".docx", ".pdf"));
|
||||
}
|
||||
|
||||
//更新操作时间
|
||||
System.IO.File.SetLastAccessTime(outPutFilePath, DateTime.Now);
|
||||
|
||||
#region --- Add trade_contract_document and trade_contract_r records
|
||||
|
||||
if (needAddData)
|
||||
{
|
||||
var nowDate = DateTime.Now;
|
||||
|
||||
var contractRecord = new trade_contract_document();
|
||||
DbContext.trade_contract_document.Add(contractRecord);
|
||||
contractRecord.Code = dic["{{合同编号}}"].ToString();
|
||||
contractRecord.ValueDate = valuedateBLL.ValueDate;
|
||||
contractRecord.BuyerId = isGJBuyer ? 0 : trade.ClientId;
|
||||
contractRecord.BuyerName = isGJBuyer ? PS.Config.CompanyFullName : trade.ClientName;
|
||||
contractRecord.SellerId = isGJBuyer ? trade.ClientId : 0;
|
||||
contractRecord.SellerName = isGJBuyer ? trade.ClientName : PS.Config.CompanyFullName;
|
||||
contractRecord.FileType = FileTypeEnum.Word;
|
||||
contractRecord.Status = ContractStatusEnum.Draft;
|
||||
contractRecord.Paths = $"App_Docs\\GTJA\\{outPutFileName}";
|
||||
contractRecord.FileName = outPutFileName;
|
||||
contractRecord.Type = ContractTypeEnum.UnWind;
|
||||
contractRecord.OptId = UserId;
|
||||
contractRecord.OptName = UserName;
|
||||
contractRecord.OptDate = nowDate;
|
||||
|
||||
var contractTradeRelation = new trade_contract_r();
|
||||
DbContext.trade_contract_r.Add(contractTradeRelation);
|
||||
contractTradeRelation.TradeCashId = tradeCash.id;
|
||||
contractTradeRelation.TradeId = trade.id;
|
||||
contractTradeRelation.TradeNumber = trade.TradeNumber;
|
||||
contractTradeRelation.ContractCode = contractRecord.Code;
|
||||
contractTradeRelation.TradeClearCode = contractRecord.Code;
|
||||
contractTradeRelation.Type = ContractTypeEnum.UnWind;
|
||||
contractTradeRelation.OptId = UserId;
|
||||
contractTradeRelation.OptName = UserName;
|
||||
contractTradeRelation.OptDate = nowDate;
|
||||
contractTradeRelation.IsValid = true;
|
||||
|
||||
DbContext.SaveChanges();
|
||||
}
|
||||
|
||||
#endregion --- Add trade_contract_document and trade_contract_r records
|
||||
|
||||
return new TradeDocGenerateResult(trade)
|
||||
{
|
||||
OutputFilePath = $"/App_Docs/GTJA/{(docType == "PDF" ? outPutFileName.Replace(".docx", ".pdf") : outPutFileName)}"
|
||||
};
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogFactory.GetLogger<UnwindReportGenerateService>().Error("GenerateSingleUnwindReport出错", ex);
|
||||
return new TradeDocGenerateResult(trade)
|
||||
{
|
||||
ErrorMessage = "出错:" + ex.Message
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user