diff --git a/Framework/YLErp.Core/DBModels/BaseSystemUser.cs b/Framework/YLErp.Core/DBModels/BaseSystemUser.cs index b0aa782f..cfd75fd4 100644 --- a/Framework/YLErp.Core/DBModels/BaseSystemUser.cs +++ b/Framework/YLErp.Core/DBModels/BaseSystemUser.cs @@ -1,4 +1,5 @@ using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; namespace YLErp.DBModels { @@ -54,6 +55,13 @@ namespace YLErp.DBModels [DisplayName("品种")] public string VarietyIds { get; set; } + /// + /// oa账号 + /// + [DisplayName("OA账号")] + [Column("oa_account")] + public string OaAccount { get; set; } + public List VarietyIdList { get diff --git a/Framework/YLErp.Core/DBModels/trade_contract_oa_result.cs b/Framework/YLErp.Core/DBModels/trade_contract_oa_result.cs new file mode 100644 index 00000000..157ad5d9 --- /dev/null +++ b/Framework/YLErp.Core/DBModels/trade_contract_oa_result.cs @@ -0,0 +1,46 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations.Schema; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace YLErp.DBModels +{ + /// + /// 确认书OA审批结果 + /// + [Table("trade_contract_oa_result")] + public class trade_contract_oa_result : DBModelBaseV6 + { + /// + /// 交易id + /// + public int trade_id { get; set; } + /// + /// 确认书编号 + /// + public string contract_code { get; set; } + /// + /// oa审批返回id + /// + public string oa_fileid { get; set; } + /// + /// 状态 + /// + public string status { get; set; } + /// + /// oa审批返回消息 + /// + public string oa_msg { get; set; } + /// + /// oa返回url + /// + public string oa_url { get; set; } + /// + /// 是否有效 + /// + public bool is_valid { get; set; } + + } +} diff --git a/Framework/YLErp.Core/Models/OptUserInfo.cs b/Framework/YLErp.Core/Models/OptUserInfo.cs index b36cabe0..41024eb3 100644 --- a/Framework/YLErp.Core/Models/OptUserInfo.cs +++ b/Framework/YLErp.Core/Models/OptUserInfo.cs @@ -23,6 +23,10 @@ namespace YLErp /// 用户名称 /// public string UserName { get; set; } + /// + /// oa账户 + /// + public string OaAccount { get; set; } /// /// 用户组 diff --git a/UnitTestProject/Modules/UnderlyingModule/UnderlyingHelperTest.cs b/UnitTestProject/Modules/UnderlyingModule/UnderlyingHelperTest.cs index 7e722e0a..cd78397a 100644 --- a/UnitTestProject/Modules/UnderlyingModule/UnderlyingHelperTest.cs +++ b/UnitTestProject/Modules/UnderlyingModule/UnderlyingHelperTest.cs @@ -27,10 +27,10 @@ namespace YLErp.UnitTestProject.Modules.UnderlyingModule // (5,10]年,应返回10年 var code3 = "UNLIMITED_10Y"; - var maturity3 = new DateTime(2040, 1, 1); + var maturity3 = new DateTime(2030, 8, 2); var underlying3 = CreateTestUnderlying(code3, null, maturity3); var valueDate3 = maturity3.AddYears(-7); // 剩余13年 - var valueDate3_2 = maturity3.AddYears(-10); // 剩余10年 + var valueDate3_2 = DateTime.Now.Date; // 剩余10年 var result3 = UnderlyingHelper.GetApplicableMarginTerm(code3, valueDate3_2); Assert.AreEqual(ConsMarginTerm.TenYear, result3, "(5,10]年 应为10年"); diff --git a/UnitTestProject/Program.cs b/UnitTestProject/Program.cs index bd9fe128..557a48aa 100644 --- a/UnitTestProject/Program.cs +++ b/UnitTestProject/Program.cs @@ -43,7 +43,7 @@ namespace YLErp }); ServiceProvider = services.BuildServiceProvider(); - + YLServiceLocator.SetServiceProvider(ServiceProvider); OtcAppContext.Initialize(s => { var s2 = s.Trim('/').Replace("/", "\\"); diff --git a/YLErpDAL/AppManager.cs b/YLErpDAL/AppManager.cs index 8adcd9ad..a486f9aa 100644 --- a/YLErpDAL/AppManager.cs +++ b/YLErpDAL/AppManager.cs @@ -1,4 +1,4 @@ -using Autofac; +using Autofac; using Microsoft.Extensions.Configuration; using System.Collections.Concurrent; using System.Diagnostics; @@ -176,6 +176,14 @@ namespace YLErp }; } + /// + /// 获取配置对象 + /// + public static IConfiguration GetConfiguration() + { + return _configuration; + } + /// /// 解析IOC容器中的实现(当前主要用于插件) /// diff --git a/YLErpDAL/BLL_System/UserBLL.cs b/YLErpDAL/BLL_System/UserBLL.cs index 941902c4..7cac9d3f 100644 --- a/YLErpDAL/BLL_System/UserBLL.cs +++ b/YLErpDAL/BLL_System/UserBLL.cs @@ -289,6 +289,7 @@ namespace BaseOUDAL State = source.State, UserGroup = source.UserGroup, AccountPost = source.AccountPost + "", + OaAccount=source.OaAccount }; var result = query.OrderBy(u => u.id).ToSearchList(req); diff --git a/YLErpDAL/BLL_System/ViewUser.cs b/YLErpDAL/BLL_System/ViewUser.cs index 676f0b18..4179b09e 100644 --- a/YLErpDAL/BLL_System/ViewUser.cs +++ b/YLErpDAL/BLL_System/ViewUser.cs @@ -37,5 +37,7 @@ namespace BaseOUDAL public string UserGroup { get; set; } public string AccountPost { get; set; } + + public string OaAccount { get; set; } } } diff --git a/YLErpDAL/DataBase/YLContext.cs b/YLErpDAL/DataBase/YLContext.cs index 5db0581d..73d418c8 100644 --- a/YLErpDAL/DataBase/YLContext.cs +++ b/YLErpDAL/DataBase/YLContext.cs @@ -405,5 +405,6 @@ namespace YLErp.BLL public DbSet clientMarginConfig { get; set; } public DbSet clientMarginDetail { get; set; } + public DbSet tradeContractOaResult { get; set; } } } \ No newline at end of file diff --git a/YLErpDAL/ModelBase/SystemUser.cs b/YLErpDAL/ModelBase/SystemUser.cs index de3e157a..33d8dc10 100644 --- a/YLErpDAL/ModelBase/SystemUser.cs +++ b/YLErpDAL/ModelBase/SystemUser.cs @@ -65,6 +65,7 @@ namespace BaseOUDAL AccountPost = newValue.AccountPost; ParentId = newValue.ParentId; VarietyIds = newValue.VarietyIds; + OaAccount=newValue.OaAccount; db.SaveChanges(); //刷新缓存 UserBLL.UpdateUsers(); diff --git a/YLErpDAL/Modules/SwapModule/SwapEodPositionService.cs b/YLErpDAL/Modules/SwapModule/SwapEodPositionService.cs index 20d6c497..726ac185 100644 --- a/YLErpDAL/Modules/SwapModule/SwapEodPositionService.cs +++ b/YLErpDAL/Modules/SwapModule/SwapEodPositionService.cs @@ -153,7 +153,7 @@ namespace YLErp.Modules.SwapModule var curEodPosis = DealFloatPositions(posiList, realPosiList, eodPositions, todyEodPositions, settleDate, td, preSettleDate, flowEvents); var posiLongNotional = curEodPosis.Where(s => s.PositionType == (int)PositionTypeFlag.Long).Sum(s => s.PosiNotionalValue); var posiShortNotional = curEodPosis.Where(s => s.PositionType == (int)PositionTypeFlag.Short).Sum(s => s.PosiNotionalValue); - var closePosiNotional = curEodPosis.Where(s => s.TdCloseQty > 0).Sum(s => s.TdCloseQty * s.ContractSize * s.PosiNetPrice); + var closePosiNotional = curEodPosis.Where(s => s.TdCloseQty > 0).Sum(s => s.TdCloseQty * s.ContractSize * s.PosiGrossPrice); var grossPrice = curEodPosis.Where(x => x.PosiDirection > 0).FirstOrDefault()?.PosiGrossPrice ?? 0; //处理利息腿 DealInterests(interestList, eodPositions, todyEodPositions, settleDate, td, flowEvents, autoInterests, lastEodSwap, posiLongNotional, posiShortNotional, closePosiNotional, grossPrice, orginPv); diff --git a/YLErpDAL/Modules/TradeModule/DealModule/TradeContractGenerateService.cs b/YLErpDAL/Modules/TradeModule/DealModule/TradeContractGenerateService.cs index 2132535d..019471f3 100644 --- a/YLErpDAL/Modules/TradeModule/DealModule/TradeContractGenerateService.cs +++ b/YLErpDAL/Modules/TradeModule/DealModule/TradeContractGenerateService.cs @@ -535,6 +535,9 @@ namespace YLErp.Modules.TradeModule.DealModule 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, @@ -555,6 +558,9 @@ namespace YLErp.Modules.TradeModule.DealModule 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) @@ -611,7 +617,10 @@ namespace YLErp.Modules.TradeModule.DealModule StampDocumentFileName = group.FirstOrDefault().StampDocumentFileName, OptDate = group.FirstOrDefault().OptDate, OptName = group.FirstOrDefault().OptName, - ContractDocId = group.FirstOrDefault().ContractDocId + 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); @@ -694,5 +703,9 @@ namespace YLErp.Modules.TradeModule.DealModule public int ContractDocId { get; set; } + public string OAStatus { get; set; } + public string OAURL { get; set; } + public string OAMessage { get; set; } + } } diff --git a/YLErpDAL/Modules/TradeModule/OAModels.cs b/YLErpDAL/Modules/TradeModule/OAModels.cs new file mode 100644 index 00000000..80a22e4c --- /dev/null +++ b/YLErpDAL/Modules/TradeModule/OAModels.cs @@ -0,0 +1,25 @@ +using System; + +namespace YLErp.Modules.TradeModule +{ + /// + /// OA接口响应模型 + /// + public class OAResponse + { + public bool success { get; set; } + public long time { get; set; } + public int messageCode { get; set; } + public string message { get; set; } + public OAResponseData data { get; set; } + } + + /// + /// OA接口响应数据模型 + /// + public class OAResponseData + { + public string url { get; set; } + public string fileid { get; set; } + } +} \ No newline at end of file diff --git a/YLErpDAL/Modules/TradeModule/TradeOAResult.cs b/YLErpDAL/Modules/TradeModule/TradeOAResult.cs new file mode 100644 index 00000000..837a089b --- /dev/null +++ b/YLErpDAL/Modules/TradeModule/TradeOAResult.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace YLErp.Modules.TradeModule +{ + /// + /// 交易OA处理结果 + /// + public class TradeOAResult + { + public int TradeId { get; set; } + public bool Success { get; set; } + public string Message { get; set; } + } + + /// + /// 交易OA批量处理结果 + /// + public class TradeOABatchResult : TradeOAResult + { + // 继承自TradeOAResult,避免重复定义相同属性 + // 如果需要批量处理特有的属性,可以在这里添加 + } +} \ No newline at end of file diff --git a/YLErpDAL/Modules/TradeModule/TradeOAService.cs b/YLErpDAL/Modules/TradeModule/TradeOAService.cs new file mode 100644 index 00000000..d7b96ec2 --- /dev/null +++ b/YLErpDAL/Modules/TradeModule/TradeOAService.cs @@ -0,0 +1,240 @@ +using Qdp.Foundation.Utilities; +using YLErp.DBModels; +using YLErp.DBModels.Consts; +using YLErp.DBModels.Enums; +using YLErp.Model; +using YLErp.Modules.ApiModule; +using YLErp.Modules.TradeDalModule; +using YLErp.Modules.UnderlyingModule; +using static YLErp.ConsGlobal; + +namespace YLErp.Modules.TradeModule +{ + /// + /// 交易OA服务 + /// + public class TradeOAService : YLBaseService + { + private static readonly IYcLogger logger = LogFactory.GetLogger(); + + public TradeOAService(OptUserInfo userInfo) : base(userInfo) + { + } + + public TradeOAService(YLBaseService baseService) : base(baseService) + { + } + + /// + /// 处理单个交易的OA提交 + /// + /// 交易ID + /// 处理结果 + public async Task ProcessSingleOAAsync(int tradeId) + { + try + { + // 获取交易信息 + var trade = DbContext.trade.FirstOrDefault(x=>x.id==tradeId); + if (trade == null) + { + return new TradeOAResult {TradeId=tradeId, Success = false, Message = "未找到交易信息" }; + } + + // 获取交易确认书信息 + var tcr = DbContext.trade_contract_r.Where(t => t.Type == ContractTypeEnum.Trade && t.IsValid&&t.TradeId==tradeId) + .FirstOrDefault(); + trade_contract_document tdoc = null; + if (tcr!=null) + { + tdoc = DbContext.trade_contract_document.Where(t => t.Code == tcr.ContractCode&&t.Type==tcr.Type).FirstOrDefault(); + } + + // 将之前的OA记录设置为无效 + var existingOAResults = DbContext.tradeContractOaResult.Where(x => x.trade_id == tradeId && x.is_valid == true).ToList(); + foreach (var existingResult in existingOAResults) + { + existingResult.is_valid = false; + existingResult.SetOpt(UserInfo); + } + + + // 创建OA结果记录 + var oaResult = new trade_contract_oa_result + { + trade_id = tradeId, + contract_code = tcr?.ContractCode, + status = "提交中", + is_valid = true, + }; + oaResult.SetOpt(UserInfo); + DbContext.tradeContractOaResult.Add(oaResult); + await DbContext.SaveChangesAsync(); + + // 调用OA接口 + var oaResp = await CallOAInterfaceAsync(trade, tcr?.ContractCode, tdoc, oaResult.id); + if (oaResp != null&& oaResp.success) + { + oaResult.status = "提交成功"; + oaResult.oa_fileid = oaResp.data?.fileid; + oaResult.oa_msg = oaResp.data?.url; + } + else + { + oaResult.status = "提交失败"; + oaResult.oa_msg = oaResp?.message ?? "OA接口调用失败"; + } + await DbContext.SaveChangesAsync(); + + return new TradeOAResult { TradeId = tradeId, Success = oaResult.status== "提交成功", Message = oaResult.oa_msg }; + } + catch (Exception ex) + { + logger.Error($"处理交易ID {tradeId} 的OA时发生错误: {ex.Message}", ex); + return new TradeOAResult { TradeId = tradeId, Success = false, Message = $"提交OA失败: {ex.Message}" }; + } + } + + /// + /// 调用OA接口 + /// + /// 交易信息 + /// 合同编号 + /// 交易确认书文档 + /// OA结果记录ID + /// 是否成功 + private async Task CallOAInterfaceAsync(trade trade, string contractCode, trade_contract_document tdoc, int oaResultId) + { + try + { + // 获取OA配置 + var oaConfigSection = AppManager.GetConfiguration().GetSection("oa_confg"); + var baseUrl = oaConfigSection["BaseUrl"]; + var loginName = UserInfo.OaAccount; + var systemKey = oaConfigSection["SystemKey"]; + var objectClass = oaConfigSection["ObjectClass"]; + var urgent = int.Parse(oaConfigSection["Urgent"] ?? "1"); + var issend = int.Parse(oaConfigSection["Issend"] ?? "0"); + + if (string.IsNullOrEmpty(loginName)) + { + logger.Error("OA账号未配置"); + return new OAResponse() { data = null, success = false, message = "OA账号未配置" }; + + } + if (string.IsNullOrEmpty(baseUrl)) + { + logger.Error("OA接口配置中BaseUrl为空"); + return new OAResponse() { data = null, success = false, message = "OA接口配置中地址为空" }; + } + + // 处理附件 + var attachments = new List(); + if (tdoc != null && !string.IsNullOrEmpty(tdoc.AbsolutePath)) + { + try + { + if (File.Exists(tdoc.AbsolutePath)) + { + var fileBytes = await File.ReadAllBytesAsync(tdoc.AbsolutePath); + var base64Content = Convert.ToBase64String(fileBytes); + var fileName = Path.GetFileName(tdoc.AbsolutePath); + + attachments.Add(new + { + nrtitle = fileName, + nrtype= "1", + content = base64Content + }); + + logger.Info($"成功读取附件文件:{tdoc.AbsolutePath},文件大小:{fileBytes.Length} 字节"); + } + else + { + logger.Error($"附件文件不存在:{tdoc.AbsolutePath}"); + return new OAResponse() { data = null, success = false, message = $"附件文件不存在" }; + + } + } + catch (Exception ex) + { + logger.Error($"读取附件文件失败:{tdoc.AbsolutePath},错误:{ex.Message}", ex); + return new OAResponse() { data = null, success = false, message = $"读取附件文件失败" }; + } + } + + // 计算同一客户、同一交易日期、同一多空方向的名义本金汇总 + // 1. 先获取当前交易的多空方向 + var currentPosition = DbContext.swap_position.AsNoTracking() + .Where(sp => sp.SwapTradeId == trade.id && sp.IsInitial && sp.PositionType > 0 && !sp.Invalid) + .FirstOrDefault(); + var currentPositionType = currentPosition.PositionType; + // 2. 查询同一客户、同一交易日期的所有有效交易 + var sameClientTrades = DbContext.trade.AsNoTracking() + .Where(t => t.ClientId == trade.ClientId + && t.TradeDate == trade.TradeDate + && t.ValidState != "InValid"); + + // 3. 关联持仓表,筛选相同多空方向的持仓 + var matchingPositions = from t in sameClientTrades + join sp in DbContext.swap_position.AsNoTracking() + on t.id equals sp.SwapTradeId + where sp.PositionType == currentPositionType + && sp.IsInitial && sp.PositionType > 0 && !sp.Invalid + select sp; + + // 4. 计算名义本金汇总 + var totalNotionalPrincipal = matchingPositions.Sum(sp => sp.PosiNotionalValue); + var posiTypeStr= currentPositionType == (int)PositionTypeFlag.Long ? "买入" : "卖出"; + var marginDetail=UnderlyingHelper.GetApplicableMarginRate(trade.ClientId, trade.UnderlyingCode, trade.TradeDate.Value); + var marginRate = marginDetail?.init_rate ?? 0; + // 构建OA请求参数 + var oaRequest = new + { + loginname = loginName, + systemkey = systemKey, + objectclass = objectClass, + title = $"交易确认书OA申请-{trade.ClientName}-{contractCode}", + urgent = urgent, + issend = issend, + copyattfileid = "", + je = (double)totalNotionalPrincipal, + filerela = new object[0], + groupno = "", + extinfo = new + { + busdata = new + { + BM1 = "", + BM2 = "", + BGRQ = trade.TradeDate.Value.ToString("yyyy-MM-dd"), + NGR1 = "", + NGR2 = "", + CKDX1 = "", + CKDX2 = "", + LB = "", + QSBGNR = $"各位领导:\n\t\t经友好协商,我司拟与交易对手开展以下场外利率收益互换交易:\n浮动收益交付方\t存款收益接收方\t标的\t方向\t起始日\t到期日\t合约名义本金\t保证金支付方\n浙商证券\t{trade.ClientName}\t{trade.UnderlyingInstrumentTypeCn}\t{posiTypeStr}\t{trade.StartDate?.ToString("yyyy/M/d")}\t{trade.ExerciseDate?.ToString("yyyy/M/d")}\t{totalNotionalPrincipal:N0}元\t{trade.ClientName}\n交易标的满足浙商证券标的池管理要求,交易对手方为非交易商,提供【{marginRate*100}%】名义本金的履约担保品作为初始保证金。保证金预警线与盯市追保符合内外规要求。", + MX = new object[0], + SQMX = new object[0] + }, + attachments = attachments.ToArray() + } + }; + logger.Info($"OA接口参数:{JsonHelper.Serialize(oaRequest)}"); + // 调用OA接口 + var httpClient = new HttpClientWrap(baseUrl); + var response = httpClient.PostJson("/fileDraft", oaRequest, null); + logger.Info($"OA接口返回:{response}"); + // 解析响应 + var responseObj = JsonHelper.Deserialize(response); + return responseObj; + } + catch (Exception ex) + { + logger.Error($"调用OA接口时发生异常,交易ID:{trade.id},异常信息:{ex.Message}", ex); + return new OAResponse() { data = null, success = false, message = $"调用OA接口时发生异常" }; + } + } + } + +} \ No newline at end of file diff --git a/YLErpDAL/Modules/UnderlyingModule/UnderlyingHelper.cs b/YLErpDAL/Modules/UnderlyingModule/UnderlyingHelper.cs index 5be1bc17..93d7c6c6 100644 --- a/YLErpDAL/Modules/UnderlyingModule/UnderlyingHelper.cs +++ b/YLErpDAL/Modules/UnderlyingModule/UnderlyingHelper.cs @@ -262,12 +262,14 @@ namespace YLErp.Modules.UnderlyingModule int totalMonths = (sourceDate.Value.Year - calcDate.Value.Year) * 12 + (sourceDate.Value.Month - calcDate.Value.Month); - if (sourceDate.Value.Day < calcDate.Value.Day) + double fractionalMonth = 0; + if (sourceDate.Value.Day != calcDate.Value.Day) { - totalMonths--; + int daysInMonth = DateTime.DaysInMonth(sourceDate.Value.Year, sourceDate.Value.Month); + fractionalMonth = (sourceDate.Value.Day - calcDate.Value.Day) / (double)daysInMonth; } - double yearTerm = totalMonths / 12.0; + double yearTerm = (totalMonths + fractionalMonth) / 12.0; return yearTerm; } /// diff --git a/YLErpWeb/Common/UserInfo.cs b/YLErpWeb/Common/UserInfo.cs index fe7f8e09..d9c507eb 100644 --- a/YLErpWeb/Common/UserInfo.cs +++ b/YLErpWeb/Common/UserInfo.cs @@ -265,6 +265,7 @@ namespace YLErp.Web user.UserToken = systemuser.UserToken; user.UserId = systemuser.Id; user.UserName = systemuser.Name; + user.OaAccount = systemuser.OaAccount; using (var db = new ErpBaseContext()) { user.Roles = (from o in db.RoleUsers diff --git a/YLErpWeb/Controllers/SystemController.cs b/YLErpWeb/Controllers/SystemController.cs index 017ea1e9..06118809 100644 --- a/YLErpWeb/Controllers/SystemController.cs +++ b/YLErpWeb/Controllers/SystemController.cs @@ -684,13 +684,13 @@ namespace YLErp.Web.Controllers public ActionResult userEditJson(IFormCollection collection, SystemUserDto req) { var result = UserEdit(req.Id, req.LoginName, req.Name, req.Password, - req.State, req.QQ, req.Mobile, req.Tel, req.RoleType, req.Email, req.UserGroup, collection, req.AccountPost, req.ParentId); + req.State, req.QQ, req.Mobile, req.Tel, req.RoleType, req.Email, req.UserGroup, collection, req.AccountPost, req.ParentId,req.OaAccount); return result; } [HttpPost] public ActionResult UserEdit(int id, string loginname, string name, string password, int state, string qq, - string Mobile, string tel, string roletype, string email, string userGroup, IFormCollection collection, int accountPost, int? parentId) + string Mobile, string tel, string roletype, string email, string userGroup, IFormCollection collection, int accountPost, int? parentId,string oaAccount) { var roles = roletype?.Split(','); @@ -778,6 +778,7 @@ namespace YLErp.Web.Controllers r.UserGroup = userGroup; r.AccountPost = accountPost; r.ParentId = parentId; + r.OaAccount = oaAccount; return View(r); } else @@ -797,7 +798,8 @@ namespace YLErp.Web.Controllers UserGroup = userGroup, AccountPost = accountPost, ParentId = parentId, - VarietyIds = "" + VarietyIds = "", + OaAccount=oaAccount }; r.Save(basedb, vo); diff --git a/YLErpWeb/Controllers/TradeConfirmBookController.cs b/YLErpWeb/Controllers/TradeConfirmBookController.cs index f6b2022b..f6cab407 100644 --- a/YLErpWeb/Controllers/TradeConfirmBookController.cs +++ b/YLErpWeb/Controllers/TradeConfirmBookController.cs @@ -1,4 +1,4 @@ -using Org.BouncyCastle.Ocsp; +using Org.BouncyCastle.Ocsp; using System.Diagnostics.Contracts; using YLErp.Commons; using YLErp.Configuration; @@ -108,6 +108,28 @@ namespace YLErp.Web.Controllers } } + /// + /// 发送OA + /// + /// 交易ID + /// + [HttpPost] + public async Task SendOA(int id) + { + try + { + var oaService = new TradeOAService(CurUser); + var result = await oaService.ProcessSingleOAAsync(id); + + return result.Success ? JsonSuccess(result.Message) : JsonError(result.Message); + } + catch (Exception ex) + { + logger.Error($"提交OA失败: {ex.Message}", ex); + return JsonError($"提交OA失败: {ex.Message}"); + } + } + private async Task DoSendMailSywg(string tradeId, List reciver,bool needDecryption = true) { try diff --git a/YLErpWeb/Controllers/clientController.cs b/YLErpWeb/Controllers/clientController.cs index 955f7b3d..b7bbab95 100644 --- a/YLErpWeb/Controllers/clientController.cs +++ b/YLErpWeb/Controllers/clientController.cs @@ -2628,7 +2628,7 @@ namespace YLErp.Web.Controllers From = reqModel.TradeMarketReportDateType == "当日" ? reqModel.ValueDate : (reqModel.TradeMarketReportDateType == "当月区间" ? QdpCalendarHelper.GetNonHoliday(reqModel.ValueDate.Date.AddDays(1 - reqModel.ValueDate.Day)) : DateTime.MinValue), To = reqModel.ValueDate, CurUserName = exParam.CurUser.UserName, - SendContent = string.IsNullOrEmpty(sheets) ? new List() { "账户状况", "持仓明细", "历史交易", "资金明细", "质押记录" } : sheets.Split(',').ToList(), + SendContent = string.IsNullOrEmpty(sheets) ? new List() { "账户状况", "互换估值", "互换交易流水", "资金明细"} : sheets.Split(',').ToList(), PayableFund = -1,//表示从后台获取 PayableMargin = -1,//表示从后台获取 ReportType = reqModel.ClientBalanceDataType, @@ -2662,32 +2662,6 @@ namespace YLErp.Web.Controllers message += "[客户" + clientName + "发送结算报告失败," + e.Message + "]; "; } } - - if (reqModel.HasTradeDetails) - { - try - { - var req = new TradeDetailsReq() - { - ClientId = client.Key, - StartDate = reqModel.TradeDetailsDateType == "当日" ? reqModel.ValueDate : (reqModel.TradeDetailsDateType == "当月区间" ? QdpCalendarHelper.GetNonHoliday(reqModel.ValueDate.Date.AddDays(1 - reqModel.ValueDate.Day)) : DateTime.MinValue), - EndDate = reqModel.ValueDate, - DetailStatuses = "成交,提前终止,到期" - }; - var tradeDetailsResult = new tradeController().SendReportMails(req, exParam.CurUser, exParam.detailTemplateName, exParam.tradeListHtmlViewPath, exParam.detailReceiver).Result; - var data = tradeDetailsResult.Value as Result; - if (!data.success) - { - message += "[客户" + clientName + "发送交易明细失败," + data.msg + "]; "; - } - } - catch (Exception e) - { - LogFactory.GetLogger().Error(e, "发送结算报告失败2"); - var msg = e.InnerException != null ? e.InnerException.Message : e.Message; - message += "[客户" + clientName + "发送交易明细失败," + msg + "]; "; - } - } return message; } @@ -2827,11 +2801,9 @@ namespace YLErp.Web.Controllers var message = ""; var tempFolder = Server.MapPath("~/App_Docs/Temp"); var marketFolder = Path.Combine(tempFolder, "结算报告" + DateTime.Now.ToString("yyyyMMddHHmmss")); - var detailsFolder = Path.Combine(tempFolder, "交易明细" + DateTime.Now.ToString("yyyyMMddHHmmss")); //如果没有相关数据,会创建一个空文件夹 Directory.CreateDirectory(marketFolder); - Directory.CreateDirectory(detailsFolder); foreach (var clientId in clientIds) { @@ -2879,29 +2851,6 @@ namespace YLErp.Web.Controllers message += "[客户" + clientName + "生成结算报告失败," + e.Message + "]; "; } } - - if (input.HasTradeDetails) - { - try - { - var req = new TradeDetailsReq() - { - ClientId = int.Parse(clientId), - StartDate = input.TradeDetailsDateType == "当日" ? input.ValueDate : (input.TradeDetailsDateType == "当月区间" ? QdpCalendarHelper.GetNonHoliday(input.ValueDate.Date.AddDays(1 - input.ValueDate.Day)) : DateTime.MinValue), - EndDate = input.ValueDate, - DetailStatuses = "成交,提前终止,到期", - OutputFolder = detailsFolder - }; - var biaoTou = DBCacheManager.Single.GetStr(CacheTable.TradeDetailsBiaoTou, detailTemplate); - var biaoWei = DBCacheManager.Single.GetStr(CacheTable.TradeDetailsBiaoWei, detailTemplate); - var tradeDetailsService = new TradeDetailsQueryService(CurUser); - tradeDetailsService.ExportReport(req, biaoTou, biaoWei, true); - } - catch (Exception e) - { - message += "[客户" + clientName + "生成交易明细失败," + e.Message + "]; "; - } - } } } @@ -2909,22 +2858,15 @@ namespace YLErp.Web.Controllers + (input.TradeMarketReportDateType == "当日" ? (input.ValueDate.ToString("yyyyMMdd") + "-") : (input.TradeMarketReportDateType == "当月区间" ? (QdpCalendarHelper.GetNonHoliday(input.ValueDate.Date.AddDays(1 - input.ValueDate.Day)).ToString("yyyyMMdd") + "-") : "")) + input.ValueDate.ToString("yyyyMMdd") + ".zip"; - var detailsZipFileName = "交易明细" - + (input.TradeDetailsDateType == "当日" ? (input.ValueDate.ToString("yyyyMMdd") + "-") : (input.TradeDetailsDateType == "当月区间" ? (QdpCalendarHelper.GetNonHoliday(input.ValueDate.Date.AddDays(1 - input.ValueDate.Day)).ToString("yyyyMMdd") + "-") : "")) - + input.ValueDate.ToString("yyyyMMdd") - + ".zip"; var zipWebPath = $"/App_Docs/Temp/"; var zipLocalFolder = Server.MapPath(zipWebPath); Directory.CreateDirectory(zipLocalFolder); var marketZipFile = Path.Combine(zipLocalFolder, marketZipFileName); - var detailsZipFile = Path.Combine(zipLocalFolder, detailsZipFileName); ZipHelper.ZipDirectory(marketFolder, marketZipFile); - ZipHelper.ZipDirectory(detailsFolder, detailsZipFile); Directory.Delete(marketFolder, true); - Directory.Delete(detailsFolder, true); if (!string.IsNullOrEmpty(message)) { @@ -2933,8 +2875,7 @@ namespace YLErp.Web.Controllers return JsonSuccess("批量下载成功", new { - marketZipFile = zipWebPath + marketZipFileName, - detailsZipFile = zipWebPath + detailsZipFileName + marketZipFile = zipWebPath + marketZipFileName }); } diff --git a/YLErpWeb/Controllers/clientbalanceController.cs b/YLErpWeb/Controllers/clientbalanceController.cs index 02a0ecdd..51e55e0a 100644 --- a/YLErpWeb/Controllers/clientbalanceController.cs +++ b/YLErpWeb/Controllers/clientbalanceController.cs @@ -563,8 +563,8 @@ namespace YLErp.Web.Controllers } else { - var report = new SettlementReportService(user).GetReportData(emailData, userAssetUnits, template); - new SettlementReportService(user).GenerateFileEntry(report, "excel"); + var report = new SettlementReportFotShanXiService(user).GetReportData(emailData, userAssetUnits, template); + new SettlementReportFotShanXiService(user).GenerateFileEntry(report, "excel"); } } diff --git a/YLErpWeb/Hubs/TradeConfirmSendOAHub.cs b/YLErpWeb/Hubs/TradeConfirmSendOAHub.cs new file mode 100644 index 00000000..fea2f3cf --- /dev/null +++ b/YLErpWeb/Hubs/TradeConfirmSendOAHub.cs @@ -0,0 +1,99 @@ +using Microsoft.AspNetCore.SignalR; +using YLErp.DBModels; +using YLErp.Enums; +using YLErp.MailKit; +using YLErp.Model; +using YLErp.Modules.RiskModule; +using YLErp.Modules.SwapModule; +using YLErp.Modules.TradeModule; +using static YLErp.ConsGlobal; + +namespace YLErp.Web.Hubs +{ + public class TradeConfirmSendOAHub : Hub + { + private static bool isProcessing = false; + protected static IYcLogger Log = LogFactory.GetLogger(typeof(TradeConfirmSendOAHub).FullName); + static readonly Dictionary _dic = new Dictionary(StringComparer.OrdinalIgnoreCase); + private static readonly Dictionary _clientProgressDic = new Dictionary(); + + public async Task StartProcessing(string jsonString) + { + var req = JsonHelper.Deserialize(jsonString); + var client = Clients.Caller; + + if (Context.User == null) + { + await client.SendAsync("ExceptionMessage", "登录已失效,请重新登录"); + return; + } + + var user = Server.CacheProvider.Get("loginUser^" + Context.User.GetUserId()) as UserInfo; + if (user == null) + { + await client.SendAsync("ExceptionMessage", "登录已失效,请重新登录"); + return; + } + + if (isProcessing) + { + await client.SendAsync("ExceptionMessage", "正在发送OA,请稍后再试"); + return; + } + isProcessing = true; + + try + { + await ProcessOAByIds(req.ids.ToString(), user); + isProcessing = false; + await Clients.Caller.SendAsync("ProcessCompleted", ""); + } + catch (Exception ex) + { + Log.Error(ex.Message, ex); + isProcessing = false; + await Clients.Caller.SendAsync("ExceptionMessage", ex.Message); + } + } + + private async Task ProcessOAByIds(string idsJson, UserInfo user) + { + var ids = JsonHelper.Deserialize>(idsJson); + + foreach (var id in ids) + { + var key = id.ToString(); + _clientProgressDic[key] = "提交中"; + await Clients.All.SendAsync("UpdateProgress", GetUpdateProcess(key, "提交中")); + var result = await ProcessSingleOA(id, user); + _clientProgressDic[key] = result; + await Clients.All.SendAsync("UpdateProgress", GetUpdateProcess(key, result)); + } + } + private async Task ProcessSingleOA(int id, UserInfo user) + { + try + { + var oaService = new TradeOAService(user); + var result = await oaService.ProcessSingleOAAsync(id); + + return result.Success ? "提交成功" : result.Message; + } + catch (Exception ex) + { + Log.Error($"处理交易ID {id} 的OA时发生错误: {ex.Message}", ex); + return $"提交失败: {ex.Message}"; + } + } + + private string GetUpdateProcess(string key, string msg) + { + var resp = new + { + key = key, + send_oa_result = msg + }; + return JsonHelper.Serialize(resp); + } + } +} \ No newline at end of file diff --git a/YLErpWeb/Program.cs b/YLErpWeb/Program.cs index 10ea1e48..a694469d 100644 --- a/YLErpWeb/Program.cs +++ b/YLErpWeb/Program.cs @@ -1,4 +1,4 @@ -using Microsoft.AspNetCore.Http.Features; +using Microsoft.AspNetCore.Http.Features; using Microsoft.AspNetCore.ResponseCompression; using Microsoft.AspNetCore.StaticFiles; using Microsoft.Extensions.FileProviders; @@ -150,7 +150,8 @@ try { endpoints.MapHub("/swapflow/combookinghub"); // 映射Hub路径 endpoints.MapHub("/swapflow/resethub"); // 映射Hub路径 - endpoints.MapHub("/tradeconfirm/sendemailhub"); // 映射Hub路径 + endpoints.MapHub("/tradeconfirm/sendemailhub"); // 映射Hub路径 + endpoints.MapHub("/tradeconfirm/sendoahub"); // 映射OA Hub路径 }); var provider = new FileExtensionContentTypeProvider(); provider.Mappings[".pdf"] = "application/pdf"; diff --git a/YLErpWeb/Views/System/UserEdit.cshtml b/YLErpWeb/Views/System/UserEdit.cshtml index 57252de2..85e60d8a 100644 --- a/YLErpWeb/Views/System/UserEdit.cshtml +++ b/YLErpWeb/Views/System/UserEdit.cshtml @@ -133,6 +133,7 @@ @Html.MyTextFor(model => model.Mobile) @Html.MyTextFor(model => model.Tel) @Html.MyTextFor(model => model.QQ) + @Html.MyTextFor(model => model.OaAccount) @if (ConsUserGroup.HasGroup) { diff --git a/YLErpWeb/Views/System/UserIndex.cshtml b/YLErpWeb/Views/System/UserIndex.cshtml index 1f0e831d..a012d7be 100644 --- a/YLErpWeb/Views/System/UserIndex.cshtml +++ b/YLErpWeb/Views/System/UserIndex.cshtml @@ -64,6 +64,7 @@ { name: 'Tel', label: "座机", index: 'Tel', width: 100 }, { name: 'Mobile', label: "手机", index: 'Mobile', width: 100 }, { name: 'QQ', label: "QT", index: 'QQ', width: 100 }, + { name: 'OaAccount', label: "OA账号", index: 'OaAccount', width: 100 }, { name: 'UserGroup', label: "用户组", sortable: false, width: 150, hide: page.HasGroup, optionHide: page.HasGroup }, { name: 'Roles', label: "角色", sortable: false, align: 'left', width: 200 }, { name: 'AccountPost', label: "账号岗位", sortable: false, align: 'left', width: 200 }, diff --git a/YLErpWeb/Views/System/UserView.cshtml b/YLErpWeb/Views/System/UserView.cshtml index 03f3ce51..ba95f6aa 100644 --- a/YLErpWeb/Views/System/UserView.cshtml +++ b/YLErpWeb/Views/System/UserView.cshtml @@ -37,6 +37,7 @@ @Html.MyDisplayFor(m => m.Mobile) @Html.MyDisplayFor(m => m.Tel) @Html.MyDisplayFor(m => m.QQ) + @Html.MyDisplayFor(m => m.OaAccount) @if (ConsUserGroup.HasGroup) { diff --git a/YLErpWeb/Views/TradeConfirmBook/ConfirmBookListByClient.cshtml b/YLErpWeb/Views/TradeConfirmBook/ConfirmBookListByClient.cshtml index c2197733..dae3ef1a 100644 --- a/YLErpWeb/Views/TradeConfirmBook/ConfirmBookListByClient.cshtml +++ b/YLErpWeb/Views/TradeConfirmBook/ConfirmBookListByClient.cshtml @@ -69,6 +69,7 @@ } @MyControls.Btn("批量下载交易确认书", "BatchDownLoadDoc()") 批量发送邮件 + 批量发送OA @if (PS.GetErpConfig().IsAutoSealAndUploadFiles && !PS.GetErpConfig().IsAutoSealAfterGeneratedBook) { @MyControls.Btn("批量确认书用印", "BatchSealContracts()") diff --git a/YLErpWeb/Views/client/clientRiskMonitorBatchSend.cshtml b/YLErpWeb/Views/client/clientRiskMonitorBatchSend.cshtml index 91e0fbe4..9f5bce40 100644 --- a/YLErpWeb/Views/client/clientRiskMonitorBatchSend.cshtml +++ b/YLErpWeb/Views/client/clientRiskMonitorBatchSend.cshtml @@ -77,12 +77,7 @@ var balanceTemplate = $("#setTemplate").val(); if (thisObj.Model.HasTradeDetails || thisObj.Model.HasTradeMarketReport) { main.post("/client/BatchDownloadClientRiskMonitor", { input: thisObj.Model, balanceTemplate: balanceTemplate, detailTemplate: detailTemplate}).done(function (res) { - if (thisObj.Model.HasTradeDetails) { - window.open(res.obj.detailsZipFile); - } - if (thisObj.Model.HasTradeMarketReport) { - window.open(res.obj.marketZipFile); - } + window.open(res.obj.marketZipFile); });; } else { diff --git a/YLErpWeb/appsettings.local.json b/YLErpWeb/appsettings.local.json index 4463f59d..4e435ca1 100644 --- a/YLErpWeb/appsettings.local.json +++ b/YLErpWeb/appsettings.local.json @@ -1,32 +1,32 @@ { - "Logging": { - "LogLevel": { - "Default": "Information", - "Microsoft.AspNetCore": "Warning" - } - }, - "AllowedHosts": "*", - "ConnectionStrings": { - "ylcms": "server=139.196.109.225;uid=root;pooling=true;port=3306;pwd=Midnight001!@#$;database=yltrs_ylcms;charset=utf8;Allow User Variables=True;SslMode=none;Connection Timeout=30;IgnoreCommandTransaction=true;", - "yladmin": "server=139.196.109.225;uid=root;pooling=true;port=3306;pwd=Midnight001!@#$;database=yltrs_admin;charset=utf8;Allow User Variables=True;SslMode=none;Connection Timeout=30;IgnoreCommandTransaction=true;", - "ylclient": "server=139.196.109.225;uid=root;pooling=true;port=3306;pwd=Midnight001!@#$;database=yltrs_client;charset=utf8;Allow User Variables=True;SslMode=none;Connection Timeout=30;IgnoreCommandTransaction=true;", - "bondoms": "server=139.196.109.225;uid=root;pooling=true;port=3306;pwd=Midnight001!@#$;database=bond_oms;charset=utf8;Allow User Variables=True;SslMode=none;Connection Timeout=30;IgnoreCommandTransaction=true;" - // "apex_oracle": "Data Source=(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)(HOST=122.112.205.57)(PORT=11521)))(CONNECT_DATA=(SERVICE_NAME=xe)));User ID=system;Password=oracle;" - }, - "AppSettings": { - "VirtualPathRoot": "", - "UseRightAligned": "", - "PluginFolder": "D:\\gitCode\\zszq-trs\\Plugins\\build\\ZheShang\\Debug\\net6.0" - }, - "LibreOffice": { - "ExePath": "", - "UserInstallation": "" - }, - "EPPlus": { - "ExcelPackage": { - "LicenseContext": "NonCommercial" //The license context used - } - }, + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + }, + "AllowedHosts": "*", + "ConnectionStrings": { + "ylcms": "server=139.196.109.225;uid=root;pooling=true;port=3306;pwd=Midnight001!@#$;database=yltrs_ylcms;charset=utf8;Allow User Variables=True;SslMode=none;Connection Timeout=30;IgnoreCommandTransaction=true;", + "yladmin": "server=139.196.109.225;uid=root;pooling=true;port=3306;pwd=Midnight001!@#$;database=yltrs_admin;charset=utf8;Allow User Variables=True;SslMode=none;Connection Timeout=30;IgnoreCommandTransaction=true;", + "ylclient": "server=139.196.109.225;uid=root;pooling=true;port=3306;pwd=Midnight001!@#$;database=yltrs_client;charset=utf8;Allow User Variables=True;SslMode=none;Connection Timeout=30;IgnoreCommandTransaction=true;", + "bondoms": "server=139.196.109.225;uid=root;pooling=true;port=3306;pwd=Midnight001!@#$;database=bond_oms;charset=utf8;Allow User Variables=True;SslMode=none;Connection Timeout=30;IgnoreCommandTransaction=true;" + // "apex_oracle": "Data Source=(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)(HOST=122.112.205.57)(PORT=11521)))(CONNECT_DATA=(SERVICE_NAME=xe)));User ID=system;Password=oracle;" + }, + "AppSettings": { + "VirtualPathRoot": "", + "UseRightAligned": "", + "PluginFolder": "D:\\project\\zsza-trs\\Plugins\\build\\ZheShang\\Debug\\net6.0" + }, + "LibreOffice": { + "ExePath": "", + "UserInstallation": "" + }, + "EPPlus": { + "ExcelPackage": { + "LicenseContext": "NonCommercial" //The license context used + } + }, "KafkaConfig": { "BootstrapServers": "139.196.109.225:9092", // Kafka 集群的地址 "Acks": -1, // 消息确认方式,可以是 All(-1)、Leader(1)、None(0) 中的一种 @@ -65,14 +65,21 @@ "YiLian_HolidayResetGroupId": "YiLian_HedgingOrderGroup1", //交易日历缓存重新加载消费 Group "YiLian_SwapFlowTopic": "YiLian_SwapFlow", //交易端同步流水 "YiLian_SwapFlowGroup": "YiLian_SwapFlowGroup1", //交易端同步流水消费组 - "YiLian_SysUserInfoChangeTopic": "YiLian_SysUserInfoChangeTopic"//管理端系统用户变更 + "YiLian_SysUserInfoChangeTopic": "YiLian_SysUserInfoChangeTopic" //管理端系统用户变更 }, - "BondOmsInterface": { - "BaseUrl": "http://trs.yiliantech.com:8080/trs_hub_api" - }, - "OrcaleDatabaseConfig": { - "Schema": "APEX_040000" - }, - "SendKafakaCron": "10 0 * * *", - "MaxThreadPercent": 0.6 //占系统资源最多60%的线程数量 + "BondOmsInterface": { + "BaseUrl": "http://trs.yiliantech.com:8080/trs_hub_api" + }, + "OrcaleDatabaseConfig": { + "Schema": "APEX_040000" + }, + "SendKafakaCron": "10 0 * * *", + "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自动发送下一步 + } } diff --git a/YLErpWeb/wwwroot/Scripts/app/trade/tradeConfirmBookListByClient.js b/YLErpWeb/wwwroot/Scripts/app/trade/tradeConfirmBookListByClient.js index ae3018bb..63a535ab 100644 --- a/YLErpWeb/wwwroot/Scripts/app/trade/tradeConfirmBookListByClient.js +++ b/YLErpWeb/wwwroot/Scripts/app/trade/tradeConfirmBookListByClient.js @@ -37,6 +37,16 @@ const colModelGrid = (new function () { return html; } }, + { label: 'OA状态', name: 'OAStatus', width: 100, align: 'center' }, + { label: 'OA-URL', name: 'OAURL', width: 150, align: 'center', + formatter: function (cellValue, options, rowObject) { + if (cellValue && cellValue.length > 0) { + return '查看'; + } + return ''; + } + }, + { label: 'OA消息', name: 'OAMessage', width: 150, align: 'left' }, { label: '交易数量', name: 'tradeCount', width: 80, align: 'center' }, { label: 'tradeIds', name: 'tradeIds', hidden: true, optionHide: true }]; this.upload = function (encryptId, sendMail) { @@ -156,6 +166,7 @@ $(function () { // $("#batchSendMailBtn").click(BatchSendMail); initJqGrid(); SendEmailHub() + SendOAHub(); // 初始化OA发送功能 }); // 初始化jqGrid函数 @@ -244,8 +255,12 @@ function showToolName(cellValue, options, rowObject) { html += "" .template(rowObject.EncryptId, "发送Email"); } - var canUpload = page.canGenerate == true && rowObject.ContractDocUrl ? "" : "disabled"; + var canUpload = page.canGenerate == true && rowObject.ContractDocUrl ? "" : "disabled"; html += "".template(rowObject.ContractCode, canUpload); + + // 添加发送OA按钮 + html += "" + .template(rowObject.id); return html; } @@ -597,7 +612,147 @@ function SendEmailHub() { }, 3000); // 3秒 }); } +function SendOAHub() { + // 创建SignalR连接并连接到服务器上的Hub + var connection = new signalR.HubConnectionBuilder() + .withUrl('/tradeconfirm/sendoahub') + .withAutomaticReconnect() + .build(); + connection.start() + .then(function () { + $("#batchSendOA").click(function () { + var jgrid = jQuery('#listGrid'); + var rowIds = jgrid.jqGrid('getGridParam', 'selarrrow'); + if (rowIds.length == 0) { + main.alert("请至少选择一笔交易"); return; + } + + // 检查选中的行中是否有无确认书的情况 + var hasNoConfirmBook = false; + var hasOAStatus = false; + var ids = []; + var contractCodes = []; + + rowIds.forEach((v, i, arr) => { + var rowId = v; + var data = jgrid.jqGrid('getRowData', rowId); + if (data.id) { + ids.push(data.id); + contractCodes.push(data.ContractCode); + + // 检查是否有无确认书的情况 + if (!data.ContractCode) { + hasNoConfirmBook = true; + } + + // 检查是否有已发送OA的情况 + if (data.OAStatus && data.OAStatus !== "") { + hasOAStatus = true; + } + } + }); + + // 根据不同情况显示不同提示 + if (hasNoConfirmBook) { + main.confirm("选中的交易中有无确认书附件的情况,确定提交OA吗?", function() { + batchSubmitOA(connection, ids); + }); + } else if (hasOAStatus) { + main.confirm("选中的交易中有已经提交过OA的情况,确定再次提交新的OA吗?", function() { + batchSubmitOA(connection, ids); + }); + } else { + // 有确认书且OA状态为未发送过:无提示,直接在OA中起草内容 + batchSubmitOA(connection, ids); + } + }); + + // 批量提交OA的函数 + function batchSubmitOA(connection, ids) { + var req = { + ids: ids, + } + connection.invoke('StartProcessing', JSON.stringify(req)); + main.waitMe(true); + } + }).catch(function (error) { + console.error(error); + }); + // 监听服务器发送的消息。 + connection.on('UpdateProgress', function (msg) { + if (msg != null && msg != '') { + let jsonObject = JSON.parse(msg); + SearchClick(true); // 刷新列表 + } + }); + // 监听服务器发送的异常消息。 + connection.on('ExceptionMessage', function (msg) { + if (msg.indexOf("正在发送OA") < 0) { + main.waitMe(false); + SearchClick(true); + } + main.alert(msg); + }); + // 监听服务器发送的完成消息。 + connection.on('ProcessCompleted', function () { + main.alert("OA发送处理完毕"); + main.waitMe(false); + SearchClick(true); + }); + // 监听连接关闭,启动重连 + connection.onclose(async (error) => { + console.log("连接断开"); + // 等待3秒后尝试重新连接 + setTimeout(async () => { + try { + await connection.start(); + console.log("已重新连接"); + } catch (err) { + console.error("重新连接失败: ", err); + } + }, 3000); // 3秒 + }); +} +// 单个发送OA函数 +function sendOA(id) { + // 获取当前行数据 + var jgrid = jQuery('#listGrid'); + var rowData = jgrid.jqGrid('getRowData', id); + + if (!rowData) return; + + var tradeIdArray = rowData.tradeIds ? rowData.tradeIds.split(",") : []; + if (tradeIdArray.length === 0) return; + + // 根据不同情况显示不同提示 + if (!rowData.ContractCode) { + // 无确认书:提示用户 + main.confirm("目前无确认书附件,确定提交OA吗?", function() { + submitOA(id); + }); + } else if (!rowData.OAStatus || rowData.OAStatus === "") { + // 有确认书,OA状态为未发送过:无提示,直接在OA中起草内容 + submitOA(id); + } else { + // OA状态已经有值:提示用户是否再次提交 + main.confirm("已经提交过OA,确定再次提交一笔新的OA吗?", function() { + submitOA(id); + }); + } +} + +// 提交OA请求 +function submitOA(id) { + var req = { + id: id + }; + main.post("/TradeConfirmBook/SendOA", req).done(function (res) { + SearchClick(true); + }).fail(function (xhr, status, error) { + SearchClick(true); + }); +} function openWindowWithPost(url, data) { var form = document.createElement("form"); form.target = "_blank"; diff --git a/YLWinSer/RealTimeCalcPositionService/ClientNoDMABalanceTask.cs b/YLWinSer/RealTimeCalcPositionService/ClientNoDMABalanceTask.cs index 10262f01..b0cd9f53 100644 --- a/YLWinSer/RealTimeCalcPositionService/ClientNoDMABalanceTask.cs +++ b/YLWinSer/RealTimeCalcPositionService/ClientNoDMABalanceTask.cs @@ -55,8 +55,6 @@ namespace RealTimeCalcPositionService { try { - using var clientDb = new ClientDBContext(); - var clients= clientDb.client.ToList(); //系统交易日 var valuedate = valuedateBLL.ValueDate; var clientSettles = new RealTimeClientBanlanceService(new OptUserInfo(0, "实时客户资金服务", OptUserFrom.Service)).GetBalances(); diff --git a/YLWinSer/RealTimeCalcPositionService/Program.cs b/YLWinSer/RealTimeCalcPositionService/Program.cs index 873c3f92..b72d12e5 100644 --- a/YLWinSer/RealTimeCalcPositionService/Program.cs +++ b/YLWinSer/RealTimeCalcPositionService/Program.cs @@ -6,6 +6,7 @@ using YLErp; using YLErp.Abstract; using YLErp.Helpers; using YLErp.Model; +using static alglib; internal class Program { @@ -28,6 +29,7 @@ internal class Program services.AddHostedService(); services.AddHostedService(); services.AddHostedService(); + }).ConfigureLogging(logging => { logging.ClearProviders(); @@ -35,8 +37,7 @@ internal class Program }) .UseNLog() .Build(); - - //YLServiceLocator.SetServiceProvider(host.Services); + YLServiceLocator.SetServiceProvider(host.Services); await host.RunAsync(); }