快递模块对接费用等接口

optimize
zhangxiaofeng 12 months ago
parent 2ddd852fa3
commit 2206f7ab88

@ -0,0 +1,49 @@
using System;
using SqlSugar;
using System.ComponentModel;
using Myshipping.Core.Entity;
namespace Myshipping.Application.Entity
{
/// <summary>
/// 快递费用
/// </summary>
[SugarTable("express_delivery_fee")]
[Description("快递费用")]
public class ExpressDeliveryFee : DBEntityTenant
{
/// <summary>
/// 快递订单记录主键
/// </summary>
public long? OrderId { get; set; }
/// <summary>
/// 快递运单号
/// </summary>
public string KDNO { get; set; }
/// <summary>
/// 费用类型编码
/// </summary>
public string FeeTypeCode { get; set; }
/// <summary>
/// 费用类型名称
/// </summary>
public string FeeTypeName { get; set; }
/// <summary>
/// 费用金额
/// </summary>
public decimal FeeAmount { get; set; }
/// <summary>
/// 付款账号
/// </summary>
public string Account { get; set; }
/// <summary>
/// 结费类型代码1现结2月结3到付
/// </summary>
public string SettleAccountsTypeCode { get; set; }
}
}

@ -107,10 +107,17 @@ namespace Myshipping.Application.Entity
/// 寄件数量
/// </summary>
public int? KDNum { get; set; }
///// <summary>
///// 快递费
///// </summary>
//public decimal? KDFee { get; set; }
/// <summary>
/// 快递费
/// 计费重量
/// </summary>
public decimal? KDFee { get; set; }
public float? FeeWeight { get; set; }
/// <summary>
/// 备注
/// </summary>

@ -0,0 +1,33 @@
using Myshipping.Application.Entity;
using System.Threading.Tasks;
namespace Myshipping.Application
{
/// <summary>
/// 快递对接接口
/// </summary>
public interface IDeliverySend
{
/// <summary>
/// 快递下单
/// </summary>
/// <param name="expressDeliveryOrder">快递订单记录</param>
/// <returns>快递单号</returns>
Task<string> CreateOrder(ExpressDeliveryOrder expressDeliveryOrder);
/// <summary>
/// 快递消单
/// </summary>
/// <param name="orderId">快递订单记录主键</param>
/// <returns>是否消单成功</returns>
Task<bool> CancelOrder(string orderId);
/// <summary>
/// 下载快递面单
/// </summary>
/// <param name="waybillNo">快递单号</param>
/// <param name="savePath">快递面单保存地址</param>
/// <returns></returns>
Task DownloadWaybillFile(string waybillNo,string savePath);
}
}

