Files
zszq-trs/YLErpDAL/Modules/TradeModule/DealModule/TradeContractGenerateService.cs
T
tengyufan b3484c3618 fix: 国联民生收益互换支持审批前生成交易确认书
- 仅国联民生收益互换支持在新增待确认、修改待确认、审批中生成交易确认书,期权、其他公司及其他交易状态保持原限制
- 交易确认书页面同步开放上述交易的“生成确认书”按钮,后端批量生成链路同步放开状态过滤
- 审批前生成仅校验客户、标的、初始持仓等模板必需核心数据;不以银行账户、联系人、保证金等非模板必填资料阻断
- 审批前已生成确认书的交易被修改时,使该交易原确认书关联失效,重新生成仍按原覆盖逻辑处理
- 审批拒绝时清理该交易审批前生成的确认书关联、OA 结果及用印队列;无其他有效引用时删除确认书数据,避免遗留无效确认书
- 保持原交易编号逻辑:自动生成和手工填写均不复用已拒绝交易编号
- 新增审批前适用范围、确认书关联及 OA 清理谓词专项单测
2026-07-30 11:10:48 +08:00

809 lines
39 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using BaseOUDAL;
using DocumentFormat.OpenXml.Office.Word;
using System.Collections.Concurrent;
using System.Drawing.Printing;
using YLErp.Configuration;
using YLErp.DBModels.Consts;
using YLErp.Model;
using YLErp.Model.Enum;
using YLErp.Models;
using YLErp.Modules.TradeDalModule;
using YLErp.Modules.TradeModule.DocGenerateModule;
namespace YLErp.Modules.TradeModule.DealModule
{
/// <summary>
/// 交易确认书生成
/// </summary>
public class TradeContractGenerateService : YLBaseService
{
public TradeContractGenerateService(YLBaseService baseService) : base(baseService)
{
}
public TradeContractGenerateService(OptUserInfo userInfo) : base(userInfo)
{
}
/// <summary>
/// 确认书生成队列
/// </summary>
private static readonly ConcurrentQueue<_ContractInfoModel> _ContractQueue = new ConcurrentQueue<_ContractInfoModel>();
/// <summary>
/// 确认书缓存队列结构
/// </summary>
private class _ContractInfoModel
{
public string ContractType;
public List<int> TradeIds;
public _ContractInfoModel(string contractType, List<int> tradeIds)
{
this.ContractType = contractType;
this.TradeIds = tradeIds;
}
}
/// <summary>
/// 异步生成交易确认书
/// </summary>
public void GenerateContractsAsync(List<int> tradeIds, string contractType = "其它")
{
var status = false;
lock (_ContractQueue)
{
status = _ContractQueue.IsEmpty;
_ContractQueue.Enqueue(new _ContractInfoModel(contractType, tradeIds));
}
if (status)
{
Task.Run(() =>
{
while (!_ContractQueue.IsEmpty)
{
if (!_ContractQueue.TryPeek(out var obj))
{
continue;
}
new TradeContractGenerateService(this).GenerateContracts(obj.TradeIds, obj.ContractType);
lock (_ContractQueue)
{
_ContractQueue.TryDequeue(out _);
}
}
});
}
}
/// <summary>
/// 同步生成交易确认书
/// </summary>
/// <param name="tradeIds"></param>
/// <param name="contractType">contractType为确认书的话,表示生成交易确认书;否则则生成提前终止确认书或者到期结算单</param>
private TradeContractGenerateResultModel GenerateContracts(List<int> tradeIds, string contractType = "其它")
{
ResetDbContext();
var result = new TradeContractGenerateResultModel();
try
{
if (contractType == "确认书")
{
result.ContractType = "确认书";
result.Success = GJGenerateConfirmBook(tradeIds, "PDF", out var errors, out _);
result.Message = result.Success ? "生成确认书成功" : string.Join("\r\n", errors.AsEnumerable());
return result;
}
var clearingTradeIds = new List<int>();
var unwindReportInputModels = new List<UnwindReportInputModel>();
var tcQuery = from tc in DbContext.trade_cash
join t in DbContext.trade on tc.TradeId equals t.id
where tradeIds.Contains(tc.TradeId) && !tc.IsDeleted
select new
{
tc.id,
tc.TradeId,
tc.Action,
tc.ExerciseWay,
tc.IsLastAction,
ValueDate = tc.HappenedDate ?? tc.ValueDate,
t.ExerciseDate
};
var lookUp = tcQuery.ToLookup(tc => tc.TradeId);
var tradeCashes = lookUp.Select(l => l.OrderByDescending(m => m.id).First()).ToList();
foreach (var tc in tradeCashes)
{
if (tc.Action == ClientCashInCashOut.系统操作_平仓费 ||
(tc.Action == ClientCashInCashOut.系统操作_行权费 && tc.ExerciseWay == TradeCashExerciseWayEnum.提前终止行权))
{
unwindReportInputModels.Add(new UnwindReportInputModel { TradeId = tc.TradeId, TradeCashId = tc.id });
}
else if (tc.Action == ClientCashInCashOut.系统操作_行权费)
{
clearingTradeIds.Add(tc.TradeId);
}
else if (tc.Action == ClientCashInCashOut.系统操作_票息)
{
if (tc.ValueDate >= tc.ExerciseDate)
{
clearingTradeIds.Add(tc.TradeId);
}
else
{
unwindReportInputModels.Add(new UnwindReportInputModel { TradeId = tc.TradeId, TradeCashId = tc.id });
}
}
}
var hasUnwindReport = unwindReportInputModels.Count > 0;
if (hasUnwindReport)
{
result.ContractType = "提前终止确认书";
result.Success = GJGenerateUnwindReport(unwindReportInputModels, "PDF", out var errors, out _);
result.Message = result.Success ? "生成提前终止确认书成功" : string.Join("\r\n", errors.AsEnumerable());
}
if (clearingTradeIds.Count > 0)
{
result.ContractType = "到期结算单";
if (GJGenerateSettleBill(clearingTradeIds, "PDF", out var errors, out _))
{
if (!hasUnwindReport)
{
result.Success = true;
result.Message = "生成到期结算单成功";
}
else if (result.Success)
{
result.Message = "生成到期结算单或提前终止确认书成功";
}
}
else if (result.Success)
{
result.Success = false;
result.Message = string.Join("\r\n", errors.AsEnumerable());
}
else
{
result.Message += (string.IsNullOrEmpty(result.Message) ? string.Empty : "\r\n") + string.Join("\r\n", errors.AsEnumerable());
}
}
return result;
}
catch (Exception ex)
{
result.Exception = ex;
LogFactory.GetLogger("生成确认书").Error("确认书类型:" + result.ContractType, ex);
}
return result;
}
/// <summary>
/// 生成交易确认书
/// </summary>
public bool GJGenerateConfirmBook(List<int> tradeIds, string docType,
out IEnumerable<string> errors, out IEnumerable<string> files, DateTime? startDate = null, DateTime? endDate = null)
{
var logger = LogFactory.GetLogger("生成确认书");
logger.Info($"[GJGenerateConfirmBook] 开始生成确认书 - tradeIds.Count: {tradeIds?.Count ?? 0}, docType: {docType}, startDate: {startDate}, endDate: {endDate}");
Func<int, string> getUnderlyingInstrumentType = new Func<int, string>((underlyingId) =>
{
return DataCacheProvider.GetUnderlyingDataSource().GetData(underlyingId)?.UnderlyingInstrumentType;
});
List<TradeDocGenerateResult> results = new List<TradeDocGenerateResult>();
List<string> error = new List<string>();
List<string> file = new List<string>();
logger.Info("[GJGenerateConfirmBook] 生成确认书流程");
if (tradeIds == null || !tradeIds.Any())
{
logger.Info("[GJGenerateConfirmBook] tradeIds 为空,直接返回");
errors = new List<string>();
files = new List<string>();
return true;
}
var trades = DbContext.trade.Where(x => tradeIds.Contains(x.id)).AsNoTracking().ToList();
logger.Info($"[GJGenerateConfirmBook] 查询到交易记录数: {trades.Count}");
if (!trades.Any())
{
logger.Info("[GJGenerateConfirmBook] 未找到交易记录,直接返回");
errors = new List<string>();
files = new List<string>();
return true;
}
// 仅国联收益互换允许在审批前生成确认书,其他交易保持原状态限制。
var invalidStatusList = new List<string> { ConsTrade.新增待确认, ConsTrade.修改待确认, ConsTrade.审批中 };
var invalidTrades = trades.Where(t => invalidStatusList.Contains(t.TradeStatus)
&& !GuolianSwapConfirmBookScope.IsPreApprovalTrade(t)).ToList();
if (invalidTrades.Any())
{
error.AddRange(invalidTrades.Select(t => $"交易 {t.TradeNumber} 状态为【{t.TradeStatus}】,不能生成确认书"));
tradeIds = tradeIds.Where(id => !invalidTrades.Any(t => t.id == id)).ToList();
trades = trades.Where(t => !invalidTrades.Any(it => it.id == t.id)).ToList();
logger.Info($"[GJGenerateConfirmBook] 过滤掉 {invalidTrades.Count} 笔待确认/审批中交易");
}
var preApprovalTrades = trades.Where(GuolianSwapConfirmBookScope.IsPreApprovalTrade).ToList();
foreach (var trade in preApprovalTrades)
{
var validationErrors = new GuolianSwapConfirmBookValidationService(this).Validate(trade);
if (!validationErrors.Any())
{
continue;
}
error.Add($"交易 {trade.TradeNumber} 无法生成确认书:{string.Join("", validationErrors)}");
tradeIds = tradeIds.Where(id => id != trade.id).ToList();
trades = trades.Where(item => item.id != trade.id).ToList();
}
if (!trades.Any())
{
logger.Info("[GJGenerateConfirmBook] 过滤后无有效交易可生成确认书");
errors = error;
files = new List<string>();
return false;
}
var clientIds = trades.Select(x => x.ClientId).Distinct().ToList();
logger.Info($"[GJGenerateConfirmBook] 客户ID数: {clientIds.Count}");
foreach (var item in trades)
{
groupGenerateHandle_Date(new List<int> { item.id }, docType, startDate, endDate, results, error, file);
}
errors = results.Where(n => !string.IsNullOrWhiteSpace(n.ErrorMessage)).Select(n => n.ErrorMessage).ToList();
files = results.Where(n => !string.IsNullOrWhiteSpace(n.OutputFilePath)).Select(n => n.OutputFilePath).ToList();
logger.Info($"[GJGenerateConfirmBook] 完成生成确认书 - 错误数: {errors.Count()}, 文件数: {files.Count()}");
return !errors.Any();
}
private void groupGenerateHandle_Date(List<int> ids, string docType, DateTime? startDate, DateTime? endDate, List<TradeDocGenerateResult> results, List<string> error, List<string> file)
{
var logger = LogFactory.GetLogger("生成确认书");
logger.Info($"[groupGenerateHandle_Date] 开始处理 - ids.Count: {ids?.Count ?? 0}");
if (ids == null || !ids.Any())
{
logger.Info("[groupGenerateHandle_Date] ids 为空,直接返回");
return;
}
var trades = DbContext.trade.Where(c => ids.Contains(c.id)).ToList();
logger.Info($"[groupGenerateHandle_Date] 查询到交易数: {trades.Count}");
if (!trades.Any())
{
logger.Info("[groupGenerateHandle_Date] 未找到交易记录,直接返回");
return;
}
var firstTrade = trades.FirstOrDefault();
if (firstTrade == null)
{
logger.Info("[groupGenerateHandle_Date] 第一条交易记录为 null,直接返回");
return;
}
var client = DataCacheProvider.GetClientDataSource().GetData(firstTrade.ClientId);
if (client == null)
{
logger.Info($"[groupGenerateHandle_Date] 未找到客户信息 - ClientId: {firstTrade.ClientId}");
return;
}
if (string.IsNullOrEmpty(client.Code))
{
throw new ServiceException($"对手方代码缩写缺失,请联系运营组同事维护: {firstTrade.ClientName}");
}
var supProtocolDate = client.SupProtocolDate;
logger.Info($"[groupGenerateHandle_Date] 客户补充协议日期: {supProtocolDate}");
var groupDateDouble = trades.Where(x => supProtocolDate == null || x.TradeDate < supProtocolDate).Select(x => x.id).ToList();
var groupDateSingle = trades.Where(x => supProtocolDate != null && x.TradeDate >= supProtocolDate).Select(x => x.id).ToList();
logger.Info($"[groupGenerateHandle_Date] 双章确认书交易数: {groupDateDouble.Count}, 单章确认书交易数: {groupDateSingle.Count}");
// 单章确认书和双章确认书同时生成要生成两个文件
if (groupDateDouble.Any() && groupDateSingle.Any())
{
logger.Info("[groupGenerateHandle_Date] 同时生成单章和双章确认书");
groupGenerateHandle(groupDateDouble, docType, startDate, supProtocolDate.Value.AddDays(-1), results, error, file);
groupGenerateHandle(groupDateSingle, docType, supProtocolDate, endDate, results, error, file);
}
else if (groupDateDouble.Any())
{
logger.Info("[groupGenerateHandle_Date] 仅生成双章确认书");
groupGenerateHandle(groupDateDouble, docType, startDate, endDate, results, error, file);
}
else if (groupDateSingle.Any())
{
logger.Info("[groupGenerateHandle_Date] 仅生成单章确认书");
groupGenerateHandle(groupDateSingle, docType, startDate, endDate, results, error, file);
}
else
{
logger.Info("[groupGenerateHandle_Date] 没有需要生成的确认书");
}
}
private void groupGenerateHandle(List<int> ids, string docType, DateTime? startDate, DateTime? endDate, List<TradeDocGenerateResult> results, List<string> error, List<string> file)
{
var logger = LogFactory.GetLogger("生成确认书");
logger.Info($"[groupGenerateHandle] 开始处理 - ids.Count: {ids?.Count ?? 0}, docType: {docType}");
if (ids == null || !ids.Any())
{
logger.Info("[groupGenerateHandle] ids 为空,直接返回");
return;
}
var trade_contract_r = DbContext.trade_contract_r.Where(c => ids.Contains(c.TradeId) && c.Type == "交易确认书" && c.IsValid).ToList();
logger.Info($"[groupGenerateHandle] 找到已存在的确认书记录数: {trade_contract_r.Count}");
//DbContext.trade_contract_r.RemoveRange(trade_contract_r);
trade_contract_r.ForEach(O => O.IsValid = false);
DbContext.SaveChanges();
logger.Info("[groupGenerateHandle] 调用 BatchConfirmationGenerateService.Generate");
var result = new BatchConfirmationGenerateService(this).Generate(ids, docType, startDate, endDate);
logger.Info($"[groupGenerateHandle] 生成结果 - 成功数: {result.Count(r => string.IsNullOrWhiteSpace(r.ErrorMessage))}, 失败数: {result.Count(r => !string.IsNullOrWhiteSpace(r.ErrorMessage))}");
results.AddRange(result);
error.AddRange(results.Where(n => !string.IsNullOrWhiteSpace(n.ErrorMessage)).Select(n => n.ErrorMessage).ToArray());
file.AddRange(results.Where(n => !string.IsNullOrWhiteSpace(n.OutputFilePath)).Select(n => n.OutputFilePath).ToList());
logger.Info($"[groupGenerateHandle] 完成处理 - 当前总错误数: {error.Count}, 当前总文件数: {file.Count}");
}
public bool GXJY_CorrespondingConfirmationTemplate(List<int> tradeIds, out string ErrMsg)
{
bool IsExist = true;
ErrMsg = "";
var listTrade = DbContext.trade.Where(l => tradeIds.Contains(l.id));
foreach (var t in listTrade)
{
bool IsExistChild = false;
var exerciseMode = t.ExerciseMode ?? "";
switch (t.TradeType)
{
case "亚式期权":
IsExistChild = true;
break;
case "结构化交易":
switch (t.StructureType)
{
case "普通亚式带保底":
case "增强亚式":
case "增强亚式价差":
case "增强亚式价差组合标的":
IsExistChild = true;
break;
}
break;
default:
IsExistChild = true;
break;
}
if (IsExistChild == false)
{
IsExist = false;
ErrMsg += t.TradeNumber.ToString() + ",";
}
}
if (!string.IsNullOrWhiteSpace(ErrMsg))
{
ErrMsg = ErrMsg.Substring(0, ErrMsg.Length - 1);
ErrMsg += "该交易没有相应确认书模板";
}
return IsExist;
}
/// <summary>
/// 生成提前中止确认书
/// </summary>
public bool GJGenerateUnwindReport(List<UnwindReportInputModel> trades, string docType,
out List<string> errors, out List<string> files)
{
var tdIds = trades.Select(t => t.TradeId).ToList();
if (PS.Config.Company == CompanyEnum.国信金阳)
{
var IsTradeContract = DbContext.trade_contract_r.Where(l => l.IsValid && tdIds.Contains(l.TradeId) && l.Type == "交易确认书").Select(l => l.TradeId).ToList();
var IsTradeIds = tdIds.Where(l => !IsTradeContract.Contains(l)).ToList();
if (IsTradeIds.Count > 0)
{
throw new ServiceException(String.Join(",", DbContext.trade.Where(l => IsTradeIds.Contains(l.id)).Select(l => l.TradeNumber).ToArray()) + "请生成该交易编号相应交易确认书");
}
if (!GXJY_CorrespondingConfirmationTemplate(tdIds, out string Msg))
{
throw new ServiceException(Msg);
}
}
files = new List<string>();
errors = new List<string>();
if (PS.Config.Company == CompanyEnum.兴证)
{
IEnumerable<TradeDocGenerateResult> results = null;
results = new BatchUnwindReportGenerateService(this).Generate(trades, docType, UserId, UserName);
errors = results.Where(n => !string.IsNullOrWhiteSpace(n.ErrorMessage)).Select(n => n.ErrorMessage).ToList();
files = results.Where(n => !string.IsNullOrWhiteSpace(n.OutputFilePath)).Select(n => n.OutputFilePath).ToList();
}
else if (PS.Config.Company == CompanyEnum.海通)
{
var tradeCashIds = trades.Select(O => O.TradeCashId);
var tradeCashStatus = new string[] { ClientCashInCashOut.系统操作_行权费, ClientCashInCashOut.系统操作_平仓费 };
var query = from t in DbContext.trade
join tc in DbContext.trade_cash
on t.id equals tc.TradeId
where
tradeCashIds.Contains(tc.id) &&
tc.ValidState != ConsGlobal.InValid && !tc.IsDeleted &&
tradeCashStatus.Contains(tc.Action) &&
tc.ExerciseWay == TradeCashExerciseWayEnum.提前终止行权
select new { t.id, tradeCashId = tc.id, t.ClientId };
var clientTradeDict = query.AsEnumerable().GroupBy(O => O.ClientId)
.ToDictionary(K => K.Key, V => V.Select(O => new UnwindReportInputModel() { TradeId = O.id, TradeCashId = O.tradeCashId }).ToList());
foreach (var ctrades in clientTradeDict)
{
var results = new BatchUnwindReportGenerateService(this).Generate(ctrades.Value, "PDF", UserId, UserName);
errors.AddRange(results.Where(n => !string.IsNullOrWhiteSpace(n.ErrorMessage)).Select(n => n.ErrorMessage).ToArray());
files.AddRange(results.Where(n => !string.IsNullOrWhiteSpace(n.OutputFilePath)).Select(n => n.OutputFilePath).ToList());
if (errors.Any()) break;
}
}
else if (PS.Config.Is方顿) //同一笔交易结构化交易在一个确认书里
{
List<TradeDocGenerateResult> results = new List<TradeDocGenerateResult>();
List<string> error = new List<string>();
List<string> file = new List<string>();
var tradeIds = trades.Select(O => O.TradeId).ToArray();
var query = DbContext.trade.Where(O => tradeIds.Contains(O.id)).Select(O => new { O.id, O.ParentTradeId }).ToList();
var group = query.GroupBy(O => O.ParentTradeId).ToDictionary(K => K.Key, V => V.Select(O => O.id).ToList());
foreach (var item in group)
{
if (item.Key == 0)
{
foreach (var item2 in item.Value)
{
var tradeCashIds = trades.Where(x => x.TradeId == item2).ToList();
var CashIds = trades.Where(x => x.TradeId == item2).Select(x => x.TradeId).ToList();
var trade_contract_r = DbContext.trade_contract_r.Where(c => CashIds.Contains(c.TradeCashId.Value) && c.IsValid).ToList();
trade_contract_r.ForEach(o => o.IsValid = false);
DbContext.SaveChanges();
var result = new BatchUnwindReportGenerateService(this).Generate(tradeCashIds, docType, UserId, UserName);
results.AddRange(result);
error.AddRange(results.Where(n => !string.IsNullOrWhiteSpace(n.ErrorMessage)).Select(n => n.ErrorMessage).ToArray());
file.AddRange(results.Where(n => !string.IsNullOrWhiteSpace(n.OutputFilePath)).Select(n => n.OutputFilePath).ToList());
if (error.Any()) break; ;
}
}
else
{
var tradeCashIds = (from t1 in item.Value join tc in trades on t1 equals tc.TradeId select tc).ToList();
var CashIds = (from t1 in item.Value join tc in trades on t1 equals tc.TradeId select tc.TradeId).ToList();
var trade_contract_r = DbContext.trade_contract_r.Where(c => CashIds.Contains(c.TradeCashId.Value) && c.IsValid).ToList();
trade_contract_r.ForEach(o => o.IsValid = false);
DbContext.SaveChanges();
var result = new BatchUnwindReportGenerateService(this).Generate(tradeCashIds, docType, UserId, UserName);
results.AddRange(result);
error.AddRange(results.Where(n => !string.IsNullOrWhiteSpace(n.ErrorMessage)).Select(n => n.ErrorMessage).ToArray());
file.AddRange(results.Where(n => !string.IsNullOrWhiteSpace(n.OutputFilePath)).Select(n => n.OutputFilePath).ToList());
if (error.Any()) break; ;
}
}
errors = results.Where(n => !string.IsNullOrWhiteSpace(n.ErrorMessage)).Select(n => n.ErrorMessage).ToList();
files = results.Where(n => !string.IsNullOrWhiteSpace(n.OutputFilePath)).Select(n => n.OutputFilePath).ToList();
}
else
{
List<TradeDocGenerateResult> results = new List<TradeDocGenerateResult>();
if (PS.Config.Is国泰君安)
{
List<string> error = new List<string>();
List<string> file = new List<string>();
var tradeIds = trades.Select(O => O.TradeId);
var tradecashId = trades.Select(o => o.TradeCashId).ToList();
Func<int, string> getUnderlyingInstrumentType = new Func<int, string>((underlyingId) =>
{
return DataCacheProvider.GetUnderlyingDataSource().GetData(underlyingId).UnderlyingInstrumentType;
});
List<string> instrumentTypeArr = new List<string>() { ConsGlobal.InstrumentType.Stock, ConsGlobal.InstrumentType.StockIF };
var query = DbContext.trade.Where(O => tradeIds.Contains(O.id)).Select(O => new { O.id, O.UnderlyingId, O.ClientId, O.TradeType }).ToList();
if (query.Any(O => instrumentTypeArr.Contains(getUnderlyingInstrumentType(O.UnderlyingId)) || O.TradeType == "雪球期权"))
{
//暂时将所有子交易都作为判断依据,等拿到模板后再根据模板做调整更改;
//目前是否为权益类的判断条件只是是否是股票,没有考虑IC IF等品种;
int count = query.GroupBy(O => new { UnderlyingInstrumentType = (instrumentTypeArr.Contains(getUnderlyingInstrumentType(O.UnderlyingId)) || O.TradeType == "雪球期权") ? 1 : 0 }).Count();
if (count > 1)
{
throw new ServiceException("不应勾选多个非股票(含股指期货)标的的交易");
}
var group = query.GroupBy(O => new { O.ClientId }).ToDictionary(K => K.Key, V => V.Select(O => O.id).ToList());
foreach (var item in group)
{
var tradeCashIds = (from t1 in item.Value join tc in trades on t1 equals tc.TradeId select tc).ToList();
var CashIds = (from t1 in item.Value join tc in trades on t1 equals tc.TradeId select tc.TradeId).ToList();
var trade_contract_r = DbContext.trade_contract_r.Where(c => CashIds.Contains(c.TradeCashId.Value) && c.IsValid).ToList();
//DbContext.trade_contract_r.RemoveRange(trade_contract_r);
trade_contract_r.ForEach(o => o.IsValid = false);
DbContext.SaveChanges();
var result = new BatchUnwindReportGenerateService(this).Generate(tradeCashIds, docType, UserId, UserName);
results.AddRange(result);
error.AddRange(results.Where(n => !string.IsNullOrWhiteSpace(n.ErrorMessage)).Select(n => n.ErrorMessage).ToArray());
file.AddRange(results.Where(n => !string.IsNullOrWhiteSpace(n.OutputFilePath)).Select(n => n.OutputFilePath).ToList());
if (error.Any()) break; ;
}
}
}
if (results.Count == 0)
{
results = (List<TradeDocGenerateResult>)new UnwindReportGenerateService(this).Generate(trades, docType);
}
errors = results.Where(n => !string.IsNullOrWhiteSpace(n.ErrorMessage)).Select(n => n.ErrorMessage).ToList();
files = results.Where(n => !string.IsNullOrWhiteSpace(n.OutputFilePath)).Select(n => n.OutputFilePath).ToList();
}
return !errors.Any();
}
/// <summary>
/// 生成结算确认书
/// </summary>
public bool GJGenerateSettleBill(List<int> tradeIds, string docType,
out IEnumerable<string> errors, out IEnumerable<string> files)
{
IEnumerable<TradeDocGenerateResult> results;
var settleSv = new SettlementBillGenerateService(this);
results = settleSv.Generate(null, tradeIds, docType, UserId, UserName);
errors = results.Where(n => !string.IsNullOrWhiteSpace(n.ErrorMessage)).Select(n => n.ErrorMessage).ToArray();
files = results.Where(n => !string.IsNullOrWhiteSpace(n.OutputFilePath)).Select(n => n.OutputFilePath).ToArray();
return !errors.Any();
}
/// <summary>
/// 根据传进来的合约代码过滤出已存在的合约代码
/// </summary>
public IEnumerable<string> GetExistsContractCode(IEnumerable<string> contractCodes)
{
if (contractCodes == null)
{
throw new ArgumentNullException(nameof(contractCodes));
}
if (!contractCodes.Any())
{
return Enumerable.Empty<string>();
}
var query = (from a in DbContext.trade_contract_r.AsNoTracking()
join b in DbContext.trade.AsNoTracking() on a.TradeId equals b.id
where contractCodes.Contains(a.ContractCode) && b.ValidState != "InValid" && a.IsValid
select a.ContractCode).Union
(from tm in DbContext.TradeMeta.AsNoTracking()
join t in DbContext.trade.AsNoTracking() on tm.TradeId equals t.id
where (tm.MetaKey == ConsTradeMetaKey.ContractCode || tm.MetaKey.Contains("确认书")) && //伴星确认书编号的Key是合约编号,长江确认书编号的Key是日期+(交易确认书、结算确认书和提前终止确认书)+序号
t.ValidState != "InValid"
&& contractCodes.Contains(tm.MetaValue)
select tm.MetaValue);
//.Union
//(from t in DbContext.trade.AsNoTracking()
// where t.ValidState != "InValid" && contractCodes.Contains(t.TradeNumber)
// select t.TradeNumber);
return query.ToArray();
}
public SearchListResult<clientContractR> GetConfirmBookListByClient(ClientConfirmBookListReq req)
{
var result = new SearchListResult<clientContractR>();
var contractList = new List<clientContractR>();
var query = from t in DbContext.trade.AsNoTracking().Where(x => x.TradeType == "收益互换" && x.ValidState != "InValid")
join tcrs in DbContext.trade_contract_r
on t.id equals tcrs.TradeId into tcrsGroup
from tcr in tcrsGroup.Where(r => r.IsValid && r.Type == ContractTypeEnum.Trade).DefaultIfEmpty()
join tcds in DbContext.trade_contract_document
on tcr.ContractCode equals tcds.Code into tcdsGroup
from tcd in tcdsGroup.DefaultIfEmpty()
join sp in DbContext.swap_position.AsNoTracking().Where(s => s.IsInitial && s.PositionType > 0 && !s.Invalid)
on t.id equals sp.SwapTradeId
join oa in DbContext.tradeContractOaResult on t.id equals oa.trade_id into oaTemp
from oa in oaTemp.DefaultIfEmpty()
where oa == null || oa.is_valid == true
select new
{
t.id,
t.TradeDate,
t.StartDate,
tcr.ContractCode,
t.ClientId,
t.ClientNumber,
t.ClientName,
tcr.send_email_result,
tcd.Status,
tcd.RelativePath,
tcd.SealResult,
ContractId = tcr != null ? tcr.id : 0,
sp.PositionType,
t.SentMailCount,
tcd.StampDocumentFileName,
tcr.OptDate,
tcr.OptName,
ContractDocId = tcd != null ? tcd.id : 0,
OAStatus = oa != null ? oa.status : "",
OAURL = oa != null ? oa.oa_url : "",
OAMessage = oa != null ? oa.oa_msg : ""
};
if (req.StartDate != null && req.StartDate != DateTime.MinValue)
{
query = query.Where(o => o.TradeDate >= req.StartDate);
}
if (req.EndDate != null && req.EndDate != DateTime.MaxValue)
{
query = query.Where(o => o.TradeDate <= req.EndDate);
}
if (req.ClientIds != null && req.ClientIds.Count > 0)
{
query = query.Where(o => req.ClientIds.Contains(o.ClientId));
}
if (!string.IsNullOrEmpty(req.ContractCode))
{
query = query.Where(o => o.ContractCode.Contains(req.ContractCode));
}
if (req.PositionTypes != null && req.PositionTypes.Count() > 0)
{
query = query.Where(o => req.PositionTypes.Contains(o.PositionType));
}
//客户希望用StartDate分组, 默认业务中StartDate会是TradeDate+1个交易日
var contractGroups = query.AsEnumerable()
.GroupBy(x => new { x.StartDate, x.ClientId, x.PositionType })
.Select(group => group.ToList())
.ToList();
// 构建返回结果
foreach (var group in contractGroups)
{
var sealResult = group.FirstOrDefault().SealResult;
contractList.Add(new clientContractR
{
id = group.FirstOrDefault().id,
ContractCode = group.FirstOrDefault().ContractCode,
TradeDate = group.FirstOrDefault().TradeDate.Value,
ClientNumber = group.FirstOrDefault().ClientNumber,
ClientName = group.FirstOrDefault().ClientName,
StampStatus = group.FirstOrDefault().Status,
EmailResult = group.FirstOrDefault().send_email_result,
ContractDocUrl = group.FirstOrDefault().RelativePath,
tradeIds = group.Select(x => x.id).Distinct().ToList(),
SealResult = sealResult != null ? Enum.GetName(typeof(SealResultEnum), sealResult) : "",
HasGeneratedConfirmBook = group.FirstOrDefault().ContractId != 0,
ContractId = group.FirstOrDefault().ContractId,
tradeCount = group.Select(x => x.id).Distinct().Count(),
PositionType = group.FirstOrDefault().PositionType,
SentMailCount = group.FirstOrDefault().SentMailCount ?? 0,
StampDocumentFileName = group.FirstOrDefault().StampDocumentFileName,
OptDate = group.FirstOrDefault().OptDate,
OptName = group.FirstOrDefault().OptName,
ContractDocId = group.FirstOrDefault().ContractDocId,
OAStatus = group.FirstOrDefault().OAStatus,
OAURL = group.FirstOrDefault().OAURL,
OAMessage = group.FirstOrDefault().OAMessage
});
}
result = contractList.OrderByDescending(r => r.TradeDate).AsQueryable().ToSearchList(req);
return result;
}
}
/// <summary>
/// 交易确认书生成结果
/// </summary>
public class TradeContractGenerateResultModel
{
public bool Success;
public string Message;
public string ContractType;
public Exception Exception;
}
public class ClientConfirmBookListReq : BaseSearchReq
{
//合约编号
public string ContractCode { get; set; }
//开仓起始时间
public DateTime? StartDate { get; set; }
//开仓结束时间
public DateTime? EndDate { get; set; }
//客户
public List<int>? ClientIds { get; set; }
public List<int>? PositionTypes { get; set; }
}
public class clientContractR
{
public int id { get; set; }
public string ContractCode { get; set; }
public DateTime TradeDate { get; set; }
public string ClientNumber { get; set; }
public string ClientName { get; set; }
public string StampStatus { get; set; }
public string EmailResult { get; set; }
public List<int> tradeIds { get; set; }
public string ContractDocUrl { get; set; }
public string SealResult { get; set; }
public string ContractEncryptId { get; set; }
public bool HasGeneratedConfirmBook { get; set; }
public int ContractId { get; set; }
public int PositionType { get; set; }
public int tradeCount { get; set; }
public int SentMailCount { get; set; }
public string StampDocumentFileName { get; set; }
public DateTime? OptDate { get; set; }
public string OptName { get; set; }
public int ContractDocId { get; set; }
public string OAStatus { get; set; }
public string OAURL { get; set; }
public string OAMessage { get; set; }
}
}