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
{
///
/// 生成交易确认书
///
public class BatchConfirmationGenerateService : YLBaseService
{
public BatchConfirmationGenerateService(OptUserInfo userInfo) : base(userInfo)
{
}
public BatchConfirmationGenerateService(YLBaseService baseService) : base(baseService)
{
}
///
/// 生成交易确认书
///
public IEnumerable Generate(IEnumerable 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() {
ConsTrade.确认成交
};
if (GlobalConfig.EnableGenerateOnTradeClosed)
{
statusList.Add(ConsTrade.已到期);
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;
//----------------------------------
// 交易现金交割记录
//----------------------------------
List allTrades = DbContext.trade.Where(x => tradeIds.Contains(x.id)).ToList();
if (allTrades.Count < 1)
{
throw new ServiceException("没有已确认的记录信息!");
}
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 resultList = new List();
AppManager.TryResolve(out ITradeConfirmationGenerator generatorV2);
var tradeContractGroupTradeIds = tradeDic.Values.Select(x => x.trade.id).ToList();
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;
}
///
///
///
private TradeDocGenerateResult GenerateSingleV2(ITradeConfirmationGenerator generator, List trades, List 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
};
}
}
///
///
///
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
{
["{{乙方名称}}"] = 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().Error("GenerateSingleConfirmBook出错", e);
return new TradeDocGenerateResult(trade) { ErrorMessage = e.Message };
}
}
}
}