using BaseOUDAL; using Microsoft.Extensions.DependencyInjection; using Org.BouncyCastle.Crypto.Tls; using Qdp.Foundation.Utilities; using System.Data; using YieldChain.Commons; using YLErp.Abstract; using YLErp.Commons; using YLErp.Model; using YLErp.Models.Tag; using YLErp.Modules.ClientModule.Dto; using YLErp.Modules.TagModule; namespace YLErp.Modules.ClientModule { /// /// 客户黑名单服务 /// public class ClientBlackService : ClientBaseService { private IKafkaProduce _kafkaProduce; public ClientBlackService(OptUserInfo userInfo) : base(userInfo) { _kafkaProduce = YLServiceLocator.ServiceProvider.GetService(); } /// /// 查询黑名单列表 /// public SearchListResult SearchList(ClientBlackReq req) { var predicate = PredicateBuilder.True(); if (req.ids != null && req.ids.Any()) { predicate = PredicateBuilder.Create(n => req.ids.Contains(n.id)); } else { if (!string.IsNullOrEmpty(req.Name)) { predicate = predicate.And(d => d.Name.Contains(req.Name)); } if (!string.IsNullOrEmpty(req.ClientBlackStates)) { var states = req.ClientBlackStates.Split(',', StringSplitOptions.RemoveEmptyEntries); predicate = predicate.And(d => states.Contains(d.State)); } if (req.DateFromOptDate.HasValue) { predicate = predicate.And(d => d.OptDate >= req.DateFromOptDate.Value); } if (req.DateToOptDate.HasValue) { predicate = predicate.And(d => d.OptDate < req.DateToOptDate.Value.AddDays(1)); } } var query = DbContext.client_black.AsNoTracking().Where(predicate); if (string.IsNullOrEmpty(req.sidx)) { req.sidx = "id"; req.sord = "asc"; } var retListResult = query.ToSearchList(req); if (retListResult != null && retListResult.rows != null && retListResult.rows.Any()) { var names = retListResult.rows.Select(p => p.Name).Distinct().ToList(); var clients = DbContext.client.AsNoTracking().Where(p => names.Contains(p.Name)).Select(p => new ClientSimpleDto { id = p.id, Name = p.Name }).ToList(); if (clients != null && clients.Count > 0) { Dictionary> clientTagList = null; if (clients != null && clients.Any()) { using (var tagService = new TagService(OptUser)) { clientTagList = tagService.GetTagByClientIds(clients.Select(p => p.id).Distinct().ToList()); } } if (clientTagList == null) { clientTagList = new Dictionary>(); } clients.ForEach(p => { var retInfo = retListResult.rows.FirstOrDefault(d => d.Name.Equals(p.Name)); if (retInfo != null) { //拼装标签值 if (clientTagList.ContainsKey(p.id)) { retInfo.Tags = clientTagList[p.id]; retInfo.OutputTags = TagService.GetOutputTagsStr(retInfo.Tags); } } }); } } return retListResult; } public List ProcessList() { return DbContextFactory.GetYLDbContext().approvalprocess .Where(s => s.processType == "ClientBlackProcess") .OrderBy(s => s.order) .ToList(); } public int DeleteClientBlack(IEnumerable ids) { var idList = ids?.Distinct().ToList() ?? new List(); if (idList.Count == 0) { throw new ServiceException("请选择要移出的黑名单客户"); } var rows = DbContext.client_black.Where(x => idList.Contains(x.id)).ToList(); if (rows.Count != idList.Count) { throw new ServiceException("未找到要删除的数据"); } var hasProcess = ProcessList().Any(); var submitRemovalApprovalCount = 0; foreach (var row in rows) { if (ClientBlackApprovalPolicy.CanDeleteDraft(row.State)) { DbContext.client_black.Remove(row); ClientBlackCategoryLog(row.id, "已删除"); continue; } if (!ClientBlackApprovalPolicy.CanRequestRemoval(row.State)) { throw new ServiceException($"黑名单客户{row.Name}当前状态不允许移出"); } if (hasProcess) { var result = ClientBlackApprovalPolicy.GetRemovalResult(true); row.State = result.State; row.ApprovalProcess = result.ApprovalProcess; row.ApprovalOptName = UserName; row.ApprovalOptDate = DateTime.Now; ClientBlackCategoryLog(row.id, client_black.删除审批中); submitRemovalApprovalCount++; } else { RemoveEffectiveBlack(row); } } DbContext.SaveChanges(); return submitRemovalApprovalCount; } public void WithdrawApprovalClientBlack(List ids, out int withdrawCount, out string msg) { withdrawCount = 0; msg = ""; var rows = DbContext.client_black.Where(x => ids.Contains(x.id)).ToList(); foreach (var row in rows) { if (!ClientBlackApprovalPolicy.CanWithdraw(row.State, row.ApprovalProcess)) { if (row.ApprovalProcess > 1) { msg += row.Name + ","; } continue; } var result = ClientBlackApprovalPolicy.GetWithdrawResult(row.State); row.State = result.State; row.ApprovalProcess = result.ApprovalProcess; row.ApprovalOptName = null; row.ApprovalOptDate = null; ClientBlackCategoryLog(row.id, row.State); withdrawCount++; } DbContext.SaveChanges(); } public void SubmitApprovalClientBlack(List ids) { var rows = DbContext.client_black.Where(x => ids.Contains(x.id)).ToList(); var process = ProcessList(); foreach (var row in rows) { if (!ClientBlackApprovalPolicy.CanSubmitAddition(row.State)) { continue; } if (process.Count == 0) { row.State = client_black.已加入; row.ApprovalProcess = -2; row.ApprovalOptName = UserName; row.ApprovalOptDate = DateTime.Now; var notifications = new List<(Client oldClient, Client newClient)>(); ApplyEffectiveAddition(row.Name, notifications); ClientBlackCategoryLog(row.id, client_black.已加入, "未设置审批流程,直接通过"); DbContext.SaveChanges(); SendClientNotifications(notifications); continue; } row.State = client_black.新增审批中; row.ApprovalProcess = 1; row.ApprovalOptName = UserName; row.ApprovalOptDate = DateTime.Now; ClientBlackCategoryLog(row.id, client_black.新增审批中); } DbContext.SaveChanges(); } public string AuditClientBlack(ClientBlackAuditReq req, bool isBatch = false, string optType = "") { var row = DbContext.client_black.Find(req.id); if (row == null) { throw new ServiceException("审批失败,系统中没有该黑名单记录"); } if (row.State != client_black.新增审批中 && row.State != client_black.删除审批中) { throw new ServiceException("当前黑名单不在审批中"); } var process = ProcessList(); var currentNode = process.FirstOrDefault(x => x.order == row.ApprovalProcess); if (currentNode == null || !UserBLL.GetRolesByUserId(UserId).Any(x => x.Id == currentNode.roleId)) { throw new ServiceException("当前用户无权审批该节点"); } if (req.status == "reject") { row.State = ClientBlackApprovalPolicy.GetRejectedState(row.State); row.ApprovalProcess = -1; row.ApprovalOptDate = DateTime.Now; row.OptId = UserId; row.OptName = UserName; row.OptDate = DateTime.Now; ClientBlackCategoryLog(row.id, row.State, req.auditComment); DbContext.SaveChanges(); return "提交成功"; } if (req.status != "pass") { throw new ServiceException("status参数不支持:" + req.status); } var nextNode = process.FirstOrDefault(x => x.order > row.ApprovalProcess); if (nextNode != null) { row.ApprovalProcess = nextNode.order; row.ApprovalOptDate = DateTime.Now; row.OptId = UserId; row.OptName = UserName; row.OptDate = DateTime.Now; ClientBlackCategoryLog(row.id, row.State, req.auditComment); DbContext.SaveChanges(); return "提交成功"; } var final = ClientBlackApprovalPolicy.GetFinalResult(row.State); if (final.ShouldDelete) { RemoveEffectiveBlack(row, req.auditComment, isBatch ? optType : null); DbContext.SaveChanges(); } else { row.State = final.State; row.ApprovalProcess = -2; row.ApprovalOptDate = DateTime.Now; var notifications = new List<(Client oldClient, Client newClient)>(); ApplyEffectiveAddition(row.Name, notifications); ClientBlackCategoryLog(row.id, isBatch ? optType : row.State, req.auditComment); DbContext.SaveChanges(); SendClientNotifications(notifications); } return "提交成功"; } public SearchListResult ClientBlackApprovalQuery(ClientBlackReq req) { var process = ProcessList(); var predicate = PredicateBuilder.Create(x => x.ApprovalProcess > 0); if (!string.IsNullOrWhiteSpace(req.Name)) { predicate = predicate.And(x => x.Name.Contains(req.Name)); } var query = from row in DbContext.client_black.AsNoTracking().Where(predicate) select new ClientBlackApprovalQueryRes { id = row.id, EncryptId = row.EncryptId, ProcessOrderId = row.ApprovalProcess, ProcessRoleId = 0, ProcessStatus = "审批中 流程" + (row.ApprovalProcess - 1) + "/" + process.Count, State = row.State, ClientName = row.Name, Comments = row.Remarks, ApprovalOptName = row.ApprovalOptName, ApprovalOptDate = row.ApprovalOptDate, creator_id = row.creator_id, creator_name = row.creator_name, creator_time = row.creator_time }; if (string.IsNullOrEmpty(req.sidx)) { req.sidx = "ApprovalOptDate"; req.sord = "desc"; } var result = query.OrderByDescending(x => x.ApprovalOptDate).ToSearchList(req); var roles = new ErpBaseContext().Roles .Select(x => new { x.Id, x.Name }) .ToDictionary(x => x.Id, x => x.Name); foreach (var item in result.rows) { var node = process.FirstOrDefault(x => x.order == item.ProcessOrderId); if (node == null) { continue; } item.ProcessRoleId = node.roleId; item.ProcessRoleName = roles.TryGetValue(node.roleId, out var roleName) ? roleName : string.Empty; } return result; } private void ApplyEffectiveAddition(string name, List<(Client oldClient, Client newClient)> notifications) { var client = DbContext.client.FirstOrDefault(c => c.Name == name); if (client == null) { return; } var dt = DateTime.Now; var oldClient = client.Clone(); if (client.ProcessStatus == "已开户") { client.ProcessOrderId = -4; client.ProcessStatus = "已休眠"; client.OptId = UserId; client.OptName = UserName; client.OptDate = dt; DbContext.ClientAuditLog.Add(new ClientAuditLog { ClientId = client.id, OptType = "休眠", Changes = string.Empty, DataType = "00", OptId = UserId, OptName = UserName, OptDate = dt }); notifications.Add((oldClient, client)); } DbContext.ClientAuditLog.Add(new ClientAuditLog { ClientId = client.id, OptType = "加入黑名单", Changes = string.Empty, DataType = "00", OptId = UserId, OptName = UserName, OptDate = dt }); } private void RemoveEffectiveBlack(client_black row, string changes = null, string optType = null) { var client = DbContext.client.FirstOrDefault(c => c.Name == row.Name); if (client != null) { DbContext.ClientAuditLog.Add(new ClientAuditLog { ClientId = client.id, OptType = "移除黑名单", Changes = string.Empty, DataType = "00", OptId = UserId, OptName = UserName, OptDate = DateTime.Now }); } DbContext.client_black.Remove(row); ClientBlackCategoryLog(row.id, optType ?? "已删除", changes); } private void SendClientNotifications(List<(Client oldClient, Client newClient)> notifications) { foreach (var (oldClient, newClient) in notifications) { new ClientKafkaService(_kafkaProduce).Send(newClient, oldClient); } } public void ClientBlackCategoryLog(int clientblackId, string optType, string changes = null) { DbContext.client_blacklog.Add(new ClientBlackLog { ClientBlackId = clientblackId, OptType = optType, Changes = changes, DataType = "00", OptId = UserId, OptName = UserName, OptDate = DateTime.Now }); } /// /// 客户黑名单导入 /// public void ImportxlsxClientBlack(Stream stream, bool checkStatus) { //当前编码支持ansi和utf with bom var ds = Office.ExcelHelper.ReadExcelAsDataSet(stream); if (ds.Tables.Count < 1 || ds.Tables[0].Rows.Count < 1) { throw new ServiceException("读取导入数据失败:数据为空") { Tag = "111" }; } var table = ds.Tables[0]; if (table.Rows.Count < 1) { throw new ServiceException("导入数据不能为空!"); } var list = new List(); foreach (DataRow row in table.Rows) { if (row.IsNull("客户名称")) { throw new ServiceException("导入客户名称不能为空!"); } var importModel = new client_black { Name = row["客户名称"].ToString(), Remarks = row.IsNull("备注") ? "" : row["备注"].ToString() }; if (table.Columns.Contains("标签值") && !string.IsNullOrEmpty(row["标签值"].ToString())) { var tagStrArr = row["标签值"].ToString().Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries); if (tagStrArr != null && tagStrArr.Length > 0) { importModel.Tags = tagStrArr.Select(p => new YLErp.Models.Tag.TagDto { Name = p }).ToList(); } } if (list.Where(x => x.Name == importModel.Name).Count() > 0) throw new ServiceException($"第{row.Table.Rows.IndexOf(row) + 2}行客户名称:'{importModel.Name}'重复!"); else list.Add(importModel); } var importHasTagClientNames = list.Where(p => p.Tags != null && p.Tags.Count > 0).Select(p => p.Name).Distinct().ToList(); if (importHasTagClientNames != null && importHasTagClientNames.Count > 0) { var dbClientNames = DbContext.client.AsNoTracking().Where(p => importHasTagClientNames.Contains(p.Name)).Select(p => p.Name).Distinct().ToList(); if (dbClientNames != null && dbClientNames.Count > 0) { dbClientNames.ForEach(p => { importHasTagClientNames.Remove(p); }); } if (importHasTagClientNames.Count > 0) { throw new ServiceException(String.Join(",", importHasTagClientNames) + "不存在开户记录,无法设置标签值,请清除表格中对应客户的标签值再继续导入"); } } var importHasLongTagClientNames = list.Where(p => p.Tags != null && p.Tags.Any(d => d.Name.Length > 30)).Select(p => p.Name).Distinct().ToList(); if (importHasLongTagClientNames != null && importHasLongTagClientNames.Count > 0) { throw new ServiceException(String.Join(",", importHasLongTagClientNames) + "存在过长的标签值(每个标签值限制30个字符,多个以英文分号隔开),请调整完成后再导入"); } AddClientBlack(list, checkStatus); } public void AddClientBlack(IEnumerable list, bool checkStatus) { var inputList = list?.ToList() ?? new List(); var errMsgList = new List(); var nameList = inputList.Select(O => O.Name).ToList(); var dbList = DbContext.client_black.Where(O => nameList.Contains(O.Name)).ToList(); foreach (var item in dbList) { var obj = inputList.FirstOrDefault(O => O.Name.Equals(item.Name, StringComparison.OrdinalIgnoreCase)); if (obj == null) { continue; } if (!ClientBlackApprovalPolicy.CanReplaceRemarks(item.State)) { throw new ServiceException("黑名单客户在审批中无法修改!"); } if (checkStatus && !string.IsNullOrWhiteSpace(item.Remarks) && item.Remarks != obj.Remarks) { errMsgList.Add($"{item.Name}"); } } if (checkStatus) { if (errMsgList.Count > 0) { var msg = ""; if (errMsgList.Count <= 5) { msg = $"客户:{string.Join(",", errMsgList)}当前已在黑名单中,本次将修改备注,备注已存在,是否确认?"; } else { msg = $"{string.Join(",", errMsgList.Take(5))} 等{errMsgList.Count}个客户当前已在黑名单中,本次将修改备注,备注已存在,是否确认?"; } throw new ServiceException(msg); } } // 在外部定义列表来保存需要通知的客户对 var clientsToNotify = new List<(Client oldClient, Client newClient)>(); var newItems = new List(); var processList = ProcessList(); foreach (var item in inputList) { if (string.IsNullOrWhiteSpace(item.Name)) { throw new ServiceException("导入客户名称不能为空!"); } item.Name = item.Name?.ToString() ?? ""; item.Remarks = item.Remarks?.ToString() ?? ""; item.OptId = UserId; item.OptName = UserName; item.OptDate = DateTime.Now; var existing = dbList.FirstOrDefault(x => x.Name.Equals(item.Name, StringComparison.OrdinalIgnoreCase)); if (existing != null) { var oldRemarks = existing.Remarks; existing.Remarks = item.Remarks; existing.OptId = UserId; existing.OptName = UserName; existing.OptDate = DateTime.Now; if (oldRemarks != existing.Remarks) { ClientBlackCategoryLog(existing.id, "修改备注", $"备注:{oldRemarks ?? string.Empty} -> {existing.Remarks ?? string.Empty}"); } continue; } var additionResult = ClientBlackApprovalPolicy.GetAdditionResult(processList.Any()); item.State = additionResult.State; item.ApprovalProcess = additionResult.ApprovalProcess; item.creator_id = UserId; item.creator_name = UserName; item.creator_time = DateTime.Now; if (additionResult.IsEffective) { ApplyEffectiveAddition(item.Name, clientsToNotify); } newItems.Add(item); } DbContext.client_black.AddRange(newItems); DbContext.SaveChanges(); foreach (var item in newItems) { ClientBlackCategoryLog(item.id, item.State); } DbContext.SaveChanges(); // 发送Kafka消息 foreach (var (oldClient, newClient) in clientsToNotify) { new ClientKafkaService(_kafkaProduce).Send(newClient, oldClient); } var importHasTagClientNames = inputList.Where(p => p.Tags != null && p.Tags.Count > 0).Select(p => p.Name).Distinct().ToList(); if (importHasTagClientNames != null && importHasTagClientNames.Count > 0) { var dbClients = DbContext.client.AsNoTracking().Where(p => importHasTagClientNames.Contains(p.Name)).Select(p => new ClientSimpleDto { id = p.id, Name = p.Name }).ToList(); if (dbClients != null && dbClients.Count > 0) { var tagService = new TagService(OptUser); dbClients.ForEach(p => { var importInfo = inputList.FirstOrDefault(d => d.Name.Equals(p.Name)); if (importInfo != null) { tagService.SetClientTagForClientImport(new TagModule.Dto.SetClientTagForClientEditRequest { ClientId = p.id, Tags = importInfo.Tags }); } }); } } } /// /// 黑名单导出 /// public byte[] ExportClientBlack(ClientBlackReq req) { if (req.ids == null || !req.ids.Any()) { req.ids = null; req.rows = 10000; } else { req.Name = null; } var slist = SearchList(req); var dc = new List { new ExcelHelper.DataColumnModel("客户名称", "Name"), new ExcelHelper.DataColumnModel("备注", "Remarks",typeof(string)) }; new ExcelHelper().ListToExcel(dc.ToArray(), slist.rows.ToList(), "黑名单导出", true, out var buffer); return buffer; } } }