@ -0,0 +1,289 @@
using Furion.DependencyInjection;
using Furion.FriendlyException;
using Furion.RemoteRequest.Extensions;
using Microsoft.Extensions.Logging;
using Myshipping.Application.Entity;
using Myshipping.Application.Service.ExpressDelivery.Dto;
using Myshipping.Core;
using Myshipping.Core.Service;
using Newtonsoft.Json.Linq;
using StackExchange.Profiling.Internal;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
namespace Myshipping.Application
{
/// <summary>
/// 快递
/// </summary>
public class SFDeliverySend : IDeliverySend, ITransient
{
/// <summary>
/// Redis中用于保存访问顺丰API的Token的键名
/// </summary>
private const string SF_API_TOKEN_KEY = $"SfApiToken";
private readonly ISysCacheService cache;
private readonly ILogger<ExpressDeliveryService> logger;
public SFDeliverySend(ISysCacheService cache, ILogger<ExpressDeliveryService> logger)
{
this.cache = cache;
this.logger = logger;
}
#region IDeliverySend接口实现
public async Task<string> CreateOrder(ExpressDeliveryOrder order)
{
SFCreateOrderDto sFSend = new SFCreateOrderDto()
{
orderId = order.Id.ToString(),
language = "zh_CN",
cargoDetails = new List<CargoDetailsItem>()
{
new CargoDetailsItem()
{
count = (int)order.KDNum,
name = order.GOODSNAME
}
}
};
if (order.SettleAccountsTypeCode == "2")
{
if (string.IsNullOrWhiteSpace(order.MonthlyCard))
{
throw Oops.Bah("当结费类型为月结时,月结卡号不能为空");
}
sFSend.monthlyCard = order.MonthlyCard;
}
List<ContactInfoListItem> contactList = new()
{
new ContactInfoListItem
{
address = $"{order.FJProvince}{order.FJCity}{order.FJAddress}",
contact = order.FJPeople,
contactType = 1,
country = "CN",
tel = order.FJTel,
},
new ContactInfoListItem
{
address = $"{order.SJProvince}{order.SJCity}{order.SJAddress}",
contact = order.SJPeople,
contactType = 2,
country = "CN",
tel = order.SJTel,
}
};
sFSend.contactInfoList = contactList;
(string url, object body) apiParam = await BuildApiParamAsync("EXP_RECE_CREATE_ORDER", sFSend);
logger.LogInformation("调用顺丰下单接口,参数:" + apiParam.body.ToJson());
var strRtn = await apiParam.url.SetBody(apiParam.body, "application/x-www-form-urlencoded").PostAsStringAsync();
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)
{
var waybillNoInfoObj = resultDataObj.GetJObjectValue("msgData").GetJArrayValue("waybillNoInfoList")[0].Value<JObject>();
var waybillNo = waybillNoInfoObj.GetStringValue("waybillNo");
return waybillNo;
}
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);
}
}
public async Task<bool> CancelOrder(string orderId)
{
var param = new
{
dealType = 2,
orderId
};
(string url, object body) apiParam = await BuildApiParamAsync("EXP_RECE_UPDATE_ORDER", param);
logger.LogInformation($"调用顺丰订单取消接口,参数:{apiParam.body.ToJson()}");
var strRtn = await apiParam.url.SetBody(apiParam.body, "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"))
{
return true;
}
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);
}
}
public async Task DownloadWaybillFile(string waybillNo, string savePath)
{
logger.LogInformation($"调用顺丰面单PDF下载接口开始...");
var waybillDownloadInfo = await GetWaybillDownloadInfo(waybillNo);
var header = new Dictionary<string, object>() { { "X-Auth-token", waybillDownloadInfo.Token } };
using var stream = await waybillDownloadInfo.Url.SetHeaders(header).GetAsStreamAsync();
using FileStream fs = new FileStream(savePath, FileMode.Create);
await stream.CopyToAsync(fs);
logger.LogInformation($"顺丰面单PDF文件保存完成保存地址{savePath}");
}
#endregion
/// <summary>
/// 请求获取顺丰面单Pdf下载地址及访问Token
/// </summary>
/// <returns></returns>
private async Task<(string Url, string Token)> GetWaybillDownloadInfo(string masterWaybillNo)
{
SFPrintWaybillDto sFSend = new SFPrintWaybillDto()
{
fileType = "pdf",
sync = true,
templateCode = "fm_150_standard_DSWYR7LUN7FB",
version = "2.0",
documents = new List<SFPrintWaybillDto.Document>() {
new SFPrintWaybillDto.Document(masterWaybillNo)
}
};
(string url, object body) apiParam = await BuildApiParamAsync("COM_RECE_CLOUD_PRINT_WAYBILLS", sFSend);
logger.LogInformation("调用顺丰获取顺丰面单Pdf下载地址接口参数" + apiParam.body.ToJson());
var strRtn = await apiParam.url.SetBody(apiParam.body, "application/x-www-form-urlencoded").PostAsStringAsync();
logger.LogInformation("调用顺丰获取顺丰面单Pdf下载地址接口返回" + strRtn);
var jobj = strRtn.ToJObject();
if (jobj.GetStringValue("apiResultCode") == "A1000")
{
var resultDataObj = jobj.GetStringValue("apiResultData").ToJObject();
bool isSuccess = resultDataObj.GetBooleanValue("success");
if (isSuccess)
{
var fileObj = resultDataObj.GetJObjectValue("obj").GetJArrayValue("files")[0].Value<JObject>();
var token = fileObj.GetStringValue("token");
var url = fileObj.GetStringValue("url");
return (url, token);
}
else
{
var errorMsg = resultDataObj.GetStringValue("errorMsg");
logger.LogInformation("调用顺丰获取顺丰面单Pdf下载地址接口返回异常errorMsg" + errorMsg);
throw Oops.Bah(errorMsg);
}
}
else
{
var apiErrorMsg = jobj.GetStringValue("apiErrorMsg");
logger.LogInformation("调用顺丰获取顺丰面单Pdf下载地址接口返回异常apiErrorMsg" + apiErrorMsg);
throw Oops.Bah(apiErrorMsg);
}
}
/// <summary>
/// 构建请求顺丰接口所需的Url及Body参数
/// </summary>
/// <param name="apiCode">接口编码</param>
/// <param name="businessData">参数</param>
/// <returns></returns>
private async Task<(string url, object body)> BuildApiParamAsync(string apiCode, object businessData)
{
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(SF_API_TOKEN_KEY))
{
accessToken = cache.Get(SF_API_TOKEN_KEY);
}
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(SF_API_TOKEN_KEY, accessToken, TimeSpan.FromHours(2));
}
else
{
throw Oops.Bah("调用顺丰Token查询接口时发生异常" + jobj.GetStringValue("apiErrorMsg"));
}
}
var dict = new Dictionary<string, object>()
{
{ "partnerID", partnerId },
{ "serviceCode", apiCode},
{ "requestID", Guid.NewGuid().ToString()},
{ "timestamp", DateTimeOffset.Now.ToUnixTimeSeconds()},
{ "accessToken", accessToken},
{ "msgData", businessData}
};
return (url + "/std/service", dict);
}
}
}

