diff --git a/mall-common/src/main/java/com/suisung/mall/common/pojo/dto/WxOrderBaseInfoDTO.java b/mall-common/src/main/java/com/suisung/mall/common/pojo/dto/WxOrderBaseInfoDTO.java new file mode 100644 index 00000000..038bd05f --- /dev/null +++ b/mall-common/src/main/java/com/suisung/mall/common/pojo/dto/WxOrderBaseInfoDTO.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2024. Lorem ipsum dolor sit amet, consectetur adipiscing elit. + * Morbi non lorem porttitor neque feugiat blandit. Ut vitae ipsum eget quam lacinia accumsan. + * Etiam sed turpis ac ipsum condimentum fringilla. Maecenas magna. + * Proin dapibus sapien vel ante. Aliquam erat volutpat. Pellentesque sagittis ligula eget metus. + * Vestibulum commodo. Ut rhoncus gravida arcu. + */ + +package com.suisung.mall.common.pojo.dto; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; + +@Data +@AllArgsConstructor +@NoArgsConstructor +/** + * 标准的地址实体类 + */ +public class WxOrderBaseInfoDTO implements Serializable { + private Integer store_id; // 店铺Id + private String out_trade_no; // 商户订单号 + private String transaction_id; // 原支付交易对应的微信订单号 + private String subject; // 订单标题 + private Integer user_id; // 用户Id + private String openid; // 微信 openId + private String lkl_merchant_no; // 拉卡拉商户号 + private String lkl_term_no; // 拉卡拉终端号 + private String da_mobile; // 收货人手机 + private String da_name; // 收货人姓名 +} diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/order/mapper/ShopOrderBaseMapper.java b/mall-shop/src/main/java/com/suisung/mall/shop/order/mapper/ShopOrderBaseMapper.java index 8f2d6d23..9e81e92e 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/order/mapper/ShopOrderBaseMapper.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/order/mapper/ShopOrderBaseMapper.java @@ -5,6 +5,7 @@ import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.suisung.mall.common.modules.order.ShopOrderBase; import com.suisung.mall.common.modules.order.dto.MchOrderInfoDTO; +import com.suisung.mall.common.pojo.dto.WxOrderBaseInfoDTO; import org.apache.ibatis.annotations.Param; import org.springframework.stereotype.Repository; @@ -69,4 +70,13 @@ public interface ShopOrderBaseMapper extends BaseMapper { * @return */ IPage selectMchOrderPageList(@Param("storeId") Integer storeId, @Param("keyword") String keyword, @Param("delivery") Integer delivery, @Param("status") Integer status, @Param("expireSeconds") Long expireSeconds, IPage page); + + + /** + * 获取微信发货订单基本信息 + * + * @param orderId + * @return + */ + WxOrderBaseInfoDTO getWxOrderBaseInfo(@Param("orderId") String orderId); } diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/order/service/ShopOrderBaseService.java b/mall-shop/src/main/java/com/suisung/mall/shop/order/service/ShopOrderBaseService.java index c609d53e..88828d64 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/order/service/ShopOrderBaseService.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/order/service/ShopOrderBaseService.java @@ -7,6 +7,7 @@ import com.suisung.mall.common.modules.order.ShopOrderBase; import com.suisung.mall.common.modules.order.ShopOrderInfo; import com.suisung.mall.common.modules.order.ShopOrderLogistics; import com.suisung.mall.common.modules.order.dto.MchOrderInfoDTO; +import com.suisung.mall.common.pojo.dto.WxOrderBaseInfoDTO; import com.suisung.mall.common.pojo.req.SFCreateOrderReq; import com.suisung.mall.core.web.service.IBaseService; import com.suisung.mall.shop.order.vo.OrdeListVo; @@ -556,4 +557,12 @@ public interface ShopOrderBaseService extends IBaseService { * @return */ JSONObject mchOrderCountByStoreId(Integer storeId); + + /** + * 获取微信发货订单基本信息 + * + * @param orderId + * @return + */ + WxOrderBaseInfoDTO getWxOrderBaseInfo(String orderId); } diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/order/service/impl/ShopOrderBaseServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/order/service/impl/ShopOrderBaseServiceImpl.java index 25706c8d..f6ac6ef8 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/order/service/impl/ShopOrderBaseServiceImpl.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/order/service/impl/ShopOrderBaseServiceImpl.java @@ -57,6 +57,7 @@ import com.suisung.mall.common.modules.product.ShopProductValidPeriod; import com.suisung.mall.common.modules.store.*; import com.suisung.mall.common.modules.user.*; import com.suisung.mall.common.pojo.dto.StandardAddressDTO; +import com.suisung.mall.common.pojo.dto.WxOrderBaseInfoDTO; import com.suisung.mall.common.pojo.req.*; import com.suisung.mall.common.pojo.to.MsgTO; import com.suisung.mall.common.pojo.to.PayMoneyTO; @@ -8641,6 +8642,21 @@ public class ShopOrderBaseServiceImpl extends BaseServiceImpl uploadShippingInfoToWx(String orderId, String expressNo, String trackingNo); + Pair uploadShippingInfoToWx(Integer logisticsType, String orderId, String expressNo, String trackingNo); /** * 通知微信用户确认收货 diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/wechat/service/impl/WxOrderShippingServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/wechat/service/impl/WxOrderShippingServiceImpl.java index 7ad2552d..0889f98b 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/wechat/service/impl/WxOrderShippingServiceImpl.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/wechat/service/impl/WxOrderShippingServiceImpl.java @@ -9,15 +9,23 @@ package com.suisung.mall.shop.wechat.service.impl; import cn.hutool.core.util.StrUtil; +import cn.hutool.json.JSONArray; import cn.hutool.json.JSONObject; +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.shop.order.service.ShopOrderBaseService; import com.suisung.mall.shop.wechat.service.WxOrderShippingService; import com.suisung.mall.shop.wechat.utils.WxUtil; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Lazy; import org.springframework.data.util.Pair; import org.springframework.stereotype.Service; +import org.springframework.web.client.HttpClientErrorException; + +import java.time.LocalDateTime; @Slf4j @Service @@ -27,20 +35,87 @@ public class WxOrderShippingServiceImpl implements WxOrderShippingService { @Autowired private WxUtil wxUtil; + @Lazy + @Autowired + private ShopOrderBaseService shopOrderBaseService; + /** * 上传发货信息到微信 * 参考: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 orderId 订单ID - * @param expressNo 快递公司编号 - * @param trackingNo 物流单号 + * @param logisticsType 物流模式,发货方式枚举值:1、实体物流配送采用快递公司进行实体物流配送形式 2、同城配送 3、虚拟商品,虚拟商品,例如话费充值,点卡等,无实体配送形式 4、用户自提 + * @param orderId 订单ID + * @param expressNo 快递公司编号 + * @param trackingNo 物流单号 * @return 返回上传结果,包含成功状态和错误消息 */ @Override - public Pair uploadShippingInfoToWx(String orderId, String expressNo, String trackingNo) { - return null; + public Pair 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); + } + + try { + String accessToken = wxUtil.getAccessToken(); + if (StrUtil.isBlank(accessToken)) { + log.error("{},订单ID: {}", ACCESS_TOKEN_ERROR, orderId); + return Pair.of(false, ACCESS_TOKEN_ERROR); + } + + WxOrderBaseInfoDTO orderBaseInfo = shopOrderBaseService.getWxOrderBaseInfo(orderId); + if (orderBaseInfo == null) { + log.error("{},订单ID: {}", ORDER_RECORD_ERROR, orderId); + return Pair.of(false, ORDER_RECORD_ERROR); + } + + JSONObject paramsJSON = new JSONObject() + .set("order_key.order_number_type", 2) + .set("order_key.transaction_id", orderBaseInfo.getTransaction_id()) + .set("delivery_mode", 1) + .set("logistics_type", logisticsType) + .set("shipping_list", new JSONArray()) + .set("upload_time", DateTimeUtils.formatDateTime(LocalDateTime.now(), "yyyy-MM-dd'T'HH:mm:ss.SSSXXX")) + .set("payer.openid", orderBaseInfo.getOpenid()); + + 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 + ",返回结果为空"); + } + + 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.info("发货信息录入成功, 订单ID: {}", orderId); + return Pair.of(true, "发货信息录入成功"); + + } 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()); + } } + /** * 通知微信用户确认收货 * 参考:https://developers.weixin.qq.com/miniprogram/dev/platform-capabilities/business-capabilities/order-shipping/order-shipping.html#%E4%BA%94%E3%80%81%E7%A1%AE%E8%AE%A4%E6%94%B6%E8%B4%A7%E6%8F%90%E9%86%92%E6%8E%A5%E5%8F%A3 @@ -55,34 +130,48 @@ public class WxOrderShippingServiceImpl implements WxOrderShippingService { } try { - + // Cache or reuse accessToken to reduce redundant API calls String accessToken = wxUtil.getAccessToken(); if (StrUtil.isBlank(accessToken)) { + log.error("获取AccessToken失败,订单ID: {}", orderId); return Pair.of(false, "获取AccessToken失败"); } - JSONObject paramsJSON = new JSONObject(); - paramsJSON.put("transaction_id", orderId); - paramsJSON.put("merchant_id", orderId); - paramsJSON.put("merchant_trade_no", orderId); - paramsJSON.put("received_time", System.currentTimeMillis() / 1000); + WxOrderBaseInfoDTO orderBaseInfo = shopOrderBaseService.getWxOrderBaseInfo(orderId); + if (orderBaseInfo == null) { + log.error("无法获取订单记录,订单ID: {}", orderId); + return Pair.of(false, "无法获取订单记录"); + } + JSONObject paramsJSON = new JSONObject() + .set("transaction_id", orderBaseInfo.getTransaction_id()) + .set("merchant_id", orderBaseInfo.getLkl_merchant_no()) + .set("merchant_trade_no", orderId) + .set("received_time", System.currentTimeMillis() / 1000); + + JSONObject respObj = RestTemplateHttpUtil.sendPost( + "https://api.weixin.qq.com/wxa/sec/order/notify_confirm_receive?access_token=" + accessToken, + null, paramsJSON, JSONObject.class + ); - JSONObject respObj = RestTemplateHttpUtil.sendPost("https://api.weixin.qq.com/wxa/sec/order/notify_confirm_receive?access_token=" + accessToken, null, paramsJSON, JSONObject.class); if (respObj == null) { log.error("通知微信用户确认收货失败,订单ID: {}, 返回结果为空", orderId); return Pair.of(false, "通知微信用户确认收货失败,返回结果为空"); } - if (respObj.getInt("errcode") != 0) { - String errorMsg = respObj.getStr("errmsg"); - log.error("通知微信用户确认收货失败,订单ID: {}, 错误信息: {}", orderId, errorMsg); + int errCode = respObj.getInt("errcode", -1); // Default to -1 if errcode is missing + if (errCode != 0) { + String errorMsg = respObj.getStr("errmsg", "未知错误"); + log.error("通知微信用户确认收货失败,订单ID: {}, 错误码: {}, 错误信息: {}", orderId, errCode, errorMsg); return Pair.of(false, "通知微信用户确认收货失败: " + errorMsg); } - log.info("通知微信用户确认收货成功,订单号:{}", orderId); + log.info("通知微信用户确认收货成功, 订单ID: {}", orderId); return Pair.of(true, "通知微信用户确认收货成功"); + } catch (HttpClientErrorException e) { + log.error("HTTP请求错误,订单ID: {}, 状态码: {}, 错误信息: {}", orderId, e.getStatusCode(), e.getMessage(), e); + return Pair.of(false, "HTTP请求错误: " + e.getMessage()); } catch (Exception e) { log.error("通知微信确认收货失败,订单ID: {}, 错误信息: {}", orderId, e.getMessage(), e); return Pair.of(false, "通知微信确认收货失败: " + e.getMessage()); diff --git a/mall-shop/src/main/resources/mapper/order/ShopOrderBaseMapper.xml b/mall-shop/src/main/resources/mapper/order/ShopOrderBaseMapper.xml index 1b90db8f..50ce5ac7 100644 --- a/mall-shop/src/main/resources/mapper/order/ShopOrderBaseMapper.xml +++ b/mall-shop/src/main/resources/mapper/order/ShopOrderBaseMapper.xml @@ -8,6 +8,20 @@ buyer_user_id, buyer_user_name, order_state_id, easy_pay_id + + + + + + + + + + + + + + + +