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

193 lines
6.4 KiB
C#

using System.Linq.Expressions;
using YLErp.Configuration;
using YLErp.DBModels;
using YLErp.DBModels.Consts;
using YLErp.DBModels.Enums;
using YLErp.Model;
namespace YLErp.Modules.TradeModule.DocGenerateModule
{
/// <summary>
/// 国联收益互换审批前生成确认书的范围与资料校验。
/// </summary>
public static class GuolianSwapConfirmBookScope
{
private static readonly HashSet<string> PreApprovalStatuses = new()
{
ConsTrade.新增待确认,
ConsTrade.修改待确认,
ConsTrade.审批中
};
public static bool IsPreApprovalTrade(trade trade)
{
return IsPreApprovalTrade(trade, PS.Config.Company);
}
public static bool IsPreApprovalTrade(trade trade, CompanyEnum company)
{
return IsGuolianSwap(trade, company)
&& trade.ValidState != ConsGlobal.InValid
&& IsPreApprovalStatus(trade.TradeStatus);
}
public static bool IsGuolianSwap(trade trade)
{
return IsGuolianSwap(trade, PS.Config.Company);
}
public static bool IsGuolianSwap(trade trade, CompanyEnum company)
{
return company == CompanyEnum.国联 && trade.TradeType == "收益互换";
}
public static bool IsPreApprovalStatus(string tradeStatus)
{
return PreApprovalStatuses.Contains(tradeStatus);
}
}
/// <summary>
/// 清理国联收益互换审批前生成的确认书,不复用按合同编号批量清理的通用逻辑。
/// </summary>
public class GuolianSwapConfirmBookCleanupService : YLBaseService
{
public GuolianSwapConfirmBookCleanupService(YLBaseService baseService) : base(baseService)
{
}
public void InvalidateAfterEdit(trade trade)
{
if (!GuolianSwapConfirmBookScope.IsGuolianSwap(trade)
|| !GuolianSwapConfirmBookScope.IsPreApprovalStatus(trade.TradeStatus))
{
return;
}
InvalidateRelations(trade.id);
}
public void CleanRejectedPreApprovalTrade(trade trade)
{
if (!GuolianSwapConfirmBookScope.IsGuolianSwap(trade))
{
return;
}
GlobalConfig.SealHandler.RemoveQueue(trade.id);
InvalidateOaResults(trade.id);
var contractCodes = InvalidateRelations(trade.id);
foreach (var contractCode in contractCodes)
{
var hasActiveReference = DbContext.trade_contract_r.Any(
BuildOtherActiveReferencePredicate(contractCode, trade.id));
if (!hasActiveReference)
{
var documents = DbContext.trade_contract_document.Where(x => x.Code == contractCode
&& x.Type == ContractTypeEnum.Trade);
DbContext.trade_contract_document.RemoveRange(documents);
}
}
}
public static Expression<Func<trade_contract_r, bool>> BuildOtherActiveReferencePredicate(
string contractCode,
int rejectedTradeId)
{
return relation => relation.ContractCode == contractCode
&& relation.Type == ContractTypeEnum.Trade
&& relation.IsValid
&& relation.TradeId != rejectedTradeId;
}
public static Expression<Func<trade_contract_r, bool>> BuildTradeConfirmationRelationPredicate(
int tradeId)
{
return relation => relation.TradeId == tradeId
&& relation.Type == ContractTypeEnum.Trade;
}
public static Expression<Func<trade_contract_oa_result, bool>> BuildActiveOaResultPredicate(
int tradeId)
{
return result => result.trade_id == tradeId && result.is_valid;
}
private void InvalidateOaResults(int tradeId)
{
var oaResults = DbContext.tradeContractOaResult
.Where(BuildActiveOaResultPredicate(tradeId))
.ToList();
oaResults.ForEach(x => x.is_valid = false);
}
private List<string> InvalidateRelations(int tradeId)
{
var relations = DbContext.trade_contract_r
.Where(BuildTradeConfirmationRelationPredicate(tradeId))
.ToList();
relations.Where(x => x.IsValid).ToList().ForEach(x => x.IsValid = false);
return relations.Select(x => x.ContractCode).Distinct().ToList();
}
}
/// <summary>
/// 仅校验模板无法正常生成或选择时必需的交易数据。
/// </summary>
public class GuolianSwapConfirmBookValidationService : YLBaseService
{
public GuolianSwapConfirmBookValidationService(YLBaseService baseService) : base(baseService)
{
}
public List<string> Validate(trade trade)
{
var errors = new List<string>();
var client = DataCacheProvider.GetClientDataSource().GetData(trade.ClientId);
var underlying = DataCacheProvider.GetUnderlyingDataSource().GetData(trade.UnderlyingCode);
if (client == null)
{
errors.Add("客户信息不存在");
return errors;
}
if (underlying == null)
{
errors.Add("标的信息不存在");
}
ValidateInitialPosition(trade, errors);
return errors;
}
private void ValidateInitialPosition(trade trade, List<string> errors)
{
var position = DbContext.swap_position.FirstOrDefault(x => x.SwapTradeId == trade.id
&& x.IsInitial
&& !x.Invalid
&& (x.PositionType == (int)PositionTypeFlag.Long || x.PositionType == (int)PositionTypeFlag.Short));
if (position == null)
{
errors.Add("缺少初始标的持仓");
return;
}
if (position.PosiDirection != (int)SwapDirectionEnum.支付
&& position.PosiDirection != (int)SwapDirectionEnum.收取)
{
errors.Add("初始标的持仓收支方向无效");
}
if (string.IsNullOrWhiteSpace(position.UnderlyingCode))
{
errors.Add("初始标的持仓缺少标的代码");
}
}
}
}