微信小程序-上传发货信息

This commit is contained in:
pikachu1995@126.com 2024-07-18 13:51:37 +08:00
parent 80a0e0e8c7
commit 5ae4d8b4fa
4 changed files with 403 additions and 1 deletions

View File

@ -0,0 +1,48 @@
package cn.lili.event.impl;
import cn.lili.event.OrderStatusChangeEvent;
import cn.lili.modules.order.order.entity.dto.OrderMessage;
import cn.lili.modules.wechat.service.WechatMPService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service ;
/**
* 微信小程序执行器
*
* @author Chopper
* @version v1.0 2021-04-19 14:25
*/
@Slf4j
@Service
public class WechatMPExecute implements OrderStatusChangeEvent {
@Autowired
private WechatMPService wechatMPService;
/**
* 订单已发货待提货待核验状态 如果是微信小程序的订单则进行 订单发货信息录入
*
* @param orderMessage 订单消息
*/
@Override
public void orderChange(OrderMessage orderMessage) {
switch (orderMessage.getNewStatus()) {
case TAKE:
case STAY_PICKED_UP:
case DELIVERED:
try {
wechatMPService.uploadShippingInfo(orderMessage.getOrderSn());
} catch (Exception e) {
log.error("发货信息录入失败", e);
}
break;
default:
break;
}
}
}

View File

@ -20,6 +20,7 @@ import cn.lili.modules.connect.entity.Connect;
import cn.lili.modules.connect.entity.enums.SourceEnum;
import cn.lili.modules.connect.service.ConnectService;
import cn.lili.modules.member.entity.dto.ConnectQueryDTO;
import cn.lili.modules.order.order.entity.dos.Order;
import cn.lili.modules.order.order.service.OrderService;
import cn.lili.modules.payment.entity.RefundLog;
import cn.lili.modules.payment.entity.enums.PaymentMethodEnum;
@ -48,6 +49,7 @@ import cn.lili.modules.system.service.SettingService;
import cn.lili.modules.wallet.entity.dos.MemberWithdrawApply;
import cn.lili.modules.wallet.entity.dto.TransferResultDTO;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.google.gson.Gson;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
@ -161,6 +163,8 @@ public class WechatPlugin implements Payment {
JSONUtil.toJsonStr(unifiedOrderModel)
);
updateOrderPayNo(payParam,outOrderNo);
return ResultUtil.data(JSONUtil.toJsonStr(response.getBody()));
} catch (Exception e) {
log.error("微信H5支付错误", e);
@ -232,6 +236,8 @@ public class WechatPlugin implements Payment {
Map<String, String> map = WxPayKit.jsApiCreateSign(appid, prepayId, setting.getApiclient_key());
log.info("唤起支付参数:{}", map);
updateOrderPayNo(payParam,outOrderNo);
return ResultUtil.data(map);
}
log.error("微信支付参数验证错误,请及时处理");
@ -299,6 +305,8 @@ public class WechatPlugin implements Payment {
setting.getApiclient_key(), SignType.MD5);
log.info("唤起支付参数:{}", map);
updateOrderPayNo(payParam,outOrderNo);
return ResultUtil.data(map);
}
log.error("微信支付参数验证错误,请及时处理");
@ -359,6 +367,8 @@ public class WechatPlugin implements Payment {
log.info("verifySignature: {}", verifySignature);
if (verifySignature) {
updateOrderPayNo(payParam,outOrderNo);
return ResultUtil.data(new JSONObject(response.getBody()).getStr("code_url"));
} else {
log.error("微信支付参数验证错误,请及时处理");
@ -438,7 +448,7 @@ public class WechatPlugin implements Payment {
String prepayId = jsonObject.getStr("prepay_id");
Map<String, String> map = WxPayKit.jsApiCreateSign(appid, prepayId, setting.getApiclient_key());
log.info("唤起支付参数:{}", map);
updateOrderPayNo(payParam,outOrderNo);
return ResultUtil.data(map);
}
log.error("微信支付参数验证错误,请及时处理");
@ -783,4 +793,21 @@ public class WechatPlugin implements Payment {
cipherText
);
}
/**
* 修改订单支付单号
* @param payParam 支付参数
* @param outOrderNo 订单号
*/
private void updateOrderPayNo(PayParam payParam,String outOrderNo ){
if(payParam.getOrderType().equals("ORDER")){
orderService.update(new LambdaUpdateWrapper<Order>()
.eq(Order::getSn,payParam.getSn())
.set(Order::getPayOrderNo,outOrderNo));
}else if(payParam.getOrderType().equals("TRADE")){
orderService.update(new LambdaUpdateWrapper<Order>()
.eq(Order::getTradeSn,payParam.getSn())
.set(Order::getPayOrderNo,outOrderNo));
}
}
}

