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

850 lines
41 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.DependencyInjection;
using Furion.DynamicApiController;
using Furion.FriendlyException;
using Furion.RemoteRequest.Extensions;
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.Core;
using Myshipping.Core.Attributes;
using Myshipping.Core.Service;
using Newtonsoft.Json.Linq;
using SqlSugar;
using StackExchange.Profiling.Internal;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
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 = "快递消单";
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;
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)
{
_logger = logger;
_cache = cache;
_orderRep = orderRep;
_businessRep = businessRep;
_statusRep = statusRep;
_bookingStatuslogRep = bookingStatuslogRep;
_bookingOrderRep = bookingOrderRep;
_addressRep = templeteRep;
}
/// <summary>
/// 分页查询快递主表
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpGet("Page")]
public async Task<dynamic> 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.KDNO.Contains(input.SJCompany))
.WhereIF(!string.IsNullOrWhiteSpace(input.SJPeople), u => u.KDNO.Contains(input.SJPeople))
.WhereIF(!string.IsNullOrWhiteSpace(input.SJTel), u => u.KDNO.Contains(input.SJTel))
.WhereIF(!string.IsNullOrWhiteSpace(input.FJCompany), u => u.KDNO.Contains(input.FJCompany))
.WhereIF(!string.IsNullOrWhiteSpace(input.FJPeople), u => u.KDNO.Contains(input.FJPeople))
.WhereIF(!string.IsNullOrWhiteSpace(input.FJTel), u => u.KDNO.Contains(input.FJTel))
.WhereIF(!string.IsNullOrWhiteSpace(input.VESSEL), u => u.KDNO.Contains(input.VESSEL))
.WhereIF(!string.IsNullOrWhiteSpace(input.VOYNO), u => u.KDNO.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>
/// <returns></returns>
[HttpPost("Save")]
[JoinValidateMessge]
public async Task<dynamic> Save(ExpressDeliveryDto input)
{
var entity = input.Adapt<ExpressDeliveryOrder>();
string logGuid = Guid.NewGuid().ToString();
_logger.LogInformation($"快递订单保存操作开始,{logGuid}");
if (input.Id == 0)
{
entity.CurrentStateCode = "DJY01";
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
{
_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 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 = "DJY04",
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("Get")]
public async Task<dynamic> 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;
}
return ordOut;
}
/// <summary>
/// 发送快递
/// </summary>
/// <param name="Id"></param>
/// <returns></returns>
[HttpPost("SendBooking")]
public async Task<dynamic> SendBooking(long Id)
{
var rt = String.Empty;
SFSendBooking sFSend = new SFSendBooking();
var order = _orderRep.FirstOrDefault(x => x.Id == Id);
if (order == null)
{
throw Oops.Bah("请选择正确数据!");
}
sFSend.orderId = Id.ToString();
sFSend.language = "zh_CN";
List<CargoDetailsItem> cargo = new List<CargoDetailsItem>();
cargo.Add(new CargoDetailsItem
{
count = (int)order.KDNum,
name = order.GOODSNAME
});
List<ContactInfoListItem> contactList = new List<ContactInfoListItem>();
contactList.Add(new ContactInfoListItem
{
address = $"{order.FJProvince}{order.FJCity}{order.FJAddress}",
contact = order.FJPeople,
contactType = 1,
country = "CN",
//postCode = order.FJPostCode,
tel = order.FJTel,
});
contactList.Add(new ContactInfoListItem
{
address = $"{order.SJProvince}{order.SJCity}{order.SJAddress}",
contact = order.SJPeople,
contactType = 2,
country = "CN",
//postCode = order.SJPostCode,
tel = order.SJTel,
});
sFSend.contactInfoList = contactList;
sFSend.cargoDetails = cargo;
(string url, Dictionary<string, object> dict) apiParam = await CreateSFApiParams("EXP_RECE_CREATE_ORDER", sFSend);
_logger.LogInformation("调用顺丰下单接口,参数:" + apiParam.dict.ToJson());
var strRtn = await apiParam.url.SetBody(apiParam.dict, "application/x-www-form-urlencoded").PostAsStringAsync();
//var strRtn = "{\"apiErrorMsg\":\"\",\"apiResponseID\":\"00018BF4CE37D63FDF38696876F68A3F\",\"apiResultCode\":\"A1000\",\"apiResultData\":\"{\\\"success\\\":true,\\\"errorCode\\\":\\\"S0000\\\",\\\"errorMsg\\\":null,\\\"msgData\\\":{\\\"orderId\\\":\\\"485172445380677\\\",\\\"originCode\\\":\\\"759\\\",\\\"destCode\\\":\\\"886\\\",\\\"filterResult\\\":2,\\\"remark\\\":\\\"\\\",\\\"url\\\":null,\\\"paymentLink\\\":null,\\\"isUpstairs\\\":null,\\\"isSpecialWarehouseService\\\":null,\\\"mappingMark\\\":null,\\\"agentMailno\\\":null,\\\"returnExtraInfoList\\\":null,\\\"waybillNoInfoList\\\":[{\\\"waybillType\\\":1,\\\"waybillNo\\\":\\\"SF7444473840720\\\",\\\"boxNo\\\":null,\\\"length\\\":null,\\\"width\\\":null,\\\"height\\\":null,\\\"weight\\\":null,\\\"volume\\\":null}],\\\"routeLabelInfo\\\":[{\\\"code\\\":\\\"1000\\\",\\\"routeLabelData\\\":{\\\"waybillNo\\\":\\\"SF7444473840720\\\",\\\"sourceTransferCode\\\":\\\"759VA\\\",\\\"sourceCityCode\\\":\\\"759\\\",\\\"sourceDeptCode\\\":\\\"759\\\",\\\"sourceTeamCode\\\":\\\"\\\",\\\"destCityCode\\\":\\\"886\\\",\\\"destDeptCode\\\":\\\"886\\\",\\\"destDeptCodeMapping\\\":\\\"\\\",\\\"destTeamCode\\\":\\\"\\\",\\\"destTeamCodeMapping\\\":\\\"\\\",\\\"destTransferCode\\\":\\\"886WA\\\",\\\"destRouteLabel\\\":\\\"886WA-886\\\",\\\"proName\\\":\\\"\\\",\\\"cargoTypeCode\\\":\\\"C201\\\",\\\"limitTypeCode\\\":\\\"T4\\\",\\\"expressTypeCode\\\":\\\"B1\\\",\\\"codingMapping\\\":\\\"WU\\\",\\\"codingMappingOut\\\":\\\"\\\",\\\"xbFlag\\\":\\\"0\\\",\\\"printFlag\\\":\\\"000000000\\\",\\\"twoDimensionCode\\\":\\\"MMM={'k1':'886WA','k2':'886','k3':'','k4':'T4','k5':'SF7444473840720','k6':'','k7':'ce37f885'}\\\",\\\"proCode\\\":\\\"特快\\\",\\\"printIcon\\\":\\\"00000000\\\",\\\"abFlag\\\":\\\"\\\",\\\"destPortCode\\\":null,\\\"destCountry\\\":null,\\\"destPostCode\\\":null,\\\"goodsValueTotal\\\":\\\"\\\",\\\"currencySymbol\\\":null,\\\"cusBatch\\\":\\\"\\\",\\\"goodsNumber\\\":null,\\\"errMsg\\\":\\\"\\\",\\\"checkCode\\\":\\\"ce37f885\\\",\\\"proIcon\\\":\\\"\\\",\\\"fileIcon\\\":\\\"\\\",\\\"fbaIcon\\\":\\\"\\\",\\\"icsmIcon\\\":\\\"\\\",\\\"destGisDeptCode\\\":\\\"886\\\",\\\"newIcon\\\":null,\\\"sendAreaCode\\\":null,\\\"destinationStationCode\\\":null,\\\"sxLabelDestCode\\\":null,\\\"sxDestTransferCode\\\":null,\\\"sxCompany\\\":null,\\\"newAbFlag\\\":null,\\\"destAddrKeyWord\\\":\\\"\\\",\\\"rongType\\\":null,\\\"waybillIconList\\\":null},\\\"message\\\":\\\"SF7444473840720:\\\"}],\\\"contactInfoList\\\":null,\\\"sendStartTm\\\":null,\\\"customerRights\\\":null,\\\"expressTypeId\\\":null}}\"}";
_logger.LogInformation("调用顺丰下单接口,返回:" + strRtn);
var jobj = strRtn.ToJObject();
if (jobj.GetStringValue("apiResultCode") == "A1000")
{
var resultDataObj = jobj.GetStringValue("apiResultData").ToJObject();
bool isSuccess = resultDataObj.GetBooleanValue("success");
if (isSuccess)
{
rt = "下单成功!";
var waybillNoInfoObj = resultDataObj.GetJObjectValue("msgData").GetJArrayValue("waybillNoInfoList")[0].Value<JObject>();
var waybillNo = waybillNoInfoObj.GetStringValue("waybillNo");
string statusDesc = $"{STATUS_SEND}(单号:{waybillNo}";
#region 添加快递动态
var status = new ExpressDeliveryStatus()
{
OrderId = Id,
MailNo = waybillNo,
StatusCode = "DJY02",
StatusDesc = statusDesc
};
await _statusRep.InsertAsync(status);
#endregion
#region 为与快递关联的订舱添加动态
List<string> mblnoList = await _businessRep.AsQueryable(b => b.PId == Id).Select(b => b.MBLNO).ToListAsync();
await InsertNewBookingStatusWithMblnoList(mblnoList, statusDesc);
#endregion
#region 向快递订单表反写快递单号与状态
ExpressDeliveryOrder updateOrder = new ExpressDeliveryOrder()
{
Id = Id,
KDNO = waybillNo,
CurrentStateCode = status.StatusCode,
CurrentStateDesc = status.StatusDesc,
};
await _orderRep.AsUpdateable(updateOrder)
.UpdateColumns(o => new { o.KDNO, o.CurrentStateCode, o.CurrentStateDesc })
.ExecuteCommandAsync();
UnifyContext.Fill(new { KDNO = waybillNo });
#endregion
#region 地址簿维护
await SaveOrUpdateAddress(new ExpressDeliveryAddressDto()
{
Address = order.SJAddress,
City = order.SJCity,
Company = order.SJCompany,
People = order.SJPeople,
Province = order.SJProvince,
ProvinceId = order.SJProvinceId,
Tel = order.SJTel
});
await SaveOrUpdateAddress(new ExpressDeliveryAddressDto()
{
Address = order.FJAddress,
City = order.FJCity,
Company = order.FJCompany,
People = order.FJPeople,
Province = order.FJProvince,
ProvinceId = order.FJProvinceId,
Tel = order.FJTel
});
#endregion
}
else
{
var errorMsg = resultDataObj.GetStringValue("errorMsg");
_logger.LogInformation("调用顺丰下单接口返回异常errorMsg" + errorMsg);
throw Oops.Bah(errorMsg);
}
}
else
{
var apiErrorMsg = jobj.GetStringValue("apiErrorMsg");
_logger.LogInformation("调用顺丰下单接口返回异常apiErrorMsg" + apiErrorMsg);
throw Oops.Bah(apiErrorMsg);
}
return rt;
}
/// <summary>
/// 取消快递下单
/// </summary>
/// <param name="Id"></param>
/// <returns></returns>
[HttpPost("CancelBooking")]
public async Task<string> CancelBooking(long Id)
{
var param = new
{
dealType = 2,
orderId = Id
};
(string url, Dictionary<string, object> dict) apiParam = await CreateSFApiParams("EXP_RECE_UPDATE_ORDER", param);
_logger.LogInformation("调用顺丰订单取消接口,参数:" + apiParam.dict.ToJson());
var strRtn = await apiParam.url.SetBody(apiParam.dict, "application/x-www-form-urlencoded").PostAsStringAsync();
//var strRtn = "{\"apiErrorMsg\":\"\",\"apiResponseID\":\"00018BF5250ADD3FEE59BC8A2F42CE3F\",\"apiResultCode\":\"A1000\",\"apiResultData\":\"{\\\"success\\\":true,\\\"errorCode\\\":\\\"S0000\\\",\\\"errorMsg\\\":null,\\\"msgData\\\":{\\\"orderId\\\":\\\"485172445380677\\\",\\\"waybillNoInfoList\\\":[{\\\"waybillType\\\":1,\\\"waybillNo\\\":\\\"SF7444473840720\\\"}],\\\"resStatus\\\":2,\\\"extraInfoList\\\":null}}\"}";
_logger.LogInformation("调用顺丰订单取消接口,返回:" + strRtn);
var jobj = strRtn.ToJObject();
if (jobj.GetStringValue("apiResultCode") == "A1000")
{
var resultDataObj = jobj.GetStringValue("apiResultData").ToJObject();
if (resultDataObj.GetBooleanValue("success"))
{
ExpressDeliveryOrder order = await _orderRep.AsQueryable(e => e.Id == Id).FirstAsync();
#region 添加快递动态
var status = new ExpressDeliveryStatus()
{
OrderId = Id,
MailNo = order.KDNO,
StatusCode = "DJY03",
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 "取消成功";
}
else
{
var errorMsg = resultDataObj.GetStringValue("errorMsg");
_logger.LogInformation("顺丰取消快递下单接口返回异常errorMsg" + errorMsg);
throw Oops.Bah(errorMsg);
}
}
else
{
var apiErrorMsg = jobj.GetStringValue("apiErrorMsg");
_logger.LogInformation("顺丰取消快递下单接口,返回异常:" + apiErrorMsg);
throw Oops.Bah(apiErrorMsg);
}
}
/// <summary>
/// 订单结果查询接口
/// </summary>
/// <param name="Id"></param>
/// <returns></returns>
[HttpPost("QueryKDSchedule")]
public async Task<dynamic> QueryKDSchedule(long Id)
{
var rt = String.Empty;
var json = new
{
orderId = Id.ToString()
};
(string url, Dictionary<string, object> dict) apiParam = await CreateSFApiParams("EXP_RECE_SEARCH_ORDER_RESP", json);
_logger.LogInformation("调用顺丰订单结果查询接口,参数:" + apiParam.dict.ToJson());
var strRtn = await apiParam.url.SetBody(apiParam.dict, "application/x-www-form-urlencoded").PostAsStringAsync();
_logger.LogInformation("调用顺丰订单结果查询接口,返回:" + strRtn);
var jobj = strRtn.ToJObject();
if (jobj.GetStringValue("apiResultCode") == "A1000")
{
var resultDataObj = jobj.GetStringValue("apiResultData").ToJObject();
if (resultDataObj.GetBooleanValue("success"))
{
rt = jobj.GetStringValue("apiResultData").ToJsonString();
}
else
{
throw Oops.Bah(resultDataObj.GetStringValue("errorMsg"));
}
}
else
{
throw Oops.Bah(jobj.GetStringValue("apiErrorMsg"));
}
return rt;
}
/// <summary>
/// 获取顺丰API接口调用参数
/// </summary>
/// <returns></returns>
[NonAction]
private async Task<(string url, Dictionary<string, object> param)> CreateSFApiParams(string serviceCode, object msgData)
{
var cacheDictData = await _cache.GetAllDictData();
var url = cacheDictData.FirstOrDefault(x => x.TypeCode == "url_set" && x.Code == "sf_api_url")?.Value;
if (string.IsNullOrEmpty(url))
{
throw Oops.Bah("需配置顺丰Api接口字典参数url地址sf_api_url");
}
var partnerId = cacheDictData.FirstOrDefault(x => x.TypeCode == "SFCode" && x.Code == "partnerId")?.Value;
if (string.IsNullOrEmpty(partnerId))
{
throw Oops.Bah("需配置顺丰Api接口字典参数合作伙伴编码即顾客编码partnerId");
}
string accessToken;
if (_cache.Exists($"SFToken{UserManager.TENANT_ID}"))
{
accessToken = _cache.Get($"SFToken{UserManager.TENANT_ID}");
}
else
{
var secret = cacheDictData.FirstOrDefault(x => x.TypeCode == "SFCode" && x.Code == "secret")?.Value;
if (string.IsNullOrEmpty(partnerId))
{
throw Oops.Bah("需配置顺丰Api接口字典参数合作伙伴密钥即校验码secret");
}
var getTokenParam = new Dictionary<string, string>()
{
{ "partnerID",partnerId },
{ "grantType", "password"},
{ "secret", secret}
};
_logger.LogInformation("调用顺丰Token查询接口参数" + getTokenParam.ToJson());
var strRtn = await (url + "/oauth2/accessToken").SetBody(getTokenParam, "application/x-www-form-urlencoded").PostAsStringAsync();
_logger.LogInformation("调用顺丰Token查询接口返回" + strRtn);
var jobj = strRtn.ToJObject();
if (jobj.GetStringValue("apiResultCode") == "A1000")
{
accessToken = jobj.GetStringValue("accessToken");
//设置token过期时间2小时
await _cache.SetTimeoutAsync($"SFToken{UserManager.TENANT_ID}", accessToken, TimeSpan.FromHours(2));
}
else
{
throw Oops.Bah("调用顺丰Token查询接口时发生异常" + jobj.GetStringValue("apiErrorMsg"));
}
}
var dict = new Dictionary<string, object>()
{
{ "partnerID", partnerId },
{ "serviceCode", serviceCode},
{ "requestID", Guid.NewGuid().ToString()},
{ "timestamp", DateTimeOffset.Now.ToUnixTimeSeconds()},
{ "accessToken", accessToken},
{ "msgData", msgData}
};
return (url + "/std/service", dict);
}
/// <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>
[AllowAnonymous]
[NonUnify]
[HttpPost("AddStatus")]
public async Task<object> AddStatus(SFAddOrderStatus orderStatus)
{
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;
ExpressDeliveryStatus lastStatus = item.MaxBy(e => e.StatusId);
ExpressDeliveryOrder order = await _orderRep.AsQueryable(e => e.Id == orderId)
.Filter(null, true)
.FirstAsync();
if (order == null)
{
_logger.LogInformation($"未找到相应的快递订单,{logGuid}Id{orderId}");
continue;
}
#region 更新快递订单当前的状态
_logger.LogInformation($"当前快递订单的状态,{logGuid}Code{order.CurrentStateCode}Desc{order.CurrentStateDesc}");
// 因为此方法为匿名方法所以需要手动设置一下租户Id
expressDeliveryStatusList.Where(s => s.OrderId == orderId).ToList().ForEach(e => e.TenantId = order.TenantId);
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 = "成功" };
}
#region 地址簿相关
/// <summary>
/// 获取快递地址簿列表
/// </summary>
[HttpGet("GetAddressList")]
public async Task<List<ExpressDeliveryAddressDto>> GetAddressList()
{
var modelList = await _addressRep.ToListAsync();
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 existsAddress = await _addressRep.FirstOrDefaultAsync(a => a.People == input.People && a.Tel == input.Tel);
if (existsAddress == null)
{
// 新增
var model = input.Adapt<ExpressDeliveryAddress>();
await _addressRep.InsertAsync(model);
}
else
{
// 更新
var model = input.Adapt<ExpressDeliveryAddress>();
model.Id = existsAddress.Id;
await _addressRep.AsUpdateable(model)
.IgnoreColumns(a => a.TenantId)
.ExecuteCommandAsync();
}
}
#endregion
}
}