You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
BookingHeChuan/Myshipping.Application/Service/ExpressDelivery/ExpressDeliveryService.cs

1019 lines
47 KiB
C#

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

using Furion;
using Furion.DataEncryption;
using Furion.DependencyInjection;
using Furion.DynamicApiController;
using Furion.FriendlyException;
using Furion.UnifyResult;
using Mapster;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using Myshipping.Application.Entity;
using Myshipping.Application.Service.ExpressDelivery.Dto;
using Myshipping.Application.Service.ExpressDelivery.Dto.SF;
using Myshipping.Core;
using Myshipping.Core.Attributes;
using Myshipping.Core.Service;
using Newtonsoft.Json;
using SqlSugar;
using StackExchange.Profiling.Internal;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
namespace Myshipping.Application
{
/// <summary>
/// 快递订单服务
/// </summary>
[ApiDescriptionSettings("Application", Name = "ExpressDelivery", Description = "快递订单服务", Order = 20)]
[Route("/ExpressDelivery")]
public class ExpressDeliveryService : IExpressDeliveryService, IDynamicApiController, ITransient
{
private const string STATUS_ASSOCIATION = "关联快递订单";
private const string STATUS_DISASSOCIATION = "取消关联快递订单";
private const string STATUS_DELETE = "关联快递订单已删除";
private const string STATUS_SEND = "快递已下单";
private const string STATUS_CANCEL = "快递已消单";
/// <summary>
/// 保存面单文件的文件夹名称
/// </summary>
private const string WAY_BILL_DIRECTORY = "WaybillFile";
private readonly ILogger<ExpressDeliveryService> _logger;
private readonly ISysCacheService _cache;
private readonly SqlSugarRepository<BookingStatusLog> _bookingStatuslogRep;
private readonly SqlSugarRepository<BookingOrder> _bookingOrderRep;
private readonly SqlSugarRepository<ExpressDeliveryOrder> _orderRep;
private readonly SqlSugarRepository<ExpressDeliveryBusiness> _businessRep;
private readonly SqlSugarRepository<ExpressDeliveryStatus> _statusRep;
private readonly SqlSugarRepository<ExpressDeliveryAddress> _addressRep;
private readonly SqlSugarRepository<ExpressDeliveryFee> _feeRep;
private readonly INamedServiceProvider<IDeliverySend> _deliverySendServiceProvider;
public ExpressDeliveryService(ILogger<ExpressDeliveryService> logger,
ISysCacheService cache,
SqlSugarRepository<BookingStatusLog> bookingStatuslogRep,
SqlSugarRepository<BookingOrder> bookingOrderRep,
SqlSugarRepository<ExpressDeliveryOrder> orderRep,
SqlSugarRepository<ExpressDeliveryBusiness> businessRep,
SqlSugarRepository<ExpressDeliveryStatus> statusRep,
SqlSugarRepository<ExpressDeliveryAddress> templeteRep,
INamedServiceProvider<IDeliverySend> deliverySendServiceProvider,
SqlSugarRepository<ExpressDeliveryFee> feeRep)
{
_logger = logger;
_cache = cache;
_orderRep = orderRep;
_businessRep = businessRep;
_statusRep = statusRep;
_bookingStatuslogRep = bookingStatuslogRep;
_bookingOrderRep = bookingOrderRep;
_addressRep = templeteRep;
_deliverySendServiceProvider = deliverySendServiceProvider;
_feeRep = feeRep;
}
/// <summary>
/// 分页查询快递主表
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpGet("Page")]
public async Task<SqlSugarPagedList<ExpressDeliveryDto>> Page([FromQuery] ExpressDeliveryInput input)
{
var entities = await _orderRep.AsQueryable().Filter(null, true)
.Where(x => x.TenantId == UserManager.TENANT_ID && x.IsDeleted == false)
.WhereIF(!string.IsNullOrWhiteSpace(input.KDNO), u => u.KDNO.Contains(input.KDNO))
.WhereIF(!string.IsNullOrWhiteSpace(input.SJCompany), u => u.SJCompany.Contains(input.SJCompany))
.WhereIF(!string.IsNullOrWhiteSpace(input.SJPeople), u => u.SJPeople.Contains(input.SJPeople))
.WhereIF(!string.IsNullOrWhiteSpace(input.SJTel), u => u.SJTel.Contains(input.SJTel))
.WhereIF(!string.IsNullOrWhiteSpace(input.FJCompany), u => u.FJCompany.Contains(input.FJCompany))
.WhereIF(!string.IsNullOrWhiteSpace(input.FJPeople), u => u.FJPeople.Contains(input.FJPeople))
.WhereIF(!string.IsNullOrWhiteSpace(input.FJTel), u => u.FJTel.Contains(input.FJTel))
.WhereIF(!string.IsNullOrWhiteSpace(input.VESSEL), u => u.VESSEL.Contains(input.VESSEL))
.WhereIF(!string.IsNullOrWhiteSpace(input.VOYNO), u => u.VOYNO.Contains(input.VOYNO))
.WhereIF(input.BDate != null, u => u.Date >= input.BDate)
.WhereIF(input.EDate != null, u => u.Date <= input.EDate)
.OrderBy(PageInputOrder.OrderBuilder(input.SortField, input.DescSort))
.ToPagedListAsync(input.PageNo, input.PageSize);
var list = entities.Adapt<SqlSugarPagedList<ExpressDeliveryDto>>();
foreach (var item in list.Items)
{
item.Business = await _businessRep.AsQueryable().Filter(null, true).Where(x => x.PId == item.Id).ToListAsync();
}
return list;
}
/// <summary>
/// 获取详情
/// </summary>
/// <param name="Id"></param>
/// <returns></returns>
[HttpPost("Get")]
public async Task<ExpressDeliveryDto> Get(long Id)
{
ExpressDeliveryDto ordOut = new ExpressDeliveryDto();
var main = await _orderRep.FirstOrDefaultAsync(u => u.Id == Id);
if (main != null)
{
ordOut = main.Adapt<ExpressDeliveryDto>();
var business = await _businessRep.AsQueryable().Where(x => x.PId == Id).ToListAsync();
ordOut.Business = business;
var feeList = await _feeRep.AsQueryable().Where(x => x.OrderId == Id).ToListAsync();
ordOut.FeeList = feeList;
}
return ordOut;
}
/// <summary>
/// 保存并返回数据
/// </summary>
/// <returns></returns>
[HttpPost("Save")]
[JoinValidateMessge]
public async Task<ExpressDeliveryDto> Save(ExpressDeliveryDto input)
{
var entity = input.Adapt<ExpressDeliveryOrder>();
string logGuid = Guid.NewGuid().ToString();
_logger.LogInformation($"快递订单保存操作开始,{logGuid}");
if (input.Id == 0)
{
entity.CurrentStateCode = "DJY02";
entity.CurrentStateDesc = "已保存";
_logger.LogInformation($"快递订单新增操作开始,{logGuid}");
await _orderRep.InsertAsync(entity);
if (input.Business != null && input.Business.Count > 0)
{
#region 保存关联的业务信息
_logger.LogInformation($"快递订单新增关联的业务信息,{logGuid}");
input.Business.ForEach(b => b.PId = entity.Id);
await _businessRep.InsertAsync(input.Business);
#endregion
#region 向与快递关联的订舱列表中添加动态
List<string> mblNoList = input.Business.Select(b => b.MBLNO).ToList();
await InsertNewBookingStatusWithMblnoList(mblNoList, STATUS_ASSOCIATION);
#endregion
}
// 添加快递动态
_logger.LogInformation($"快递订单新增快递动态,{logGuid}");
var status = new ExpressDeliveryStatus()
{
OrderId = entity.Id,
MailNo = "",
StatusCode = entity.CurrentStateCode,
StatusDesc = entity.CurrentStateDesc
};
await _statusRep.InsertAsync(status);
}
else
{
var oldOrder = _orderRep.FirstOrDefault(x => x.Id == input.Id);
if (oldOrder.CurrentStateCode != "DJY02")
{
throw Oops.Bah("修改失败,原因:下单过的快递单无法修改信息");
}
_logger.LogInformation($"快递订单修改操作开始,{logGuid}");
await _orderRep.AsUpdateable(entity).IgnoreColumns(it => new
{
it.CurrentStateCode,
it.CurrentStateDesc,
it.TenantId,
it.CreatedTime,
it.CreatedUserId,
it.CreatedUserName,
}).ExecuteCommandAsync();
#region 向与快递关联的订舱列表中添加动态,并新增或更新业务信息
List<ExpressDeliveryBusiness> businessList = await _businessRep.AsQueryable().Where(x => x.PId == input.Id).ToListAsync();
if (businessList.Count == 0)
{
if (input.Business?.Count != 0)
{
// 直接得到:要关联快递的提单号列表
List<string> mblNoList = input.Business.Select(b => b.MBLNO).ToList();
await InsertNewBookingStatusWithMblnoList(mblNoList, STATUS_ASSOCIATION);
// 直接得到:要新增的业务信息
input.Business.ForEach(b => b.PId = entity.Id);
await _businessRep.InsertAsync(input.Business);
}
}
else
{
if (input.Business?.Count == 0)
{
// 直接得到:要取消关联快递的提单号列表
List<string> mblNoList = businessList.Select(b => b.MBLNO).ToList();
await InsertNewBookingStatusWithMblnoList(mblNoList, STATUS_DISASSOCIATION);
// 直接得到:要删除的业务信息
await _businessRep.DeleteAsync(x => x.PId == entity.Id);
}
else
{
// 分析对比,判断哪些关联,哪些取消关联
List<string> oldMblnoList = businessList.Select(b => b.MBLNO).ToList();
List<string> newMblnoList = input.Business.Select(b => b.MBLNO).ToList();
// 新增关联的提单号列表:
List<string> addMblnoList = newMblnoList.Except(oldMblnoList).ToList();
await InsertNewBookingStatusWithMblnoList(addMblnoList, STATUS_ASSOCIATION);
// 取消关联的提单号列表
List<string> cancelMblnoList = oldMblnoList.Except(newMblnoList).ToList();
await InsertNewBookingStatusWithMblnoList(cancelMblnoList, STATUS_DISASSOCIATION);
// 先删除,再新增业务信息
await _businessRep.DeleteAsync(x => x.PId == entity.Id);
input.Business.ForEach(b => b.PId = entity.Id);
await _businessRep.InsertAsync(input.Business);
}
}
#endregion
}
return await Get(entity.Id);
}
/// <summary>
/// 删除单据
/// </summary>
/// <param name="Ids"></param>
/// <returns></returns>
[SqlSugarUnitOfWork]
[HttpPost("Delete")]
public async Task Delete(string Ids)
{
var arr = Ids.Split(",");
if (arr.Length > 0)
{
foreach (var ar in arr)
{
long Id = Convert.ToInt64(ar);
ExpressDeliveryOrder order = await _orderRep.AsQueryable(e => e.Id == Id).FirstAsync() ?? throw Oops.Bah("未找到快递订单");
// 添加快递动态
var status = new ExpressDeliveryStatus()
{
OrderId = Id,
MailNo = order.KDNO,
StatusCode = "DJY05",
StatusDesc = "快递单已删除"
};
await _statusRep.InsertAsync(status);
// 更新快递订单表
await _orderRep.UpdateAsync(x => x.Id == Id, x => new ExpressDeliveryOrder
{
IsDeleted = true,
CurrentStateCode = status.StatusCode,
CurrentStateDesc = status.StatusDesc
});
// 快递关联的订舱添加动态
List<string> mblnoList = await _businessRep.AsQueryable(x => x.PId == Id).Select(b => b.MBLNO).ToListAsync();
await InsertNewBookingStatusWithMblnoList(mblnoList, STATUS_DELETE);
// 删除快递关联的业务表数据
await _businessRep.DeleteAsync(x => x.PId == Id);
}
}
else
{
throw Oops.Bah("请上传正确参数");
}
}
/// <summary>
/// 发送快递
/// </summary>
/// <param name="Id"></param>
/// <returns></returns>
[HttpPost("SendBooking")]
public async Task<dynamic> SendBooking(long Id)
{
var order = _orderRep.FirstOrDefault(x => x.Id == Id);
if (order == null)
{
throw Oops.Bah("请选择正确数据!");
}
if (order.CurrentStateCode == "DJY01")
{
throw Oops.Bah("下单失败,原因:尚未保存");
}
if (order.CurrentStateCode != "DJY02")
{
throw Oops.Bah("下单失败,原因:重复下单");
}
IDeliverySend deliverySend = GetDeliverySend(order.KDCompany);
string waybillNo = await deliverySend.CreateOrder(order);
string statusDesc = $"{STATUS_SEND}(单号:{waybillNo}";
// 不需要等待的任务,并且不会因为异常导致当前请求终止
_ = Task.Run(async () =>
{
#region 添加快递动态
try
{
var status = new ExpressDeliveryStatus()
{
OrderId = Id,
MailNo = waybillNo,
StatusCode = "DJY03",
StatusDesc = statusDesc
};
await _statusRep.InsertAsync(status);
}
catch (Exception ex)
{
_logger.LogError(ex, "调用快递接口下单后,添加快递动态的过程中发生异常");
}
#endregion
#region 为与快递关联的订舱添加动态
try
{
List<string> mblnoList = await _businessRep.AsQueryable(b => b.PId == Id).Select(b => b.MBLNO).ToListAsync();
_ = InsertNewBookingStatusWithMblnoList(mblnoList, statusDesc);
}
catch (Exception ex)
{
_logger.LogError(ex, "调用快递接口下单后,为与快递关联的订舱添加动态的过程中发生异常");
}
#endregion
#region 维护地址簿
try
{
if (!await _addressRep.IsExistsAsync(a => a.People == order.SJPeople && a.Tel == order.SJTel))
{
await _addressRep.InsertAsync(new ExpressDeliveryAddress()
{
Address = order.SJAddress,
City = order.SJCity,
Company = order.SJCompany,
People = order.SJPeople,
Province = order.SJProvince,
ProvinceId = order.SJProvinceId,
Tel = order.SJTel,
Type = 1
});
}
if (!await _addressRep.IsExistsAsync(a => a.People == order.FJPeople && a.Tel == order.FJTel))
{
await _addressRep.InsertAsync(new ExpressDeliveryAddress()
{
Address = order.FJAddress,
City = order.FJCity,
Company = order.FJCompany,
People = order.FJPeople,
Province = order.FJProvince,
ProvinceId = order.FJProvinceId,
Tel = order.FJTel,
Type = 2
});
}
}
catch (Exception ex)
{
_logger.LogError(ex, "调用快递接口下单后,维护地址簿的过程中发生异常");
}
#endregion
});
// 需要等待的任务
#region 下载面单PDF保存到本地不会因异常终止当前请求
string filePath = null;
try
{
var dic = Path.Combine(App.WebHostEnvironment.WebRootPath, WAY_BILL_DIRECTORY);
if (!Directory.Exists(dic))
{
Directory.CreateDirectory(dic);
}
var fileName = $"{waybillNo}_{order.Id}.pdf";
filePath = Path.Combine(dic, fileName);
await deliverySend.DownloadWaybillFile(waybillNo, filePath);
}
catch (Exception ex)
{
_logger.LogError(ex, "调用下单接口后,下载面单的过程中发生异常");
}
#endregion
#region 向快递订单表反写快递单号与状态
ExpressDeliveryOrder updateOrder = new ExpressDeliveryOrder()
{
Id = Id,
KDNO = waybillNo,
CurrentStateCode = "DJY03",
CurrentStateDesc = statusDesc,
WaybillFilePath = filePath
};
await _orderRep.AsUpdateable(updateOrder)
.UpdateColumns(o => new { o.KDNO, o.CurrentStateCode, o.CurrentStateDesc, o.WaybillFilePath })
.ExecuteCommandAsync();
#endregion
UnifyContext.Fill(new
{
KDNO = waybillNo,
currentStateCode = "DJY03",
currentStateDesc = statusDesc
});
return "下单成功!";
}
/// <summary>
/// 取消快递下单
/// </summary>
/// <param name="Id"></param>
/// <returns></returns>
[HttpPost("CancelBooking")]
public async Task<string> CancelBooking(long Id)
{
var order = _orderRep.FirstOrDefault(x => x.Id == Id) ?? throw Oops.Bah("请选择正确数据!");
if (order.CurrentStateCode is "DJY01" or "DJY02")
{
throw Oops.Bah("消单失败,原因:尚未下单,无需消单");
}
if (order.CurrentStateCode is "DJY04")
{
throw Oops.Bah("消单失败,原因:已消单,无需再次消单");
}
IDeliverySend deliverySend = GetDeliverySend(order.KDCompany);
await deliverySend.CancelOrder(order.Id.ToString());
#region 添加快递动态
var status = new ExpressDeliveryStatus()
{
OrderId = Id,
MailNo = order.KDNO,
StatusCode = "DJY04",
StatusDesc = STATUS_CANCEL
};
await _statusRep.InsertAsync(status);
#endregion
#region 为与快递关联的订舱添加动态
List<string> mblnoList = await _businessRep.AsQueryable(b => b.PId == Id).Select(b => b.MBLNO).ToListAsync();
await InsertNewBookingStatusWithMblnoList(mblnoList, STATUS_CANCEL);
#endregion
#region 更新快递订单状态
ExpressDeliveryOrder updateOrder = new ExpressDeliveryOrder()
{
Id = Id,
CurrentStateCode = status.StatusCode,
CurrentStateDesc = status.StatusDesc,
};
await _orderRep.AsUpdateable(updateOrder)
.UpdateColumns(o => new { o.CurrentStateCode, o.CurrentStateDesc })
.ExecuteCommandAsync();
#endregion
return "取消成功!";
}
/// <summary>
/// 打印面单根据快递订单Id读取相应的面单文件并返回
/// </summary>
/// <param name="authorization">Jwt令牌</param>
/// <param name="orderId">快递订单Id</param>
/// <returns></returns>
[HttpGet("PrintWaybill")]
[NonUnify]
[AllowAnonymous]
public async Task<IActionResult> PrintWaybill([FromQuery][Required] string authorization, [FromQuery][Required] long orderId)
{
var validateResult = JWTEncryption.Validate(authorization);
if (!validateResult.IsValid)
{
return new BadPageResult(403) { Title = "接口鉴权未通过", Description = null, };
//return new UnauthorizedObjectResult("接口鉴权未通过");
}
var order = await _orderRep.AsQueryable().Filter(null, true).FirstAsync(x => x.Id == orderId);
if (order == null)
{
return new BadPageResult(400) { Title = "请选择正确快递单", Description = null, };
}
if (order.CurrentStateCode is "DJY01" or "DJY02")
{
return new BadPageResult(400) { Title = "请先保存并下单后,再打印面单", Description = null, };
}
if (string.IsNullOrEmpty(order.KDNO))
{
return new BadPageResult(500) { Title = "未知异常:快递单号为空", Description = null, };
}
try
{
var dic = Path.Combine(App.WebHostEnvironment.WebRootPath, WAY_BILL_DIRECTORY);
var filePath = Path.Combine(dic, order.WaybillFilePath);
if (!File.Exists(filePath))
{
_logger.LogInformation("快递面单文件不存在,尝试重新下载...");
IDeliverySend deliverySend = GetDeliverySend(order.KDCompany);
await deliverySend.DownloadWaybillFile(order.KDNO, filePath);
}
var data = File.ReadAllBytes(filePath);
FileContentResult result = new FileContentResult(data, "application/pdf");
return result;
}
catch (Exception ex)
{
_logger.LogError(ex, "打印面单的过程中发生未知异常");
return new BadPageResult(500) { Title = "打印失败", Description = ex.Message, };
}
}
/// <summary>
/// 根据提单号列表,向与之快递关联的订舱动态中,添加快递动态
/// </summary>
/// <param name="mblnoList">需要添加快递动态的提单号列表</param>
/// <param name="status">快递动态描述</param>
/// <param name="logGuid">日志标志</param>
[NonAction]
private async Task InsertNewBookingStatusWithMblnoList(List<string> mblnoList, string status, string logGuid = "")
{
if (mblnoList == null || mblnoList.Count == 0)
{
_logger.LogInformation($"快递订单关联订舱增加动态,{logGuid}mblNoList为空return");
return;
}
_logger.LogInformation($"快递订单关联订舱增加动态,{logGuid}mblNoList:{string.Join(',', mblnoList)}");
List<string> filteredList = mblnoList.Where(m => !string.IsNullOrWhiteSpace(m)).ToList(); // 如果提单号为空,则不进行处理
if (filteredList == null || filteredList.Count == 0)
{
return;
}
var bookingIdMapMblnoList = await _bookingOrderRep.AsQueryable(o => o.ParentId == 0 && filteredList.Contains(o.MBLNO))
.Select(o => new { o.Id, o.MBLNO })
.ToListAsync();
var bookingStatusLogList = new List<BookingStatusLog>();
foreach (string mblNo in filteredList)
{
var bookingOrderIdListTemp = bookingIdMapMblnoList.Where(o => o.MBLNO == mblNo);
if (bookingOrderIdListTemp == null)
{
_logger.LogInformation($"根据提单号{mblNo}查询订舱记录主键结果为空,{logGuid}");
continue;
}
else if (bookingOrderIdListTemp.Count() > 1)
{
_logger.LogInformation($"根据提单号{mblNo}查询订舱记录主键时查出多条记录ids{string.Join(',', bookingOrderIdListTemp.Select(b => b.Id).ToArray())}{logGuid}");
continue;
}
long? bookingOrderId = bookingOrderIdListTemp.First().Id;
_logger.LogInformation($"根据提单号{mblNo}查询订舱记录主键为{bookingOrderId}{logGuid}");
bookingStatusLogList.Add(new BookingStatusLog()
{
BookingId = bookingOrderId,
Status = status,
Category = "kuaidi",
OpTime = DateTime.Now,
MBLNO = mblNo
});
}
if (bookingStatusLogList.Count > 0)
{
await _bookingStatuslogRep.InsertAsync(bookingStatusLogList);
}
}
/// <summary>
/// 根据不同的快递公司,解析出不同的实现类
/// </summary>
/// <param name="kdCompany"></param>
/// <returns></returns>
private IDeliverySend GetDeliverySend(string kdCompany)
{
return _deliverySendServiceProvider.GetService<IScoped>(kdCompany switch
{
"sf" => nameof(SFDeliverySend),
"jd" => throw Oops.Oh("京东快递以后会对接的"),
"ems" => throw Oops.Oh("EMS快递以后会对接的"),
_ => throw Oops.Oh("未知快递公司")
});
}
#region 顺丰推送接口
/// <summary>
/// 接收顺丰推送的路由动态
/// </summary>
[AllowAnonymous]
[NonUnify]
[HttpPost("ReceiveSfRoute")]
public async Task<object> ReceiveSfRoute(SFReceiveRouteDto orderStatus)
{
try
{
string logGuid = Guid.NewGuid().ToString();
_logger.LogInformation($"接收到顺丰路由动态,{logGuid},入参:{orderStatus?.ToJsonString()}");
var expressDeliveryStatusList = new List<ExpressDeliveryStatus>();
foreach (WaybillRoute item in orderStatus.Body.WaybillRoute)
{
expressDeliveryStatusList.Add(new ExpressDeliveryStatus()
{
OrderId = long.Parse(item.Orderid),
AcceptAddress = item.AcceptAddress,
AcceptTime = string.IsNullOrEmpty(item.AcceptTime) ? null : DateTime.Parse(item.AcceptTime),
ErrorCode = item.ReasonCode,
ErrorDesc = item.ReasonName,
MailNo = item.Mailno,
StatusId = item.Id,
StatusCode = item.OpCode,
StatusDesc = item.Remark
});
}
IEnumerable<IGrouping<long?, ExpressDeliveryStatus>> statusGroupList = expressDeliveryStatusList.GroupBy(e => e.OrderId);
foreach (IGrouping<long?, ExpressDeliveryStatus> item in statusGroupList)
{
long? orderId = item.Key;
ExpressDeliveryOrder order = await _orderRep.AsQueryable(e => e.Id == orderId)
.Filter(null, true)
.FirstAsync();
if (order == null)
{
_logger.LogInformation($"未找到相应的快递订单,{logGuid}Id{orderId}");
continue;
}
// 因为此方法为匿名方法所以需要手动设置一下租户Id
expressDeliveryStatusList.Where(s => s.OrderId == orderId).ToList().ForEach(e => e.TenantId = order.TenantId);
#region 更新快递订单当前的状态
_logger.LogInformation($"当前快递订单的状态,{logGuid}Code{order.CurrentStateCode}Desc{order.CurrentStateDesc}");
ExpressDeliveryStatus lastStatus = item.MaxBy(e => e.StatusId);
Lazy<IUpdateable<ExpressDeliveryOrder>> waitUpdate = new(() => _orderRep.Context.Updateable<ExpressDeliveryOrder>());
if (order.CurrentStateCode != lastStatus.StatusCode)
{
waitUpdate.Value.SetColumns(o => o.CurrentStateCode == lastStatus.StatusCode);
}
if (order.CurrentStateDesc != lastStatus.StatusDesc)
{
waitUpdate.Value.SetColumns(o => o.CurrentStateDesc == lastStatus.StatusDesc);
}
if (waitUpdate.IsValueCreated)
{
_logger.LogInformation($"快递订单的状态更新为,{logGuid}Code{lastStatus.StatusCode}Desc{lastStatus.StatusDesc}");
await waitUpdate.Value.Where(e => e.Id == orderId).ExecuteCommandAsync();
}
#endregion
#region 向与快递关联的订舱列表中添加动态(如果一票快递关联了多条订舱,则每条订舱都要添加动态)
List<string> mblNoList = await _businessRep.AsQueryable(b => b.PId == orderId && b.TenantId == order.TenantId).Filter(null, true).Select(b => b.MBLNO).ToListAsync();
List<string> filteredList = mblNoList.Where(m => !string.IsNullOrWhiteSpace(m)).ToList();
if (filteredList == null)
{
_logger.LogInformation($"根据快递订单主键查询关联业务表的提单号,查询结果为空,{logGuid}");
}
else
{
_logger.LogInformation($"根据快递订单主键查询关联业务表的提单号共查出以下记录MblNos{string.Join(',', filteredList)}{logGuid}");
var bookingIdMapMblnoList = await _bookingOrderRep.AsQueryable(o => o.ParentId == 0 && o.TenantId == order.TenantId && filteredList.Contains(o.MBLNO))
.Filter(null, true)
.Select(o => new { o.Id, o.MBLNO })
.ToListAsync();
var bookingStatusLogList = new List<BookingStatusLog>();
foreach (string mblnoItem in filteredList)
{
var bookingOrderIdListTemp = bookingIdMapMblnoList.Where(o => o.MBLNO == mblnoItem);
if (bookingOrderIdListTemp == null)
{
_logger.LogInformation($"根据提单号{mblnoItem}查询订舱记录主键结果为空,{logGuid}");
continue;
}
else if (bookingOrderIdListTemp.Count() > 1)
{
_logger.LogInformation($"根据提单号{mblnoItem}查询订舱记录主键时查出多条记录ids{string.Join(',', bookingOrderIdListTemp.Select(b => b.Id).ToArray())}{logGuid}");
continue;
}
long? bookingOrderId = bookingOrderIdListTemp.First().Id;
_logger.LogInformation($"根据提单号{mblnoItem}查询订舱记录主键为{bookingOrderId}{logGuid}");
foreach (ExpressDeliveryStatus statusItem in item)
{
bookingStatusLogList.Add(new BookingStatusLog()
{
BookingId = bookingOrderId,
Status = statusItem.StatusDesc,
Category = "kuaidi",
OpTime = DateTime.Now,
MBLNO = bookingOrderIdListTemp.First().MBLNO,
TenantId = order.TenantId
});
}
}
await _bookingStatuslogRep.InsertAsync(bookingStatusLogList);
}
#endregion
}
#region 保存快递动态
// 如果租户Id不为null或0说明接收到的快递动态能找到相应的快递订单然后再进行动态新增操作
expressDeliveryStatusList = expressDeliveryStatusList.Where(e => e.TenantId != null && e.TenantId != 0).ToList();
if (expressDeliveryStatusList != null && expressDeliveryStatusList.Count > 0)
{
await _statusRep.InsertAsync(expressDeliveryStatusList);
}
#endregion
return new { return_code = "0000", return_msg = "成功" };
}
catch (Exception ex)
{
_logger.LogError(ex, "接收顺丰推送的路由状态时发生异常");
return new { return_code = "1000", return_msg = ex.Message };
}
}
/// <summary>
/// 接收顺丰推送的订单动态
/// </summary>
[AllowAnonymous]
[NonUnify]
[HttpPost("ReceiveSfOrderState")]
public async Task<object> ReceiveSfOrderState(ReceiveSfOrderStateDto receive)
{
try
{
string logGuid = Guid.NewGuid().ToString();
_logger.LogInformation($"接收到顺丰快递动态,{logGuid},入参:{receive?.ToJsonString()}");
var expressDeliveryStatusList = new List<ExpressDeliveryStatus>();
foreach (ReceiveSfOrderStateDto.OrderState item in receive.orderState)
{
expressDeliveryStatusList.Add(new ExpressDeliveryStatus()
{
OrderId = long.Parse(item.orderNo),
AcceptAddress = "",
AcceptTime = null,
ErrorCode = "",
ErrorDesc = "",
MailNo = item.waybillNo,
StatusId = receive.requestId,
StatusCode = item.orderStateCode,
StatusDesc = item.orderStateDesc
});
}
IEnumerable<IGrouping<long?, ExpressDeliveryStatus>> statusGroupList = expressDeliveryStatusList.GroupBy(e => e.OrderId);
foreach (IGrouping<long?, ExpressDeliveryStatus> item in statusGroupList)
{
long? orderId = item.Key;
ExpressDeliveryOrder order = await _orderRep.AsQueryable(e => e.Id == orderId)
.Filter(null, true)
.FirstAsync();
if (order == null)
{
_logger.LogInformation($"未找到相应的快递订单,{logGuid}Id{orderId}");
continue;
}
// 因为此方法为匿名方法所以需要手动设置一下租户Id
expressDeliveryStatusList.Where(s => s.OrderId == orderId).ToList().ForEach(e => e.TenantId = order.TenantId);
#region 更新快递订单当前的状态
_logger.LogInformation($"当前快递订单的状态,{logGuid}Code{order.CurrentStateCode}Desc{order.CurrentStateDesc}");
ExpressDeliveryStatus lastStatus = item.MaxBy(e => e.StatusId);
Lazy<IUpdateable<ExpressDeliveryOrder>> waitUpdate = new(() => _orderRep.Context.Updateable<ExpressDeliveryOrder>());
if (order.CurrentStateCode != lastStatus.StatusCode)
{
waitUpdate.Value.SetColumns(o => o.CurrentStateCode == lastStatus.StatusCode);
}
if (order.CurrentStateDesc != lastStatus.StatusDesc)
{
waitUpdate.Value.SetColumns(o => o.CurrentStateDesc == lastStatus.StatusDesc);
}
if (waitUpdate.IsValueCreated)
{
_logger.LogInformation($"快递订单的状态更新为,{logGuid}Code{lastStatus.StatusCode}Desc{lastStatus.StatusDesc}");
await waitUpdate.Value.Where(e => e.Id == orderId).ExecuteCommandAsync();
}
#endregion
#region 向与快递关联的订舱列表中添加动态(如果一票快递关联了多条订舱,则每条订舱都要添加动态)
List<string> mblNoList = await _businessRep.AsQueryable(b => b.PId == orderId && b.TenantId == order.TenantId).Filter(null, true).Select(b => b.MBLNO).ToListAsync();
List<string> filteredList = mblNoList.Where(m => !string.IsNullOrWhiteSpace(m)).ToList();
if (filteredList == null)
{
_logger.LogInformation($"根据快递订单主键查询关联业务表的提单号,查询结果为空,{logGuid}");
}
else
{
_logger.LogInformation($"根据快递订单主键查询关联业务表的提单号共查出以下记录MblNos{string.Join(',', filteredList)}{logGuid}");
var bookingIdMapMblnoList = await _bookingOrderRep.AsQueryable(o => o.ParentId == 0 && o.TenantId == order.TenantId && filteredList.Contains(o.MBLNO))
.Filter(null, true)
.Select(o => new { o.Id, o.MBLNO })
.ToListAsync();
var bookingStatusLogList = new List<BookingStatusLog>();
foreach (string mblnoItem in filteredList)
{
var bookingOrderIdListTemp = bookingIdMapMblnoList.Where(o => o.MBLNO == mblnoItem);
if (bookingOrderIdListTemp == null)
{
_logger.LogInformation($"根据提单号{mblnoItem}查询订舱记录主键结果为空,{logGuid}");
continue;
}
else if (bookingOrderIdListTemp.Count() > 1)
{
_logger.LogInformation($"根据提单号{mblnoItem}查询订舱记录主键时查出多条记录ids{string.Join(',', bookingOrderIdListTemp.Select(b => b.Id).ToArray())}{logGuid}");
continue;
}
long? bookingOrderId = bookingOrderIdListTemp.First().Id;
_logger.LogInformation($"根据提单号{mblnoItem}查询订舱记录主键为{bookingOrderId}{logGuid}");
foreach (ExpressDeliveryStatus statusItem in item)
{
bookingStatusLogList.Add(new BookingStatusLog()
{
BookingId = bookingOrderId,
Status = statusItem.StatusDesc,
Category = "kuaidi",
OpTime = DateTime.Now,
MBLNO = bookingOrderIdListTemp.First().MBLNO,
TenantId = order.TenantId
});
}
}
await _bookingStatuslogRep.InsertAsync(bookingStatusLogList);
}
#endregion
}
#region 保存快递动态
// 如果租户Id不为null或0说明接收到的快递动态能找到相应的快递订单然后再进行动态新增操作
expressDeliveryStatusList = expressDeliveryStatusList.Where(e => e.TenantId != null && e.TenantId != 0).ToList();
if (expressDeliveryStatusList != null && expressDeliveryStatusList.Count > 0)
{
await _statusRep.InsertAsync(expressDeliveryStatusList);
}
#endregion
return new { success = "true", code = "0", msg = "" };
}
catch (Exception ex)
{
_logger.LogError(ex, "接收顺丰推送的订单状态时发生异常");
return new { success = "false", code = "0", msg = ex.Message };
}
}
/// <summary>
/// 接收顺丰推送的费用信息
/// </summary>
[AllowAnonymous]
[NonUnify]
[HttpPost("ReceiveSfFee")]
[HttpGet("ReceiveSfFee")]
public async Task<object> ReceiveSfFee([FromForm] ReceiveSfFeeDto receive)
{
try
{
string logGuid = Guid.NewGuid().ToString();
_logger.LogInformation($"接收到顺丰快递费用信息,{logGuid},入参:{receive?.ToJsonString()}");
ContentModel content = JsonConvert.DeserializeObject<ContentModel>(receive.content);
long orderId = long.Parse(content.orderNo);
ExpressDeliveryOrder order = await _orderRep.AsQueryable(e => e.Id == orderId)
.Filter(null, true)
.FirstAsync();
if (order == null)
{
_logger.LogInformation($"未找到相应的快递订单,{logGuid}Id{orderId}");
return new { code = "200", partnerCode = "", service = "", msgData = "" };
}
// 保存计费重量
var feeWeight = float.Parse(content.meterageWeightQty);
await _orderRep.Context.Updateable<ExpressDeliveryOrder>()
.SetColumns(o => o.FeeWeight == feeWeight + "kg")
.Where(e => e.Id == orderId)
.ExecuteCommandAsync();
List<ExpressDeliveryFee> feeList = new(content.feeList.Count);
// 保存费用信息
foreach (Fee item in content.feeList)
{
feeList.Add(new ExpressDeliveryFee()
{
Account = item.customerAcctCode,
FeeAmount = item.feeAmt,
FeeTypeCode = item.feeTypeCode,
FeeTypeName = item.feeTypeCode switch { "1" => "主运费", "2" => "其他费用", "3" => "保费", "4" => "代收货款服务费", "5" => "代收货款", _ => "未知费用类型" },
KDNO = item.waybillNo,
OrderId = orderId,
SettleAccountsTypeCode = item.settlementTypeCode
});
}
// 因为此方法为匿名方法所以需要手动设置一下租户Id
feeList.Where(s => s.OrderId == orderId).ToList().ForEach(e => e.TenantId = order.TenantId);
await _feeRep.InsertAsync(feeList);
return new { code = "200", partnerCode = "", service = "", msgData = "" };
}
catch (Exception ex)
{
_logger.LogError(ex, "接收顺丰推送的费用信息时发生异常");
return new { code = "400", partnerCode = "", service = "", msgData = "" };
}
}
#endregion
#region 地址簿相关
/// <summary>
/// 获取快递地址簿列表
/// </summary>
[HttpGet("GetAddressList")]
public async Task<List<ExpressDeliveryAddressDto>> GetAddressList()
{
var modelList = await _addressRep.ToListAsync(e => true, e => e.Type, OrderByType.Desc);
var result = modelList.Adapt<List<ExpressDeliveryAddressDto>>();
return result;
}
/// <summary>
/// 删除快递地址簿
/// </summary>
[HttpPost("DeleteAddress")]
public async Task DeleteAddress([Required] string ids)
{
long[] idArr = ids.Split(',').Adapt<long[]>();
await _addressRep.DeleteAsync(a => idArr.Contains(a.Id));
}
/// <summary>
/// 新增或修改地址簿
/// </summary>
[HttpPost("SaveOrUpdateAddress")]
public async Task SaveOrUpdateAddress(ExpressDeliveryAddressDto input)
{
if (input == null) return;
var inputModel = input.Adapt<ExpressDeliveryAddress>();
if (inputModel.Id == 0)
{
await _addressRep.InsertAsync(inputModel);
}
else
{
await _addressRep.AsUpdateable(inputModel)
.IgnoreColumns(a => a.TenantId)
.ExecuteCommandAsync();
}
}
#endregion
}
}