View File

@ -0,0 +1,14 @@
package cn.lili.modules.wechat.service;
/**
* 微信小程序 业务层
* @author Chopper
*/
public interface WechatMPService {
/**
* 微信小程序-上传发货信息
* @param orderSn
*/
void uploadShippingInfo(String orderSn);
}

View File

@ -0,0 +1,313 @@
package cn.lili.modules.wechat.serviceimpl;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import cn.lili.common.enums.ClientTypeEnum;
import cn.lili.common.exception.ServiceException;
import cn.lili.common.security.context.UserContext;
import cn.lili.common.utils.HttpUtils;
import cn.lili.modules.connect.entity.Connect;
import cn.lili.modules.connect.entity.enums.SourceEnum;
import cn.lili.modules.connect.service.ConnectService;
import cn.lili.modules.member.entity.dto.ConnectQueryDTO;
import cn.lili.modules.order.order.entity.dos.Order;
import cn.lili.modules.order.order.entity.dos.OrderItem;
import cn.lili.modules.order.order.entity.enums.OrderStatusEnum;
import cn.lili.modules.order.order.service.OrderItemService;
import cn.lili.modules.order.order.service.OrderService;
import cn.lili.modules.system.entity.dos.Setting;
import cn.lili.modules.system.entity.dto.payment.WechatPaymentSetting;
import cn.lili.modules.system.entity.enums.SettingEnum;
import cn.lili.modules.system.service.SettingService;
import cn.lili.modules.wechat.service.WechatMPService;
import cn.lili.modules.wechat.util.WechatAccessTokenUtil;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 微信小程序 业务实现
*
* @author Bulbasaur
*/
@Service
@Slf4j
public class WechatMPServiceImpl implements WechatMPService {
@Autowired
private OrderService orderService;
@Autowired
private OrderItemService orderItemService;
@Autowired
private ConnectService connectService;
@Autowired
private WechatAccessTokenUtil wechatAccessTokenUtil;
@Autowired
private SettingService settingService;
/**
* 发货信息接口
*/
String url = "https://api.weixin.qq.com/wxa/sec/order/upload_shipping_info?access_token=";
/**
* 物流公司列表
*/
String DeliveryUrl = "https://api.weixin.qq.com/cgi-bin/express/delivery/open_msg/get_delivery_list?access_token=";
/**
* 是否开通发货信息管理
*/
String isTradeManagedUrl = "https://api.weixin.qq.com/wxa/sec/order/is_trade_managed?access_token=";
/**
* 发货信息录入
*
* @param orderSn 订单号
*/
@Override
public void uploadShippingInfo(String orderSn) {
Order order = orderService.getBySn(orderSn);
//是否是微信小程序订单 && 微信支付
if (!order.getClientType().equals(ClientTypeEnum.WECHAT_MP.name())
|| !order.getPaymentMethod().equals(ClientTypeEnum.WECHAT_MP.name())) {
return;
}
//是否开通发货信息管理
if (!isTradeManaged()) {
return;
}
Map<String, Object> map = new HashMap<>(2);
//发货信息录入
//订单需要上传物流信息的订单
map.put("order_key", new OrderKey(order));
if (order.getOrderStatus().equals(OrderStatusEnum.TAKE.name())) {
//物流模式发货方式枚举值1实体物流配送采用快递公司进行实体物流配送形式 2同城配送 3虚拟商品虚拟商品例如话费充值点卡等无实体配送形式 4用户自提
map.put("logistics_type", 3);
//发货模式发货模式枚举值1UNIFIED_DELIVERY统一发货2SPLIT_DELIVERY分拆发货 示例值: UNIFIED_DELIVERY
map.put("delivery_mode", 1);
} else if (order.getOrderStatus().equals(OrderStatusEnum.DELIVERED.name())) {
//物流模式发货方式枚举值1实体物流配送采用快递公司进行实体物流配送形式 2同城配送 3虚拟商品虚拟商品例如话费充值点卡等无实体配送形式 4用户自提
map.put("logistics_type", 1);
//发货模式发货模式枚举值1UNIFIED_DELIVERY统一发货2SPLIT_DELIVERY分拆发货 示例值: UNIFIED_DELIVERY
map.put("delivery_mode", 1);
//物流信息列表发货物流单列表支持统一发货单个物流单和分拆发货多个物流单两种模式多重性: [1, 10]
List<Shipping> shippingList = new ArrayList<>();
Shipping shipping = new Shipping();
shipping.setTracking_no(order.getLogisticsNo());
shipping.setExpress_company(getDeliveryList(order));
//商品信息例如微信红包抱枕*1个限120个字以内
List<OrderItem> orderItemList = orderItemService.getByOrderSn(order.getSn());
shipping.setItem_desc(orderItemList.get(0).getGoodsName());
//联系方式当发货的物流公司为顺丰时联系方式为必填收件人或寄件人联系方式二选一
Contact contact = new Contact();
contact.setReceiver_contact(order.getConsigneeMobile());
shipping.setContact(contact);
shippingList.add(shipping);
map.put("shipping_list", shippingList);
} else if (order.getOrderStatus().equals(OrderStatusEnum.STAY_PICKED_UP.name())) {
//物流模式发货方式枚举值1实体物流配送采用快递公司进行实体物流配送形式 2同城配送 3虚拟商品虚拟商品例如话费充值点卡等无实体配送形式 4用户自提
map.put("logistics_type", 4);
//发货模式发货模式枚举值1UNIFIED_DELIVERY统一发货2SPLIT_DELIVERY分拆发货 示例值: UNIFIED_DELIVERY
map.put("delivery_mode", 1);
}
//上传时间用于标识请求的先后顺序 示例值: `2022-12-15T13:29:35.120+08:00`
map.put("upload_time", DateTimeFormatter.ISO_OFFSET_DATE_TIME.format(ZonedDateTime.now()));
//支付者支付者信息
Connect connect = connectService.queryConnect(ConnectQueryDTO.builder().userId(UserContext.getCurrentUser().getId()).unionType(SourceEnum.WECHAT_MP_OPEN_ID.name()).build());
if (connect == null) {
return;
}
map.put("payer", new Payer(connect.getUnionId()));
this.doPostWithJson(url, map);
}
/**
* 是否已开通发货信息管理服务
* https://developers.weixin.qq.com/miniprogram/dev/platform-capabilities/business-capabilities/order-shipping/order-shipping.html#%E4%B8%83%E3%80%81%E6%9F%A5%E8%AF%A2%E5%B0%8F%E7%A8%8B%E5%BA%8F%E6%98%AF%E5%90%A6%E5%B7%B2%E5%BC%80%E9%80%9A%E5%8F%91%E8%B4%A7%E4%BF%A1%E6%81%AF%E7%AE%A1%E7%90%86%E6%9C%8D%E5%8A%A1
*/
private Boolean isTradeManaged() {
Setting systemSetting = settingService.get(SettingEnum.WECHAT_PAYMENT.name());
WechatPaymentSetting wechatPaymentSetting = JSONUtil.toBean(systemSetting.getSettingValue(), WechatPaymentSetting.class);
//发送url
Map<String, Object> map = new HashMap<>(2);
map.put("appid", wechatPaymentSetting.getMpAppId());
JSONObject jsonObject = this.doPostWithJson(isTradeManagedUrl, map);
return jsonObject.getBool("is_trade_managed");
}
/**
* 查询物流公司编码列表
* https://developers.weixin.qq.com/miniprogram/dev/platform-capabilities/industry/express/business/express_search.html#%E8%8E%B7%E5%8F%96%E8%BF%90%E5%8A%9Bid%E5%88%97%E8%A1%A8get-delivery-list
*/
private String getDeliveryList(Order order) {
//发送url
Map<String, Object> map = new HashMap<>(2);
JSONObject jsonObject = this.doPostWithJson(DeliveryUrl, map);
Map<String, String> roomMap = new HashMap<>(2);
List<Delivery> deliveryList = JSONUtil.toList(jsonObject.getStr("delivery_list"), Delivery.class);
for (Delivery delivery : deliveryList) {
if (order.getLogisticsName().equals(delivery.getDelivery_name())) {
return delivery.getDelivery_id();
}
}
throw new RuntimeException("未找到快递公司");
}
/**
* 请求微信接口
*
* @param url 链接
* @param map 参数
* @return 返回内容
*/
private JSONObject doPostWithJson(String url, Map map) {
//获取token
String token = wechatAccessTokenUtil.cgiAccessToken(ClientTypeEnum.WECHAT_MP);
//请求链接添加token
url += token;
//发起请求
String content = HttpUtils.doPostWithJson(url, map);
//记录请求结果
log.info("微信小程序请求结果:" + content);
//获取请求内容如果token过期则重新获取如果出错则抛出错误
JSONObject jsonObject = new JSONObject(content);
if (("0").equals(jsonObject.get("errcode").toString())) {
return jsonObject;
} else if (("40001").equals(jsonObject.get("errcode"))) {
wechatAccessTokenUtil.removeAccessToken(ClientTypeEnum.WECHAT_MP);
return this.doPostWithJson(url, map);
} else {
throw new ServiceException(jsonObject.get("errmsg").toString());
}
}
@Data
@AllArgsConstructor
@NoArgsConstructor
class Contact {
/**
* 寄件人联系方式寄件人联系方式采用掩码传输最后4位数字不能打掩码 示例值: `189****1234, 021-****1234, ****1234, 0**2-***1234, 0**2-******23-10, ****123-8008` 值限制: 0 value 1024
*/
String consignor_contact;
/**
* 收件人联系方式收件人联系方式为采用掩码传输最后4位数字不能打掩码 示例值: `189****1234, 021-****1234, ****1234, 0**2-***1234, 0**2-******23-10, ****123-8008` 值限制: 0 value 1024
*/
String receiver_contact;
}
@Data
@AllArgsConstructor
@NoArgsConstructor
class Delivery {
private String delivery_id;
private String delivery_name;
}
@Data
@AllArgsConstructor
@NoArgsConstructor
class OrderKey {
/**
* 订单单号类型用于确认需要上传详情的订单枚举值1使用下单商户号和商户侧单号枚举值2使用微信支付单号
*/
private Integer order_number_type;
/**
* 原支付交易对应的微信订单号
*/
private String transaction_id;
/**
* 支付下单商户的商户号由微信支付生成并下发
*/
private String mchid;
/**
* 商户系统内部订单号只能是数字大小写字母`_-*`且在同一个商户号下唯一
*/
private String out_trade_no;
public OrderKey(Order order) {
this.order_number_type = 2;
this.out_trade_no = order.getPayOrderNo();
this.transaction_id = order.getReceivableNo();
}
}
@Data
@NoArgsConstructor
class Payer {
/**
* 用户标识用户在小程序appid下的唯一标识 下单前需获取到用户的Openid 示例值: oUpF8uMuAJO_M2pxb1Q9zNjWeS6o 字符字节限制: [1, 128]
*/
String openid;
public Payer(String openid) {
this.openid = openid;
}
}
@Data
@AllArgsConstructor
@NoArgsConstructor
class Shipping {
/**
* 物流单号物流快递发货时必填示例值: 323244567777 字符字节限制: [1, 128]
*/
private String tracking_no;
/**
* 物流公司编码快递公司ID参见查询物流公司编码列表物流快递发货时必填 示例值: DHL 字符字节限制: [1, 128]
*/
private String express_company;
/**
* 商品信息例如微信红包抱枕*1个限120个字以内
*/
private String item_desc;
/**
* 联系方式当发货的物流公司为顺丰时联系方式为必填收件人或寄件人联系方式二选一
*/
private Contact contact;
}
}