微信发货接口对接,逻辑编写

This commit is contained in:
Jack 2025-06-07 00:59:42 +08:00
parent 328fa9d802
commit a9b0d07b8d
4 changed files with 78 additions and 53 deletions

View File

@ -19,4 +19,12 @@ public interface ShopOrderLogisticsService extends IBaseService<ShopOrderLogisti
CommonResult saveOrderLogistics(ShopOrderLogistics orderLogistics, Integer ss_id);
/**
* 根据订单Id获取订单物流信息
*
* @param orderId
* @return
*/
ShopOrderLogistics getShopOrderLogistics(String orderId);
}

View File

@ -1,7 +1,9 @@
package com.suisung.mall.shop.order.service.impl;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.suisung.mall.common.api.CommonResult;
import com.suisung.mall.common.api.ResultCode;
@ -251,6 +253,28 @@ public class ShopOrderLogisticsServiceImpl extends BaseServiceImpl<ShopOrderLogi
return CommonResult.success();
}
/**
* 根据订单Id获取订单物流信息
*
* @param orderId
* @return
*/
@Override
public ShopOrderLogistics getShopOrderLogistics(String orderId) {
if (StrUtil.isBlank(orderId)) {
return null;
}
QueryWrapper<ShopOrderLogistics> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("order_id", orderId);
List<ShopOrderLogistics> logisticsList = list(queryWrapper);
if (CollUtil.isEmpty(logisticsList)) {
return null;
}
return logisticsList.get(0);
}
/**
* 检测订单是否完全发货完毕
* 1.检测订单状态处于出库审核完毕

View File

@ -18,11 +18,9 @@ public interface WxOrderShippingService {
*
* @param logisticsType 物流模式发货方式枚举值1实体物流配送采用快递公司进行实体物流配送形式 2同城配送 3虚拟商品虚拟商品例如话费充值点卡等无实体配送形式 4用户自提
* @param orderId 订单ID
* @param expressNo 快递公司编号
* @param trackingNo 物流单号
* @return 返回上传结果包含成功状态和错误消息
*/
Pair<Boolean, String> uploadShippingInfoToWx(Integer logisticsType, String orderId, String expressNo, String trackingNo);
Pair<Boolean, String> uploadShippingInfoToWx(Integer logisticsType, String orderId);
/**
* 通知微信用户确认收货

View File

@ -12,12 +12,14 @@ import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import com.suisung.mall.common.constant.CommonConstant;
import com.suisung.mall.common.modules.order.ShopOrderLogistics;
import com.suisung.mall.common.modules.store.ShopStoreSfOrder;
import com.suisung.mall.common.pojo.dto.WxOrderBaseInfoDTO;
import com.suisung.mall.common.utils.DateTimeUtils;
import com.suisung.mall.common.utils.RestTemplateHttpUtil;
import com.suisung.mall.common.utils.phone.PhoneNumberUtils;
import com.suisung.mall.shop.order.service.ShopOrderBaseService;
import com.suisung.mall.shop.order.service.ShopOrderLogisticsService;
import com.suisung.mall.shop.store.service.ShopStoreSfOrderService;
import com.suisung.mall.shop.wechat.service.WxOrderShippingService;
import com.suisung.mall.shop.wechat.utils.WxUtil;
@ -47,26 +49,23 @@ public class WxOrderShippingServiceImpl implements WxOrderShippingService {
@Autowired
private ShopStoreSfOrderService shopStoreSfOrderService;
@Lazy
@Autowired
private ShopOrderLogisticsService shopOrderLogisticsService;
/**
* 上传发货信息到微信
* 参考https://developers.weixin.qq.com/miniprogram/dev/platform-capabilities/business-capabilities/order-shipping/order-shipping.html#%E4%B8%80%E3%80%81%E5%8F%91%E8%B4%A7%E4%BF%A1%E6%81%AF%E5%BD%95%E5%85%A5%E6%8E%A5%E5%8F%A3
*
* @param logisticsType 物流模式发货方式枚举值1实体物流配送采用快递公司进行实体物流配送形式 2同城配送 3虚拟商品虚拟商品例如话费充值点卡等无实体配送形式 4用户自提
* @param orderId 订单ID
* @param expressNo 快递公司编号
* @param trackingNo 物流单号
* @return 返回上传结果包含成功状态和错误消息
*/
@Override
public Pair<Boolean, String> uploadShippingInfoToWx(Integer logisticsType, String orderId, String expressNo, String trackingNo) {
final String PARAMETER_ERROR = "必要参数不能为空";
final String ACCESS_TOKEN_ERROR = "获取AccessToken失败";
final String ORDER_RECORD_ERROR = "无法获取订单记录";
final String SHIPPING_INFO_ERROR = "发货信息录入失败";
if (StringUtils.isAnyBlank(orderId, expressNo, trackingNo)) {
log.error(PARAMETER_ERROR);
return Pair.of(false, PARAMETER_ERROR);
public Pair<Boolean, String> uploadShippingInfoToWx(Integer logisticsType, String orderId) {
if (StringUtils.isBlank(orderId)) {
log.error("缺少订单Id");
return Pair.of(false, "缺少订单Id");
}
if (logisticsType == null || logisticsType < 1 || logisticsType > 4) {
@ -75,57 +74,55 @@ public class WxOrderShippingServiceImpl implements WxOrderShippingService {
}
try {
// Step 1: Get access token
String accessToken = wxUtil.getAccessToken();
if (StrUtil.isBlank(accessToken)) {
log.error("{}订单ID: {}", ACCESS_TOKEN_ERROR, orderId);
return Pair.of(false, ACCESS_TOKEN_ERROR);
log.error("获取AccessToken失败订单ID: {}", orderId);
return Pair.of(false, "获取AccessToken失败");
}
// Step 2: Get order base info
WxOrderBaseInfoDTO orderBaseInfo = shopOrderBaseService.getWxOrderBaseInfo(orderId);
if (orderBaseInfo == null) {
log.error("{}订单ID: {}", ORDER_RECORD_ERROR, orderId);
return Pair.of(false, ORDER_RECORD_ERROR);
if (orderBaseInfo == null || StrUtil.isBlank(orderBaseInfo.getDa_mobile())) {
log.error("无法获取订单记录订单ID: {}", orderId);
return Pair.of(false, "无法获取订单记录");
}
//shop_order_logistics shop_store_sf_order
// Step 3: Prepare shipping item
JSONObject shippingItem = new JSONObject();
shippingItem.set("item_desc", orderBaseInfo.getSubject()); // 必填项
shippingItem.set("item_desc", orderBaseInfo.getSubject());
String receiverContact;
try {
receiverContact = CommonConstant.IDD_ZH_CN + "-" + PhoneNumberUtils.maskPhoneNumber(orderBaseInfo.getDa_mobile());
} catch (Exception e) {
log.warn("手机号脱敏失败订单ID: {}, 错误信息: {}", orderId, e.getMessage());
receiverContact = CommonConstant.IDD_ZH_CN + "-" + orderBaseInfo.getDa_mobile();
}
String trackingId = "";
String expressCompany = "";
String receiverMobile = "";
if (logisticsType == 1) {
// 实体物流配送
shippingItem.set("shipping_type", 2);
shippingItem.set("shipping_id", orderBaseInfo.getLkl_merchant_no());
ShopOrderLogistics shopOrderLogistics = shopOrderLogisticsService.getShopOrderLogistics(orderId);
if (shopOrderLogistics == null) {
log.error("无法获取快递信息订单ID: {}", orderId);
return Pair.of(false, "无法获取快递信息");
}
shippingItem.set("tracking_no", shopOrderLogistics.getOrder_tracking_number());
shippingItem.set("express_company", shopOrderLogistics.getLogistics_number());
shippingItem.set("contact.receiver_contact", receiverContact);
} else if (logisticsType == 2) {
// 同城配送(顺丰同城)
ShopStoreSfOrder shopStoreSfOrder = shopStoreSfOrderService.getBySfOrderId(orderId);
if (shopStoreSfOrder == null) {
log.error("无法获取顺丰同城订单记录订单ID: {}", orderId);
return Pair.of(false, "无法获取顺丰同城订单记录");
}
trackingId = shopStoreSfOrder.getSf_bill_id();
expressCompany = "SF"; // 顺丰同城的快递公司代码
receiverMobile = "";
} else if (logisticsType == 3) {
// 虚拟商品
shippingItem.set("shipping_type", 4);
} else {
// 用户自提
shippingItem.set("shipping_type", 1);
shippingItem.set("tracking_no", shopStoreSfOrder.getSf_bill_id());
shippingItem.set("express_company", "SF");
shippingItem.set("contact.receiver_contact", receiverContact);
}
// 发物流快递的必填字段
shippingItem.set("tracking_no", trackingId);
shippingItem.set("express_company", expressCompany);
shippingItem.set("contact.receiver_contact", CommonConstant.IDD_ZH_CN + "-" + PhoneNumberUtils.maskPhoneNumber("13128998786"));
// Step 4: Prepare request payload
JSONArray shippingList = new JSONArray().put(shippingItem);
JSONObject paramsJSON = new JSONObject()
.set("order_key.order_number_type", 2)
.set("order_key.transaction_id", orderBaseInfo.getTransaction_id())
@ -135,21 +132,22 @@ public class WxOrderShippingServiceImpl implements WxOrderShippingService {
.set("upload_time", DateTimeUtils.formatDateTimeRFC3339(new Date()))
.set("payer.openid", orderBaseInfo.getOpenid());
// Step 5: Send request to WeChat API
JSONObject respObj = RestTemplateHttpUtil.sendPost(
"https://api.weixin.qq.com/wxa/sec/order/upload_shipping_info?access_token=" + accessToken,
null, paramsJSON, JSONObject.class
);
if (respObj == null) {
log.error("{}订单ID: {}, 返回结果为空", SHIPPING_INFO_ERROR, orderId);
return Pair.of(false, SHIPPING_INFO_ERROR + ",返回结果为空");
log.error("发货信息录入失败订单ID: {}, 返回结果为空", orderId);
return Pair.of(false, "发货信息录入失败,返回结果为空");
}
int errCode = respObj.getInt("errcode", -1);
if (errCode != 0) {
String errorMsg = respObj.getStr("errmsg", "未知错误");
log.error("{}订单ID: {}, 错误码: {}, 错误信息: {}", SHIPPING_INFO_ERROR, orderId, errCode, errorMsg);
return Pair.of(false, SHIPPING_INFO_ERROR + ": " + errorMsg);
log.error("发货信息录入失败订单ID: {}, 错误码: {}, 错误信息: {}", orderId, errCode, errorMsg);
return Pair.of(false, "发货信息录入失败: " + errorMsg);
}
log.info("发货信息录入成功, 订单ID: {}", orderId);
@ -158,12 +156,9 @@ public class WxOrderShippingServiceImpl implements WxOrderShippingService {
} catch (HttpClientErrorException e) {
log.error("HTTP请求错误订单ID: {}, 状态码: {}, 错误信息: {}", orderId, e.getStatusCode(), e.getMessage(), e);
return Pair.of(false, "HTTP请求错误: " + e.getMessage());
} catch (IllegalArgumentException e) {
log.error("参数错误订单ID: {}, 错误信息: {}", orderId, e.getMessage(), e);
return Pair.of(false, "参数错误: " + e.getMessage());
} catch (Exception e) {
log.error("{}订单ID: {}, 错误信息: {}", SHIPPING_INFO_ERROR, orderId, e.getMessage(), e);
return Pair.of(false, SHIPPING_INFO_ERROR + ": " + e.getMessage());
log.error("发货信息录入失败订单ID: {}, 错误信息: {}", orderId, e.getMessage(), e);
return Pair.of(false, "发货信息录入失败: " + e.getMessage());
}
}