using EntrustSettle.Common; using EntrustSettle.Controllers; using EntrustSettle.IServices; using EntrustSettle.Model; using EntrustSettle.Model.Dtos; using EntrustSettle.Model.Models; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Newtonsoft.Json; using RestSharp; namespace EntrustSettle.Api.Controllers { /// /// 对外提供的委托结算相关接口 /// [AllowAnonymous] public class OpenController : BaseApiController { private readonly IOrderService orderService; private readonly IAnnexService annexService; private readonly IOrderAnnexService orderAnnexService; private readonly ILogger logger; private readonly IOrderHistoryService orderHistoryService; private readonly IQueueService queueService; private readonly IOrderFeeService orderFeeService; private readonly IInvoiceApplyService invoiceApplyService; public OpenController(IOrderService orderService, ILogger logger, IOrderHistoryService orderHistoryService, IQueueService queueService, IOrderFeeService orderFeeService, IAnnexService annexService, IOrderAnnexService orderAnnexService, IInvoiceApplyService invoiceApplyService) { this.orderService = orderService; this.logger = logger; this.orderHistoryService = orderHistoryService; this.queueService = queueService; this.orderFeeService = orderFeeService; this.annexService = annexService; this.orderAnnexService = orderAnnexService; this.invoiceApplyService = invoiceApplyService; } /// /// 下单 /// [HttpPost] [ApiUser(ApiCode = "EntrustSettle")] public async Task>> OrderSubmit(OrderSubmitDto inputDto) { var result = await App.GetService().Submit(inputDto); return result; } /// /// 附件上传 /// /// 附件文件 /// 文件类型 [HttpPost] [ApiUser(ApiCode = "EntrustSettle")] public async Task> AnnexUpload([FromForm] IFormFile file, [FromForm] FileTypeEnum fileType) { var result = await App.GetService().Upload(file, fileType); return result; } /// /// 反馈信息(为订单追加附件或信息) /// /// [HttpPost] [ApiUser(ApiCode = "EntrustSettle")] public async Task BindAnnexOrInfo([FromBody] BindAnnexOrInfoDto bindDto) { var result = await App.GetService().BindAnnexOrInfo(bindDto); return result; } /// /// 获取附件 /// /// 文件记录主键 [HttpGet] [ApiUser(ApiCode = "EntrustSettle")] public async Task AnnexDownload([FromQuery] long annexId) { var result = await App.GetService().DownloadFile(annexId); return result; } /// /// 发票申请 /// [HttpPost] [ApiUser(ApiCode = "EntrustSettle")] public async Task ApplyInvoice(ApplyInvoiceDto input) { var result = await App.GetService().ApplyInvoice(input); return result; } /// /// 账单申请 /// [HttpPost] [ApiUser(ApiCode = "EntrustSettle")] public async Task ApplyBill(ApplyBillDto input) { var result = await App.GetService().ApplyBill(input); return result; } /// /// 海运达状态回推接口 /// [HttpPost] [ApiUser(ApiCode = "PushOrderStatus")] public async Task PushOrderStatus([FromBody] HydQueryResultDto input) { // 推送类型 1:订单状态、费用、账单、外部往来单据 2:发票 int pushType = 0; List invoiceApplyList = null; var orderList = await orderService.Query(x => x.Bsno == input.id); if (orderList != null && orderList.Count > 0) { pushType = 1; logger.LogInformation($"订单Id[{input.id}]接收到回推后,判断操作类型为[反馈订单状态/费用/外部往来单据/账单]"); } else { invoiceApplyList = await invoiceApplyService.Query(x => x.Bsno == input.id); if (invoiceApplyList != null && invoiceApplyList.Count > 0) { pushType = 2; logger.LogInformation($"订单Id[{input.id}]接收到回推后,判断操作类型为[反馈发票]"); } else { string msg = $"订单Id[{input.id}]接收到回推后未查询到本地订单或发票申请订单"; logger.LogInformation(msg); return FailedMsg(msg); } } if (pushType == 1) { var order = orderList[0]; bool isHasBill = false; // 保存【往来单据附件】或【账单附件】 if (input.feedbackList != null && input.feedbackList.Count > 0) { var outerFileIdList = input.feedbackList.Select(x => x.id).ToList(); var existsOuterFileIdList = await orderAnnexService.AsQueryable() .LeftJoin((o, a) => o.AnnexId == a.Id) .Where((o, a) => o.OrderId == order.Id && outerFileIdList.Contains((long)a.OuterFileId)) .Select((o, a) => a.OuterFileId) .ToListAsync(); foreach (var item in input.feedbackList) { // 如果文件不是外部推送的,不处理 if (item.sendType != 1) continue; // 如果文件信息已经存在,不处理 if (existsOuterFileIdList.Contains(item.id)) continue; // 保存附件信息 var annex = new Annex() { OuterFileId = item.id, Name = item.fileName, Remark = item.remark, BusinessTime = item.createTime, //Path = relativePath //Type }; // 海运达规定:海运达返回的账单会以“[反馈账单]”为开头,同时billApplyFlag = 1 if (item.billApplyFlag == 1 && item.remark?.StartsWith("[反馈账单]") == true) { annex.Type = 3; isHasBill = true; } else { annex.Type = 5; } string fullPath = null; if (!string.IsNullOrEmpty(item.fileUrl)) { // 检查文件保存目录 var dir = Path.Combine(App.WebHostEnvironment.WebRootPath, "files"); if (!Directory.Exists(dir)) { Directory.CreateDirectory(dir); } // 文件名 var newFileName = Guid.NewGuid().ToString("N") + Path.GetExtension(item.fileName); // 相对路径 var relativePath = Path.Combine("files", newFileName); // 完整路径 fullPath = Path.Combine(dir, newFileName); annex.Path = relativePath; } await annexService.Add(annex); var orderAnnex = new OrderAnnex() { OrderId = order.Id, AnnexId = annex.Id }; await orderAnnexService.Add(orderAnnex); // 记录订单状态历史 var orderStatusModelList = new OrderHistory() { Pid = order.Id, StatusTime = DateTime.Now, Status = annex.Type switch { 3 => 8, 5 => 9, _ => -1 }, Remark = item.remark, }; await orderHistoryService.Add(orderStatusModelList); if (!string.IsNullOrEmpty(item.fileUrl)) { var restClient = new RestClient(item.fileUrl); var request = new RestRequest(); using var stream = await restClient.DownloadStreamAsync(request); using FileStream fileStream = new FileStream(fullPath, FileMode.Create); await stream.CopyToAsync(fileStream); } } } // 更新订单状态 bool isUpdate = false; var orderUpdateable = orderService.AsUpdateable(); // 海运达正式环境上线后才提出:只有已接单和已完结两种状态,所以这里做了映射 if (input.status is 0 or 1 && input.status != order.Status) { isUpdate = true; order.Status = input.status; orderUpdateable.SetColumns(x => x.Status == order.Status); // 记录订单状态变更历史 await orderHistoryService.Add(new OrderHistory() { Pid = order.Id, Status = (int)order.Status, StatusTime = DateTime.Now, CreateBy = "系统", Remark = "(状态接收)" }); } else if (input.status == 4 && order.Status is 0 or 1) { isUpdate = true; order.Status = 2; orderUpdateable.SetColumns(x => x.Status == 2); // 记录订单状态变更历史 await orderHistoryService.Add(new OrderHistory() { Pid = order.Id, Status = 2, StatusTime = DateTime.Now, CreateBy = "系统", Remark = "(状态接收)" }); } if (isHasBill) { isUpdate = true; orderUpdateable.SetColumns(x => x.IsApplyBill == false); } if (isUpdate) { await orderUpdateable.Where(x => x.Bsno == input.id).ExecuteCommandAsync(); } // 将更新后的状态、费用、外部往来单据 推送到消息队列 // 将账单附件 推送到消息队列 if (AppSettings.app("RabbitMQ", "Enabled").ObjToBool()) { string logTitle = $"Id:[{order.Id}],提单号[{order.Mblno}],推送费用、状态、往来单据"; try { StatusPushDto pushDto = new() { OrderId = order.Id, Mblno = order.Mblno, MessageType = 1, MessageDesc = "状态更新推送", Remark = "", Status = order.Status ?? 0, StatusDesc = order.Status switch { 0 => "已下单", 1 => "已接单", 2 => "待缴费", 3 => "已缴费", 4 => "已完结", _ => "未知状态", } }; 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(); } var json = JsonConvert.SerializeObject(pushDto, Formatting.Indented, new JsonSerializerSettings() { NullValueHandling = NullValueHandling.Ignore }); queueService.Push(logTitle, order.CompanyId, json); } catch (Exception ex) { logger.LogError(ex, $"{logTitle}时发生未知异常"); } if (isHasBill) { string logTitle2 = $"订单Id[{input.id}],提单号[{order.Mblno}],接收到账单然后推送账单"; try { var billIdList = await orderAnnexService.AsQueryable() .LeftJoin((o, a) => o.AnnexId == a.Id) .Where((o, a) => o.OrderId == order.Id && a.Type == 3) .Select((o, a) => a.Id) .ToListAsync(); BillPushDto pushDto = new() { OrderId = order.Id, Mblno = order.Mblno, AnnexIdList = billIdList, MessageType = 2, MessageDesc = "账单附件信息推送" }; var json = JsonConvert.SerializeObject(pushDto, Formatting.Indented, new JsonSerializerSettings() { NullValueHandling = NullValueHandling.Ignore }); queueService.Push(logTitle2, order.CompanyId, json); } catch (Exception ex) { logger.LogError(ex, $"{logTitle2}时发生未知异常"); } } } return SuccessMsg(); } else if (pushType == 2) { // 保存【发票附件】 // 推送【发票附件】到消息队列 List waitSendOrderIdList = new(); if (input.feedbackList != null && input.feedbackList.Count > 0) { var outerFileIdList = input.feedbackList.Select(x => x.id).ToList(); foreach (var feedbackItem in input.feedbackList) { // 如果文件不是外部推送的,不处理 if (feedbackItem.sendType != 1) continue; // 待绑定此发票附件的订单Id列表 List waitBindOrderIdList = new(); // 如果文件信息已经存在,不处理 foreach (var applyItem in invoiceApplyList) { var isExists = await orderAnnexService.AsQueryable() .LeftJoin((o, a) => o.AnnexId == a.Id) .Where((o, a) => a.OuterFileId == feedbackItem.id && o.OrderId == applyItem.OrderId) .AnyAsync(); if (!isExists) { waitBindOrderIdList.Add(applyItem.OrderId); } } if (waitBindOrderIdList.Count == 0) { continue; } waitSendOrderIdList.AddRange(waitBindOrderIdList); // 保存附件信息 var annex = new Annex() { OuterFileId = feedbackItem.id, Name = feedbackItem.fileName, Remark = feedbackItem.remark, BusinessTime = feedbackItem.createTime, Type = 4, //Path = relativePath }; string fullPath = null; if (!string.IsNullOrEmpty(feedbackItem.fileUrl)) { // 检查文件保存目录 var dir = Path.Combine(App.WebHostEnvironment.WebRootPath, "files"); if (!Directory.Exists(dir)) { Directory.CreateDirectory(dir); } // 文件名 var newFileName = Guid.NewGuid().ToString("N") + Path.GetExtension(feedbackItem.fileName); // 相对路径 var relativePath = Path.Combine("files", newFileName); // 完整路径 fullPath = Path.Combine(dir, newFileName); annex.Path = relativePath; } await annexService.Add(annex); // 下载附件 if (!string.IsNullOrEmpty(feedbackItem.fileUrl)) { var restClient = new RestClient(feedbackItem.fileUrl); var request = new RestRequest(); using var stream = await restClient.DownloadStreamAsync(request); using FileStream fileStream = new FileStream(fullPath, FileMode.Create); await stream.CopyToAsync(fileStream); } // 为订单列表统一绑定此附件 var orderAnndexList = waitBindOrderIdList.Select(x => new OrderAnnex() { OrderId = x, AnnexId = annex.Id }).ToList(); await orderAnnexService.Add(orderAnndexList); // 记录订单状态历史 var orderStatusModelList = waitBindOrderIdList.Select(x => new OrderHistory() { Pid = x, StatusTime = DateTime.Now, Status = 7, Remark = feedbackItem.remark, }).ToList(); await orderHistoryService.Add(orderStatusModelList); } } if (waitSendOrderIdList.Count != 0) { waitSendOrderIdList = waitSendOrderIdList.Distinct().ToList(); // 更新订单状态 await orderService.AsUpdateable() .SetColumns(x => x.IsApplyInvoice == false) .SetColumns(x => x.Status == 4) // 2024.6.18 上线后提出需求:收到海运达发票后,订单状态改为已完结 .Where(x => waitSendOrderIdList.Contains(x.Id)) .ExecuteCommandAsync(); // 将 发票附件 推送到消息队列 var orderInfoList = await orderService.AsQueryable().Where(x => waitSendOrderIdList.Contains(x.Id)) .Select(x => new { x.Id, x.Mblno, x.CompanyId, x.MailBillNo, x.MailFlag, x.Status, }).ToListAsync(); var logTitle = $"Id列表:[{string.Join(',', orderInfoList.Select(x => x.Id))}],提单号列表:[{string.Join(',', orderInfoList.Select(x => x.Mblno))}],将每一票所有的发票及已完结状态推送队列"; logger.LogInformation(logTitle); try { var invoiceAnnexList = await orderAnnexService.AsQueryable() .LeftJoin((o, a) => o.AnnexId == a.Id) .Where((o, a) => waitSendOrderIdList.Contains(o.OrderId) && a.Type == 4) .Select((o, a) => o) .ToListAsync(); foreach (var item in orderInfoList) { var invoiceAnnexIdList = invoiceAnnexList.Where(x => x.OrderId == item.Id).Select(x => x.AnnexId).ToList(); if (invoiceAnnexIdList.Count == 0) continue; var logItemTitle = $"Id:[{item.Id}],提单号:[{item.Mblno}],附件Id列表:[({string.Join(',', invoiceAnnexIdList)})]开始推送队列"; // 推送发票 BillPushDto pushDto1 = new() { MessageType = 3, MessageDesc = "发票附件信息推送", AnnexIdList = invoiceAnnexIdList, OrderId = item.Id, Mblno = item.Mblno, MailFlag = item.MailFlag, MailBillNo = item.MailBillNo, }; var json1 = JsonConvert.SerializeObject(pushDto1, Formatting.Indented, new JsonSerializerSettings() { NullValueHandling = NullValueHandling.Ignore }); queueService.Push(logItemTitle, item.CompanyId, json1); // 推送状态 StatusPushDto pushDto2 = new() { OrderId = item.Id, Mblno = item.Mblno, MessageType = 1, MessageDesc = "状态更新推送", Remark = "", Status = item.Status ?? 0, StatusDesc = item.Status switch { 0 => "已下单", 1 => "已接单", 2 => "待缴费", 3 => "已缴费", 4 => "已完结", _ => "未知状态", } }; var feeList = orderFeeService.AsQueryable().Where(x => x.OrderId == item.Id).ToList(); if (feeList.Count > 0) { pushDto2.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 == item.Id && a.Type == 5) .Select((o, a) => a) .ToList(); if (annexList.Count > 0) { pushDto2.FeebackAnnexList = annexList.Select(x => new StatusPushDto.FeebackAnnex() { Id = x.Id, BusinessTime = x.BusinessTime, FileName = x.Name, Remark = x.Remark }).ToList(); } var json2 = JsonConvert.SerializeObject(pushDto2, Formatting.Indented, new JsonSerializerSettings() { NullValueHandling = NullValueHandling.Ignore }); queueService.Push(logTitle, item.CompanyId, json2); } } catch (Exception ex) { logger.LogError(ex, $"{logTitle}的过程中发生未知异常"); } } return SuccessMsg(); } else { throw new Exception($"订单Id[{input.id}]接收到回推后,无法判断操作类型"); } } //[HttpGet] //public string TestTime() //{ // return DateTime.Now.ToString(); //} //[HttpGet] //public void TestError() //{ // throw new Exception("测试异常"); //} //[HttpGet] //public async Task TestSetRedis(string key, string value) //{ // var caching = App.GetService(); // await caching.SetAsync(key, value, TimeSpan.FromHours(3)); // return SuccessMsg(); //} //[HttpGet] //public async Task> TestGetRedis(string key) //{ // var caching = App.GetService(); // var value = await caching.GetStringAsync(key); // return Success(value); //} } }