@ -108,10 +108,17 @@ namespace Myshipping.Application.Service.ExpressDelivery.Dto
/// 寄件数量
/// </summary>
public int? KDNum { get; set; }
/// <summary>
/// 快递费
/// 计费重量
/// </summary>
public decimal? KDFee { get; set; }
public float? FeeWeight { get; set; }
///// <summary>
///// 快递费
///// </summary>
//public decimal? KDFee { get; set; }
/// <summary>
/// 备注
/// </summary>
@ -156,6 +163,8 @@ namespace Myshipping.Application.Service.ExpressDelivery.Dto
public List<ExpressDeliveryBusiness> Business { get; set; }
public List<ExpressDeliveryFee> FeeList { get; set; }
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
if (SettleAccountsTypeCode == "2" && string.IsNullOrWhiteSpace(MonthlyCard))

@ -0,0 +1,28 @@
using System.Collections.Generic;
namespace Myshipping.Application.Service.ExpressDelivery.Dto.SF
{
public class ReceiveSfFeeDto
{
public string content { get; set; }
}
public class ContentModel
{
public string orderNo { get; set; }
public string waybillNo { get; set; }
public string meterageWeightQty { get; set; }
public List<Fee> feeList { get; set; }
}
public class Fee
{
public decimal feeAmt { get; set; }
public string settlementTypeCode { get; set; }
public string feeTypeCode { get; set; }
public string customerAcctCode { get; set; }
public string waybillNo { get; set; }
}
}

@ -0,0 +1,18 @@
using System.Collections.Generic;
namespace Myshipping.Application.Service.ExpressDelivery.Dto.SF
{
public class ReceiveSfOrderStateDto
{
public string requestId { get; set; }
public List<OrderState> orderState { get; set; }
public class OrderState
{
public string orderNo { get; set; }
public string waybillNo { get; set; }
public string orderStateCode { get; set; }
public string orderStateDesc { get; set; }
}
}
}

