소스 검색

微信支付分后付费项目参数处理

skyline 2 주 전
부모
커밋
59750c24d0

+ 36 - 0
docs/微信支付分智慧零售(无人设备)场景post_payments(后付费项目)字段传参说明.md

@@ -0,0 +1,36 @@
+## 1. 概述
+
+接入微信支付分的商户需在创建、完结、修改订单金额时,通过API接口中的post\_payments参数回传详细的后付费项目明细。该明细将在支付分订单详情页面展示,减少用户对订单金额的疑问。
+
+post\_payments为数组类型参数,该参数可包含多条“后付费项目明细”,至少传1条明细,最多可传100条明细,每条“后付费项目明细”包含name、amount、description、count四个参数。
+
+## 2. 后付费项目参数传值要求
+
+### 2.1 创建支付分订单接口
+
+智慧零售(无人设备)行业的商户在[创建支付分订单](https://pay.weixin.qq.com/doc/v3/merchant/4012587900.md)时,无需回传post\_payments【后付费项目】参数,用户购买的商品信息在完结接口进行回传,然后在支付分订单明细中向用户展示所购商品收费信息。
+
+### 2.2 完结支付分订单接口
+
+当服务结束后,商户调用[完结支付分订单](https://pay.weixin.qq.com/doc/v3/merchant/4012587955.md)接口,需通过post\_payments【后付费项目】参数回传订单实际的商品信息,在智慧零售(无人设备)行业中,只允许回传“商品信息”这1类付费项目。
+
+post\_payments必须包含至少一笔“商品信息”的后付费项目;若实际收费中,用户购买了多个商品,请按照实际情况添加各“商品信息”的后付费项目明细。
+
+例如:如果用户购买了一个商品A,则只需回传一笔“商品信息”的后付费项目明细,如果用户至购买了一个商品A,一个商品B,共两样商品,则需回传两笔“商品信息”的后付费项目明细,分别对应商品A与商品B,详见传值示例。
+
+post\_payments参数传值要求:
+
+| 字段简称 | 字段名 | 类型\[长度限制\] | 是否必填 | 示例值 | 描述 | 传值示例(购买一个商品) | 传值示例(购买多个商品) |
+| --- | --- | --- | --- | --- | --- | --- | --- |
+| 后付费项目名称 | name | string\[1, 20\] | 必填 | 首重费 | 付费项目名称,只可填写“商品信息”四个字 | "post\_payments" :  \[{<br>"name" :   "商品信息",<br>"amount" : 300,<br>"description": "可乐",<br>"count": 1<br>}\] | "post\_payments" :  \[{<br>"name" :   "商品信息",<br>"amount" : 300,<br>"description": "可乐",<br>"count": 1<br>}, {<br>"name" :   "商品信息",<br>"amount" : 300,<br>"description": "雪碧",<br>"count": 1<br>}\] |
+| 后付费项目金额 | amount | int | 必填 | 300 | 付费项目金额,单位为分 | "post\_payments" :  \[{<br>"name" :   "商品信息",<br>"amount" : 300,<br>"description": "可乐",<br>"count": 1<br>}\] | "post\_payments" :  \[{<br>"name" :   "商品信息",<br>"amount" : 300,<br>"description": "可乐",<br>"count": 1<br>}, {<br>"name" :   "商品信息",<br>"amount" : 300,<br>"description": "雪碧",<br>"count": 1<br>}\] |
+| 后付费项目说明 | description | string \[1, 30\] | 必填 | 可乐 | 商品名称 | "post\_payments" :  \[{<br>"name" :   "商品信息",<br>"amount" : 300,<br>"description": "可乐",<br>"count": 1<br>}\] | "post\_payments" :  \[{<br>"name" :   "商品信息",<br>"amount" : 300,<br>"description": "可乐",<br>"count": 1<br>}, {<br>"name" :   "商品信息",<br>"amount" : 300,<br>"description": "雪碧",<br>"count": 1<br>}\] |
+| 后付费项目的数量 | count | int | 必填 | 1 | 商品数量 | "post\_payments" :  \[{<br>"name" :   "商品信息",<br>"amount" : 300,<br>"description": "可乐",<br>"count": 1<br>}\] | "post\_payments" :  \[{<br>"name" :   "商品信息",<br>"amount" : 300,<br>"description": "可乐",<br>"count": 1<br>}, {<br>"name" :   "商品信息",<br>"amount" : 300,<br>"description": "雪碧",<br>"count": 1<br>}\] |
+
+后付费项目明细在支付分订单页面的实际展示效果(以下两种呈现形式为版本差异,均符合预期):
+
+![](https://gtimg.wechatpay.cn/resource/xres/mmpaydoc/static/img/b2bd279b51f6d511e603449b3c8d4efd.png)
+
+### 2.3 修改订单金额接口
+
+完结支付分订单后,且订单还处于“待支付(USER\_PAYING)”状态时,可调用[修改订单金额](https://pay.weixin.qq.com/doc/v3/merchant/4012587957.md)接口“下调”订单的金额,传值要求与完结支付分订单接口传值要求一致。

+ 38 - 1
haha-service/src/main/java/com/haha/service/impl/HahaCallbackServiceImpl.java

@@ -28,6 +28,7 @@ import com.haha.service.DoorRecordService;
 import com.haha.service.UserCouponService;
 import com.haha.service.CouponTemplateService;
 import com.haha.service.config.DeviceAlertProperties;
+import com.haha.service.payment.payscore.PayScoreCreateRequest;
 import com.haha.service.payment.payscore.PayScoreResult;
 import com.haha.service.payment.payscore.PayScoreService;
 import org.springframework.data.redis.core.StringRedisTemplate;
@@ -1301,6 +1302,40 @@ public class HahaCallbackServiceImpl implements HahaCallbackService {
         }
     }
 
+    /**
+     * 构建后付费项目列表(post_payments)
+     * 从 order_goods 表查询已保存的商品,按微信支付分智慧零售规范构建
+     * name="商品信息", description=商品名, amount=单价(元), count=数量
+     */
+    private List<PayScoreCreateRequest.PostPayment> buildPostPayments(Long orderId) {
+        List<PayScoreCreateRequest.PostPayment> payments = new ArrayList<>();
+        try {
+            List<OrderGoods> goodsList = orderGoodsMapper.selectList(
+                    new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<OrderGoods>()
+                            .eq(OrderGoods::getOrderId, orderId));
+
+            if (goodsList == null || goodsList.isEmpty()) {
+                log.warn("未找到订单商品信息,无法构建post_payments - orderId: {}", orderId);
+                return payments;
+            }
+
+            for (OrderGoods goods : goodsList) {
+                PayScoreCreateRequest.PostPayment payment = new PayScoreCreateRequest.PostPayment();
+                payment.setName("商品信息");
+                payment.setAmount(goods.getPrice() != null ? goods.getPrice()
+                        : (goods.getMoney() != null ? goods.getMoney() : BigDecimal.ZERO));
+                payment.setDescription(goods.getProductName() != null ? goods.getProductName() : "未知商品");
+                payment.setCount(goods.getProductNum() != null ? goods.getProductNum() : 1);
+                payments.add(payment);
+            }
+
+            log.info("构建post_payments成功 - orderId: {}, 商品数量: {}", orderId, payments.size());
+        } catch (Exception e) {
+            log.error("构建post_payments失败 - orderId: {}", orderId, e);
+        }
+        return payments;
+    }
+
     /**
      * 处理支付分扣费
      * 如果订单使用了微信支付分,调用支付分完结接口进行扣费
@@ -1341,7 +1376,9 @@ public class HahaCallbackServiceImpl implements HahaCallbackService {
             log.info("开始处理支付分扣费 - orderId: {}, payScoreOrderId: {}, amount: {}元",
                     order.getId(), order.getPayScoreOrderId(), totalAmount);
 
-            PayScoreResult result = payScoreService.completePayScoreOrder(order.getId(), totalAmount, null);
+            List<PayScoreCreateRequest.PostPayment> payments = buildPostPayments(order.getId());
+
+            PayScoreResult result = payScoreService.completePayScoreOrder(order.getId(), totalAmount, payments);
 
             if (result.isSuccess()) {
                 String state = result.getState();

+ 43 - 1
haha-service/src/main/java/com/haha/service/impl/OrderServiceImpl.java

@@ -20,9 +20,11 @@ import com.haha.common.vo.OrderStatisticsVO;
 import com.haha.common.vo.OrderVO;
 import com.haha.entity.Device;
 import com.haha.entity.Order;
+import com.haha.entity.OrderGoods;
 import com.haha.entity.Shop;
 import com.haha.entity.User;
 import com.haha.mapper.DeviceMapper;
+import com.haha.mapper.OrderGoodsMapper;
 import com.haha.mapper.OrderMapper;
 import com.haha.mapper.ShopMapper;
 import com.haha.mapper.UserMapper;
@@ -32,6 +34,7 @@ import com.haha.service.OrderService;
 import com.haha.service.InviteActivityService;
 import com.haha.service.payment.PaymentService;
 import com.haha.service.payment.RefundResult;
+import com.haha.service.payment.payscore.PayScoreCreateRequest;
 import com.haha.service.payment.payscore.PayScoreResult;
 import com.haha.service.payment.payscore.PayScoreService;
 import lombok.RequiredArgsConstructor;
@@ -81,6 +84,10 @@ public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements
     @Lazy
     private InviteActivityService inviteActivityService;
 
+    @Autowired
+    @Lazy
+    private OrderGoodsMapper orderGoodsMapper;
+
     @Override
     public IPage<Order> getPage(int page, int pageSize, String orderNo, String deviceId,
                                  String payStatus, Integer status, String startDate, String endDate,
@@ -583,6 +590,40 @@ public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements
         return order;
     }
 
+    /**
+     * 构建后付费项目列表(post_payments)
+     * 从 order_goods 表查询已保存的商品,按微信支付分智慧零售规范构建
+     * name="商品信息", description=商品名, amount=单价(元), count=数量
+     */
+    private List<PayScoreCreateRequest.PostPayment> buildPostPayments(Long orderId) {
+        List<PayScoreCreateRequest.PostPayment> payments = new ArrayList<>();
+        try {
+            List<OrderGoods> goodsList = orderGoodsMapper.selectList(
+                    new LambdaQueryWrapper<OrderGoods>()
+                            .eq(OrderGoods::getOrderId, orderId));
+
+            if (goodsList == null || goodsList.isEmpty()) {
+                log.warn("未找到订单商品信息,无法构建post_payments - orderId: {}", orderId);
+                return payments;
+            }
+
+            for (OrderGoods goods : goodsList) {
+                PayScoreCreateRequest.PostPayment payment = new PayScoreCreateRequest.PostPayment();
+                payment.setName("商品信息");
+                payment.setAmount(goods.getPrice() != null ? goods.getPrice()
+                        : (goods.getMoney() != null ? goods.getMoney() : BigDecimal.ZERO));
+                payment.setDescription(goods.getProductName() != null ? goods.getProductName() : "未知商品");
+                payment.setCount(goods.getProductNum() != null ? goods.getProductNum() : 1);
+                payments.add(payment);
+            }
+
+            log.info("构建post_payments成功 - orderId: {}, 商品数量: {}", orderId, payments.size());
+        } catch (Exception e) {
+            log.error("构建post_payments失败 - orderId: {}", orderId, e);
+        }
+        return payments;
+    }
+
     /**
      * 使用支付分完结订单(扣费)
      *
@@ -626,7 +667,8 @@ public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements
         }
 
         try {
-            PayScoreResult result = payScoreService.completePayScoreOrder(orderId, totalAmount, null);
+            List<PayScoreCreateRequest.PostPayment> payments = buildPostPayments(orderId);
+            PayScoreResult result = payScoreService.completePayScoreOrder(orderId, totalAmount, payments);
 
             if (result.isSuccess()) {
                 log.info("[支付分集成] 支付分完结成功 - orderId: {}, state: {}", orderId, result.getState());