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
{
///
/// 生成交易确认书
///
public class ConfirmationGenerateService : YLBaseService
{
public ConfirmationGenerateService(OptUserInfo userInfo) : base(userInfo)
{
}
public ConfirmationGenerateService(YLBaseService baseService) : base(baseService)
{
}
///
/// 生成交易确认书
///
public List Generate(IEnumerable tradeIds, string docType)
{
var logger = LogFactory.GetLogger("生成确认书详细日志");
logger.Info($"[Generate] 开始生成确认书 - tradeIds: {string.Join(",", tradeIds)}, docType: {docType}");
if (tradeIds == null)
{
logger.Error("[Generate] tradeIds 为 null");
throw new ArgumentNullException(nameof(tradeIds));
}
if (docType == null)
{
logger.Error("[Generate] docType 为 null");
throw new ArgumentNullException(nameof(docType));
}
//----------------------------------
// 获取当日行权 平仓 到期的有效交易
//----------------------------------
List statusList = new List() {
ConsTrade.确认成交
};
if (GlobalConfig.EnableGenerateOnTradeClosed)
{
statusList.Add(ConsTrade.已到期);
statusList.Add(ConsTrade.已平仓);
statusList.Add(ConsTrade.已执行);
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;
//----------------------------------
// 交易现金交割记录
//----------------------------------
logger.Info("[Generate] 开始查询交易数据");
List allTradeList = allTradeList = DbContext.trade.Where(x => tradeIds.Contains(x.id)).ToList();
logger.Info($"[Generate] 查询到交易数: {allTradeList.Count}");
if (allTradeList.Count < 1)
{
logger.Error("[Generate] 没有找到交易记录");
throw new ServiceException("没有已确认的记录信息!");
}
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 });
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 cashTig = new List();
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();
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);
LogFactory.GetLogger("交易确认书").Info("交易确认书1:" + string.Join(",", tradeContractGroupTradeIds));
if (PS.Config.Company == Configuration.CompanyEnum.浙商)
{
LogFactory.GetLogger("交易确认书").Info("交易确认书浙商");
if (generatorV2 != null)
{
LogFactory.GetLogger("交易确认书").Info("交易确认书插件");
var result = GenerateSingleV2(generatorV2, null, docType , allTradeList);
resultList.Add(result);
}
}
else
{
foreach (var tradeContractGroup in tradeDic.Values)
{
//判断是否为期权交易(非收益互换的交易强制走默认逻辑V1,不走插件)
var isOptionTrade = tradeContractGroup.trade.TradeType != "收益互换";
//插件版本(期权交易强制使用V1默认逻辑)
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 && !isOptionTrade)
{
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;
}
///
///
///
private TradeDocGenerateResult GenerateSingleV2(ITradeConfirmationGenerator generator, trade_contract_group tradeContractGroup, string docType = "DOCX", List allTrades = null)
{
try
{
//修改调用的构造方法
List trades = new List();
if (allTrades != null && allTrades.Count() > 0)
{
trades = allTrades;
}else
{
trades = new List() { tradeContractGroup.trade };
}
List ids = new List();
if (tradeContractGroup != null && 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);
LogFactory.GetLogger("交易确认书").Info("交易确认书init");
return generator.GenerateDocument();
}
catch (Exception ex)
{
LogFactory.GetLogger("GenerateSingleV2").Error(ex);
return new TradeDocGenerateResult(tradeContractGroup.trade)
{
ErrorMessage = ex.Message
};
}
}
///
///
///
private TradeDocGenerateResult GenerateSingleV1(trade_contract_group contractGroup, string docType = "DOCX")
{
var logger = LogFactory.GetLogger("生成确认书详细日志");
logger.Info($"[GenerateSingleV1] 开始处理 - docType: {docType}");
if (contractGroup == null)
{
logger.Error("[GenerateSingleV1] contractGroup 为 null");
throw new ArgumentNullException(nameof(contractGroup));
}
var trade = contractGroup.trade;
logger.Info($"[GenerateSingleV1] 交易信息 - TradeId: {trade?.id}, TradeNumber: {trade?.TradeNumber}, TradeType: {trade?.TradeType}");
var contractBLL = new TradeContractBLL(this);
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
{
["{{乙方名称}}"] = 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["{{补充}}"] = "补充";
var confirmLogger = LogFactory.GetLogger("生成确认书详细日志");
try
{
confirmLogger.Info($"[GenerateSingleConfirmBook] 开始生成 - TradeId: {trade?.id}, TradeNumber: {trade?.TradeNumber}, TradeType: {trade?.TradeType}");
confirmLogger.Info($"[GenerateSingleConfirmBook] 模板路径配置 - TradeType: {trade.TradeType}, IsUsePremiumRate: {trade.IsUsePremiumRate}");
var templateDir = OtcAppContext.MapPath("~/App_Docs/GTJA");
confirmLogger.Info($"[GenerateSingleConfirmBook] templateDir: {templateDir}");
var templatePath = OtcAppContext.MapPath("~/App_Docs/导出模板/交易确认书模板.docx");
confirmLogger.Info($"[GenerateSingleConfirmBook] 默认模板路径: {templatePath}");
if (trade.TradeType == "亚式期权")
{
templatePath = OtcAppContext.MapPath("~/App_Docs/导出模板/交易确认书(亚式期权)模板.docx");
confirmLogger.Info($"[GenerateSingleConfirmBook] 使用亚式期权模板: {templatePath}");
}
if (trade.IsUsePremiumRate != null && trade.IsUsePremiumRate.Value)
{
templatePath = OtcAppContext.MapPath("~/App_Docs/导出模板/交易确认书(名义本金)模板.docx");
confirmLogger.Info($"[GenerateSingleConfirmBook] 使用名义本金模板: {templatePath}");
}
confirmLogger.Info($"[GenerateSingleConfirmBook] 最终模板路径: {templatePath}");
confirmLogger.Info($"[GenerateSingleConfirmBook] 输出文件名: {outPutFileName}");
// 检查模板文件是否存在
if (!File.Exists(templatePath))
{
confirmLogger.Error($"[GenerateSingleConfirmBook] 模板文件不存在: {templatePath}");
return new TradeDocGenerateResult(trade) { ErrorMessage = $"模板文件不存在: {templatePath}" };
}
confirmLogger.Info($"[GenerateSingleConfirmBook] 模板文件存在,准备生成");
LogFactory.GetLogger("交易确认书").Info("交易确认书:" + outPutFileName);
string outPutFilePath = Path.Combine(templateDir, outPutFileName);
confirmLogger.Info($"[GenerateSingleConfirmBook] 输出文件路径: {outPutFilePath}");
// 确保输出目录存在
if (!Directory.Exists(templateDir))
{
confirmLogger.Info($"[GenerateSingleConfirmBook] 创建输出目录: {templateDir}");
Directory.CreateDirectory(templateDir);
}
confirmLogger.Info($"[GenerateSingleConfirmBook] 调用 MsWordTempalteHelper.GenerateFromTemplate");
MsWordTempalteHelper.GenerateFromTemplate(templatePath, dic, outPutFilePath);
confirmLogger.Info($"[GenerateSingleConfirmBook] MsWordTempalteHelper.GenerateFromTemplate 完成");
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.SourceType = 1; // 系统生成
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)
{
confirmLogger.Error($"[GenerateSingleConfirmBook] 发生异常 - TradeId: {trade?.id}, TradeNumber: {trade?.TradeNumber}", e);
confirmLogger.Error($"[GenerateSingleConfirmBook] 异常类型: {e.GetType().FullName}");
confirmLogger.Error($"[GenerateSingleConfirmBook] 异常消息: {e.Message}");
confirmLogger.Error($"[GenerateSingleConfirmBook] 异常堆栈: {e.StackTrace}");
// 检查是否是内部异常
if (e.InnerException != null)
{
confirmLogger.Error($"[GenerateSingleConfirmBook] 内部异常类型: {e.InnerException.GetType().FullName}");
confirmLogger.Error($"[GenerateSingleConfirmBook] 内部异常消息: {e.InnerException.Message}");
confirmLogger.Error($"[GenerateSingleConfirmBook] 内部异常堆栈: {e.InnerException.StackTrace}");
}
LogFactory.GetLogger().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)
{
var contractCodeName = PS.Config.Company == YLErp.Configuration.CompanyEnum.国联
? "交易确认书编号"
: "合约编号";
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
{
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, $"{contractCodeName}已存在", 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, "");
}
}
///
/// 单笔交易上传确认书。
/// 会将该 tradeId 对应的旧 trade_contract_r 置为无效,并新增一条有效记录;同时创建/更新 trade_contract_document 并保存上传文件。
///
public UploadContractFileNewResult UploadContractFileNew(
int tradeId,
bool useContractCode,
string contractCode,
bool isCounterpartyDoc,
UploadFileModel uploadFileModel)
{
var nowDate = DateTime.Now;
var isGuolian = PS.Config.Company == YLErp.Configuration.CompanyEnum.国联;
var contractCodeName = isGuolian
? "交易确认书编号"
: "合约编号";
if (tradeId <= 0)
{
return new UploadContractFileNewResult { Success = false, Message = "请传入参数", OptDate = nowDate, DocumentPath = string.Empty };
}
if (!TryValidateUploadContractFileNew(new[] { tradeId }, uploadFileModel, out _, out var errMsg))
{
return new UploadContractFileNewResult { Success = false, Message = errMsg, OptDate = nowDate, DocumentPath = string.Empty };
}
try
{
var db = DbContextFactory.GetYLDbContext();
var trade = db.trade.AsNoTracking().FirstOrDefault(t => t.id == tradeId && t.ValidState != "InValid");
if (trade == null)
{
return new UploadContractFileNewResult { Success = false, Message = "未找到交易数据", OptDate = nowDate, DocumentPath = string.Empty };
}
var oldR = db.trade_contract_r
.Where(r => r.TradeId == tradeId && r.Type == ContractTypeEnum.Trade && r.IsValid)
.OrderByDescending(r => r.id)
.FirstOrDefault();
var oldCode = (oldR?.ContractCode ?? "").Trim();
var activeCode = "";
if (useContractCode)
{
activeCode = (contractCode ?? "").Trim();
if (string.IsNullOrWhiteSpace(activeCode))
{
return new UploadContractFileNewResult { Success = false, Message = $"{contractCodeName}必填", OptDate = nowDate, DocumentPath = string.Empty };
}
if (!string.Equals(oldCode, activeCode, StringComparison.OrdinalIgnoreCase))
{
var isExists = new TradeContractGenerateService(OptUser).GetExistsContractCode(new[] { activeCode }).Any();
if (isExists)
{
return new UploadContractFileNewResult { Success = false, Message = $"{contractCodeName}已存在", OptDate = nowDate, DocumentPath = string.Empty };
}
}
}
else
{
if (!string.IsNullOrWhiteSpace(oldCode))
{
activeCode = oldCode;
}
else
{
if (isGuolian)
{
activeCode = trade.TradeNumber;
}
else
{
var client = DataCacheProvider.GetClientDataSource().GetData(trade.ClientId);
if (string.IsNullOrEmpty(client?.Code))
{
return new UploadContractFileNewResult { Success = false, Message = "对手方代码缩写缺失,请联系运营组同事维护", OptDate = nowDate, DocumentPath = string.Empty };
}
activeCode = GenerateContractCodeForTrade(db, trade, client?.Code);
}
}
}
if (string.IsNullOrWhiteSpace(activeCode))
{
return new UploadContractFileNewResult { Success = false, Message = $"{contractCodeName}生成失败", OptDate = nowDate, DocumentPath = string.Empty };
}
trade_contract_document oldDoc = null;
if (!string.IsNullOrWhiteSpace(oldCode))
{
oldDoc = db.trade_contract_document.FirstOrDefault(d => d.Code == oldCode && d.Type == ContractTypeEnum.Trade);
}
var oldValidRs = new List();
if (oldR != null)
{
oldValidRs.Add(oldR);
oldR.IsValid = false;
oldR.OptDate = nowDate;
oldR.OptId = OptUser.UserId;
oldR.OptName = OptUser.UserName;
}
var newDoc = new trade_contract_document();
db.trade_contract_document.Add(newDoc);
if (oldDoc != null)
{
newDoc.ValueDate = oldDoc.ValueDate;
newDoc.BuyerId = oldDoc.BuyerId;
newDoc.BuyerName = oldDoc.BuyerName;
newDoc.SellerId = oldDoc.SellerId;
newDoc.SellerName = oldDoc.SellerName;
newDoc.ContractVersion = oldDoc.ContractVersion;
newDoc.FileType = oldDoc.FileType;
newDoc.DayNumber = oldDoc.DayNumber;
newDoc.ClientId = oldDoc.ClientId;
newDoc.Comments = oldDoc.Comments;
db.trade_contract_document.Remove(oldDoc);
}
else
{
var isGJBuyer = trade.BuySell == "买入";
newDoc.ValueDate = valuedateBLL.ValueDate;
newDoc.BuyerId = isGJBuyer ? 0 : trade.ClientId;
newDoc.BuyerName = isGJBuyer ? (PS.Config.CompanyName ?? "") : trade.ClientName;
newDoc.SellerId = isGJBuyer ? trade.ClientId : 0;
newDoc.SellerName = isGJBuyer ? trade.ClientName : (PS.Config.CompanyName ?? "");
newDoc.ClientId = trade.ClientId;
}
newDoc.Code = activeCode;
newDoc.Status = ContractStatusEnum.Draft;
newDoc.SourceType = isCounterpartyDoc ? 2 : 1;
newDoc.Type = ContractTypeEnum.Trade;
newDoc.OptId = OptUser.UserId;
newDoc.OptName = OptUser.UserName;
newDoc.OptDate = nowDate;
SaveUploadFile(activeCode, uploadFileModel, out var outputRelativeDir);
newDoc.Paths = outputRelativeDir;
newDoc.FileName = uploadFileModel.FileName;
var newR = new trade_contract_r();
db.trade_contract_r.Add(newR);
newR.TradeId = tradeId;
newR.TradeNumber = trade.TradeNumber;
newR.ContractCode = activeCode;
newR.TradeClearCode = activeCode;
newR.Type = ContractTypeEnum.Trade;
newR.IsValid = true;
newR.OptId = OptUser.UserId;
newR.OptName = OptUser.UserName;
newR.OptDate = nowDate;
new TradeConfirmService(OptUser, db).EditReportStatus(tradeId, true);
db.SaveChanges();
return new UploadContractFileNewResult
{
Success = true,
Message = "上传成功",
OptDate = newDoc.OptDate ?? nowDate,
DocumentPath = newDoc.RelativePath
};
}
catch (Exception ex)
{
LogFactory.GetLogger("UploadContractFileNew").Error("UploadContractFileNew出错", ex);
return new UploadContractFileNewResult { Success = false, Message = "操作出错", OptDate = nowDate, DocumentPath = string.Empty };
}
}
private static string GenerateContractCodeForTrade(YLContext db, trade trade, string clientCode)
{
if (trade.TradeType == "收益互换")
{
return GuolianContractNoGenerator.Generate(db, trade, clientCode ?? string.Empty);
}
return trade.TradeNumber;
}
private static bool TryValidateUploadContractFileNew(
IReadOnlyCollection tradeIds,
UploadFileModel uploadFileModel,
out HashSet tradeIdSet,
out string errMsg)
{
tradeIdSet = new HashSet();
errMsg = null;
if (tradeIds == null || tradeIds.Count == 0)
{
errMsg = "请传入参数";
return false;
}
if (uploadFileModel == null || uploadFileModel.Length <= 0)
{
errMsg = "请选择需上传的文件";
return false;
}
var fileExt = System.IO.Path.GetExtension(uploadFileModel.FileName)?.ToLowerInvariant();
if (fileExt != ".xlsx" && fileExt != ".xls" && fileExt != ".pdf" && fileExt != ".docx" && fileExt != ".doc")
{
errMsg = "请上传PDF/Word/Excel格式的文件";
return false;
}
foreach (var tid in tradeIds)
{
if (tid > 0)
{
tradeIdSet.Add(tid);
}
}
if (tradeIdSet.Count == 0)
{
errMsg = "请传入参数";
return false;
}
return true;
}
///
/// 保存上传的文件到服务器,并返回相对路径和文件名
///
///
///
///
///
private static void SaveUploadFile(string contractCode, UploadFileModel uploadFileModel, out string outputRelativeDir)
{
var outputDir = Path.Combine(OtcAppContext.AppDocsPath, "contractdoc", "output");
if (!Directory.Exists(outputDir))
{
Directory.CreateDirectory(outputDir);
}
var ext = Path.GetExtension(uploadFileModel.FileName) ?? "";
var outputFullPath = Path.Combine(outputDir, uploadFileModel.FileName);
if (File.Exists(outputFullPath))
{
File.Delete(outputFullPath);
}
using (var fs = new FileStream(outputFullPath, FileMode.Create, FileAccess.Write, FileShare.None))
using (var sr = uploadFileModel.OpenReadStream())
{
sr.CopyTo(fs);
}
outputRelativeDir = Path.Combine("App_Docs", "contractdoc", "output");
}
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;
}
///
/// 判断确认书是否生成过
///
/// trade_contract_r.id
///
public bool IsContractGenerated(List ids,List 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;
}
///
/// 批量用印
///
/// trade_contract_r.id
///
public void SealContracts(List ids,List 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);
}
}
}
}
}