using EntrustSettle.Common; using EntrustSettle.Common.Const; using EntrustSettle.Common.Extensions; using EntrustSettle.Common.Helper; using EntrustSettle.Controllers; using EntrustSettle.IServices; using EntrustSettle.IServices.Base; using EntrustSettle.Model; using EntrustSettle.Model.Dtos; using EntrustSettle.Model.Models; using EntrustSettle.Model.Models.DJY; using EntrustSettle.Model.Validator; using EntrustSettle.Repository.UnitOfWorks; using FluentValidation; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Newtonsoft.Json; namespace EntrustSettle.Api.Controllers { /// /// 订单 /// public class OrderController : BaseApiController { private readonly IOrderService orderService; private readonly IOrderAnnexService orderAnnexService; private readonly IAnnexService annexService; private readonly ILogger logger; private readonly IUnitOfWorkManage unitOfWorkManage; private readonly IOrderHistoryService orderHistoryService; private readonly IHYDService hydService; private readonly IOrderFeeService orderFeeService; private readonly IQueueService queueService; public OrderController(IOrderService orderService, IOrderAnnexService orderFileService, ILogger logger, IUnitOfWorkManage unitOfWorkManage, IOrderHistoryService orderHistoryService, IHYDService hydService, IAnnexService annexService, IOrderFeeService orderFeeService, IQueueService queueService) { this.orderService = orderService; this.orderAnnexService = orderFileService; this.logger = logger; this.unitOfWorkManage = unitOfWorkManage; this.orderHistoryService = orderHistoryService; this.hydService = hydService; this.annexService = annexService; this.orderFeeService = orderFeeService; this.queueService = queueService; } /// /// 获取订单列表 /// [HttpGet] public async Task>> List([FromQuery] OrderListInputDto input) { if (input.QueryType == 2) { if (!App.User.CompanyName.Contains("东胜伟业") && !App.User.CompanyName.Contains("大简云")) { throw new Exception("访问权限与实际拥有菜单权限不符"); } } PageModel result = await orderService.AsQueryable() .WhereIF(input.QueryType != 2, x => x.CompanyId == App.User.CompanyId) .WhereIF(!string.IsNullOrWhiteSpace(input.Mblno), x => x.Mblno.Contains(input.Mblno)) .WhereIF(!string.IsNullOrWhiteSpace(input.CompanyName), x => x.CompanyName.Contains(input.CompanyName)) .WhereIF(!string.IsNullOrWhiteSpace(input.Remark), x => x.Remark.Contains(input.Remark)) .WhereIF(input.ServiceType != null, x => x.ServiceType == input.ServiceType) .WhereIF(input.Status != null, x => x.Status == (int)input.Status) .WhereIF(input.CreateTimeStart != null, x => x.CreateTime >= input.CreateTimeStart) .WhereIF(input.CreateTimeEnd != null, x => x.CreateTime <= input.CreateTimeEnd) .Select() .OrderBy("id desc") .ToPageListAsyncExtension(input.pageIndex, input.pageSize); var orderIdList = result.data.Select(x => x.Id).ToList(); if (orderIdList.Count > 0) { var orderWithTypeList = await orderAnnexService.AsQueryable() .LeftJoin((o, a) => o.AnnexId == a.Id) .Where((o, a) => orderIdList.Contains(o.OrderId) && (a.Type == 3 || a.Type == 4)) .Select((o, a) => new { o.OrderId, a.Type }) .Distinct() .ToListAsync(); var group = orderWithTypeList.GroupBy(x => x.OrderId).ToList(); foreach (var item in group) { var order = result.data.FirstOrDefault(x => x.Id == item.Key); if (item.Any(x => x.Type == 3)) { order.IsHasBillAnnex = true; } if (item.Any(x => x.Type == 4)) { order.IsHasInvoiceAnnex = true; } } result.data.ForEach(x => { if (!string.IsNullOrWhiteSpace(x.MailBillNo)) { x.IsHasInvoiceAnnex = true; } }); } return SuccessPage(result); } [HttpGet] [AllowAnonymous] //[ApiUser(ApiCode = "OrderSubmit")] public async Task Test() { CustFee custFeeModel = new CustFee() { SENDTYPE = 0, SENDTIME = DateTime.Now, CtnrInfo = string.Empty, CtnrCount = 0, GID = Guid.NewGuid().ToString(), }; string msg = "123"; logger.LogInformation($"{msg},扣费记录内容:{{custFeeModel}}", custFeeModel.ToJson()); var a = App.User.Name; var b = App.User.ID; await Task.CompletedTask; var c = new { a, b }; return Success(c); } /// /// 下单 /// [HttpPost] //[UseTran] public async Task>> Submit(OrderSubmitDto inputDto) { var validator = new OrderSubmitDtoValidator(); validator.ValidateAndThrow(inputDto); // 订单信息保存 inputDto.MblnoList = inputDto.MblnoList.Where(x => !string.IsNullOrWhiteSpace(x)).Select(x => x.Trim()).ToArray(); StringHelper.TrimStringProperties(inputDto); // 查询税号 var custBalanceService = App.GetService>(); var taxCode = await custBalanceService.Db.Queryable().Where(x => x.CompId == inputDto.CompanyId).Select(x => x.TaxCode).FirstAsync(); var orderList = new List(); foreach (var item in inputDto.MblnoList) { var order = new Order { Mblno = item, CompanyId = inputDto.CompanyId, CompanyName = inputDto.CompanyName, TaxCode = taxCode, ServiceType = inputDto.ServiceType, ProjectType = inputDto.ProjectType, IsSend = false, Status = null, ContactId = inputDto.ContactId, ContactName = inputDto.ContactName, ContactTel = inputDto.ContactTel, Remark = inputDto.Remark }; orderList.Add(order); } unitOfWorkManage.BeginTran(); foreach (var item in orderList) { var id = await orderService.AsInsertable(item).ExecuteReturnSnowflakeIdAsync(); item.Id = id; } var orderIdList = orderList.Select(x => x.Id).ToList(); // 附件关联信息保存 if (inputDto.AnnexIdList?.Count > 0) { var orderFileModelList = new List(); foreach (var orderId in orderIdList) { foreach (var annexId in inputDto.AnnexIdList) { orderFileModelList.Add(new OrderAnnex() { OrderId = orderId, AnnexId = annexId }); } }; await orderAnnexService.Add(orderFileModelList); } // 状态历史保存 //var historyModelList = new List(); //foreach (var item in orderIdList) //{ // historyModelList.Add(new OrderHistory // { // Pid = item, // Status = (int)OrderStatusEnum.已下单, // StatusTime = DateTime.Now // }); //} //await orderHistoryService.Add(historyModelList); unitOfWorkManage.CommitTran(); // 查询所有待处理订单列表 var pendingOrderList = await orderService.Query(x => x.IsSend == false && orderIdList.Contains(x.Id)); var result = orderList.Select(x => new OrderSubmitResultDto() { OrderId = x.Id, Mblno = x.Mblno }).ToList(); if (pendingOrderList.Count == 0) { return Success(result); } string domainUrl = AppSettings.app(["Startup", "Domain"]); foreach (Order orderItem in pendingOrderList) { try { List annexList = await orderAnnexService.AsQueryable() .InnerJoin((o, a) => o.AnnexId == a.Id) .Where(o => o.OrderId == orderItem.Id) .Select((o, a) => a) .ToListAsync(); // 构建提交数据 string fileNameStr = string.Join(",", annexList.Select(x => x.Name)); string fileUrl = string.Join(",", annexList.Select(x => $"{domainUrl}/api/Annex/Download?key={x.Key}")); string remark = "备注:客户所选服务:"; var projects = orderItem.ProjectType.Split(","); foreach (var project in projects) { remark += project switch { "1" => "港杂费代结,", "2" => "堆存费代结,", _ => "(未维护),", }; } remark = remark.Remove(remark.Length - 1, 1); remark += Environment.NewLine; remark += "客户备注:" + orderItem.Remark; HydSubmitDto submitDto = new HydSubmitDto() { billNoList = new List() { orderItem.Mblno }, customerName = orderItem.CompanyName, tel = orderItem.ContactTel, fileName = fileNameStr, fileUrl = fileUrl, remark = remark, registerFlag = 1, registerUser = new HydSubmitDto.RegisterUser() { phone = orderItem.ContactTel?.Trim(), userName = orderItem.ContactName?.Trim(), enterpriseName = orderItem.CompanyName?.Trim(), sex = 1, dutyNo = orderItem.TaxCode?.Trim() ?? "" } }; // 开始提交 long bsno = await hydService.Submit(submitDto); // 更新订单状态 orderItem.Status = (int)OrderStatusEnum.已下单; orderItem.Bsno = bsno; orderItem.IsSend = true; await orderService.Update(orderItem, x => new { x.Status, x.Bsno, x.IsSend }); // 记录状态历史 await orderHistoryService.Add(new OrderHistory() { Pid = orderItem.Id, StatusTime = DateTime.Now, Status = (int)OrderStatusEnum.已下单, Remark = orderItem.Remark }); } catch (Exception ex) { logger.LogError(ex, $"提单号{orderItem.Mblno}下单时发生未知异常,继续处理下一票"); continue; } } return Success(result); } /// /// 获取订单附件信息列表 /// /// 订单Id /// 附件类型 [HttpGet] public async Task>> GetAnnexInfoList(long id, FileTypeEnum fileType) { var result = await orderAnnexService.Db.Queryable((o, a) => o.AnnexId == a.Id) .Where((o, a) => o.OrderId == id && a.Type == (int)fileType) .Select((o, a) => new AnnexDto() { Name = a.Name, Type = a.Type, Id = a.Id }) .ToListAsync(); return Success(result); } /// /// 订单状态变更 /// [HttpPost] public async Task ChangeStatus(ChangeStatusDto changeStatusDto) { new ChangeStatusDtoValidator().ValidateAndThrow(changeStatusDto); var order = await orderService.QueryById(changeStatusDto.Id); if (order == null) { throw new Exception("未找到该订单"); } order.Status = (int)changeStatusDto.Status; decimal sumAmount = 0; bool isBeginTran = false; try { // 执行扣费 if (changeStatusDto.FeeList != null && changeStatusDto.FeeList.Count > 0) { string logMsg = $"订单Id:{changeStatusDto.Id},提单号:{order.Mblno}"; try { sumAmount = changeStatusDto.FeeList.Select(x => x.Amount).Sum(); logger.LogInformation($"{logMsg}, 手动更新状态时,需要扣费,总金额:{sumAmount}"); var custBalanceService = App.GetService>(); var balance = await custBalanceService.AsQueryable().FirstAsync(x => x.COMNAME == order.CompanyName); if (balance == null) { logger.LogInformation($"{logMsg},扣费失败:没有账户钱包!"); throw new Exception("扣费失败:没有账户钱包!"); } if (balance.Balance < sumAmount) { logger.LogInformation($"{logMsg},扣费失败:账户余额不足!{sumAmount}"); throw new Exception($"账户余额不足!{sumAmount} {order.CompanyName}"); } logger.LogInformation($"{logMsg},开始写入消费记录"); var custFeeService = App.GetService>(); var beizhu = string.Join(',', changeStatusDto.FeeList.Select(x => x.Name + ":" + x.Amount)); CustFee custFeeModel = new CustFee() { BEIZHU = beizhu, BSNO = order.Id.ToString(), COMNAME = order.CompanyName, MBLNO = order.Mblno, BSTYPE = CommonConst.WEITUOJIESUAN, CREATETIME = DateTime.Now, LURURENID = order.ContactId, LURUREN = order.ContactName, COMID = order.CompanyId, SENDUSERID = order.ContactId, SENDUSER = order.ContactName, SENDCOM = order.CompanyName, SENDTYPE = 0, SENDTIME = DateTime.Now, CtnrInfo = string.Empty, CtnrCount = 0, GID = Guid.NewGuid().ToString(), PRICE = sumAmount }; logger.LogInformation($"{logMsg},扣费记录内容:{{custFeeModel}}", custFeeModel.ToJson()); unitOfWorkManage.BeginTran(); isBeginTran = true; // 添加扣费记录 var num = await custFeeService.AsInsertable(custFeeModel).ExecuteCommandAsync(); if (num <= 0) { unitOfWorkManage.RollbackTran(); throw new Exception($"{logMsg},添加扣费记录失败!"); } else { logger.LogInformation($"{logMsg},添加扣费记录成功"); } // 更新余额 num = await custBalanceService.AsUpdateable() .SetColumns(x => x.Balance == x.Balance - sumAmount) .Where(x => x.COMNAME == order.CompanyName) .ExecuteCommandAsync(); if (num <= 0) { unitOfWorkManage.RollbackTran(); throw new Exception($"{logMsg},更新余额失败!"); } else { logger.LogInformation($"{logMsg},更新余额成功"); } } catch (Exception ex) { logger.LogError(ex, $"{logMsg},执行扣费时发生未知异常"); throw; } } if (!isBeginTran) { unitOfWorkManage.BeginTran(); } // 添加新的费用信息 if (changeStatusDto.FeeList != null && changeStatusDto.FeeList.Count > 0) { // 清除原有费用信息 //await orderFeeService.Delete(x => x.OrderId == changeStatusDto.Id); //order.Amount = order.Amount == null ? null : 0; var orderFeeModelList = changeStatusDto.FeeList.Select(x => new OrderFee() { Name = x.Name, Amount = x.Amount, OrderId = changeStatusDto.Id }).ToList(); await orderFeeService.Add(orderFeeModelList); // 查出来现有的费用记录,更新 var sumAllAmount = await orderFeeService.AsQueryable() .Where(x => x.OrderId == changeStatusDto.Id) .SumAsync(x => x.Amount); order.Amount = sumAllAmount; } await orderService.Update(order, x => new { x.Status, x.Amount }); var orderHistory = new OrderHistory { Pid = order.Id, Status = (int)changeStatusDto.Status, Remark = changeStatusDto.Remark, Amount = sumAmount, StatusTime = DateTime.Now, }; await orderHistoryService.Add(orderHistory); unitOfWorkManage.CommitTran(); } catch (Exception) { unitOfWorkManage.RollbackTran(); throw; } // 将更新后的状态及费用推送到消息队列 if (AppSettings.app("RabbitMQ", "Enabled").ObjToBool()) { _ = Task.Run(() => { string msg = $"Id:[{order.Id}],提单号:[{order.Mblno}],手动更新状态后推送队列"; try { StatusPushDto pushDto = new() { OrderId = order.Id, Mblno = order.Mblno, MessageType = 1, MessageDesc = "状态更新推送", Remark = changeStatusDto.Remark, Status = (int)changeStatusDto.Status, StatusDesc = changeStatusDto.Status.ToString() }; var feeList = orderFeeService.AsQueryable().Where(x => x.OrderId == order.Id).ToList(); if (feeList.Count > 0) { pushDto.FeeList = feeList.Select(x => new StatusPushDto.FeeDto() { FeeId = x.Id, FeeName = x.Name, FeeAmount = x.Amount }).ToList(); } var annexList = orderAnnexService.AsQueryable() .LeftJoin((o, a) => o.AnnexId == a.Id) .Where((o, a) => o.OrderId == order.Id && a.Type == 5) .Select((o, a) => a) .ToList(); if (annexList.Count > 0) { pushDto.FeebackAnnexList = annexList.Select(x => new StatusPushDto.FeebackAnnex() { Id = x.Id, BusinessTime = x.BusinessTime, FileName = x.Name, Remark = x.Remark }).ToList(); } //if (changeStatusDto.FeeList != null && changeStatusDto.FeeList.Count > 0) //{ // pushDto.FeeList = changeStatusDto.FeeList.Select(x => new StatusPushDto.FeeDto() // { // //Id = x. // FeeName = x.Name, // FeeAmount = x.Amount // }).ToList(); //} var json = JsonConvert.SerializeObject(pushDto, Formatting.Indented, new JsonSerializerSettings() { NullValueHandling = NullValueHandling.Ignore }); queueService.Push(msg, order.CompanyId, json); } catch (Exception ex) { logger.LogError(ex, $"{msg},失败"); } }); } return SuccessMsg(); } /// /// 为订单追加附件或信息 /// /// [HttpPost] public async Task BindAnnexOrInfo(BindAnnexOrInfoDto bindDto) { var order = await orderService.QueryById(bindDto.OrderId); if (order == null) { throw new Exception("未找到该订单"); } // 反馈附件需要请求海运达接口,所以需要先判断是否反馈成功,成功后再执行后续操作 if (bindDto.OperType == FileTypeEnum.反馈附件) { if (order.Status == null) { throw new Exception("请等待具有已下单状态后再进行反馈"); } if (order.Status == (int)OrderStatusEnum.已完结) { throw new Exception("该订单已完结,无法进行反馈"); } List hydFeedbackDtoList = new List(); if (bindDto.AnnexIdList != null && bindDto.AnnexIdList.Count > 0) { string domainUrl = AppSettings.app(["Startup", "Domain"]); var annexList = await annexService.Query(x => bindDto.AnnexIdList.Contains(x.Id)); foreach (Annex item in annexList) { string fileUrl = string.Join(",", annexList.Select(x => $"{domainUrl}/api/Annex/Download?key={x.Key}")); hydFeedbackDtoList.Add(new HydFeedbackDto() { fileName = item.Name, fileUrl = fileUrl, orderNo = (long)order.Bsno, remark = bindDto.Remark }); } } else { hydFeedbackDtoList.Add(new HydFeedbackDto() { orderNo = (long)order.Bsno, remark = bindDto.Remark }); } bool isSuccess = await hydService.FeedBack(hydFeedbackDtoList); if (!isSuccess) { logger.LogError($"提单号:{order.Mblno}向海运达反馈时发生异常"); throw new Exception("反馈失败,请稍后重试"); } else { logger.LogInformation($"提单号:{order.Mblno}向海运达反馈成功"); } } unitOfWorkManage.BeginTran(); // 如果操作类型为账单或发票,则先删除原有的绑定信息 if (bindDto.OperType == FileTypeEnum.反馈附件) { if (bindDto.AnnexIdList != null && bindDto.AnnexIdList.Count > 0) { // 添加要新增绑定的附件信息 var orderAnnexModelList = bindDto.AnnexIdList.Select(x => new OrderAnnex() { AnnexId = x, OrderId = bindDto.OrderId }).ToList(); await orderAnnexService.Add(orderAnnexModelList); } } else if (bindDto.OperType == FileTypeEnum.账单 || bindDto.OperType == FileTypeEnum.发票) { var oldAnnexIdList = await orderAnnexService.AsQueryable() .InnerJoin((o, a) => o.AnnexId == a.Id) .Where((o, a) => o.OrderId == bindDto.OrderId && a.Type == (int)bindDto.OperType) .Select((o, a) => a.Id) .ToListAsync(); // 处理要删除的 var waitDelAnndexIdList = oldAnnexIdList.Except(bindDto.AnnexIdList).ToList(); if (waitDelAnndexIdList.Any()) { await orderAnnexService.Delete(x => x.OrderId == bindDto.OrderId && waitDelAnndexIdList.Contains(x.AnnexId)); await annexService.Delete(x => waitDelAnndexIdList.Contains(x.Id)); } // 处理要新增的 var waitAddAnnexIdList = bindDto.AnnexIdList.Except(oldAnnexIdList); if (waitAddAnnexIdList.Any()) { var orderAnnexModelList = waitAddAnnexIdList.Select(x => new OrderAnnex() { AnnexId = x, OrderId = bindDto.OrderId }).ToList(); await orderAnnexService.Add(orderAnnexModelList); } } orderService.Db.Tracking(order); if (bindDto.OperType == FileTypeEnum.反馈附件) { if (!string.IsNullOrWhiteSpace(bindDto.Remark)) { string remark = string.IsNullOrEmpty(order.Remark) ? bindDto.Remark : order.Remark += (Environment.NewLine + bindDto.Remark); order.Remark = remark; } } else if (bindDto.OperType == FileTypeEnum.发票) { if (bindDto.MailFlag != null) { order.MailFlag = bindDto.MailFlag; } order.MailBillNo = bindDto.MailBillNo; } await orderService.Db.Updateable(order).ExecuteCommandAsync(); unitOfWorkManage.CommitTran(); // 如果操作类型为发票或账单,将反馈推送到消息队列 if ((bindDto.OperType is FileTypeEnum.发票 or FileTypeEnum.账单) && AppSettings.app("RabbitMQ", "Enabled").ObjToBool()) { _ = Task.Run(() => { string msg = $"Id:[{order.Id}],提单号:[{order.Mblno}],更新账单或发票后推送队列"; try { BillPushDto pushDto = new() { OrderId = order.Id, Mblno = order.Mblno, AnnexIdList = bindDto.AnnexIdList, }; if (bindDto.OperType == FileTypeEnum.账单) { pushDto.MessageType = 2; pushDto.MessageDesc = "账单附件信息推送"; } else if (bindDto.OperType == FileTypeEnum.发票) { pushDto.MessageType = 3; pushDto.MessageDesc = "发票附件信息推送"; pushDto.MailFlag = bindDto.MailFlag; pushDto.MailBillNo = bindDto.MailBillNo; } var json = JsonConvert.SerializeObject(pushDto, Formatting.Indented, new JsonSerializerSettings() { NullValueHandling = NullValueHandling.Ignore }); queueService.Push(msg, order.CompanyId, json); } catch (Exception ex) { logger.LogError(ex, $"{msg},失败"); } }); } return SuccessMsg(); } /// /// 获取订单详情 /// [HttpGet] public async Task> Detail(long id) { var result = await orderService.AsQueryable() .Where(x => x.Id == id) .Select() .FirstAsync(); if (result == null) { throw new Exception("为找到该订单,请刷新后重试"); } var annexList = await orderAnnexService.Db.Queryable((o, a) => o.AnnexId == a.Id) .Where((o, a) => o.OrderId == id) .Where((o, a) => a.Type == (int)FileTypeEnum.原始附件 || a.Type == (int)FileTypeEnum.反馈附件 || a.Type == (int)FileTypeEnum.外部往来单据) .Select((o, a) => new AnnexDto() { Id = a.Id, Name = a.Name, Type = a.Type, Remark = a.Remark, CreateTime = a.CreateTime, CreateBy = a.CreateBy }) .ToListAsync(); result.AnnexList = annexList; return Success(result); } /// /// 获取订单费用列表 /// [HttpGet] public async Task>> FeeList(long id) { var result = await orderFeeService.AsQueryable() .Where(x => x.OrderId == id) .Select() .ToListAsync(); return Success(result); } } }