#EQD-6604 国联民生-确认书编码生成环节移到簿记(支持手工录入)

feat: 国联民生收益互换簿记后按确认书规则生成交易编号

- - 国联收益互换首次入库后复用原交易确认书编号规则生成交易编号,保留手工填写的交易编号
- 覆盖手工新增、系统流水自动簿记、普通交易导入、流水导入和日终合成今日交易流水
- 自动流水簿记增加本地事务,交易编号回写与基础簿记数据失败时统一回滚
- 交易确认书生成时直接取交易编号,不再重新生成确认书编号
- 结算管理-交易确认书页面将合约编号更名为交易确认书编号
- 上传确认书时将合约编号更名为交易确认书编号
- 历史交易编号不处理
This commit is contained in:
tengyufan
2026-07-29 16:45:29 +08:00
parent 4bebcf7fcb
commit e1c5f72418
10 changed files with 172 additions and 84 deletions
@@ -10,6 +10,7 @@ using YLErp.Modules.CalculationModule;
using YLErp.Modules.DataProviderModule;
using YLErp.Modules.TradeModule;
using YLErp.Modules.TradeModule.DealModule;
using YLErp.Modules.TradeModule.DocGenerateModule;
using YLErp.Modules.TradeModule.OrderModule;
using YLErp.QdpModule;
@@ -855,7 +856,14 @@ namespace YLErp.Modules.EodModule
{
if (string.IsNullOrWhiteSpace(td.TradeNumber))
{
td.TradeNumber = BizLogicSingleton.Instance.GenerateTradeNumberBeforeConfirm(td, DbContext);
if (GuolianContractNoGenerator.IsGuolianSwapTrade(td))
{
GuolianContractNoGenerator.TryGenerateTradeNumberAfterSave(DbContext, td);
}
else
{
td.TradeNumber = BizLogicSingleton.Instance.GenerateTradeNumberBeforeConfirm(td, DbContext);
}
}
}
+71 -49
View File
@@ -32,6 +32,7 @@ using YLErp.Modules.RiskModule;
using YLErp.Modules.SalesModule;
using YLErp.Modules.TradeModule;
using YLErp.Modules.TradeModule.DealModule;
using YLErp.Modules.TradeModule.DocGenerateModule;
using YLErp.Modules.TradeModule.QueryModule;
using YLErp.Modules.UnderlyingModule;
using YLErp.QdpModule;
@@ -271,55 +272,67 @@ namespace YLErp.Modules.SwapModule
string structureType = "普通债券类收益互换",
bool cashNeedAfter = false)
{
int SwapEndDays = UnderlyingHelper.GetApplicableMarginRate(client.id,underlying.UnderlyingCode,flowMerge.OccurTime)?.swap_days??14;
var td = PrepareTrade(flowMerge, client, asset, underlying, SwapEndDays, structureType);
PrepareTradeExtend(flowMerge, td, underlying, swapFloatRate);
td.TradeNumber = BizLogicSingleton.Instance.GenerateTradeNumberBeforeConfirm(td, DbContext);
flowMerge.SwapTradeNo = td.TradeNumber;
PrepareSwapTrade(td, TradeSourceEnum., underlying);
DbContext.trade.Add(td);
DbContext.SaveChanges();
td.trade_Initial_Margin = new trade_initial_margin()
trade td;
using (var trans = BeginTransaction())
{
TradeId = td.id,
MarginType = 1,
Direction = (int)SwapDirectionEnum.,
MarginValue = 0,
};
AddTradeMeta(false, td.id, YLErp.DBModels.Consts.ConsTradeMetaKey.MainProtocolCode, client.MainProtocolCode);
AddTradeMeta(false, td.id, YLErp.DBModels.Consts.ConsTradeMetaKey.SupProtocolCode, client.SupProtocolCode);
AddTradeMeta(false, td.id, YLErp.DBModels.Consts.ConsTradeMetaKey.TradingPlace, "柜台市场");
if (!string.IsNullOrEmpty(clearingAgency))
{
AddTradeMeta(false, td.id, YLErp.DBModels.Consts.ConsTradeMetaKey.ClearingAgency, clearingAgency);
int SwapEndDays = UnderlyingHelper.GetApplicableMarginRate(client.id,underlying.UnderlyingCode,flowMerge.OccurTime)?.swap_days??14;
td = PrepareTrade(flowMerge, client, asset, underlying, SwapEndDays, structureType);
PrepareTradeExtend(flowMerge, td, underlying, swapFloatRate);
if (!GuolianContractNoGenerator.IsGuolianSwapTrade(td))
{
td.TradeNumber = BizLogicSingleton.Instance.GenerateTradeNumberBeforeConfirm(td, DbContext);
}
PrepareSwapTrade(td, TradeSourceEnum., underlying);
DbContext.trade.Add(td);
DbContext.SaveChanges();
if (GuolianContractNoGenerator.TryGenerateTradeNumberAfterSave(DbContext, td))
{
DbContext.SaveChanges();
}
flowMerge.SwapTradeNo = td.TradeNumber;
td.trade_Initial_Margin = new trade_initial_margin()
{
TradeId = td.id,
MarginType = 1,
Direction = (int)SwapDirectionEnum.,
MarginValue = 0,
};
AddTradeMeta(false, td.id, YLErp.DBModels.Consts.ConsTradeMetaKey.MainProtocolCode, client.MainProtocolCode);
AddTradeMeta(false, td.id, YLErp.DBModels.Consts.ConsTradeMetaKey.SupProtocolCode, client.SupProtocolCode);
AddTradeMeta(false, td.id, YLErp.DBModels.Consts.ConsTradeMetaKey.TradingPlace, "柜台市场");
if (!string.IsNullOrEmpty(clearingAgency))
{
AddTradeMeta(false, td.id, YLErp.DBModels.Consts.ConsTradeMetaKey.ClearingAgency, clearingAgency);
}
TradeExtendJson tradeExtendJson = new TradeExtendJson()
{
FlowBookMode = (int)FlowBookModeEnum.,
FloatingPnlAnnualized = false,
NeedOpenFee = true,
OpenFeeType = 1,
Direction = 1,
InterestCalcMode = "10",
SettlementRules = cashNeedAfter ? 1 : 0,
};
if (structureType != "普通债券类收益互换")
{
tradeExtendJson.FlowBookMode = (int)FlowBookModeEnum.;
}
td.trade_extend = new trade_extend()
{
TradeId = td.id,
ExtendJson = JsonHelper.Serialize(tradeExtendJson)
};
DbContext.trade_initial_margin.Add(td.trade_Initial_Margin);
DbContext.trade_extend.Add(td.trade_extend);
foreach (var item in td.swap_positions)
{
item.SwapTradeId = td.id;
DbContext.swap_position.Add(item);
}
DbContext.SaveChanges();
trans.Commit();
}
TradeExtendJson tradeExtendJson = new TradeExtendJson()
{
FlowBookMode = (int)FlowBookModeEnum.,
FloatingPnlAnnualized = false,
NeedOpenFee = true,
OpenFeeType = 1,
Direction = 1,
InterestCalcMode = "10",
SettlementRules = cashNeedAfter ? 1 : 0,
};
if (structureType != "普通债券类收益互换")
{
tradeExtendJson.FlowBookMode = (int)FlowBookModeEnum.;
}
td.trade_extend = new trade_extend()
{
TradeId = td.id,
ExtendJson = JsonHelper.Serialize(tradeExtendJson)
};
DbContext.trade_initial_margin.Add(td.trade_Initial_Margin);
DbContext.trade_extend.Add(td.trade_extend);
foreach (var item in td.swap_positions)
{
item.SwapTradeId = td.id;
DbContext.swap_position.Add(item);
}
DbContext.SaveChanges();
new TradeConfirmService(UserInfo).SwapTradeConfirm(td, "流水自动簿记确认交易", true, flowMerge.OccurTime, "流水自动");
return td;
}
@@ -581,7 +594,9 @@ namespace YLErp.Modules.SwapModule
dbTrade.CheckTradeUpdate = Convert.ToInt32(TradeCheckEnum.StatusOfOld);
dbTrade.CheckStatus = null;
//如果是新增待确认并且修改了客户,需要重新生成交易编号
if (oldClientId != dbTrade.ClientId && canGenerateTradeNumber)
if (oldClientId != dbTrade.ClientId
&& canGenerateTradeNumber
&& !GuolianContractNoGenerator.IsGuolianSwapTrade(dbTrade))
{
dbTrade.TradeNumber = BizLogicSingleton.Instance.GenerateTradeNumberBeforeConfirm(dbTrade, DbContext);
}
@@ -614,6 +629,10 @@ namespace YLErp.Modules.SwapModule
{
//保存修改
DbContext.SaveChanges();
if (isAddNew && GuolianContractNoGenerator.TryGenerateTradeNumberAfterSave(DbContext, dbTrade))
{
DbContext.SaveChanges();
}
SaveTradeExend(dbTrade);
SaveTradeMargin(dbTrade);
SaveSwapPositions(dbTrade.swap_positions, dbTrade);
@@ -710,7 +729,10 @@ namespace YLErp.Modules.SwapModule
PrepareUnderlying(req, um);
}
req.TradeNumber = BizLogicSingleton.Instance.GenerateTradeNumberBeforeConfirm(req, DbContext);
if (!GuolianContractNoGenerator.IsGuolianSwapTrade(req))
{
req.TradeNumber = BizLogicSingleton.Instance.GenerateTradeNumberBeforeConfirm(req, DbContext);
}
}
else if (DbContext.trade.Any(n => n.TradeNumber == req.TradeNumber))
{
@@ -1356,11 +1356,7 @@ namespace YLErp.Modules.TradeModule.DocGenerateModule
{
return UniqueTimeId.GetStr();
}
if (Trade.TradeType == "收益互换")
{
return GuolianContractNoGenerator.Generate(DbContext, (trade)Trade, _client.Code);
}
return Trade.TradeNumber;
return Trade.TradeNumber;
}
/// <summary>
@@ -2881,4 +2877,4 @@ namespace YLErp.Modules.TradeModule.DocGenerateModule
return DbContext.swap_event.FirstOrDefault(x => x.id == eventId);
}
}
}
}
@@ -667,7 +667,9 @@ namespace YLErp.Modules.TradeModule.DocGenerateModule
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 = "";
@@ -707,7 +709,7 @@ namespace YLErp.Modules.TradeModule.DocGenerateModule
{
if (db.trade_contract_r.Where(O => O.ContractCode == ContractCode && O.IsValid).Any())
{
return (false, "合约编号已存在", DateTime.Now, "");
return (false, $"{contractCodeName}已存在", DateTime.Now, "");
}
else
{
@@ -854,6 +856,10 @@ namespace YLErp.Modules.TradeModule.DocGenerateModule
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 };
@@ -887,7 +893,7 @@ namespace YLErp.Modules.TradeModule.DocGenerateModule
activeCode = (contractCode ?? "").Trim();
if (string.IsNullOrWhiteSpace(activeCode))
{
return new UploadContractFileNewResult { Success = false, Message = "合约编号必填", OptDate = nowDate, DocumentPath = string.Empty };
return new UploadContractFileNewResult { Success = false, Message = $"{contractCodeName}必填", OptDate = nowDate, DocumentPath = string.Empty };
}
if (!string.Equals(oldCode, activeCode, StringComparison.OrdinalIgnoreCase))
@@ -895,7 +901,7 @@ namespace YLErp.Modules.TradeModule.DocGenerateModule
var isExists = new TradeContractGenerateService(OptUser).GetExistsContractCode(new[] { activeCode }).Any();
if (isExists)
{
return new UploadContractFileNewResult { Success = false, Message = "合约编号已存在", OptDate = nowDate, DocumentPath = string.Empty };
return new UploadContractFileNewResult { Success = false, Message = $"{contractCodeName}已存在", OptDate = nowDate, DocumentPath = string.Empty };
}
}
}
@@ -907,18 +913,25 @@ namespace YLErp.Modules.TradeModule.DocGenerateModule
}
else
{
var client = DataCacheProvider.GetClientDataSource().GetData(trade.ClientId);
if (string.IsNullOrEmpty(client?.Code))
if (isGuolian)
{
return new UploadContractFileNewResult { Success = false, Message = "对手方代码缩写缺失,请联系运营组同事维护", OptDate = nowDate, DocumentPath = string.Empty };
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);
}
activeCode = GenerateContractCodeForTrade(db, trade, client?.Code);
}
}
if (string.IsNullOrWhiteSpace(activeCode))
{
return new UploadContractFileNewResult { Success = false, Message = "合约编号生成失败", OptDate = nowDate, DocumentPath = string.Empty };
return new UploadContractFileNewResult { Success = false, Message = $"{contractCodeName}生成失败", OptDate = nowDate, DocumentPath = string.Empty };
}
trade_contract_document oldDoc = null;
@@ -1006,19 +1019,13 @@ namespace YLErp.Modules.TradeModule.DocGenerateModule
return new UploadContractFileNewResult { Success = false, Message = "操作出错", OptDate = nowDate, DocumentPath = string.Empty };
}
}
/// <summary>
/// 生成合约编号逻辑:如果是收益互换交易,使用国联的生成规则;否则默认使用 TradeNumber 作为合约编号。
/// </summary>
/// <param name="db"></param>
/// <param name="trade"></param>
/// <param name="clientCode"></param>
/// <returns></returns>
private string GenerateContractCodeForTrade(YLContext db, trade trade,string clientCode)
private static string GenerateContractCodeForTrade(YLContext db, trade trade, string clientCode)
{
if (trade.TradeType == "收益互换")
{
return GuolianContractNoGenerator.Generate(db, trade, clientCode ?? "");
return GuolianContractNoGenerator.Generate(db, trade, clientCode ?? string.Empty);
}
return trade.TradeNumber;
}
@@ -1,4 +1,5 @@
using YLErp.BLL;
using YLErp.Configuration;
using YLErp.DBModels;
using YLErp.DBModels.Consts;
using YLErp.DBModels.Enums;
@@ -17,6 +18,38 @@ namespace YLErp.Modules.TradeModule.DocGenerateModule
{
private static readonly object _syncLock = new object();
public static bool IsGuolianSwapTrade(trade trade)
{
return PS.Config.Company == CompanyEnum.
&& trade?.TradeType == "收益互换";
}
/// <summary>
/// 交易首次入库后按国联交易确认书编号规则回写交易编号。
/// </summary>
/// <returns>是否生成了交易编号</returns>
public static bool TryGenerateTradeNumberAfterSave(YLContext dbContext, trade trade)
{
if (!IsGuolianSwapTrade(trade) || !string.IsNullOrWhiteSpace(trade.TradeNumber))
{
return false;
}
if (trade.id <= 0)
{
throw new InvalidOperationException("国联收益互换交易编号必须在交易入库后生成");
}
var clientCode = DataCacheProvider.GetClientDataSource().GetData(trade.ClientId)?.Code;
if (string.IsNullOrWhiteSpace(clientCode))
{
throw new ServiceException("对手方代码缩写缺失,请联系运营组同事维护");
}
trade.TradeNumber = Generate(dbContext, trade, clientCode);
return true;
}
/// <summary>
/// 生成国贸交易确认书编号
/// </summary>
@@ -11,6 +11,7 @@ using YLErp.Enums;
using YLErp.Model.Enum;
using YLErp.Modules.CalculationModule;
using YLErp.Modules.EodModule;
using YLErp.Modules.TradeModule.DocGenerateModule;
using YLErp.Modules.TradeModule.OrderModule;
namespace YLErp.Modules.TradeModule.SwapModule
@@ -362,7 +363,10 @@ namespace YLErp.Modules.TradeModule.SwapModule
importTrade.TradeStatus = ConsTrade.;
importTrade.TradeNumber = BizLogicSingleton.Instance.GenerateTradeNumberBeforeConfirm(importTrade, DbContext);
if (!GuolianContractNoGenerator.IsGuolianSwapTrade(importTrade))
{
importTrade.TradeNumber = BizLogicSingleton.Instance.GenerateTradeNumberBeforeConfirm(importTrade, DbContext);
}
var currencyRate = new EodCurrencyRateService(UserInfo).GetCurrencyRate(importTrade.QuoteCurrency, importTrade.SettlementCurrency, importTrade.TradeDate.Value, seekPreday: importTrade.TradeDate.Value == valuedateBLL.ValueDate);
var tradePriceQuote = 0.0;
@@ -388,6 +392,10 @@ namespace YLErp.Modules.TradeModule.SwapModule
SetDBModelCreator(importTrade);
DbContext.trade.Add(importTrade);
DbContext.SaveChanges();
if (GuolianContractNoGenerator.TryGenerateTradeNumberAfterSave(DbContext, importTrade))
{
DbContext.SaveChanges();
}
importTrade.trade_swap.GetTradePrice = (importTrade.trade_swap.GetSingleFee ?? 0) * (importTrade.Lots ?? 0) + (importTrade.trade_swap.GetUnAnnualRate ?? 0) * importTrade.StockEqvNotional;
importTrade.trade_swap.GetMarginRate = marginRate;
importTrade.trade_swap.TradeId = importTrade.id;
@@ -11,6 +11,7 @@ using YLErp.Enums;
using YLErp.Model.Enum;
using YLErp.Modules.CalculationModule;
using YLErp.Modules.EodModule;
using YLErp.Modules.TradeModule.DocGenerateModule;
using YLErp.Modules.TradeModule.OrderModule;
using YLErp.QdpModule;
@@ -679,7 +680,10 @@ namespace YLErp.Modules.TradeModule.SwapModule
}
if (string.IsNullOrWhiteSpace(td.TradeNumber))
{
td.TradeNumber = BizLogicSingleton.Instance.GenerateTradeNumberBeforeConfirm(td, DbContext);
if (!GuolianContractNoGenerator.IsGuolianSwapTrade(td))
{
td.TradeNumber = BizLogicSingleton.Instance.GenerateTradeNumberBeforeConfirm(td, DbContext);
}
}
else
{
@@ -736,6 +740,10 @@ namespace YLErp.Modules.TradeModule.SwapModule
SetDBModelCreator(td);
DbContext.trade.Add(td);
DbContext.SaveChanges();
if (GuolianContractNoGenerator.TryGenerateTradeNumberAfterSave(DbContext, td))
{
DbContext.SaveChanges();
}
td.trade_swap.TradeId = td.id;
td.trade_swap.SwapType = "普通";
td.trade_swap.OptId = UserId;
+2 -1
View File
@@ -10,6 +10,7 @@
isRuiDa = YLErp.PS.Config.Company == YLErp.Configuration.CompanyEnum.瑞达,
isBoHai = YLErp.PS.Config.Company == YLErp.Configuration.CompanyEnum.渤海,
isWuChan = YLErp.PS.Config.Company == YLErp.Configuration.CompanyEnum.物产中大,
isGuoLian = YLErp.PS.Config.Company == YLErp.Configuration.CompanyEnum.国联,
ConfirmBookStampStatus = PS.Config.ErpElement.ConfirmBookStampStatus,
valuedate = valuedateBLL.ValueDate.ToString("yyyy-MM-dd"),
configcolumn = configcolumn_data.交易确认书,
@@ -56,7 +57,7 @@
<div class="searchdiv">
@Html.ShortInput("TradeNumber", "交易编号")
@Html.ShortInput("ContractCode", "合约编号")
@Html.ShortInput("ContractCode", pageObj.isGuoLian ? "交易确认书编号" : "合约编号")
@Html.MyAceDropdownInput("ClientId", "客户名称", ClientDataModel.GetAllClient())
@Html.MyAceDropdownInput("AssetId", "簿记账户", AssetunitController.GetClientassetunit())
@Html.MyAceDropdownInput("GroupId", "簿记账户组", AssetUnitModel.GetAllAssetUnitGroupItem())
@@ -1,10 +1,14 @@
@{
ViewBag.Title = "confirmBookUploadNew";
Layout = "~/Views/Shared/_InfoLayout.cshtml";
var contractCodeName = YLErp.PS.Config.Company == YLErp.Configuration.CompanyEnum.国联
? "交易确认书编号"
: "合约编号";
var pageObj = new
{
TradeId = ViewBag.TradeId
TradeId = ViewBag.TradeId,
ContractCodeName = contractCodeName
};
}
@@ -38,7 +42,7 @@
var contractCode = $("#contractCode").val();
if (useContractCode && main.isEmpty(contractCode)) {
main.message("合约编号必填");
main.message(page.ContractCodeName + "必填");
return;
}
@@ -97,8 +101,8 @@
<div class="form-group row">
<label class="formlabel col-auto">&nbsp;</label>
<div class="col">
<label class="mr-4"><input id="useContractCode" type="checkbox" value="合约编号">&nbsp;合约编号</label>
<input id="contractCode" class="form-control d-inline-block" style="width:300px;" placeholder="请输入合约编号" />
<label class="mr-4"><input id="useContractCode" type="checkbox" value="@contractCodeName">&nbsp;@contractCodeName</label>
<input id="contractCode" class="form-control d-inline-block" style="width:300px;" placeholder="请输入@contractCodeName" />
</div>
</div>
<div class="form-group row">
@@ -80,7 +80,7 @@ const colModelGrid = (new function () {
align: 'left'
}, {
name: 'ContractCode',
label: '合约编号',
label: page.isGuoLian === true ? '交易确认书编号' : '合约编号',
index: 'ContractCode',
sortIndex: i++,
width: 200,
@@ -307,15 +307,16 @@ const colModelGrid = (new function () {
this.setControl = function (encryptId) {
var button = "#bt_" + encryptId;
var inputSelect = "#ip_" + encryptId;
var contractCodeName = page.isGuoLian === true ? "交易确认书编号" : "合约编号";
if ($(inputSelect).prop("disabled")) {
$(inputSelect).prop("disabled", false);
$(button).prop("title", "保存合约编号");
$(button).prop("title", "保存" + contractCodeName);
$(button).html("<i class='fa fa-floppy-o'></i>");
} else {
this.changeCode(encryptId, $(inputSelect).val(), function () {
$(button).html("<i class='fa fa-pencil-square-o'></i>");
$(inputSelect).prop("disabled", true);
$(button).prop("title", "修改合约编号");
$(button).prop("title", "修改" + contractCodeName);
});
}
}