@ -2,9 +2,8 @@
namespace Myshipping.Application.Service.ExpressDelivery.Dto
{
public class SFSendBooking
public class SFCreateOrderDto
{
public List<CargoDetailsItem> cargoDetails { get; set; }
/// <summary>
///

@ -3,19 +3,18 @@
namespace Myshipping.Application.Service.ExpressDelivery.Dto
{
/// <summary>
/// 顺丰接收快递状态Dto类
/// 顺丰接收路由动态Dto类
/// </summary>
public partial class SFAddOrderStatus
public class SFReceiveRouteDto
{
public Body Body { get; set; }
}
public partial class Body
public class Body
{
public List<WaybillRoute> WaybillRoute { get; set; }
}
public partial class WaybillRoute
public class WaybillRoute
{
public string AcceptAddress { get; set; }
public string AcceptTime { get; set; }

@ -3,7 +3,6 @@ using Furion.DataEncryption;
using Furion.DependencyInjection;
using Furion.DynamicApiController;
using Furion.FriendlyException;
using Furion.RemoteRequest.Extensions;
using Furion.UnifyResult;
using Mapster;
using Microsoft.AspNetCore.Authorization;
@ -11,10 +10,11 @@ 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.Linq;
using Newtonsoft.Json;
using SqlSugar;
using StackExchange.Profiling.Internal;
using System;
@ -44,11 +44,6 @@ namespace Myshipping.Application
/// </summary>
private const string WAY_BILL_DIRECTORY = "WaybillFile";
/// <summary>
/// Redis中用于保存访问顺丰API Token的键名
/// </summary>
private const string SF_API_TOKEN_KEY = $"SfApiToken";
private readonly ILogger<ExpressDeliveryService> _logger;
private readonly ISysCacheService _cache;
private readonly SqlSugarRepository<BookingStatusLog> _bookingStatuslogRep;
@ -57,6 +52,8 @@ namespace Myshipping.Application
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,
@ -65,7 +62,9 @@ namespace Myshipping.Application
SqlSugarRepository<ExpressDeliveryOrder> orderRep,
SqlSugarRepository<ExpressDeliveryBusiness> businessRep,
SqlSugarRepository<ExpressDeliveryStatus> statusRep,
SqlSugarRepository<ExpressDeliveryAddress> templeteRep)
SqlSugarRepository<ExpressDeliveryAddress> templeteRep,
INamedServiceProvider<IDeliverySend> deliverySendServiceProvider,
SqlSugarRepository<ExpressDeliveryFee> feeRep)
{
_logger = logger;
_cache = cache;
@ -75,6 +74,8 @@ namespace Myshipping.Application
_bookingStatuslogRep = bookingStatuslogRep;
_bookingOrderRep = bookingOrderRep;
_addressRep = templeteRep;
_deliverySendServiceProvider = deliverySendServiceProvider;
_feeRep = feeRep;
}
/// <summary>
@ -83,7 +84,7 @@ namespace Myshipping.Application
/// <param name="input"></param>
/// <returns></returns>
[HttpGet("Page")]
public async Task<dynamic> Page([FromQuery] ExpressDeliveryInput input)
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)
@ -116,7 +117,7 @@ namespace Myshipping.Application
/// <param name="Id"></param>
/// <returns></returns>
[HttpPost("Get")]
public async Task<dynamic> Get(long Id)
public async Task<ExpressDeliveryDto> Get(long Id)
{
ExpressDeliveryDto ordOut = new ExpressDeliveryDto();
var main = await _orderRep.FirstOrDefaultAsync(u => u.Id == Id);
@ -125,6 +126,9 @@ namespace Myshipping.Application
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;
}
@ -136,7 +140,7 @@ namespace Myshipping.Application
/// <returns></returns>
[HttpPost("Save")]
[JoinValidateMessge]
public async Task<dynamic> Save(ExpressDeliveryDto input)
public async Task<ExpressDeliveryDto> Save(ExpressDeliveryDto input)
{
var entity = input.Adapt<ExpressDeliveryOrder>();
@ -242,7 +246,7 @@ namespace Myshipping.Application
}
#endregion
}
return Get(entity.Id);
return await Get(entity.Id);
}
@ -305,7 +309,6 @@ namespace Myshipping.Application
[HttpPost("SendBooking")]
public async Task<dynamic> SendBooking(long Id)
{
var rt = String.Empty;
var order = _orderRep.FirstOrDefault(x => x.Id == Id);
if (order == null)
{
@ -319,70 +322,12 @@ namespace Myshipping.Application
{
throw Oops.Bah("下单失败,原因:重复下单");
}
SFSendBooking sFSend = new SFSendBooking()
{
orderId = Id.ToString(),
language = "zh_CN",
cargoDetails = new List<CargoDetailsItem>()
{
new CargoDetailsItem()
{
count = (int)order.KDNum,
name = order.GOODSNAME
}
}
};
if (order.SettleAccountsTypeCode == "2")
{
if (string.IsNullOrWhiteSpace(order.MonthlyCard))
{
throw Oops.Bah("当结费类型为月结时,月结卡号不能为空");
}
sFSend.monthlyCard = order.MonthlyCard;
}
List<ContactInfoListItem> contactList = new()
{
new ContactInfoListItem
{
address = $"{order.FJProvince}{order.FJCity}{order.FJAddress}",
contact = order.FJPeople,
contactType = 1,
country = "CN",
tel = order.FJTel,
},
new ContactInfoListItem
{
address = $"{order.SJProvince}{order.SJCity}{order.SJAddress}",
contact = order.SJPeople,
contactType = 2,
country = "CN",
tel = order.SJTel,
}
};
sFSend.contactInfoList = contactList;
(string url, Dictionary<string, object> dict) apiParam = await BuildSFApiParams("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");
IDeliverySend deliverySend = GetDeliverySend(order.KDCompany);
string waybillNo = await deliverySend.CreateOrder(order);
string statusDesc = $"{STATUS_SEND}(单号:{waybillNo}";
// 不需要等待的任务,并且不会因为异常导致当前请求终止
_ = Task.Run(async () =>
{
@ -400,7 +345,7 @@ namespace Myshipping.Application
}
catch (Exception ex)
{
_logger.LogError(ex, "调用顺丰接口下单后,添加快递动态的过程中发生异常");
_logger.LogError(ex, "调用快递接口下单后,添加快递动态的过程中发生异常");
}
#endregion
@ -412,7 +357,7 @@ namespace Myshipping.Application
}
catch (Exception ex)
{
_logger.LogError(ex, "调用顺丰接口下单后,为与快递关联的订舱添加动态的过程中发生异常");
_logger.LogError(ex, "调用快递接口下单后,为与快递关联的订舱添加动态的过程中发生异常");
}
#endregion
@ -450,34 +395,29 @@ namespace Myshipping.Application
}
catch (Exception ex)
{
_logger.LogError(ex, "调用顺丰接口下单后,维护地址簿的过程中发生异常");
_logger.LogError(ex, "调用快递接口下单后,维护地址簿的过程中发生异常");
}
#endregion
});
// 需要等待的任务
#region 请求顺丰获取面单下载地址存库并下载PDF保存到本地
var filePath = $"{waybillNo}_{order.Id}.pdf";
#region 下载面单PDF保存到本地不会因异常终止当前请求
string filePath = null;
try
{
var waybillDownloadInfo = await GetSfWaybillDownloadUrl(waybillNo);
var header = new Dictionary<string, object>() { { "X-Auth-token", waybillDownloadInfo.Token } };
using var stream = await waybillDownloadInfo.Url.SetHeaders(header).GetAsStreamAsync();
var dic = Path.Combine(App.WebHostEnvironment.WebRootPath, WAY_BILL_DIRECTORY);
if (!Directory.Exists(dic))
{
Directory.CreateDirectory(dic);
}
var allPath = Path.Combine(dic, filePath);
_logger.LogInformation($"调用顺丰下单接口,面单文件保存地址:{allPath}");
using FileStream fs = new FileStream(allPath, FileMode.Create);
await stream.CopyToAsync(fs);
var fileName = $"{waybillNo}_{order.Id}.pdf";
filePath = Path.Combine(dic, fileName);
await deliverySend.DownloadWaybillFile(waybillNo, filePath);
}
catch (Exception ex)
{
_logger.LogError(ex, "调用顺丰接口下单后,获取面单下载地址的过程中发生异常");
_logger.LogError(ex, "调用下单接口后,下载面单的过程中发生异常");
}
#endregion
@ -502,21 +442,8 @@ namespace Myshipping.Application
currentStateCode = "DJY03",
currentStateDesc = statusDesc
});
}
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;
return "下单成功!";
}
@ -528,36 +455,18 @@ namespace Myshipping.Application
[HttpPost("CancelBooking")]
public async Task<string> CancelBooking(long Id)
{
var oldOrder = _orderRep.FirstOrDefault(x => x.Id == Id) ?? throw Oops.Bah("请选择正确数据!");
if (oldOrder.CurrentStateCode is "DJY01" or "DJY02")
var order = _orderRep.FirstOrDefault(x => x.Id == Id) ?? throw Oops.Bah("请选择正确数据!");
if (order.CurrentStateCode is "DJY01" or "DJY02")
{
throw Oops.Bah("消单失败,原因:尚未下单,无需消单");
}
if (oldOrder.CurrentStateCode is "DJY04")
if (order.CurrentStateCode is "DJY04")
{
throw Oops.Bah("消单失败,原因:已消单,无需再次消单");
}
var param = new
{
dealType = 2,
orderId = Id
};
(string url, Dictionary<string, object> dict) apiParam = await BuildSFApiParams("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();
IDeliverySend deliverySend = GetDeliverySend(order.KDCompany);
await deliverySend.CancelOrder(order.Id.ToString());
#region 添加快递动态
var status = new ExpressDeliveryStatus()
@ -587,63 +496,9 @@ namespace Myshipping.Application
.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);
}
return "取消成功!";
}
/// <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 BuildSFApiParams("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>
/// 打印面单根据快递订单Id读取相应的面单文件并返回
/// </summary>
@ -676,23 +531,15 @@ namespace Myshipping.Application
}
try
{
var filePath = Path.Combine(App.WebHostEnvironment.WebRootPath, WAY_BILL_DIRECTORY, order.WaybillFilePath);
var dic = Path.Combine(App.WebHostEnvironment.WebRootPath, WAY_BILL_DIRECTORY);
var filePath = Path.Combine(dic, order.WaybillFilePath);
if (!File.Exists(filePath))
{
_logger.LogInformation("快递面单文件不存在,尝试重新下载...");
var waybillDownloadInfo = await GetSfWaybillDownloadUrl(order.KDNO);
var header = new Dictionary<string, object>() { { "X-Auth-token", waybillDownloadInfo.Token } };
using var stream = await waybillDownloadInfo.Url.SetHeaders(header).GetAsStreamAsync();
var dic = Path.Combine(App.WebHostEnvironment.WebRootPath, WAY_BILL_DIRECTORY);
if (!Directory.Exists(dic))
{
Directory.CreateDirectory(dic);
}
_logger.LogInformation($"调用打印接口,重新下载面单文件,保存地址:{filePath}");
using FileStream fs = new FileStream(filePath, FileMode.Create);
await stream.CopyToAsync(fs);
IDeliverySend deliverySend = GetDeliverySend(order.KDCompany);
await deliverySend.DownloadWaybillFile(order.KDNO, filePath);
}
var data = File.ReadAllBytes(filePath);
FileContentResult result = new FileContentResult(data, "application/pdf");
@ -763,105 +610,192 @@ namespace Myshipping.Application
}
}
#region 顺丰相关
/// <summary>
/// 构建调用顺丰API接口的参数
/// 根据不同的快递公司,解析出不同的实现类
/// </summary>
/// <param name="kdCompany"></param>
/// <returns></returns>
[NonAction]
private async Task<(string url, Dictionary<string, object> param)> BuildSFApiParams(string serviceCode, object msgData)
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
{
var cacheDictData = await _cache.GetAllDictData();
var url = cacheDictData.FirstOrDefault(x => x.TypeCode == "url_set" && x.Code == "sf_api_url")?.Value;
if (string.IsNullOrEmpty(url))
string logGuid = Guid.NewGuid().ToString();
_logger.LogInformation($"接收到顺丰路由动态,{logGuid},入参:{orderStatus?.ToJsonString()}");
var expressDeliveryStatusList = new List<ExpressDeliveryStatus>();
foreach (WaybillRoute item in orderStatus.Body.WaybillRoute)
{
throw Oops.Bah("需配置顺丰Api接口字典参数url地址sf_api_url");
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
});
}
var partnerId = cacheDictData.FirstOrDefault(x => x.TypeCode == "SFCode" && x.Code == "partnerId")?.Value;
if (string.IsNullOrEmpty(partnerId))
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)
{
throw Oops.Bah("需配置顺丰Api接口字典参数合作伙伴编码即顾客编码partnerId");
_logger.LogInformation($"未找到相应的快递订单,{logGuid}Id{orderId}");
continue;
}
string accessToken;
if (_cache.Exists(SF_API_TOKEN_KEY))
// 因为此方法为匿名方法所以需要手动设置一下租户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)
{
accessToken = _cache.Get(SF_API_TOKEN_KEY);
waitUpdate.Value.SetColumns(o => o.CurrentStateCode == lastStatus.StatusCode);
}
else
if (order.CurrentStateDesc != lastStatus.StatusDesc)
{
var secret = cacheDictData.FirstOrDefault(x => x.TypeCode == "SFCode" && x.Code == "secret")?.Value;
if (string.IsNullOrEmpty(partnerId))
waitUpdate.Value.SetColumns(o => o.CurrentStateDesc == lastStatus.StatusDesc);
}
if (waitUpdate.IsValueCreated)
{
throw Oops.Bah("需配置顺丰Api接口字典参数合作伙伴密钥即校验码secret");
_logger.LogInformation($"快递订单的状态更新为,{logGuid}Code{lastStatus.StatusCode}Desc{lastStatus.StatusDesc}");
await waitUpdate.Value.Where(e => e.Id == orderId).ExecuteCommandAsync();
}
#endregion
var getTokenParam = new Dictionary<string, string>()
#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)
{
{ "partnerID",partnerId },
{ "grantType", "password"},
{ "secret", secret}
};
_logger.LogInformation($"根据快递订单主键查询关联业务表的提单号,查询结果为空,{logGuid}");
}
else
{
_logger.LogInformation($"根据快递订单主键查询关联业务表的提单号共查出以下记录MblNos{string.Join(',', filteredList)}{logGuid}");
_logger.LogInformation("调用顺丰Token查询接口参数" + getTokenParam.ToJson());
var strRtn = await (url + "/oauth2/accessToken").SetBody(getTokenParam, "application/x-www-form-urlencoded").PostAsStringAsync();
_logger.LogInformation("调用顺丰Token查询接口返回" + strRtn);
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 jobj = strRtn.ToJObject();
if (jobj.GetStringValue("apiResultCode") == "A1000")
var bookingStatusLogList = new List<BookingStatusLog>();
foreach (string mblnoItem in filteredList)
{
accessToken = jobj.GetStringValue("accessToken");
//设置token过期时间2小时
await _cache.SetTimeoutAsync(SF_API_TOKEN_KEY, accessToken, TimeSpan.FromHours(2));
var bookingOrderIdListTemp = bookingIdMapMblnoList.Where(o => o.MBLNO == mblnoItem);
if (bookingOrderIdListTemp == null)
{
_logger.LogInformation($"根据提单号{mblnoItem}查询订舱记录主键结果为空,{logGuid}");
continue;
}
else
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()
{
throw Oops.Bah("调用顺丰Token查询接口时发生异常" + jobj.GetStringValue("apiErrorMsg"));
BookingId = bookingOrderId,
Status = statusItem.StatusDesc,
Category = "kuaidi",
OpTime = DateTime.Now,
MBLNO = bookingOrderIdListTemp.First().MBLNO,
TenantId = order.TenantId
});
}
}
await _bookingStatuslogRep.InsertAsync(bookingStatusLogList);
}
#endregion
}
var dict = new Dictionary<string, object>()
#region 保存快递动态
// 如果租户Id不为null或0说明接收到的快递动态能找到相应的快递订单然后再进行动态新增操作
expressDeliveryStatusList = expressDeliveryStatusList.Where(e => e.TenantId != null && e.TenantId != 0).ToList();
if (expressDeliveryStatusList != null && expressDeliveryStatusList.Count > 0)
{
{ "partnerID", partnerId },
{ "serviceCode", serviceCode},
{ "requestID", Guid.NewGuid().ToString()},
{ "timestamp", DateTimeOffset.Now.ToUnixTimeSeconds()},
{ "accessToken", accessToken},
{ "msgData", msgData}
};
await _statusRep.InsertAsync(expressDeliveryStatusList);
}
#endregion
return (url + "/std/service", dict);
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("AddSfStatus")]
public async Task<object> AddSfStatus(SFAddOrderStatus orderStatus)
[HttpPost("ReceiveSfOrderState")]
public async Task<object> ReceiveSfOrderState(ReceiveSfOrderStateDto receive)
{
try
{
string logGuid = Guid.NewGuid().ToString();
_logger.LogInformation($"接收到顺丰运踪动态,{logGuid},入参:{orderStatus?.ToJsonString()}");
_logger.LogInformation($"接收到顺丰快递动态,{logGuid},入参:{receive?.ToJsonString()}");
var expressDeliveryStatusList = new List<ExpressDeliveryStatus>();
foreach (WaybillRoute item in orderStatus.Body.WaybillRoute)
foreach (ReceiveSfOrderStateDto.OrderState item in receive.orderState)
{
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
OrderId = long.Parse(item.orderNo),
AcceptAddress = "",
AcceptTime = null,
ErrorCode = "",
ErrorDesc = "",
MailNo = item.waybillNo,
StatusId = receive.requestId,
StatusCode = item.orderStateCode,
StatusDesc = item.orderStateDesc
});
}
@ -870,8 +804,6 @@ namespace Myshipping.Application
{
long? orderId = item.Key;
ExpressDeliveryStatus lastStatus = item.MaxBy(e => e.StatusId);
ExpressDeliveryOrder order = await _orderRep.AsQueryable(e => e.Id == orderId)
.Filter(null, true)
.FirstAsync();
@ -882,12 +814,13 @@ namespace Myshipping.Application
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);
#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)
{
@ -955,67 +888,85 @@ namespace Myshipping.Application
await _bookingStatuslogRep.InsertAsync(bookingStatusLogList);
}
#endregion
}
#region 保存快递动态
// 如果租户Id不为null或0说明有相应的快递订单这种情况再进行新增
// 如果租户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 = "成功" };
return new { success = "true", code = "0", msg = "" };
}
catch (Exception ex)
{
_logger.LogError(ex, "接收顺丰推送的订单状态时发生异常");
return new { success = "false", code = "0", msg = ex.Message };
}
}
/// <summary>
/// 请求获取顺丰面单Pdf下载地址
/// 接收顺丰推送的费用信息
/// </summary>
/// <returns></returns>
[NonAction]
private async Task<(string Url, string Token)> GetSfWaybillDownloadUrl(string masterWaybillNo)
[AllowAnonymous]
[NonUnify]
[HttpPost("ReceiveSfFee")]
[HttpGet("ReceiveSfFee")]
public async Task<object> ReceiveSfFee([FromForm] ReceiveSfFeeDto receive)
{
SFPrintWaybillDto sFSend = new SFPrintWaybillDto()
try
{
fileType = "pdf",
sync = true,
templateCode = "fm_150_standard_DSWYR7LUN7FB",
version = "2.0",
documents = new List<SFPrintWaybillDto.Document>() {
new SFPrintWaybillDto.Document(masterWaybillNo)
}
};
(string url, Dictionary<string, object> dict) apiParam = await BuildSFApiParams("COM_RECE_CLOUD_PRINT_WAYBILLS", sFSend);
_logger.LogInformation("调用顺丰获取顺丰面单Pdf下载地址接口参数" + apiParam.dict.ToJson());
var strRtn = await apiParam.url.SetBody(apiParam.dict, "application/x-www-form-urlencoded").PostAsStringAsync();
_logger.LogInformation("调用顺丰获取顺丰面单Pdf下载地址接口返回" + strRtn);
string logGuid = Guid.NewGuid().ToString();
_logger.LogInformation($"接收到顺丰快递费用信息,{logGuid},入参:{receive?.ToJsonString()}");
var jobj = strRtn.ToJObject();
if (jobj.GetStringValue("apiResultCode") == "A1000")
{
var resultDataObj = jobj.GetStringValue("apiResultData").ToJObject();
bool isSuccess = resultDataObj.GetBooleanValue("success");
if (isSuccess)
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)
{
var fileObj = resultDataObj.GetJObjectValue("obj").GetJArrayValue("files")[0].Value<JObject>();
var token = fileObj.GetStringValue("token");
var url = fileObj.GetStringValue("url");
return (url, token);
_logger.LogInformation($"未找到相应的快递订单,{logGuid}Id{orderId}");
return new { code = "200", partnerCode = "", service = "", msgData = "" };
}
else
// 保存计费重量
var feeWeight = float.Parse(content.meterageWeightQty);
await _orderRep.Context.Updateable<ExpressDeliveryOrder>()
.SetColumns(o => o.FeeWeight == feeWeight)
.Where(e => e.Id == orderId)
.ExecuteCommandAsync();
List<ExpressDeliveryFee> feeList = new(content.feeList.Count);
// 保存费用信息
foreach (Fee item in content.feeList)
{
var errorMsg = resultDataObj.GetStringValue("errorMsg");
_logger.LogInformation("调用顺丰获取顺丰面单Pdf下载地址接口返回异常errorMsg" + errorMsg);
return default;
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 = "" };
}
else
catch (Exception ex)
{
var apiErrorMsg = jobj.GetStringValue("apiErrorMsg");
_logger.LogInformation("调用顺丰获取顺丰面单Pdf下载地址接口返回异常apiErrorMsg" + apiErrorMsg);
return default;
_logger.LogError(ex, "接收顺丰推送的费用信息时发生异常");
return new { code = "400", partnerCode = "", service = "", msgData = "" };
}
}
#endregion

