Merge remote-tracking branch 'origin/glms/feature/1.4.2' into glms/feature/1.4.2
This commit is contained in:
@@ -26,6 +26,7 @@ namespace YLErp.DBModels.Abstract
|
||||
int? SellerId { get; set; }
|
||||
string SellerName { get; set; }
|
||||
string StampDocumentFileName { get; set; }
|
||||
int? SourceType { get; set; }
|
||||
string Status { get; set; }
|
||||
string Type { get; set; }
|
||||
DateTime? ValueDate { get; set; }
|
||||
|
||||
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
@@ -22,7 +22,8 @@ namespace YLErp.Plugins.GuoLian.DocumentGenerator
|
||||
/// <summary>
|
||||
/// 获取模板文件路径
|
||||
/// 收益互换模板选择逻辑:
|
||||
/// 1. 客户看多/看空:通过持仓方向判断(PositionType: 1=多头/看多,2=空头/看空)
|
||||
/// 1. 客户看多/看空:根据 swap_position 的 PosiDirection(收支方向)和 PositionType(多空方向)
|
||||
/// 组合出我方方向,再取反得到客户方向。
|
||||
/// 2. 标的类型:
|
||||
/// - 债券ETF:.SH后缀且511开头,或.SZ后缀且59开头
|
||||
/// - 现券:其他
|
||||
@@ -54,22 +55,31 @@ namespace YLErp.Plugins.GuoLian.DocumentGenerator
|
||||
var trade = Context.Trade;
|
||||
var underlying = Context.GetTradeUnderlying();
|
||||
|
||||
// 判断看多/看空方向(通过持仓方向判断:PositionType: 1=多头/看多,2=空头/看空)
|
||||
// 判断客户看多/看空方向:
|
||||
// 先根据 PosiDirection(收支方向)和 PositionType(多空方向)组合出我方方向,再取反得到客户方向。
|
||||
var swapPosition = Context.GetSwapPositions(trade.id, true)
|
||||
.Where(x => x.PositionType == (int)PositionTypeFlag.Long || x.PositionType == (int)PositionTypeFlag.Short)
|
||||
.FirstOrDefault();
|
||||
bool isLong = swapPosition?.PositionType == (int)PositionTypeFlag.Long;
|
||||
|
||||
bool isCustomerLong = false;
|
||||
if (swapPosition != null)
|
||||
{
|
||||
bool isOurLong = swapPosition.PosiDirection == (int)SwapDirectionEnum.支付
|
||||
? swapPosition.PositionType == (int)PositionTypeFlag.Short // 支付端:我方方向与 PositionType 相反
|
||||
: swapPosition.PositionType == (int)PositionTypeFlag.Long; // 收取端:我方方向与 PositionType 相同
|
||||
isCustomerLong = !isOurLong;
|
||||
}
|
||||
|
||||
// 判断标的类型(债券ETF vs 现券)
|
||||
bool isEtf = IsBondEtf(underlying?.UnderlyingCode ?? string.Empty);
|
||||
|
||||
// 选择对应模板(使用客户提供的原始文件名)
|
||||
string templateName;
|
||||
if (isLong && !isEtf)
|
||||
if (isCustomerLong && !isEtf)
|
||||
templateName = "国联民生-收益互换交易确认书-境内模板-【客户看多】-【现券】-清洁版.docx";
|
||||
else if (isLong && isEtf)
|
||||
else if (isCustomerLong && isEtf)
|
||||
templateName = "国联民生-收益互换交易确认书-境内模板-【客户看多】-【债券ETF】-清洁版.docx";
|
||||
else if (!isLong && !isEtf)
|
||||
else if (!isCustomerLong && !isEtf)
|
||||
templateName = "国联民生-收益互换交易确认书-境内模板-【客户看空】-【现券】-清洁版.docx";
|
||||
else
|
||||
templateName = "国联民生-收益互换交易确认书-境内模板-【客户看空】-【债券ETF】-清洁版.docx";
|
||||
@@ -80,7 +90,7 @@ namespace YLErp.Plugins.GuoLian.DocumentGenerator
|
||||
/// <summary>
|
||||
/// 判断是否为债券ETF
|
||||
/// - .SH后缀且511开头 -> 债券ETF
|
||||
/// - .SZ后缀且59开头 -> 债券ETF
|
||||
/// - .SZ后缀且159开头 -> 债券ETF
|
||||
/// - 其他 -> 现券
|
||||
/// </summary>
|
||||
private bool IsBondEtf(string underlyingCode)
|
||||
@@ -95,7 +105,7 @@ namespace YLErp.Plugins.GuoLian.DocumentGenerator
|
||||
return true;
|
||||
|
||||
// 深交所债券ETF:59开头.SZ后缀
|
||||
if (underlyingCode.EndsWith(".SZ") && underlyingCode.StartsWith("59"))
|
||||
if (underlyingCode.EndsWith(".SZ") && underlyingCode.StartsWith("159"))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
@@ -202,13 +212,17 @@ namespace YLErp.Plugins.GuoLian.DocumentGenerator
|
||||
if (swapPosition != null)
|
||||
{
|
||||
// 期初全价和净价(转换为百分比格式)
|
||||
dic["参考标的期初全价"] = ((double)swapPosition.PosiGrossPrice * 100).ToString("N4");
|
||||
dic["参考标的期初净价"] = ((double)(swapPosition.PosiNetNoFeePrice ?? 0m) * 100).ToString("N4");
|
||||
dic["参考标的期初全价"] = ((double)swapPosition.PosiGrossPrice).ToString("N4");
|
||||
dic["参考标的期初净价"] = ((double)(swapPosition.PosiNetNoFeePrice ?? 0m)).ToString("N4");
|
||||
|
||||
dic["参考标的期初全价%"] = ((double)swapPosition.PosiGrossPrice * 100).ToString("N4");
|
||||
dic["参考标的期初净价%"] = ((double)(swapPosition.PosiNetNoFeePrice ?? 0m) * 100).ToString("N4");
|
||||
|
||||
// 固定收益率(年化)- 债券期初到期收益率
|
||||
dic["固定收益率(年化)"] = swapPosition.InitYtm.HasValue
|
||||
? ((double)swapPosition.InitYtm.Value * 100).ToString("N4")
|
||||
: "0.0000";
|
||||
//dic["固定收益率(年化)"] = swapPosition.InitYtm.HasValue
|
||||
// ? ((double)swapPosition.InitYtm.Value * 100).ToString("N4")
|
||||
// : "0.0000";
|
||||
dic["固定收益率(年化)"] = "0.0000"; //需求说直接都是0
|
||||
|
||||
// 获取客户适用的保证金率
|
||||
var clientMarginRate = UnderlyingHelper.GetApplicableMarginRate(
|
||||
|
||||
@@ -343,6 +343,7 @@ namespace YLErp.BLL.GenerateDocument
|
||||
cd.SellerName = isGJBuyer ? trade.ClientName : (PS.Config.CompanyName ?? "");
|
||||
cd.FileType = FileTypeEnum.Word;
|
||||
cd.Status = ContractStatusEnum.Draft;
|
||||
cd.SourceType = 1; // 系统生成
|
||||
cd.Paths = $"App_Docs\\contractdoc\\output\\{savedOutputFileName}";
|
||||
cd.FileName = savedOutputFileName;
|
||||
cd.Type = ContractType;
|
||||
|
||||
@@ -106,6 +106,12 @@ namespace YLErp.DBModels
|
||||
get { return SellerName; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 确认书来源类型:1=系统生成,2=人工上传,null=默认为系统生成
|
||||
/// </summary>
|
||||
[DisplayName("确认书来源类型")]
|
||||
public int? SourceType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 用印文件
|
||||
/// </summary>
|
||||
|
||||
@@ -29,6 +29,8 @@ namespace YLErp.Model
|
||||
|
||||
public string RelativePath { get; set; }
|
||||
|
||||
public int? SourceType { get; set; }
|
||||
|
||||
public int? SellerId { get; set; }
|
||||
public string SellerName { get; set; }
|
||||
public string StampDocumentFileName { get; set; }
|
||||
|
||||
@@ -169,19 +169,42 @@ namespace YLErp.Modules.SwapModule
|
||||
/// </summary>
|
||||
/// <param name="tradeId"></param>
|
||||
/// <returns></returns>
|
||||
public string SendConfirmEamil(string contractCode)
|
||||
///
|
||||
public string SendConfirmEamil(int tradeId)
|
||||
{
|
||||
var tradeContract = DbContext.trade_contract_r.Where(x => x.IsValid && x.TradeId == tradeId && x.Type == ContractTypeEnum.Trade).FirstOrDefault();
|
||||
if (tradeContract == null)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
tradeContract.send_email_result = "发送中";
|
||||
DbContext.SaveChanges();
|
||||
var sendResult = SendEmail(tradeContract.ContractCode);
|
||||
if (string.IsNullOrEmpty(sendResult))
|
||||
{
|
||||
tradeContract.send_email_result = "已发送";
|
||||
}
|
||||
else
|
||||
{
|
||||
tradeContract.send_email_result = "发送失败:" + sendResult;
|
||||
}
|
||||
DbContext.SaveChanges();
|
||||
return string.IsNullOrEmpty(sendResult) ? "已发送" : "发送失败:" + sendResult;
|
||||
}
|
||||
public string SendConfirmEamil(string ContractCode)
|
||||
{
|
||||
//var tradeContract = DbContext.trade_contract_r.Where(x => x.IsValid && x.TradeId == tradeId && x.Type == ContractTypeEnum.Trade).FirstOrDefault();
|
||||
//if (tradeContract == null)
|
||||
//{
|
||||
// return "";
|
||||
//}
|
||||
var contracts = DbContext.trade_contract_r.Where(o => o.ContractCode == contractCode && o.Type == ContractTypeEnum.Trade && o.IsValid).ToArray();
|
||||
var contracts = DbContext.trade_contract_r.Where(o => o.ContractCode == ContractCode && o.Type == ContractTypeEnum.Trade && o.IsValid).ToArray();
|
||||
foreach (var tradeContract in contracts)
|
||||
{
|
||||
tradeContract.send_email_result = "发送中";
|
||||
DbContext.SaveChanges();
|
||||
}
|
||||
var contractCode = contracts.FirstOrDefault()?.ContractCode;
|
||||
|
||||
var sendResult = SendEmail(contractCode);
|
||||
foreach (var tradeContract in contracts)
|
||||
|
||||
@@ -229,49 +229,9 @@ namespace YLErp.Modules.TradeModule.DealModule
|
||||
var clientIds = trades.Select(x => x.ClientId).Distinct().ToList();
|
||||
logger.Info($"[GJGenerateConfirmBook] 客户ID数: {clientIds.Count}");
|
||||
|
||||
if (trades.Any(o => o.TradeType.Equals("收益互换")))
|
||||
foreach (var item in trades)
|
||||
{
|
||||
var allTrades = DbContext.trade.Where(x => clientIds.Contains(x.ClientId) && x.TradeType.Equals("收益互换") && x.ValidState != ConsGlobal.InValid);
|
||||
if (startDate.HasValue)
|
||||
{
|
||||
allTrades = allTrades.Where(x => x.TradeDate >= startDate);
|
||||
}
|
||||
if (endDate.HasValue)
|
||||
{
|
||||
allTrades = allTrades.Where(x => x.TradeDate <= endDate);
|
||||
}
|
||||
var Ids = allTrades.Select(o => o.id).Distinct().ToArray();
|
||||
var swapPositions = DbContext.swap_position.Where(s => Ids.Contains(s.SwapTradeId) && s.IsInitial && s.PositionType > 0 && !s.Invalid)
|
||||
.Distinct().ToList();
|
||||
logger.Info($"[GJGenerateConfirmBook] 查询到持仓记录数: {swapPositions.Count}");
|
||||
|
||||
var allTradeList = allTrades.AsNoTracking().ToList();
|
||||
foreach (var item in allTradeList)
|
||||
{
|
||||
item.swap_positions.Add(swapPositions.FirstOrDefault(o => o.SwapTradeId == item.id));
|
||||
}
|
||||
allTradeList = allTradeList.Where(x => x.swap_positions.Any()).ToList();
|
||||
logger.Info($"[GJGenerateConfirmBook] 过滤后有持仓的交易数: {allTradeList.Count}");
|
||||
|
||||
// 按照客户ID、交易日期、多空头进行分组
|
||||
var group = allTradeList.GroupBy(O => new { O.ClientId, O.StartDate, O.swap_positions.FirstOrDefault()?.PositionType })
|
||||
.ToDictionary(K => K.Key, V => V.Select(O => O.id).ToList());
|
||||
|
||||
logger.Info($"[GJGenerateConfirmBook] 分组数: {group.Count}");
|
||||
|
||||
foreach (var item in group)
|
||||
{
|
||||
var tradeCount = item.Value.Distinct().Count();
|
||||
logger.Info($"[GJGenerateConfirmBook] 处理分组 - ClientId: {item.Key.ClientId}, StartDate: {item.Key.StartDate}, PositionType: {item.Key.PositionType}, 交易数: {tradeCount}");
|
||||
groupGenerateHandle(item.Value.Distinct().ToList(), docType, startDate, endDate, results, error, file);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var item in trades)
|
||||
{
|
||||
groupGenerateHandle_Date(new List<int> { item.id }, docType, startDate, endDate, results, error, file);
|
||||
}
|
||||
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();
|
||||
|
||||
@@ -497,6 +497,7 @@ namespace YLErp.Modules.TradeModule.DocGenerateModule
|
||||
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;
|
||||
|
||||
@@ -58,6 +58,7 @@ namespace YLErp.Modules.TradeModule.DocGenerateModule
|
||||
contractRecord.ContractVersion = contractVersion;
|
||||
contractRecord.FileType = FileTypeEnum.Pdf;
|
||||
contractRecord.Status = ContractStatusEnum.Draft;
|
||||
contractRecord.SourceType = 1; // 系统生成
|
||||
contractRecord.Paths = outPath;
|
||||
contractRecord.FileName = outPath.Replace(".xlsx", ".pdf");
|
||||
contractRecord.Type = ContractTypeEnum.Trade;
|
||||
|
||||
@@ -545,6 +545,7 @@ namespace YLErp.Modules.TradeModule.DocGenerateModule
|
||||
contractRecord.SellerName = isGJBuyer ? firstTrade.ClientName : (PS.Config.CompanyName ?? "");
|
||||
contractRecord.FileType = fileType;
|
||||
contractRecord.Status = ContractStatusEnum.Draft;
|
||||
contractRecord.SourceType = 1; // 系统生成
|
||||
contractRecord.Paths = "/App_Docs/contractdoc/output/" + fileName;
|
||||
contractRecord.FileName = fileName;
|
||||
contractRecord.StampDocumentFileName = null;
|
||||
@@ -697,6 +698,7 @@ namespace YLErp.Modules.TradeModule.DocGenerateModule
|
||||
contractRecord.SellerName = isGJBuyer ? firstTrade.ClientName : (PS.Config.CompanyName ?? "");
|
||||
contractRecord.FileType = fileType;
|
||||
contractRecord.Status = ContractStatusEnum.Draft;
|
||||
contractRecord.SourceType = 1; // 系统生成
|
||||
contractRecord.Paths = "/App_Docs/contractdoc/output/" + fileName;
|
||||
contractRecord.FileName = fileName;
|
||||
contractRecord.StampDocumentFileName = null;
|
||||
@@ -1278,9 +1280,11 @@ namespace YLErp.Modules.TradeModule.DocGenerateModule
|
||||
contractNo = GenerateShanXiGuShouContractNo();
|
||||
break;
|
||||
case CompanyEnum.浙商:
|
||||
case CompanyEnum.国联:
|
||||
contractNo = GenerateZheShangContractNo();
|
||||
break;
|
||||
case CompanyEnum.国联:
|
||||
contractNo = GenerateGuolianContractNo();
|
||||
break;
|
||||
default:
|
||||
throw new ContextMarshalException("未实现");
|
||||
}
|
||||
@@ -1336,6 +1340,22 @@ namespace YLErp.Modules.TradeModule.DocGenerateModule
|
||||
}
|
||||
return Trade.TradeNumber;
|
||||
}
|
||||
|
||||
private string GenerateGuolianContractNo()
|
||||
{
|
||||
if (_contractType != ContractTypeEnum.Trade)
|
||||
{
|
||||
return UniqueTimeId.GetStr();
|
||||
}
|
||||
if (Trade.TradeType == "收益互换")
|
||||
{
|
||||
var posi = GetSwapPositions(Trade.id, true).FirstOrDefault(p => p.PositionType > 0);
|
||||
var isLong = posi?.PositionType == (int)PositionTypeFlag.Short ? false : true;
|
||||
|
||||
return "GLMS-" + _client.Number + "-" + Trade.TradeNumber;
|
||||
}
|
||||
return Trade.TradeNumber;
|
||||
}
|
||||
/// <summary>
|
||||
/// 生成国贸确认书编号
|
||||
/// </summary>
|
||||
|
||||
@@ -611,6 +611,7 @@ namespace YLErp.Modules.TradeModule.DocGenerateModule
|
||||
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;
|
||||
@@ -800,6 +801,7 @@ namespace YLErp.Modules.TradeModule.DocGenerateModule
|
||||
|
||||
#region 更新数据
|
||||
contractDoc.Comments = fileDescription;
|
||||
contractDoc.SourceType = 2; // 人工上传
|
||||
if (OurpartySeal && CounterpartySeal)
|
||||
{ contractDoc.Status = ContractStatusEnum.BothPartyStamped; }
|
||||
else if (OurpartySeal) { contractDoc.Status = ContractStatusEnum.OurPartyStamped; }
|
||||
@@ -922,6 +924,7 @@ namespace YLErp.Modules.TradeModule.DocGenerateModule
|
||||
}
|
||||
|
||||
#region 更新数据
|
||||
contractDoc.SourceType = 2; // 人工上传
|
||||
var confrimService = new TradeConfirmService(OptUser, db);
|
||||
foreach (var contractDocR in contractDocRArr)
|
||||
{
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using Newtonsoft.Json.Linq;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
@@ -61,4 +62,24 @@ namespace YLErp.Modules.TradeModule
|
||||
public string annexId { get; set; }
|
||||
public string annexName { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// OA 审批状态查询响应模型(适配新查询接口 /gateway/oaflow/getRequestData)
|
||||
/// </summary>
|
||||
public class OAStatusQueryResponse
|
||||
{
|
||||
public int code { get; set; }
|
||||
public string status { get; set; }
|
||||
public string msg { get; set; }
|
||||
public List<OAFlowData> data { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// OA 流程查询数据模型
|
||||
/// </summary>
|
||||
public class OAFlowData
|
||||
{
|
||||
public string requestId { get; set; }
|
||||
public JObject flowInfos { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -18,6 +18,10 @@ namespace YLErp.Modules.TradeModule
|
||||
public class TradeOAService : YLBaseService
|
||||
{
|
||||
private static readonly IYcLogger logger = LogFactory.GetLogger<TradeOAService>();
|
||||
private static readonly System.Net.Http.HttpClient _httpClient = new System.Net.Http.HttpClient
|
||||
{
|
||||
Timeout = TimeSpan.FromMinutes(2)
|
||||
};
|
||||
|
||||
public TradeOAService(OptUserInfo userInfo) : base(userInfo)
|
||||
{
|
||||
@@ -137,7 +141,7 @@ namespace YLErp.Modules.TradeModule
|
||||
using (var form = new MultipartFormDataContent())
|
||||
{
|
||||
// 添加文件
|
||||
var fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read);
|
||||
using var fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read);
|
||||
var fileName = Path.GetFileName(filePath);
|
||||
form.Add(new StreamContent(fileStream), "file", fileName);
|
||||
|
||||
@@ -250,6 +254,12 @@ namespace YLErp.Modules.TradeModule
|
||||
return new GuoLianOAResponse() { code = -1, data = new GuoLianOAData { msg = "上传附件失败" } };
|
||||
}
|
||||
}
|
||||
if (tdoc == null)
|
||||
{
|
||||
logger.Info("未找到确认书文档");
|
||||
return new GuoLianOAResponse() { code = -1, data = new GuoLianOAData { msg = "未找到确认书文档" } };
|
||||
}
|
||||
|
||||
//通过UserName找到LoginName
|
||||
var applicantLoginName = DbContextFactory.GetErpBaseContext().SystemUsers.Where(u => u.Name == UserInfo.UserName).Select(u => u.LoginName).FirstOrDefault();
|
||||
// 构建dataMap
|
||||
@@ -332,6 +342,314 @@ namespace YLErp.Modules.TradeModule
|
||||
return new GuoLianOAResponse() { code = -2, data = new GuoLianOAData { msg = $"调用OA接口时发生异常: {ex.Message}" } };
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 批量查询并同步 OA 用印状态
|
||||
/// </summary>
|
||||
/// <returns>处理结果列表</returns>
|
||||
public List<TradeOAResult> SyncOAStampStatus()
|
||||
{
|
||||
var results = new List<TradeOAResult>();
|
||||
|
||||
// 1. 查询提交成功且有效的 OA 记录
|
||||
var pendingOAs = DbContext.tradeContractOaResult
|
||||
.Where(x => x.is_valid && x.status == "提交成功" && !string.IsNullOrEmpty(x.oa_fileid))
|
||||
.ToList();
|
||||
|
||||
if (!pendingOAs.Any())
|
||||
{
|
||||
logger.Info("没有待同步的OA用印记录");
|
||||
return results;
|
||||
}
|
||||
|
||||
logger.Info($"找到 {pendingOAs.Count} 条待同步OA用印记录");
|
||||
|
||||
foreach (var oa in pendingOAs)
|
||||
{
|
||||
try
|
||||
{
|
||||
// 2. 调用 OA 查询接口
|
||||
var queryResult = QueryOAStatus(oa.oa_fileid);
|
||||
if (queryResult == null)
|
||||
{
|
||||
logger.Info($"OA查询返回空,requestid:{oa.oa_fileid}");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (queryResult.code != 0)
|
||||
{
|
||||
logger.Info($"OA查询失败,requestid:{oa.oa_fileid}, msg:{queryResult.msg}");
|
||||
continue;
|
||||
}
|
||||
|
||||
// 从 data 数组中找到匹配的 requestId
|
||||
var flowData = queryResult.data?.FirstOrDefault(d => d.requestId == oa.oa_fileid);
|
||||
if (flowData == null)
|
||||
{
|
||||
logger.Info($"OA查询结果中未找到匹配记录,requestid:{oa.oa_fileid}");
|
||||
continue;
|
||||
}
|
||||
|
||||
// 3. 判断用印是否完成:fj 字段为空表示未盖完章,有值表示已用印
|
||||
var fj = flowData.flowInfos?["fj"];
|
||||
if (fj == null || fj.Type == Newtonsoft.Json.Linq.JTokenType.Null)
|
||||
{
|
||||
logger.Info($"OA用印未完成,fj为空,requestid:{oa.oa_fileid}");
|
||||
continue;
|
||||
}
|
||||
|
||||
// 4. 获取用印文件并同步
|
||||
var syncResult = SyncStampFileToDoc(oa, flowData);
|
||||
results.Add(syncResult);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.Error($"同步OA状态失败,OA ID:{oa.id}, requestid:{oa.oa_fileid}, 错误:{ex.Message}", ex);
|
||||
results.Add(new TradeOAResult { TradeId = oa.trade_id, Success = false, Message = $"同步失败: {ex.Message}" });
|
||||
}
|
||||
}
|
||||
|
||||
logger.Info($"OA用印同步完成,共处理 {results.Count} 条,成功 {results.Count(r => r.Success)} 条");
|
||||
return results;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查询 OA 审批状态
|
||||
/// </summary>
|
||||
/// <param name="requestId">OA请求ID</param>
|
||||
/// <returns>查询结果</returns>
|
||||
private OAStatusQueryResponse QueryOAStatus(string requestId)
|
||||
{
|
||||
try
|
||||
{
|
||||
var oaConfigSection = AppManager.GetConfiguration().GetSection("oa_confg");
|
||||
var baseUrl = oaConfigSection["BaseUrl"];
|
||||
var queryUrl = oaConfigSection["QueryUrl"];
|
||||
var systemToken = oaConfigSection["SystemToken"];
|
||||
var systemName = oaConfigSection["SystemName"];
|
||||
|
||||
if (string.IsNullOrEmpty(baseUrl) || string.IsNullOrEmpty(queryUrl))
|
||||
{
|
||||
logger.Info("OA查询接口配置不完整");
|
||||
return null;
|
||||
}
|
||||
|
||||
var requestParam = $"{queryUrl}?requestid={Uri.EscapeDataString(requestId)}&systemToken={Uri.EscapeDataString(systemToken)}&systemName={Uri.EscapeDataString(systemName ?? string.Empty)}";
|
||||
|
||||
var httpClient = new HttpClientWrap(baseUrl, 30);
|
||||
var response = httpClient.Get(requestParam, null);
|
||||
|
||||
logger.Info($"查询OA用印状态返回: {response}");
|
||||
|
||||
if (string.IsNullOrEmpty(response))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return JsonHelper.Deserialize<OAStatusQueryResponse>(response);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.Error($"查询OA状态异常,requestid:{requestId}, 错误:{ex.Message}", ex);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 下载 OA 用印文件
|
||||
/// </summary>
|
||||
/// <param name="fileUrl">文件下载地址</param>
|
||||
/// <returns>文件字节数组</returns>
|
||||
private byte[] DownloadOAFile(string fileUrl)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (string.IsNullOrEmpty(fileUrl))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
logger.Info($"下载OA用印文件: {fileUrl}");
|
||||
|
||||
var response = _httpClient.GetAsync(fileUrl).Result;
|
||||
response.EnsureSuccessStatusCode();
|
||||
var fileBytes = response.Content.ReadAsByteArrayAsync().Result;
|
||||
|
||||
logger.Info($"下载OA用印文件成功,大小: {fileBytes.Length} 字节");
|
||||
return fileBytes;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.Error($"下载OA用印文件失败: {fileUrl}, 错误:{ex.Message}", ex);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将 OA 用印文件同步到确认书记录
|
||||
/// </summary>
|
||||
/// <param name="oa">OA结果记录</param>
|
||||
/// <param name="queryData">OA查询返回的流程数据</param>
|
||||
/// <returns>处理结果</returns>
|
||||
private TradeOAResult SyncStampFileToDoc(trade_contract_oa_result oa, OAFlowData queryData)
|
||||
{
|
||||
try
|
||||
{
|
||||
// 根据 contract_code 查找确认书文档(直接使用基类 DbContext)
|
||||
var contractDoc = DbContext.trade_contract_document.FirstOrDefault(d => d.Code == oa.contract_code);
|
||||
if (contractDoc == null)
|
||||
{
|
||||
logger.Info($"未找到确认书文档,contract_code:{oa.contract_code}");
|
||||
return new TradeOAResult { TradeId = oa.trade_id, Success = false, Message = "未找到确认书文档" };
|
||||
}
|
||||
|
||||
// 从 fj 字段提取用印文件信息
|
||||
var fj = queryData.flowInfos?["fj"];
|
||||
if (!TryExtractFileFromFj(fj, out var fileUrl, out var fileName))
|
||||
{
|
||||
logger.Info($"无法从 fj 中提取用印文件信息,contract_code:{oa.contract_code}");
|
||||
return new TradeOAResult { TradeId = oa.trade_id, Success = false, Message = "无法提取用印文件信息" };
|
||||
}
|
||||
|
||||
// 下载用印文件
|
||||
var fileBytes = DownloadOAFile(fileUrl);
|
||||
if (fileBytes == null || fileBytes.Length == 0)
|
||||
{
|
||||
logger.Info($"未获取到用印文件,contract_code:{oa.contract_code}");
|
||||
return new TradeOAResult { TradeId = oa.trade_id, Success = false, Message = "未获取到用印文件" };
|
||||
}
|
||||
|
||||
// 文件名安全过滤:防止路径遍历
|
||||
fileName = SanitizeFileName(fileName);
|
||||
if (string.IsNullOrEmpty(fileName))
|
||||
{
|
||||
fileName = $"{oa.contract_code}_用印.pdf";
|
||||
}
|
||||
|
||||
// 保存用印文件到本地
|
||||
var tradeNumber = "未知";
|
||||
var contractR = DbContext.trade_contract_r.FirstOrDefault(r => r.ContractCode == oa.contract_code && r.IsValid);
|
||||
if (contractR != null)
|
||||
{
|
||||
tradeNumber = contractR.TradeNumber;
|
||||
}
|
||||
|
||||
var filePath = Path.Combine(OtcAppContext.AppDocsPath, "contractdoc", PS.Config.Company.ToString(), tradeNumber);
|
||||
if (!Directory.Exists(filePath))
|
||||
{
|
||||
Directory.CreateDirectory(filePath);
|
||||
}
|
||||
|
||||
var stampFileFullName = Path.Combine(filePath, fileName);
|
||||
if (File.Exists(stampFileFullName))
|
||||
{
|
||||
File.Delete(stampFileFullName);
|
||||
}
|
||||
|
||||
File.WriteAllBytes(stampFileFullName, fileBytes);
|
||||
logger.Info($"用印文件保存成功: {stampFileFullName}");
|
||||
|
||||
// 更新确认书文档状态
|
||||
contractDoc.StampDocumentFileName = stampFileFullName.Replace(OtcAppContext.AppDocsPath, "/App_Docs").Replace("\\", "/");
|
||||
|
||||
// 根据 SourceType 判断用印状态:null或1=我方用印,2=双方用印
|
||||
var sourceType = contractDoc.SourceType ?? 1;
|
||||
if (sourceType == 1)
|
||||
{
|
||||
contractDoc.Status = ContractStatusEnum.OurPartyStamped; // 我方用印
|
||||
}
|
||||
else if (sourceType == 2)
|
||||
{
|
||||
contractDoc.Status = ContractStatusEnum.BothPartyStamped; // 双方用印
|
||||
}
|
||||
|
||||
contractDoc.OptDate = DateTime.Now;
|
||||
|
||||
// 更新 OA 结果状态(oa 本身由基类 DbContext 追踪,直接修改即可)
|
||||
oa.status = "用印完成";
|
||||
oa.OptDate = DateTime.Now;
|
||||
|
||||
DbContext.SaveChanges();
|
||||
|
||||
logger.Info($"确认书 {oa.contract_code} 用印状态已更新为: {contractDoc.Status}");
|
||||
return new TradeOAResult { TradeId = oa.trade_id, Success = true, Message = $"用印同步成功,状态: {contractDoc.Status}" };
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.Error($"同步用印文件失败,contract_code:{oa.contract_code}, 错误:{ex.Message}", ex);
|
||||
return new TradeOAResult { TradeId = oa.trade_id, Success = false, Message = $"同步失败: {ex.Message}" };
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 从 fj 字段尝试提取文件下载地址和文件名
|
||||
/// fj 格式:{"annexId":"url1,url2","annexName":"name1,name2"}
|
||||
/// </summary>
|
||||
private bool TryExtractFileFromFj(Newtonsoft.Json.Linq.JToken fj, out string fileUrl, out string fileName)
|
||||
{
|
||||
fileUrl = null;
|
||||
fileName = null;
|
||||
|
||||
if (fj == null || fj.Type == Newtonsoft.Json.Linq.JTokenType.Null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// 如果是字符串,直接当作 URL
|
||||
if (fj.Type == Newtonsoft.Json.Linq.JTokenType.String)
|
||||
{
|
||||
fileUrl = fj.ToString();
|
||||
fileName = Path.GetFileName(fileUrl);
|
||||
return !string.IsNullOrEmpty(fileUrl);
|
||||
}
|
||||
|
||||
// 解析 annexId(逗号分隔的 URL 数组)和 annexName(逗号分隔的文件名数组)
|
||||
var annexIdStr = fj["annexId"]?.ToString();
|
||||
var annexNameStr = fj["annexName"]?.ToString();
|
||||
|
||||
if (!string.IsNullOrEmpty(annexIdStr))
|
||||
{
|
||||
fileUrl = annexIdStr.Split(',').Select(s => s.Trim()).FirstOrDefault(s => !string.IsNullOrEmpty(s));
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(annexNameStr))
|
||||
{
|
||||
fileName = annexNameStr.Split(',').Select(s => s.Trim()).FirstOrDefault(s => !string.IsNullOrEmpty(s));
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(fileName) && !string.IsNullOrEmpty(fileUrl))
|
||||
{
|
||||
fileName = Path.GetFileName(fileUrl);
|
||||
}
|
||||
|
||||
return !string.IsNullOrEmpty(fileUrl);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 过滤文件名中的非法字符,防止路径遍历
|
||||
/// </summary>
|
||||
private string SanitizeFileName(string fileName)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(fileName))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
// 仅保留纯文件名,丢弃路径
|
||||
fileName = Path.GetFileName(fileName);
|
||||
|
||||
// 替换 Windows 非法字符
|
||||
var invalidChars = Path.GetInvalidFileNameChars();
|
||||
foreach (var c in invalidChars)
|
||||
{
|
||||
fileName = fileName.Replace(c, '_');
|
||||
}
|
||||
|
||||
// 防御 .. 路径遍历
|
||||
fileName = fileName.Replace("..", "_");
|
||||
|
||||
return fileName;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -41,7 +41,7 @@
|
||||
{Name:"资金记录",Rights:["结算管理-出入金维护"],Url:"entryexit/entryexitList"},
|
||||
{Name:"资金审批",Rights:["结算管理-资金审批页面"],Url:"entryexit/entryexitApproval"},
|
||||
{Name:"收盘操作",Rights:["结算管理-收盘操作"],Url:"eod_trade_value/eodExec"},
|
||||
{Name:"交易确认书",Rights:["结算管理-交易确认书"],Url:"TradeConfirmBook/ConfirmBookListByClient"},
|
||||
{Name:"交易确认书",Rights:["结算管理-交易确认书"],Url:"TradeConfirmBook/Index"},
|
||||
{Name:"交易确认书_期权",Rights:["结算管理-交易确认书-期权"],Url:"TradeConfirmBook/IndexOption"},
|
||||
{Name:"结算确认书",Rights:["结算管理-结算确认书"],Url:"swaptrade2/tradeEndConfirmList"},
|
||||
{Name:"每日估值报告",Rights:["结算管理-每日估值报告"],Url:"clientbalance/TradeMarketReport"},
|
||||
|
||||
@@ -1078,10 +1078,10 @@ namespace YLErp.Web.Controllers
|
||||
/// </summary>
|
||||
/// <param name="tradeId"></param>
|
||||
/// <returns></returns>
|
||||
public JsonResult SendConfimEmail(string contractCode)
|
||||
public JsonResult SendConfimEmail(int tradeId)
|
||||
{
|
||||
SwapEndConfirmService service = new SwapEndConfirmService(CurUser);
|
||||
var result = service.SendConfirmEamil(contractCode);
|
||||
var result = service.SendConfirmEamil(tradeId);
|
||||
return JsonSuccess(result);
|
||||
}
|
||||
|
||||
|
||||
@@ -186,6 +186,74 @@ namespace YLErp.Web.Controllers
|
||||
return Json(sList);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 互换确认书查询(只查询收益互换)
|
||||
/// </summary>
|
||||
public JsonResult SwapQuery(TradeReq req)
|
||||
{
|
||||
req.AssetIdList = AssetUnitModel.IntersectAssetUnits(req.AssetIdGroupList, req.AssetIdList).ToList();
|
||||
req.UserAssets = CurUser.GetAssetUnitIds();
|
||||
req.UserClients = CurUser.GetClientIdsByCurUser(CurUser.交易管理_查看所有交易);
|
||||
req.CurUserTradeIds = CurUser.GetTradeIdsByCurUser();
|
||||
// 只查询收益互换
|
||||
req.TradeTypes = "收益互换";
|
||||
var sList = new tradeBLL().SearchListForTradeConfirm(req);
|
||||
var rowList = sList.rows;
|
||||
// 增加交易确认书编号
|
||||
if (rowList != null && rowList.Any())
|
||||
{
|
||||
var tradeIds = rowList.Select(x => x.id).ToList();
|
||||
var tradeContractCodeList = (from tradeContractR in yldb.trade_contract_r
|
||||
join tradeContractDoc in (from tradeContractDocTemp in yldb.trade_contract_document where ContractTypeEnum.Trade == tradeContractDocTemp.Type select tradeContractDocTemp)
|
||||
on tradeContractR.ContractCode equals tradeContractDoc.Code into tradeContractDoc1
|
||||
from tradeContractDoc2 in tradeContractDoc1.DefaultIfEmpty()
|
||||
where tradeIds.Contains(tradeContractR.TradeId) && ContractTypeEnum.Trade == tradeContractR.Type && tradeContractR.Type == tradeContractDoc2.Type && tradeContractR.IsValid
|
||||
select new
|
||||
{
|
||||
tradeContractR.id,
|
||||
tradeContractR.TradeId,
|
||||
tradeContractR.ContractCode,
|
||||
tradeContractR.send_email_result,
|
||||
tradeContractDoc = tradeContractDoc2
|
||||
}).ToList();
|
||||
|
||||
foreach (var trade in rowList)
|
||||
{
|
||||
if (trade.TradeType == "合成价差期权")
|
||||
{
|
||||
trade.SyntheticUnderlyingTipsInfo = synthetic_underlyingBLL.GetUnderlyingTipsInfo(trade.UnderlyingCode);
|
||||
}
|
||||
var tradeContractinfo = tradeContractCodeList.FirstOrDefault(t => t.TradeId == trade.id);
|
||||
trade.MetaDic["send_email_result"] = "";
|
||||
if (tradeContractinfo != null)
|
||||
{
|
||||
trade.ContractCode = tradeContractinfo.ContractCode;
|
||||
if (null != tradeContractinfo.tradeContractDoc)
|
||||
{
|
||||
trade.MetaDic["ContractEncryptId"] = tradeContractinfo.tradeContractDoc.EncryptId;
|
||||
trade.MetaDic["ContractRId"] = tradeContractinfo.id.ToString();
|
||||
trade.MetaDic["ContractDocUrl"] = tradeContractinfo.tradeContractDoc.RelativePath;
|
||||
trade.MetaDic["HasGeneratedConfirmBook"] = "True";
|
||||
trade.MetaDic["send_email_result"] = tradeContractinfo.send_email_result;
|
||||
}
|
||||
else
|
||||
{
|
||||
trade.MetaDic["ContractEncryptId"] = "";
|
||||
trade.MetaDic["ContractRId"] = tradeContractinfo.id.ToString();
|
||||
trade.MetaDic["HasGeneratedConfirmBook"] = "False";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
trade.MetaDic["ContractEncryptId"] = "";
|
||||
trade.MetaDic["ContractRId"] = "";
|
||||
trade.MetaDic["HasGeneratedConfirmBook"] = "False";
|
||||
}
|
||||
}
|
||||
}
|
||||
return Json(sList);
|
||||
}
|
||||
|
||||
public async Task<ActionResult> SentMail(string enid, List<string> reciver)
|
||||
{
|
||||
var result = await DoSendMailSywg(enid, reciver);
|
||||
@@ -1038,6 +1106,7 @@ namespace YLErp.Web.Controllers
|
||||
contractRecord.ContractVersion = contractVersion;
|
||||
contractRecord.FileType = FileTypeEnum.Pdf;
|
||||
contractRecord.Status = ContractStatusEnum.Draft;
|
||||
contractRecord.SourceType = 1; // 系统生成
|
||||
contractRecord.Paths = outPath.ToString();
|
||||
contractRecord.FileName = outputFileName.Replace(".xlsx", ".pdf");
|
||||
contractRecord.Type = ContractTypeEnum.Trade;
|
||||
@@ -1431,6 +1500,7 @@ namespace YLErp.Web.Controllers
|
||||
contractRecord.ContractVersion = contractVersion;
|
||||
contractRecord.FileType = FileTypeEnum.Pdf;
|
||||
contractRecord.Status = ContractStatusEnum.Draft;
|
||||
contractRecord.SourceType = 1; // 系统生成
|
||||
contractRecord.Paths = Path.Combine(DocumentPathConvert.ConvertToUrlPath(outPath), outputFileName.Replace(".xlsx", ".pdf"));
|
||||
contractRecord.FileName = outputFileName.Replace(".xlsx", ".pdf");
|
||||
contractRecord.Type = ContractTypeEnum.Trade;
|
||||
|
||||
@@ -420,14 +420,13 @@
|
||||
</a>
|
||||
</td>
|
||||
<td>
|
||||
<vue-number-input v-model="item.PosiGrossPrice" v-bind:format="inputFormatMarginRateNoPercent" v-on:input="changeSpotPrice(item)" v-if="trade.StructureType!='普通收益互换'"></vue-number-input>
|
||||
<vue-number-input v-model="item.PosiGrossPrice" v-bind:format="inputFormatTradeSinglePrice" v-on:input="changeSpotPrice(item)" v-else></vue-number-input>
|
||||
<vue-number-input v-model="item.PosiGrossPrice" v-bind:format="tradeHelper.IsBond(item.UnderlyingInstrumentType)?inputFormatMarginRateNoPercent:inputFormatTradeSinglePrice" v-on:input="changeSpotPrice(item)"></vue-number-input>
|
||||
</td>
|
||||
<td>
|
||||
<vue-number-input v-model="item.PosiNetNoFeePrice" v-bind:format="inputFormatMarginRateNoPercent"></vue-number-input>
|
||||
<vue-number-input v-model="item.PosiNetNoFeePrice" v-bind:format="tradeHelper.IsBond(item.UnderlyingInstrumentType)?inputFormatMarginRateNoPercent:inputFormatTradeSinglePrice"></vue-number-input>
|
||||
</td>
|
||||
<td>
|
||||
<vue-number-input v-model="item.InitYtm" v-bind:format="inputFormatMarginRateNoPercent"></vue-number-input>
|
||||
<vue-number-input v-model="item.InitYtm" v-bind:format="tradeHelper.IsBond(item.UnderlyingInstrumentType)?inputFormatMarginRateNoPercent:inputFormatTradeSinglePrice"></vue-number-input>
|
||||
</td>
|
||||
<td>
|
||||
<vue-number-input v-model="item.PosiQuantity" v-on:input="changeQuantity(item)" v-bind:format="inputFormatTradeAmount"></vue-number-input>{{item.underlying!=null?item.underlying.QuoteUnitString:''}}
|
||||
|
||||
@@ -25,7 +25,9 @@
|
||||
IsZheQi = PS.Config.Is浙期,
|
||||
IsAutoSealAfterGeneratedBook = PS.GetErpConfig().IsAutoSealAfterGeneratedBook,
|
||||
canGenerate = CurUser.结算管理_交易确认书生成,
|
||||
canSendEmail = CurUser.结算管理_交易确认书邮件发送
|
||||
canSendEmail = CurUser.结算管理_交易确认书邮件发送,
|
||||
// 标识为互换确认书页面
|
||||
isSwapPage = true
|
||||
};
|
||||
var tradeTypes = ConsTrade.AllTradeTypes.Except(new List<string> { "场内期权", "股票" }).Concat(new List<string> { "黑箱结构" });
|
||||
}
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
using System.Text.Json;
|
||||
using YLErp.Helpers;
|
||||
using YLErp.Modules.TradeModule;
|
||||
|
||||
namespace YLErp.Web.WebAPI.Controllers
|
||||
{
|
||||
/// <summary>
|
||||
/// OA用印状态同步定时任务接口(无鉴权,供PowerJob等外部调度系统调用)
|
||||
/// </summary>
|
||||
[ApiController]
|
||||
public class TradeOAJobController : ControllerBase
|
||||
{
|
||||
private static readonly IYcLogger logger = LogFactory.GetLogger<TradeOAJobController>();
|
||||
|
||||
/// <summary>
|
||||
/// 同步OA用印状态
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 无需鉴权,建议通过内网限制或Nginx限制来源IP。
|
||||
/// 可选:在请求Header中携带 X-Job-Api-Key 进行简单校验。
|
||||
/// </remarks>
|
||||
[HttpPost]
|
||||
[Route("api/job/tradeContract/syncOAStampStatus")]
|
||||
public JsonResult SyncOAStampStatus()
|
||||
{
|
||||
try
|
||||
{
|
||||
// 可选:简单 API Key 校验
|
||||
var configKey = AppManager.GetConfiguration()["JobConfig:ApiKey"];
|
||||
if (!string.IsNullOrEmpty(configKey))
|
||||
{
|
||||
var requestKey = Request.Headers["X-Job-Api-Key"].FirstOrDefault();
|
||||
if (configKey != requestKey)
|
||||
{
|
||||
return JsonError(401, "Invalid API Key");
|
||||
}
|
||||
}
|
||||
|
||||
logger.Info("开始执行OA用印状态同步任务");
|
||||
|
||||
// 使用系统用户身份执行
|
||||
var systemUser = new OptUserInfo(0, "系统用印同步", OptUserFrom.System);
|
||||
var service = new TradeOAService(systemUser);
|
||||
|
||||
var results = service.SyncOAStampStatus();
|
||||
|
||||
var successCount = results.Count(r => r.Success);
|
||||
var failCount = results.Count(r => !r.Success);
|
||||
|
||||
logger.Info($"OA用印状态同步任务完成,共处理 {results.Count} 条,成功 {successCount} 条,失败 {failCount} 条");
|
||||
|
||||
return JsonSuccess(new
|
||||
{
|
||||
total = results.Count,
|
||||
successCount,
|
||||
failCount,
|
||||
executeTime = DateTime.Now,
|
||||
details = results.Select(r => new { r.TradeId, r.Success, r.Message }).ToList()
|
||||
});
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.Error($"OA用印状态同步任务异常: {ex.Message}", ex);
|
||||
return JsonError($"同步OA用印状态失败: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
#region JSON消息处理
|
||||
|
||||
private static readonly JsonSerializerOptions _jsonOptions = new JsonSerializerOptions
|
||||
{
|
||||
PropertyNamingPolicy = JsonNamingPolicy.CamelCase
|
||||
};
|
||||
|
||||
private JsonResult JsonSuccess(object data, string msg = null)
|
||||
{
|
||||
return new JsonResult(new ApiResult { code = 0, msg = msg, data = data }, _jsonOptions);
|
||||
}
|
||||
|
||||
private JsonResult JsonError(string msg)
|
||||
{
|
||||
return new JsonResult(new ApiResult { code = 1, msg = msg, data = null }, _jsonOptions);
|
||||
}
|
||||
|
||||
private JsonResult JsonError(int code, string msg)
|
||||
{
|
||||
return new JsonResult(new ApiResult { code = code, msg = msg, data = null }, _jsonOptions);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -15,7 +15,7 @@
|
||||
"AppSettings": {
|
||||
"VirtualPathRoot": "",
|
||||
"UseRightAligned": "",
|
||||
"PluginFolder": "D:\\shenzhengpoc\\zszq-trs\\Plugins\\build\\ZheShang\\Debug\\net6.0\\"
|
||||
"PluginFolder": "D:\\workspace\\glms\\zszq-trs\\Plugins\\YLErp.Plugins.GuoLian\\obj\\Debug\\net6.0"
|
||||
},
|
||||
"LibreOffice": {
|
||||
"ExePath": "",
|
||||
@@ -76,10 +76,12 @@
|
||||
"MaxThreadPercent": 0.6, //占系统资源最多60%的线程数量
|
||||
"oa_confg": {
|
||||
"BaseUrl": "http://ip:port",
|
||||
"SystemKey": "M001", //OA系统key
|
||||
"ObjectClass": "ZSZQ_ZDNX", //OA文件类别
|
||||
"Urgent": 1, //紧急程度,1一般 2紧急 3加急
|
||||
"Issend": 1 //流程是否自动发送,0不发送,1自动发送下一步
|
||||
"SubUrl": "",
|
||||
"UploadUrl": "/api/oa/upload", // OA附件上传接口路径
|
||||
"SystemToken": "your-system-token", // OA系统鉴权Token
|
||||
"SystemName": "OTC_TRADE", // 调用方系统标识
|
||||
"IsNextFlow": 0
|
||||
|
||||
},
|
||||
"GeneralSSO": {
|
||||
"enable": true, //是否启用通用SSO登录
|
||||
|
||||
@@ -88,10 +88,7 @@ const colModelGrid = (new function () {
|
||||
sortable: false,
|
||||
formatter: function (cellValue, options, rowObject) {
|
||||
var html = "";
|
||||
if (cellValue) {
|
||||
if (!page.isWuChan) {
|
||||
html += "<a href='javascript:;' title='修改合约编号' id='bt_" + rowObject.MetaDic.ContractEncryptId + "' onclick='colModelGrid.setControl(\"" + rowObject.MetaDic.ContractEncryptId + "\")' ><i class='fa fa-pencil-square-o'></i></a>";
|
||||
}
|
||||
if (cellValue) {
|
||||
html += "<input style='width: 100%;' id='ip_" + rowObject.MetaDic.ContractEncryptId + "' type='text' value='" + cellValue + "' disabled />";
|
||||
} else {
|
||||
html = "";
|
||||
@@ -420,7 +417,7 @@ function __initJqGrid() {
|
||||
onJqgridPaging: typeof onJqgridPaging !== 'undefined' ? onJqgridPaging : void 0
|
||||
};
|
||||
var grid = jQuery('#listGrid').jqGrid({
|
||||
url: page.isOptionPage ? '/TradeConfirmBook/OptionQuery' : '/trade/tradeConfirmEmailQuery',
|
||||
url: page.isOptionPage ? '/TradeConfirmBook/OptionQuery' : (page.isSwapPage ? '/TradeConfirmBook/SwapQuery' : '/trade/tradeConfirmEmailQuery'),
|
||||
datatype: page.initEmptyView ? 'local' : 'json',
|
||||
height: 'auto',
|
||||
width: '90%',
|
||||
|
||||
@@ -35,6 +35,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "YLErp.Cache", "Framework\YL
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "YLErp.Plugins.ZheShang", "Plugins\YLErp.Plugins.ZheShang\YLErp.Plugins.ZheShang.csproj", "{C94D2467-B0E8-48CA-B60D-CD660B73AE90}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "YLErp.Plugins.GuoLian", "Plugins\YLErp.Plugins.GuoLian\YLErp.Plugins.GuoLian.csproj", "{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
@@ -86,6 +88,10 @@ Global
|
||||
{C94D2467-B0E8-48CA-B60D-CD660B73AE90}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{C94D2467-B0E8-48CA-B60D-CD660B73AE90}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{C94D2467-B0E8-48CA-B60D-CD660B73AE90}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
@@ -100,6 +106,7 @@ Global
|
||||
{DB3402A2-7121-4F5A-9F0F-A258EC582370} = {F315B5D3-F4FE-43E5-AF22-AF92978A71BE}
|
||||
{5665673C-1157-444F-AABC-2A873D8E4703} = {F315B5D3-F4FE-43E5-AF22-AF92978A71BE}
|
||||
{C94D2467-B0E8-48CA-B60D-CD660B73AE90} = {5981434D-792E-4528-AFC8-7EB8AFD9F80C}
|
||||
{A1B2C3D4-E5F6-7890-ABCD-EF1234567890} = {5981434D-792E-4528-AFC8-7EB8AFD9F80C}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {28638B67-A6D3-4355-8ADB-EACEE98510B0}
|
||||
|
||||
Reference in New Issue
Block a user