从山证v2.3.0拷贝

This commit is contained in:
吴方海
2024-05-09 14:06:26 +08:00
parent 566ff33259
commit f9d8a256a6
4471 changed files with 1203456 additions and 9 deletions
@@ -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);
}
}
}
}
}
@@ -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
};
}
}
}
}