@ -1,5 +1,6 @@
using Microsoft.AspNetCore.Mvc;
using Myshipping.Application.Service.ExpressDelivery.Dto;
using Myshipping.Core;
using System.Collections.Generic;
using System.Threading.Tasks;
@ -7,16 +8,14 @@ namespace Myshipping.Application
{
public interface IExpressDeliveryService
{
Task<dynamic> Get(long Id);
Task<dynamic> Page([FromQuery] ExpressDeliveryInput input);
Task<dynamic> QueryKDSchedule(long Id);
Task<dynamic> Save(ExpressDeliveryDto input);
Task<ExpressDeliveryDto> Get(long Id);
Task<SqlSugarPagedList<ExpressDeliveryDto>> Page([FromQuery] ExpressDeliveryInput input);
//Task<dynamic> QueryKDSchedule(long Id);
Task<ExpressDeliveryDto> Save(ExpressDeliveryDto input);
Task<dynamic> SendBooking(long Id);
Task<object> AddSfStatus(SFAddOrderStatus orderStatus);
Task DeleteAddress(string ids);
Task<List<ExpressDeliveryAddressDto>> GetAddressList();
Task SaveOrUpdateAddress(ExpressDeliveryAddressDto input);
Task Delete(string Ids);
//IActionResult PrintWaybill(string accessToken, int orderId);
}
}
Loading…
Cancel
Save