using BaseOUDAL; using Newtonsoft.Json.Linq; using System.Data.SqlTypes; using System.Text; using System.Text.RegularExpressions; using YLErp.Abstract; using YLErp.BLL; using YLErp.BLL.EodSettlement; using YLErp.Commons; using YLErp.Configuration; using YLErp.Core.Helpers; using YLErp.DBModels.Enums; using YLErp.Helpers; using YLErp.Model; using YLErp.Model.Enum; using YLErp.Modules.DataCacheModule; using YLErp.Modules.ReportModule; using YLErp.Modules.SwapModule; using YLErp.Office; using YLErp.Office.Converters; namespace YLErp.Modules.ClientModule { /// /// 客户出入金服务 /// public class ClientCashInCashOutDataService : YLBaseService { public ClientCashInCashOutDataService(YLBaseService baseService) : base(baseService) { } public ClientCashInCashOutDataService(OptUserInfo userInfo) : base(userInfo) { } public HandleResult ImportClientBalanceGap(Stream stream, bool IsMargin) { var rows = new YLErp.Commons.ExcelHelper().ExcelToDataTable(stream, null, true); var clientNumber = string.Empty; ClientBalanceGapReq record; var records = new List(); var rowNum = 0; for (var i = 0; i < rows.Rows.Count; i++) { rowNum = i + 1; record = new ClientBalanceGapReq(); for (var j = 0; j < rows.Columns.Count; j++) { switch (rows.Columns[j].ColumnName) { case "客户编号": clientNumber = rows.Rows[i][j].ToString(); break; case "客户名称": record.ClientName = rows.Rows[i][j].ToString(); break; case "调整日期": if (DateTime.TryParse(rows.Rows[i][j].ToString(), out var date)) { record.ValueDate = date; } else { return "第" + rowNum + "行结束时间格式不对,导入失败"; } break; case "出金入金": if (string.IsNullOrWhiteSpace(rows.Rows[i][j].ToString()) || IsMargin) { record.NetFund = 0; } else if (double.TryParse(rows.Rows[i][j].ToString(), out var netFund)) { record.NetFund = netFund; } else { return "第" + rowNum + "行出金入金格式不对,导入失败"; } break; case "成交收支": if (string.IsNullOrWhiteSpace(rows.Rows[i][j].ToString()) || IsMargin) { record.OptionPremium = 0; } else if (double.TryParse(rows.Rows[i][j].ToString(), out var optionPremium)) { record.OptionPremium = optionPremium; } else { return "第" + rowNum + "行成交收支格式不对,导入失败"; } break; case "了结收支": if (string.IsNullOrWhiteSpace(rows.Rows[i][j].ToString()) || IsMargin) { record.SettlementBalance = 0; } else if (double.TryParse(rows.Rows[i][j].ToString(), out var settlementBalance)) { record.SettlementBalance = settlementBalance; } else { return "第" + rowNum + "行了结收支格式不对,导入失败"; } break; case "票息": if (string.IsNullOrWhiteSpace(rows.Rows[i][j].ToString()) || IsMargin) { record.Coupon = 0; } else if (double.TryParse(rows.Rows[i][j].ToString(), out var coupon)) { record.Coupon = coupon; } else { return "第" + rowNum + "行票息格式不对,导入失败"; } break; case "互换收支": if (string.IsNullOrWhiteSpace(rows.Rows[i][j].ToString()) || IsMargin) { record.SwapBalance = 0; } else if (double.TryParse(rows.Rows[i][j].ToString(), out var swapBalance)) { record.SwapBalance = swapBalance; } else { return "第" + rowNum + "行互换收支格式不对,导入失败"; } break; case "其他收支": if (string.IsNullOrWhiteSpace(rows.Rows[i][j].ToString()) || IsMargin) { record.OtherFund = 0; } else if (double.TryParse(rows.Rows[i][j].ToString(), out var otherFund)) { record.OtherFund = otherFund; } else { return "第" + rowNum + "行其他收支格式不对,导入失败"; } break; case "期末结存": if (string.IsNullOrWhiteSpace(rows.Rows[i][j].ToString()) || IsMargin) { record.ToDayRemainFund = 0; } else if (double.TryParse(rows.Rows[i][j].ToString(), out var toDayRemainFund)) { record.ToDayRemainFund = toDayRemainFund; } else { return "第" + rowNum + "行期末结存格式不对,导入失败"; } break; case "授信额度": if (string.IsNullOrWhiteSpace(rows.Rows[i][j].ToString()) || IsMargin) { record.Credit = 0; } else if (double.TryParse(rows.Rows[i][j].ToString(), out var credit)) { record.Credit = credit; } else { return "第" + rowNum + "行授信额度格式不对,导入失败"; } break; case "应付了交易结款": if (string.IsNullOrWhiteSpace(rows.Rows[i][j].ToString()) || IsMargin) { record.ClosedTradePayableFund = 0; } else if (double.TryParse(rows.Rows[i][j].ToString(), out var closedTradePayableFund)) { record.ClosedTradePayableFund = closedTradePayableFund; } else { return "第" + rowNum + "行应付了交易结款格式不对,导入失败"; } break; case "应付存续交易款": if (string.IsNullOrWhiteSpace(rows.Rows[i][j].ToString()) || IsMargin) { record.PositionTradePayableFund = 0; } else if (double.TryParse(rows.Rows[i][j].ToString(), out var positionTradePayableFund)) { record.PositionTradePayableFund = positionTradePayableFund; } else { return "第" + rowNum + "行应付存续交易款格式不对,导入失败"; } break; case "追保金额": if (string.IsNullOrWhiteSpace(rows.Rows[i][j].ToString()) || IsMargin) { record.MarginByPayableMargin = 0; } else if (double.TryParse(rows.Rows[i][j].ToString(), out var marginByPayableMargin)) { record.MarginByPayableMargin = marginByPayableMargin; } else { return "第" + rowNum + "行追保金额格式不对,导入失败"; } break; case "应付资金总额": if (string.IsNullOrWhiteSpace(rows.Rows[i][j].ToString()) || IsMargin) { record.PayableFund = 0; } else if (double.TryParse(rows.Rows[i][j].ToString(), out var payableFund)) { record.PayableFund = payableFund; } else { return "第" + rowNum + "行应付资金总额格式不对,导入失败"; } break; case "实现盈亏": if (string.IsNullOrWhiteSpace(rows.Rows[i][j].ToString()) || IsMargin) { record.WinLoss = 0; } else if (double.TryParse(rows.Rows[i][j].ToString(), out var winLoss)) { record.WinLoss = winLoss; } else { return "第" + rowNum + "行实现盈亏格式不对,导入失败"; } break; case "持仓盈亏": if (string.IsNullOrWhiteSpace(rows.Rows[i][j].ToString()) || IsMargin) { record.PositionPnl = 0; } else if (double.TryParse(rows.Rows[i][j].ToString(), out var positionPnl)) { record.PositionPnl = positionPnl; } else { return "第" + rowNum + "行持仓盈亏格式不对,导入失败"; } break; case "持仓市值": if (string.IsNullOrWhiteSpace(rows.Rows[i][j].ToString()) || IsMargin) { record.PositionPv = 0; } else if (double.TryParse(rows.Rows[i][j].ToString(), out var positionPv)) { record.PositionPv = positionPv; } else { return "第" + rowNum + "行持仓市值格式不对,导入失败"; } break; case "预付金占用": if (double.TryParse(rows.Rows[i][j].ToString(), out var payableMargin)) { record.PayableMargin = payableMargin; } else { return "第" + rowNum + "行预付金格式不对,导入失败"; } break; default: break; } } if (string.IsNullOrWhiteSpace(record.ClientName)) { if (string.IsNullOrWhiteSpace(clientNumber)) { return "第" + rowNum + "行客户编码和名称都为空,导入失败"; } else { var client = DataCacheProvider.GetClientDataSource().AsQueryable().Where(o => o.Number == clientNumber).FirstOrDefault(); if (client != null) { record.ClientName = client.Name; } else { return "第" + rowNum + "行客户不存在,导入失败"; } } } else { var client = ClientDataQueryService.GetClient(record.ClientName); if (client == null) { return "第" + rowNum + "行客户不存在,导入失败"; } } record.IsImportOuterMargin = IsMargin; records.Add(record); } if (records.Count() > 0) { foreach (var item in records) { ClientBalanceGapApi(item); } } else { return "未在文件中找到记录"; } return HandleResult.Success; } public void ClientBalanceGapApi(ClientBalanceGapReq req) { if (req == null) { throw new ServiceException("数据不能为空"); } if (req.ClientName == null) { throw new ServiceException("客户名称不能为空"); } if (req.ValueDate == DateTime.MinValue) { throw new ServiceException("结束日期不能为空"); } var Clieninfo = ClientDataQueryService.GetClient(req.ClientName); if (Clieninfo == null) { throw new ServiceException("客户不存在"); } if (req.ToDayRemainFund == null || req.ToDayRemainFund == 0) { req.ToDayRemainFund = req.NetFund + req.OptionPremium + req.SettlementBalance + req.Coupon + req.SwapBalance + req.OtherFund; } if (req.PayableFund == null || req.PayableFund == 0) { req.PayableFund = req.ClosedTradePayableFund + req.PositionTradePayableFund + req.MarginByPayableMargin; } var IsClientbalanceGap = DbContext.ClientBalanceGap.Where(c => c.ClientId == Clieninfo.id && c.ValueDate == req.ValueDate && c.IsImportOuterMargin == req.IsImportOuterMargin).FirstOrDefault(); if (IsClientbalanceGap == null) { IsClientbalanceGap = new ClientBalanceGap(); DbContext.ClientBalanceGap.Add(IsClientbalanceGap); } IsClientbalanceGap.ClientId = Clieninfo.id; IsClientbalanceGap.ValueDate = req.ValueDate; IsClientbalanceGap.NetFund = req.NetFund; IsClientbalanceGap.OptionPremium = req.OptionPremium; IsClientbalanceGap.SettlementBalance = req.SettlementBalance; IsClientbalanceGap.Coupon = req.Coupon; IsClientbalanceGap.SwapBalance = req.SwapBalance; IsClientbalanceGap.OtherFund = req.OtherFund; IsClientbalanceGap.ToDayRemainFund = req.ToDayRemainFund; IsClientbalanceGap.Credit = req.Credit; IsClientbalanceGap.ClosedTradePayableFund = req.ClosedTradePayableFund; IsClientbalanceGap.PositionTradePayableFund = req.PositionTradePayableFund; IsClientbalanceGap.MarginByPayableMargin = req.MarginByPayableMargin; IsClientbalanceGap.PayableFund = req.PayableFund; IsClientbalanceGap.WinLoss = req.WinLoss; IsClientbalanceGap.PositionPnl = req.PositionPnl; IsClientbalanceGap.PositionPv = req.PositionPv; IsClientbalanceGap.PayableMargin = req.PayableMargin; IsClientbalanceGap.IsImportOuterMargin = req.IsImportOuterMargin; DbContext.SaveChanges(); } /// /// 客户抵押品确认操作 /// /// public void ExcuteClientCashInCashOutProduc(IEnumerable entryids) { var entrys = DbContext.clientcashincashout_product.Where(e => entryids.Contains(e.id) && !ClientCashInCashOut.已确认.Equals(e.OptStatus)).OrderBy(t => t.OptDate).ToList(); var clientIds = entrys.Select(t => t.ClientId).Distinct().ToList(); //当前抵押且执行的抵押品记录(包含抵押执行状态的记录和赎回待执行或者赎回拒绝的记录) var entrysExecutedProduct = DbContext.clientcashincashout_product.Where(t => (ClientCashInCashOut.已确认.Equals(t.OptStatus) && Clientcashincashout_productStatusEnum.抵押.ToString().Equals(t.Status)) || (t.OptStatus != ClientCashInCashOut.已确认 && Clientcashincashout_productStatusEnum.赎回.ToString().Equals(t.Status))).ToList(); //获取客户信息 var clientList = DbContextFactory.GetClientDbContext(OptUser).client.Where(t => clientIds.Contains(t.id)).ToList(); foreach (var e in entrys) { //当前执行的出入金标的即期价格 e.SpotPrice = DataCacheProvider.GetUnderlyingDataSource().GetData(e.UnderlyingId ?? 0)?.Price; //查看客户是否被冻结需要解冻 if (Clientcashincashout_productStatusEnum.抵押.ToString().Equals(e.Status)) { var client = clientList.FirstOrDefault(t => t.id == e.ClientId); //判断是否为冻结状态 if (client.PendingMarginCallPayment == 1) { //查看当前客户可用资金是否符合出金条件 var clientbalance = ClientBalanceUtility.GetClientBanlances(new List { e.ClientId }, DateTime.MinValue, DateTime.Now.Date).FirstOrDefault(); //如果入金量大于追保金额则更改冻结状态为正常状态 if (!clientbalance.IsMargin(e.SpotPrice * e.ProductAmount * e.Rate ?? 0.0)) { client.PendingMarginCallPayment = 0; } } } e.ExcuteDate = DateTime.Now; e.ExcuteId = UserId; e.ExcuteName = UserName; e.OptStatus = ClientCashInCashOut.已确认; e.OptId = UserId; e.OptName = UserName; e.OptDate = DateTime.Now; DbContext.SaveChanges(); if (Clientcashincashout_productStatusEnum.抵押.ToString().Equals(e.Status)) { entrysExecutedProduct.Add(e); } else { entrysExecutedProduct.Remove(e); } } } /// /// 客户出入金Api /// public ClientCashInCashOut SaveEntryexitApi(SaveEntryexitApiReq req) { if (!req.ClientId.HasValue) { throw new ServiceException("ClientId参数错误"); } var exsist = new ClientDataService(OptUser).ExsistById(req.ClientId.Value); if (!exsist) { throw new ServiceException("ClientId参数错误,未找到对应客户"); } var Bankcard = ClientDataQueryService.GetBankCard(req.ClientId.Value, req.OpenBankCard); if (Bankcard == null) { throw new ServiceException("银行账号未找到"); } var model = new ClientCashInCashOut { ClientId = req.ClientId, ClientName = req.ClientName, Direction = req.Direction, Money = req.Money, OpenBankId = Bankcard.id, OpenBankCard = Bankcard.Card, HappenDate = req.HappenDate, Comments = req.Comments, CashFlag = req.CashFlag, Action = "API" }; return SaveEntryexit(0, model); } /// /// 客户出入金操作 /// public ClientCashInCashOut SaveEntryexit(int? id, ClientCashInCashOut req) { if (req is null) { throw new ArgumentNullException(nameof(req)); } if (!req.Money.HasValue) { throw new ServiceException("金额必须填写"); } if (!req.HappenDate.HasValue || req.HappenDate == DateTime.MinValue) { throw new ServiceException("出入金时间必须填写"); } if (req.Money >= 1000000000000) { throw new ServiceException("金额不能大于一万亿"); } if (req.Money <= 0) { throw new ServiceException("金额必须大于零"); } if (req.HappenDate > DateTime.Now) { throw new ServiceException("出入金时间不能大于当前时间"); } ClientCashInCashOut r; var isAddNew = id == null || id == 0; double? originalMoney = 0; var isARAP = req.Direction == "应收" || req.Direction == "应付"; var aRAPFlag = req.Direction == "应收" ? 1 : -1; string comment = null; if (isAddNew) { r = new ClientCashInCashOut { CreatorId = UserId, CreatorName = UserName, CreateDate = DateTime.Now, OptId = UserId, OptName = UserName, OptDate = DateTime.Now, State = "未确认" }; DbContext.ClientCashInCashOut.Add(r); } else { r = DbContext.ClientCashInCashOut.Find(id); if (r == null) { throw new ServiceException("数据未找到"); } originalMoney = r.ClientId == req.ClientId && r.Direction == "出金" ? r.Money : 0; } var r_copy = r.Clone(); var diffs = new List(); if (r.State != "未确认") { if (r.Comments != req.Comments) { diffs.Add("备注"); r.Comments = req.Comments; } //req.Money = (req.Direction == "其他支出" ? -1 : 1) * req.Money; } else { if (string.IsNullOrEmpty(req.Direction)) { throw new ServiceException("新增资金记录,参数Direction不能为空"); } diffs = GetDiffs(req, r); r.ClientId = req.ClientId; r.Direction = req.Direction; var client = ClientDataQueryService.GetClient(req.ClientId ?? 0, true); r.ClientName = client.Name; r.Money = (req.Direction == "其他支出" ? -1 : 1) * req.Money; r.HappenDate = req.HappenDate; r.OpenBankCard = req.OpenBankCard; r.OpenBankId = req.OpenBankId; r.Comments = req.Comments; r.ClientNumber = client.Number; r.Action = req.Action; r.CashFlag = req.CashFlag; r.CurrencyCode = req.CurrencyCode; r.cash_type = req.cash_type; r.ValidState = ConsGlobal.Valid; r.TransferOutAccount = req.TransferOutAccount; r.TransferInAccount = req.TransferInAccount; } if (isARAP) { r.Direction = ClientCashInCashOut.应收; r.Money *= aRAPFlag; } //应收为正,实收为负 //应付为负,实付为正 else if (req.Direction == "实收预付金" || req.Direction == "实收权利金") { r.Money = -r.Money; } if (isAddNew) { //新增编号 r.Number = UniqueTimeId.GetStr(); } var changecashs = DataChangeHelper.GetDataChanges(r_copy, r); comment = changecashs.ToJson(); if (r.State != "未确认") { var r_copyupdate = r.Clone(); // r_copyupdate.Money = req.Money; r_copyupdate.Comments = req.Comments; //if (req.Direction != null && req.Direction.Contains("其他")) //{ // r_copyupdate.Direction = req.Direction; // r_copyupdate.HappenDate = req.HappenDate; //} changecashs = DataChangeHelper.GetDataChanges(r_copy, r_copyupdate); } comment = changecashs.ToJson(); if (comment == "[]" && diffs.Count() == 0) { return r; } if (req.OpenBankId == null || req.OpenBankId == 0) { r.OpenBankId = null; } #region 出金申请时进行验资 if ("出金".Equals(r.Direction) && valuedateBLL.SystemDate.SpecialOperateForCashOut != 1) { //查看当前客户可用资金是否符合出金条件 var clientbalance = ClientBalanceUtility.GetClientBanlances(new List { r.ClientId.Value }, DateTime.MinValue, DateTime.Now.Date).FirstOrDefault(); // 如果余额为 null,则视为无可用资金 if (clientbalance == null) { clientbalance = new YLErp.Models.ClientSettleBalance(); } //当日可取现金 var availableFund = clientbalance.DesirableFund; //对于0.999999999情况的数据做下处理 var realAvailableFund = Math.Round((availableFund + (originalMoney ?? 0.0)) * Math.Pow(10, 8)) / Math.Pow(10, 8); //如果出金大于可用资金(修改操作时需要算差价)则抛出错误 if (Math.Abs(r.Money ?? 0.0) > realAvailableFund) { var msg = "添加出金失败,客户:" + r.ClientName + " 出金:" + r.Money + " 实际可取出资金:" + (Math.Floor(realAvailableFund * 100) / 100).ToString("0.00") + ";"; throw new ServiceException(msg); } if (r.Money <= clientbalance.VmFundSum) { // 出金金额小于等于 追保账户金额 r.cash_type = CashTypeEnum.追保账户.ToString(); } else if (clientbalance.VmFundSum==0) { r.cash_type = CashTypeEnum.初保账户.ToString(); } else { // 出金金额大于 追保账户金额,首先处理 VM 部分 r.cash_type = CashTypeEnum.追保账户.ToString(); var newMoney = r.Money - clientbalance.VmFundSum; r.Money = clientbalance.VmFundSum; var newR = r.Clone(); newR.id = 0; newR.Money = newMoney; newR.cash_type = CashTypeEnum.初保账户.ToString(); DbContext.ClientCashInCashOut.Add(newR); } } #endregion #region 划转资金时进行验资 if ("划转".Equals(r.Direction)) { var clientbalance = ClientBalanceUtility.GetClientBanlances(new List { r.ClientId.Value }, DateTime.MinValue, DateTime.Now.Date).FirstOrDefault(); if (clientbalance == null) { throw new ServiceException("查询客户资金信息失败"); } var money = r.Money ?? 0; money=isAddNew? money: money-(originalMoney??0); var netFundAll = Math.Round(clientbalance.NetFundAll,2,MidpointRounding.AwayFromZero); var vmFundSum = Math.Round(clientbalance.VmFundSum,2,MidpointRounding.AwayFromZero); var winLoss = Math.Round(clientbalance.WinLoss,2,MidpointRounding.AwayFromZero); if (r.TransferOutAccount == "初保账户" && money > netFundAll) { throw new ServiceException("划转金额不能超过初保账户金额"); } if (r.TransferOutAccount == "追保账户" && money > vmFundSum) { throw new ServiceException("划转金额不能超过追保账户金额"); } if (r.TransferOutAccount == "已实现盈亏" && money > winLoss) { throw new ServiceException("划转金额不能超过已实现盈亏"); } r.cash_type = null; } #endregion if (r.Direction != "出金" && r.Direction != "入金") { r.OpenBank = null; r.OpenBankCard = null; r.OpenBankComments = null; r.OpenBankId = null; } DbContext.SaveChanges(); if (r.State != "未确认" && changecashs.Count > 0 && !(changecashs.Count == 1 && changecashs[0][0] == "Comments")) { } else { if (id == 0 || id == null) { ClientCashLog(r.id, "新增资金"); } else { if (diffs.Count == 1 && diffs[0] == "备注") { ClientCashLog(r.id, "修改备注", comment, req.Explain); } else { ClientCashLog(r.id, "修改资金", comment, req.Explain); } } } return r; } private bool CheckClientCashOut(int ClientId, double Money, string CurrencyCode) { var client = DataCacheProvider.GetClientDataSource().GetData(ClientId); if (client != null && client.BoundSide == BoundSideEnum.南向) { var clientCashes = new EntryExitBLL().getClientCash(ClientId); if (clientCashes.TryGetValue(CurrencyCode, out var remains)) { if (remains >= Money) { return true; } } return false; } return true; } public ClientCashInCashOut saveClientCashInOutComments(int? id, EntryExitReq req) { if (req is null) { throw new ArgumentNullException(nameof(req)); } var r = DbContext.ClientCashInCashOut.Find(id); if (r == null) { throw new ServiceException("数据未找到"); } var r_copy = r.Clone(); r.Comments = req.Comments; DbContext.SaveChanges(); var changecashs = DataChangeHelper.GetDataChanges(r_copy, r); var comment = changecashs.ToJson(); ClientCashLog(r.id, "修改备注", comment, req.Explain); return r; } private List GetDiffs(ClientCashInCashOut newData, ClientCashInCashOut oldData) { var diffs = new List(); if (newData.ClientId != oldData.ClientId) { diffs.Add("客户"); } if (newData.Direction != oldData.Direction) { diffs.Add("方向"); } if (newData.HappenDate != oldData.HappenDate) { diffs.Add("发生日期"); } if (newData.Money != oldData.Money) { diffs.Add("金额"); } if (newData.OpenBankId != oldData.OpenBankId || newData.OpenBankCard != oldData.OpenBankCard) { diffs.Add("银行卡"); } if (newData.Comments != oldData.Comments) { diffs.Add("备注"); } return diffs; } public void ClientCashLog(int CashId, string Type, string changes = null, string explain = null) { DbContext.clientcash_log.Add(new ClientCashLog { CashId = CashId, Changes = changes, OptType = Type, OptId = UserId, OptName = UserName, OptDate = DateTime.Now, Explain = explain }); DbContext.SaveChanges(); } /// /// 客户出入金确认操作 /// /// public void ExcuteEntryExit(IEnumerable entryids, IKafkaProduce kafkaProduce) { var entrys = DbContext.ClientCashInCashOut.Where(e => e.ValidState != "InValid" && entryids.Contains(e.id) && !ClientCashInCashOut.已确认.Equals(e.State)).OrderBy(t => t.OptDate).ToList(); var clientIds = entrys.Select(t => t.ClientId).Distinct().ToList(); //获取客户信息 var clientList = DbContextFactory.GetClientDbContext(OptUser).client.Where(t => clientIds.Contains(t.id)).ToList(); if (entrys.Any(s => s.ApprovalProcess > 0)) { throw new ServiceException("无法对状态为审批中的资金记录进行确认,请到资金审批页面进行资金审批操作!"); } var outCashProcess = GetOutCashProcess(); SwapConsumerService swapConsumerService = new SwapConsumerService(UserInfo); if (kafkaProduce != null) { swapConsumerService.SetKafKaProduce(kafkaProduce); } foreach (var e in entrys) { if (e.Direction == "出金" && outCashProcess.Count > 0) { e.State = ClientCashInCashOut.审批中; e.ApprovalProcess = 1; } else { ExcuteEntryExit(e, clientList); e.State = ClientCashInCashOut.已确认; } e.ApprovalDate= DateTime.Now; e.OptId = UserId; e.OptName = UserName; e.OptDate = DateTime.Now; ClientCashLog(e.id, "确定操作"); DbContext.SaveChanges(); //if (kafkaProduce!=null&& e.State== ClientCashInCashOut.已确认&&(e.Direction=="入金"|| e.Direction == "出金")) //{ // Task.Run(() => // { // swapConsumerService.PushCashToHT(e.id, null) ; // }); //} } } public bool ExcuteEntryExit(int clientList, string auditComments = "") { var entry = DbContext.ClientCashInCashOut.FirstOrDefault(c => c.id == clientList); if (entry == null) { throw new ServiceException("资金记录不存在"); } var res = ExcuteEntryExit(entry, null); var notCanOperateState = new List() { ClientCashInCashOut.已确认, ClientCashInCashOut.拒绝, ClientCashInCashOut.已结算 }; if (notCanOperateState.Contains(entry.State)) { throw new ServiceException("已确认、拒绝、已结算的记录不能再次确认"); } entry.State = ClientCashInCashOut.已确认; entry.OptId = UserId; entry.OptName = UserName; entry.OptDate = DateTime.Now; entry.ApprovalProcess = Convert.ToInt32(PStatusEnum.pass); entry.ApprovalDate = DateTime.Now; ClientCashLog(entry.id, "确定操作", auditComments); DbContext.SaveChanges(); return res; } private bool ExcuteEntryExit(ClientCashInCashOut e, IEnumerable clientList) { //查看客户是否被冻结需要解冻 if ("入金".Equals(e.Direction) || ("应收".Equals(e.Direction) && ClientCashInCashOut.人工操作_预付金.Equals(e.Action))) { var client = clientList != null ? clientList.FirstOrDefault(t => t.id == e.ClientId) : DbContextFactory.GetClientDbContext(OptUser).client.Find(e.ClientId ?? 0); if (client == null) { throw new ServiceException("客户信息不存在"); } //判断是否为冻结状态 if (client.PendingMarginCallPayment == 1) { var clientbalance = ClientBalanceUtility.GetClientBanlances(new List { e.ClientId.Value }, DateTime.MinValue, DateTime.Now.Date).FirstOrDefault(); //如果入金量大于追保金额则更改冻结状态为正常状态 if (!clientbalance.IsMargin(e.Money ?? 0.0)) { client.PendingMarginCallPayment = 0; } } } //else if ((("出金".Equals(e.Direction) && PS.Config.Company != Configuration.CompanyEnum.中金) || ("应付".Equals(e.Direction) && ClientCashInCashOut.人工操作_预付金.Equals(e.Action))) && valuedateBLL.SystemDate.SpecialOperateForCashOut != 1 && PS.Config.Company != Configuration.CompanyEnum.中金) //{ // //查看当前客户可用资金是否符合出金条件 // var clientbalance = ClientBalanceUtility.GetClientBanlances(new List { e.ClientId.Value }, DateTime.MinValue, DateTime.Now.Date).FirstOrDefault(); // //当日可取现金 // var availableFund = clientbalance == null ? 0 : clientbalance.DesirableFund; // //对于0.999999999情况的数据做下处理 // var realAvailableFund = Math.Round((availableFund + (e.Money??0)) * Math.Pow(10, 8)) / Math.Pow(10, 8); // //如果当前出金金额大于可用资金(不扣除冻结出金部分)则抛出错误 // if (Math.Abs(e.Money ?? 0) > realAvailableFund) // { // if ("出金".Equals(e.Direction)) // { // throw new ServiceException($"部分确认错误 客户:{e.ClientName},出金:{e.Money},实际可取出资金:{realAvailableFund:0.00};"); // } // throw new ServiceException($"部分确认错误,客户:{e.ClientName},应付预付金:{Math.Abs(e.Money ?? 0)},实际可取出资金:{realAvailableFund:0.00};"); // } //} return true; } /// /// 客户出入金拒绝操作 /// public StringBuilder ClientCashInCashOutReject(IEnumerable entryids) { var sbmsg = new StringBuilder(); var entrys = DbContext.ClientCashInCashOut.Where(e => entryids.Contains(e.id)).ToList(); if (entrys.Any(s => s.ApprovalProcess > 0)) { throw new ServiceException("无法对状态为审批中的资金记录进行拒绝,请到资金审批页面进行资金审批操作!"); } entrys.ForEach(e => { if (!ClientCashInCashOutReject(e)) { sbmsg.AppendLine($"{e.Number}方向为{e.Direction}不能拒绝"); } }); DbContext.SaveChanges(); if (sbmsg.Length > 0) { sbmsg.AppendLine("拒绝失败"); } else { sbmsg.AppendLine("拒绝成功"); } return sbmsg; } public bool ClientCashInCashOutReject(int entryid) { var entry = DbContext.ClientCashInCashOut.FirstOrDefault(e => e.id == entryid); if (entry == null) { throw new ServiceException("资金记录不存在"); } var res = ClientCashInCashOutReject(entry); if (!res) { throw new ServiceException($"{entry.Number}方向为{entry.Direction}不能拒绝"); } DbContext.SaveChanges(); return res; } private bool ClientCashInCashOutReject(ClientCashInCashOut e, string auditComments = "") { if (EntryExitBLL.EntryDirection_Menu.Contains(e.Direction) || ClientCashInCashOut.人工操作_预付金.Equals(e.Action)) { var notCanOperateState = new List() { ClientCashInCashOut.已确认, ClientCashInCashOut.拒绝, ClientCashInCashOut.已结算 }; if (notCanOperateState.Contains(e.State)) { throw new ServiceException("已确认、拒绝、已结算的记录不能再次拒绝"); } e.State = "拒绝"; e.OptId = UserId; e.OptName = UserName; e.OptDate = DateTime.Now; e.ApprovalProcess = Convert.ToInt32(PStatusEnum.reject); e.ApprovalDate = DateTime.Now; ClientCashLog(e.id, "拒绝操作", auditComments); return true; } return false; } public List GetClientCashInCashOut(EntryExitReq req) { var query = from db in DbContext.ClientCashInCashOut where db.ValidState != "InValid" select db; if (req != null) { if (req.ClientNameList != null) { query = query.Where(O => req.ClientNameList.Contains(O.ClientName)); } if (req.ClientNumberList != null) { query = query.Where(O => req.ClientNumberList.Contains(O.ClientNumber)); } if (req.HappenDateStart != DateTime.MinValue && req.HappenDateStart != SqlDateTime.MinValue.Value) { if (req.HappenDateStart == req.HappenDateEnd) { query = query.Where(O => req.HappenDateStart == O.HappenDate); } else { query = query.Where(O => req.HappenDateStart <= O.HappenDate); } } if (req.HappenDateEnd != DateTime.MinValue && req.HappenDateEnd != SqlDateTime.MinValue.Value && req.HappenDateEnd != req.HappenDateStart) { query = query.Where(O => req.HappenDateEnd >= O.HappenDate); } if (req.DirectionList != null) { query = query.Where(O => req.DirectionList.Contains(O.Direction)); } if (req.ActionList != null) { query = query.Where(O => req.ActionList.Contains(O.Action)); } if (req.MoneyStart != null) { if (req.MoneyStart == req.MoneyEnd) { query = query.Where(O => req.MoneyStart == O.Money); } else { query = query.Where(O => req.MoneyStart <= O.Money); } } if (req.MoneyEnd != null && req.MoneyStart != req.MoneyEnd) { query = query.Where(O => req.MoneyEnd >= O.Money); } if (req.StateList != null) { query = query.Where(O => req.StateList.Contains(O.State)); } if (req.TradeNumberList != null) { query = query.Where(O => req.TradeNumberList.Contains(O.TradeNumber)); } } return query.ToList(); } /// /// 获取出金审批流程 /// /// public List GetOutCashProcess() { return DbContext.approvalprocess.Where(x => x.processType == "OutCashProcess").OrderBy(o => o.order).ToList(); } /// /// 出金审批 /// /// public void AuditClientOutCash(ClientCashAuditReq req) { var entry = DbContext.ClientCashInCashOut.FirstOrDefault(e => e.id == req.id); if (entry == null) { throw new ServiceException("资金记录不存在"); } if (entry.State != ClientCashInCashOut.审批中) { throw new ServiceException("资金记录状态不正确"); } if (req.status == "reject") { ClientCashInCashOutReject(entry, req.auditComment); return; } var outCashProcess = GetOutCashProcess(); var nextProcess = outCashProcess.Where(x => x.order > entry.ApprovalProcess).FirstOrDefault(); ; if (nextProcess != null) { entry.ApprovalProcess = nextProcess.order; entry.OptId = UserId; entry.OptName = UserName; entry.OptDate = DateTime.Now; ClientCashLog(entry.id, "审批通过", req.auditComment); DbContext.SaveChanges(); } else { ExcuteEntryExit(req.id, req.auditComment); } } /// /// 审批撤回 /// /// /// public void GoBackAuditClientCash(int id) { var entry = DbContext.ClientCashInCashOut.FirstOrDefault(e => e.id == id); if (entry == null) { throw new ServiceException("资金记录不存在"); } var outCashProcess = GetOutCashProcess(); if (entry.State != ClientCashInCashOut.审批中 || entry.ApprovalProcess > 1) { throw new ServiceException("资金记录状态不正确"); } entry.State = ClientCashInCashOut.未确认; entry.OptId = UserId; entry.OptName = UserName; entry.OptDate = DateTime.Now; entry.ApprovalProcess = 0; ClientCashLog(entry.id, "审批", "撤回审批"); DbContext.SaveChanges(); } /// /// 下载出金付款单 /// /// /// /// public string DownloadOutEntryexit(int id) { var entry = DbContext.ClientCashInCashOut.FirstOrDefault(e => e.id == id); if (entry == null) { throw new ServiceException("资金记录不存在"); } var templatePath = Path.Combine(OtcAppContext.AppDocsPath, "导出模板", "出金付款单导出模板.docx"); if (!File.Exists(templatePath)) { throw new ServiceException($"找不到模板信息"); } var clientDbContext = DbContextFactory.GetClientDbContext(OptUser); var client = clientDbContext.client.Find(entry.ClientId); ClientBankCard bankcard = null; if (entry.OpenBankId > 0) { bankcard = clientDbContext.bankcard.FirstOrDefault(x => x.ApprovalOrder < 1 && x.id == entry.OpenBankId && x.ClientId == client.id && x.ValidState != "InValid"); } else { bankcard = clientDbContext.bankcard.FirstOrDefault(x => x.ApprovalOrder < 1 && x.ClientId == client.id && x.ValidState != "InValid"); } if (bankcard == null) { throw new ServiceException($"客户{client.Name}对应的银行帐户信息未找到"); } var fileName = $"出金付款单{entry.Number}.docx"; var outputFilePath = GetOutputFilePath(fileName); var modelDic = GetOutEntryexitDic(entry, client, bankcard); var varDic = new JsonVarDic(modelDic); OfficeFileConverter.ConvertByUsingDocTemplate(templatePath, outputFilePath, varDic, false); var absolutePath = TradeContractHelper.GetAbsolutePath(outputFilePath, fileName); var appDocsPath = OtcAppContext.AppDocsPath; return $"/App_Docs{absolutePath.Replace(appDocsPath, "").Replace(appDocsPath, "").Replace("\\", "/")}"; } /// /// 获取 账户明细信息 /// /// /// public ClientDingShiReport GetClientReportData(int id) { var entry = DbContext.ClientCashInCashOut.FirstOrDefault(e => e.id == id); if (entry == null) { throw new ServiceException("资金记录不存在"); } var clientId = entry.ClientId ?? 0; var report = new ClientDingShiReport { client = DataCacheProvider.GetClientDataSource().GetData(clientId), ClientBank = new ClientDBContext().bankcard.Where(x => x.ApprovalOrder < 1 && x.ClientId == clientId && x.ValidState != "InValid").ToList(), OptUserInfo = this.UserInfo }; var toDate = DateTime.Now; report.ReportEnd = toDate; var clientBalance = ClientBalanceUtility.GetClientBanlances(new List { clientId }, DateTime.MinValue, report.ReportEnd, IsClientBalanceGap: false, IsGetOuterMarginGap: true, ParentFlag: false).FirstOrDefault(); report.FundReportModel = new FundReportModel() { LastDayRemainFund = clientBalance?.LastDayRemainFund ?? 0, LastDayRemainFundWithProduct = clientBalance?.LastDayRemainFundWithProduct ?? 0, CashInCashOutChange = clientBalance?.NetFund ?? 0, CashInChange = clientBalance?.InFund ?? 0, CashOutChange = clientBalance?.OutFund ?? 0, CashInCashOutOther = clientBalance?.OtherFund ?? 0, CashInCashOutProductChange = clientBalance?.CashInCashOutProductChange ?? 0, OptionPremium = clientBalance?.OptionPremium ?? 0, OptionPremiumSwap = clientBalance?.OptionPremiumSwap ?? 0, SettlementBalance = clientBalance?.SettlementBalance ?? 0, UnwindBalance = clientBalance?.UnwindBalance ?? 0, ExerciseBalance = clientBalance?.ExerciseBalance ?? 0, SwapBalance = clientBalance?.SwapBalance ?? 0, Coupon = clientBalance?.Coupon ?? 0, TodayRemianFund = clientBalance?.AmountFund ?? 0, TodayRemianFundProduct = clientBalance?.AmountFundWithProduct ?? 0, GuaranteesTotalAmount = clientBalance?.GuaranteesTotalAmount ?? 0, WorstCastClientPayable = clientBalance?.MinusPayableMarginTotal ?? 0, AvailableFund = clientBalance?.AvailableAmount ?? 0, TotalMargin = clientBalance?.TotalMarginTotal, Credit = clientBalance?.TotalCredit ?? 0, CreditRatio = clientBalance?.CreditUsed ?? 0, Margin = clientBalance?.MarginByPayableMarginTotal ?? 0, Amount = (PS.Config.IsPVRounded ? clientBalance?.RoundedTotalAmountTotal : clientBalance?.TotalAmountTotal) ?? 0, TotalPnl = PS.Config.IsPVRounded ? (decimal)(clientBalance?.RoundedPositionPnl ?? 0) : (decimal)(clientBalance?.PositionPnl ?? 0), PositionPremiumNetCash = clientBalance?.PositionPremiumNetCash ?? 0, SellTradePrice = clientBalance?.SellTradePrice, LastDayPositionPremiumNetCash = clientBalance?.LastDayPositionPremiumNetCash ?? 0, WinLoss = clientBalance?.WinLoss ?? 0, ClosedTradeFundGap = clientBalance?.ClosedTradeFundGap ?? 0, ClosedTradePayableFund = clientBalance?.ClosedTradePayableFundTotal ?? 0, PositionTradePayableFund = clientBalance?.PositionTradePayableFundTotal ?? 0, DesirableFund = clientBalance?.DesirableFundTotal ?? 0, PayableFund = clientBalance?.PayableFundTotal ?? 0, PositionPv = PS.Config.IsPVRounded ? (clientBalance?.RoundedPositionPv ?? 0) : (clientBalance?.PositionPv ?? 0), PrepaymentAmount = clientBalance?.PrepaymentAmount, PositionPnl = PS.Config.IsPVRounded ? (clientBalance?.RoundedPositionPnl ?? 0) : (clientBalance?.PositionPnl ?? 0), TotalNetSettlement = clientBalance?.TotalNetSettlementTotal ?? 0, ClientSellPositionPnl = clientBalance?.ClientSellPositionPnl, FreezePremium = clientBalance?.FreezePremium }; if (PS.Config.Company == CompanyEnum.润和) { report.FundReportModel.SettlementBalance += report.FundReportModel.SwapBalance; report.FundReportModel.CreditOccupy = Math.Min(report.FundReportModel.Credit ?? 0, Math.Max((report.FundReportModel.WorstCastClientPayable - report.FundReportModel.TodayRemianFund) ?? 0, 0)); report.FundReportModel.DesirableFund = Math.Max(report.FundReportModel.AvailableFund ?? 0, 0); report.FundReportModel.AvailableFund = report.FundReportModel.AvailableFund + report.FundReportModel.Credit; } var desc = DBCacheManager.Single.GetStr(CacheTable.DingShiDesc); var descList = Regex.Split(desc, "

", RegexOptions.IgnoreCase).Where(x => !string.IsNullOrWhiteSpace(x)).ToList(); var newDescList = new List(); descList.ForEach(x => { x = Regex.Replace(x, "<[^>]+>", ""); x = Regex.Replace(x, "&[^;]+;", ""); newDescList.Add(x); }); report.descList = newDescList; report.desc = desc; return report; } /// /// 获取 账户信息pdf文件 /// /// /// /// public string GenerateReportPDF(ClientDingShiReport report, string html) { var pdfHelper = new PdfHelper(); var sourcePath = OtcAppContext.MapPath("~/App_Docs/TradeMarket"); if (!Directory.Exists(sourcePath)) { Directory.CreateDirectory(sourcePath); } var clientName = report.client.Name; var fileName = $"资金结算报告_{clientName}_{report.ReportEnd:yyyy-MM-dd}"; var sourceFileName = Path.Combine(sourcePath, $"{fileName}.pdf"); pdfHelper.ToPDFFile(html, sourceFileName, true); return sourceFileName; } /// /// 付款单基础数据填充 /// /// /// /// /// private Dictionary GetOutEntryexitDic(ClientCashInCashOut entry, Client client, ClientBankCard bankcard) { var dic = new Dictionary(); FormatToDictHelper.FormatToDict("发生时间", entry.HappenDate, dic); FormatToDictHelper.FormatToDict("金额", entry.Money, dic); dic["客户银行账户名称"] = bankcard.ClientName; if (!string.IsNullOrEmpty(entry.OpenBankCard)) { dic["客户银行账户账号"] = entry.OpenBankCard; } else { dic["客户银行账户账号"] = bankcard.Card; } dic["客户银行账户开户行"] = bankcard.Bank; dic["客户名称"] = client.Name; dic["客户编号"] = client.Number; dic["备注"] = entry.Comments; return dic; } /// /// 获取生成文档的输出路径(物理路径) /// private string GetOutputFilePath(string fileName) { var folder = Path.Combine(OtcAppContext.AppDocsPath, "contractdoc\\output"); if (!Directory.Exists(folder)) { Directory.CreateDirectory(folder); } return Path.Combine(folder, fileName); } /// /// 资金审批查询 /// /// /// public SearchListResult EntryexitApprovalQuery(EntryExitApprovalQueryReq req) { var predicate = PredicateBuilder.Create(n => n.ValidState != ConsGlobal.InValid && n.IsGroup != 1 && n.ApprovalProcess > 0); if (!string.IsNullOrEmpty(req.DirectionType)) { predicate = predicate.And(x => x.Direction == req.DirectionType); } if (req.ClientIdsInt.Any()) { predicate = predicate.And(x => req.ClientIdsInt.Contains(x.ClientId ?? 0)); } if (req.OptIdLists.Any()) { predicate = predicate.And(x => req.OptIdLists.Contains(x.OptId ?? 0)); } if (!string.IsNullOrEmpty(req.Number)) { predicate = predicate.And(x => x.Number.Contains(req.Number)); } if (req.HappenDateStart.HasValue) { predicate = predicate.And(x => x.HappenDate >= req.HappenDateStart); } if (req.HappenDateEnd.HasValue) { predicate = predicate.And(x => x.HappenDate < req.HappenDateEnd.Value.AddDays(1)); } if (req.OptDateStart.HasValue) { predicate = predicate.And(x => x.OptDate >= req.OptDateStart); } if (req.OptDateEnd.HasValue) { predicate = predicate.And(x => x.OptDate < req.OptDateEnd.Value.AddDays(1)); } var approvalQuery = DbContext.approvalprocess.Where(x => x.processType == "OutCashProcess"); var approvalCount = approvalQuery.Count(); var query = from cashout in DbContext.ClientCashInCashOut.Where(predicate) join approval in approvalQuery on cashout.ApprovalProcess equals approval.order select new EntryExitApprovalQueryRes { id = cashout.id, EncryptId = cashout.EncryptId, ProcessStatus = "审批中 流程" + (cashout.ApprovalProcess - 1) + "/" + approvalCount, ProcessOrderId = cashout.ApprovalProcess, Number = cashout.Number, ProcessRoleId = approval.roleId, Direction = cashout.Direction, Money = cashout.Money ?? 0, HappenDate = cashout.HappenDate, Comments = cashout.Comments, OptName = cashout.OptName, OptDate = cashout.OptDate, ClientName = cashout.ClientName, CreatorId = cashout.CreatorId, CreatorName = cashout.CreatorName, CreateDate = cashout.CreateDate }; if (string.IsNullOrEmpty(req.sidx)) { req.sidx = "id"; req.sord = "desc"; } query = query.OrderByDescending(s => s.OptDate); var retListResult = query.ToSearchList(req); var listRoles = new ErpBaseContext().Roles.Select(n => new { n.Id, n.Name }).ToDictionary(n => n.Id, m => m.Name); foreach (var item in retListResult.rows) { item.id = 0;//不做接口返回 if (listRoles.TryGetValue(item.ProcessRoleId, out var name)) { item.ProcessRoleName = name; } } return retListResult; } } /// /// 出入金Api请求参数 /// public class SaveEntryexitApiReq { /// /// 客户Id /// public int? ClientId { get; set; } /// /// 客户名称 /// public string ClientName { get; set; } /// /// 出入金方向 /// public string Direction { get; set; } /// /// 金额 /// public double? Money { get; set; } /// /// 银行账号 /// public string OpenBankCard { get; set; } /// /// 发生时间 /// public DateTime HappenDate { get; set; } /// /// 备注 /// public string Comments { get; set; } /// /// 资金标识 /// public ClientCashFlag CashFlag { get; set; } } /// /// 财务汇总-API接口参数 /// public class ClientBalanceGapReq { /// /// 主键 /// public int id { get; set; } /// /// 客户名称 /// public string ClientName { get; set; } /// /// 结束日期 /// public DateTime ValueDate { get; set; } /// /// 净资金流入 /// public double? NetFund { get; set; } /// /// 期权费收支 /// public double? OptionPremium { get; set; } /// /// 结算收支 /// public double? SettlementBalance { get; set; } /// /// 票息 /// public double? Coupon { get; set; } /// /// 互换收支 /// public double? SwapBalance { get; set; } /// /// 其他收支 /// public double? OtherFund { get; set; } /// /// 当日资金余额 /// public double? ToDayRemainFund { get; set; } /// /// 授信额度 /// public double? Credit { get; set; } /// /// 应付了交易结款 /// public double? ClosedTradePayableFund { get; set; } /// /// 应付存续交易款 /// public double? PositionTradePayableFund { get; set; } /// /// 追保金额 /// public double? MarginByPayableMargin { get; set; } /// /// 应付资金总额 /// public double? PayableFund { get; set; } /// /// 实现盈亏 /// public double? WinLoss { get; set; } /// /// 持仓盈亏 /// public double? PositionPnl { get; set; } /// /// 持仓市值 /// public double? PositionPv { get; set; } /// /// 应付预付金 /// public double? PayableMargin { get; set; } /// /// 是否为外部预付金 /// public bool IsImportOuterMargin { get; set; } } }