瀏覽代碼

feat: 当面付收款 — trade.precreate 预下单 + trade.query 查询接口

alphah 11 小時之前
父節點
當前提交
27d9a15aa2

+ 4 - 0
java/src/main/java/com/payment/platform/core/alipay/AlipayClientFactory.java

@@ -146,6 +146,10 @@ public class AlipayClientFactory {
         return defaultClient != null || !providerClients.isEmpty();
     }
 
+    public com.payment.platform.core.alipay.AlipayConfig getPaymentConfig() {
+        return paymentAlipayConfig;
+    }
+
     // ==================== 内部方法 ====================
 
     /** 按服务商 + 业务类型获取专属客户端,无配置返回 null */

+ 13 - 0
java/src/main/java/com/payment/platform/module/payment/facetoface/controller/FacetofaceController.java

@@ -6,6 +6,9 @@ import com.payment.platform.module.payment.facetoface.dto.F2fOrderCreateDTO;
 import com.payment.platform.module.payment.facetoface.dto.F2fOrderQueryDTO;
 import com.payment.platform.module.payment.facetoface.dto.F2fOrderUpdateDTO;
 import com.payment.platform.module.payment.facetoface.dto.F2fOrderVO;
+import com.payment.platform.module.payment.facetoface.dto.F2fTradePrecreateDTO;
+import com.payment.platform.module.payment.facetoface.dto.F2fTradeQueryDTO;
+import com.payment.platform.module.payment.facetoface.dto.F2fTradeVO;
 import com.payment.platform.module.payment.facetoface.service.FacetofaceService;
 import jakarta.validation.Valid;
 import lombok.RequiredArgsConstructor;
@@ -64,4 +67,14 @@ public class FacetofaceController {
         dto.setId(orderId);
         return Result.ok(service.update(dto));
     }
+
+    @PostMapping("/trade/precreate")
+    public Result<F2fTradeVO> precreateTrade(@Valid @RequestBody F2fTradePrecreateDTO dto) {
+        return Result.ok(service.precreateTrade(dto));
+    }
+
+    @GetMapping("/trade/query")
+    public Result<F2fTradeVO> queryTrade(@Valid F2fTradeQueryDTO dto) {
+        return Result.ok(service.queryTrade(dto));
+    }
 }

+ 20 - 0
java/src/main/java/com/payment/platform/module/payment/facetoface/dto/F2fTradePrecreateDTO.java

@@ -0,0 +1,20 @@
+package com.payment.platform.module.payment.facetoface.dto;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.constraints.NotBlank;
+import lombok.Data;
+
+@Data
+public class F2fTradePrecreateDTO {
+
+    @NotBlank(message = "企业ID不能为空")
+    @Schema(description = "企业ID")
+    private String enterpriseId;
+
+    @NotBlank(message = "金额不能为空")
+    @Schema(description = "收款金额(元)")
+    private String totalAmount;
+
+    @Schema(description = "收款标题")
+    private String subject;
+}

+ 17 - 0
java/src/main/java/com/payment/platform/module/payment/facetoface/dto/F2fTradeQueryDTO.java

@@ -0,0 +1,17 @@
+package com.payment.platform.module.payment.facetoface.dto;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.constraints.NotBlank;
+import lombok.Data;
+
+@Data
+public class F2fTradeQueryDTO {
+
+    @NotBlank(message = "商户订单号不能为空")
+    @Schema(description = "商户订单号")
+    private String outTradeNo;
+
+    @NotBlank(message = "企业ID不能为空")
+    @Schema(description = "企业ID")
+    private String enterpriseId;
+}

+ 35 - 0
java/src/main/java/com/payment/platform/module/payment/facetoface/dto/F2fTradeVO.java

@@ -0,0 +1,35 @@
+package com.payment.platform.module.payment.facetoface.dto;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+@Data
+public class F2fTradeVO {
+
+    @Schema(description = "商户订单号")
+    private String outTradeNo;
+
+    @Schema(description = "支付宝交易号")
+    private String tradeNo;
+
+    @Schema(description = "收款码URL")
+    private String qrCode;
+
+    @Schema(description = "交易金额(元)")
+    private String totalAmount;
+
+    @Schema(description = "交易状态")
+    private String tradeStatus;
+
+    @Schema(description = "买家用户号")
+    private String buyerId;
+
+    @Schema(description = "买家支付宝账号")
+    private String buyerLogonId;
+
+    @Schema(description = "交易创建时间")
+    private String gmtCreate;
+
+    @Schema(description = "付款时间")
+    private String gmtPayment;
+}

+ 92 - 0
java/src/main/java/com/payment/platform/module/payment/facetoface/service/FacetofaceService.java

@@ -381,6 +381,98 @@ public class FacetofaceService {
                         .last("LIMIT 100"));
     }
 
+    // ==================== 交易收款 ====================
+
+    /**
+     * 生成当面付收款二维码 — 调用 alipay.trade.precreate
+     */
+    public F2fTradeVO precreateTrade(F2fTradePrecreateDTO dto) {
+        FacetofaceOrderEntity order = getSuccessOrder(dto.getEnterpriseId());
+
+        String outTradeNo = "F2F" + System.currentTimeMillis() + String.format("%04d", (int) (Math.random() * 10000));
+        try {
+            AlipayTradePrecreateModel model = new AlipayTradePrecreateModel();
+            model.setOutTradeNo(outTradeNo);
+            model.setTotalAmount(dto.getTotalAmount());
+            model.setSubject(StrUtil.isNotBlank(dto.getSubject()) ? dto.getSubject() : "当面付收款");
+
+            AlipayTradePrecreateRequest request = new AlipayTradePrecreateRequest();
+            request.setBizModel(model);
+            request.setNotifyUrl(alipayClientFactory.getPaymentConfig().getNotifyUrl());
+            request.putOtherTextParam("app_auth_token", order.getAppAuthToken());
+
+            AlipayTradePrecreateResponse response = alipayClientFactory.getClient(dto.getEnterpriseId(), ServiceProviderBizType.FACETOFACE_NOTIFY.getValue()).execute(request);
+
+            if (!response.isSuccess()) {
+                throw new BusinessException(400, "生成收款码失败: " +
+                        (response.getSubMsg() != null ? response.getSubMsg() : response.getMsg()));
+            }
+
+            log.info("当面付收款码生成成功: out_trade_no={}, qr_code={}", outTradeNo, response.getQrCode());
+
+            F2fTradeVO vo = new F2fTradeVO();
+            vo.setOutTradeNo(outTradeNo);
+            vo.setQrCode(response.getQrCode());
+            return vo;
+
+        } catch (AlipayApiException ex) {
+            throw new BusinessException(400, "生成收款码失败: " + ex.getMessage());
+        }
+    }
+
+    /** 查询交易状态 — 调用 alipay.trade.query */
+    public F2fTradeVO queryTrade(F2fTradeQueryDTO dto) {
+        FacetofaceOrderEntity order = getSuccessOrder(dto.getEnterpriseId());
+
+        try {
+            AlipayTradeQueryModel model = new AlipayTradeQueryModel();
+            model.setOutTradeNo(dto.getOutTradeNo());
+
+            AlipayTradeQueryRequest request = new AlipayTradeQueryRequest();
+            request.setBizModel(model);
+            request.putOtherTextParam("app_auth_token", order.getAppAuthToken());
+
+            AlipayTradeQueryResponse response = alipayClientFactory.getClient(dto.getEnterpriseId(), ServiceProviderBizType.FACETOFACE_NOTIFY.getValue()).execute(request);
+
+            if (!response.isSuccess()) {
+                throw new BusinessException(400, "查询交易状态失败: " +
+                        (response.getSubMsg() != null ? response.getSubMsg() : response.getMsg()));
+            }
+
+            F2fTradeVO vo = new F2fTradeVO();
+            vo.setOutTradeNo(dto.getOutTradeNo());
+            vo.setTradeNo(response.getTradeNo());
+            vo.setTotalAmount(response.getTotalAmount());
+            vo.setTradeStatus(response.getTradeStatus());
+            vo.setBuyerId(response.getBuyerUserId());
+            vo.setBuyerLogonId(response.getBuyerLogonId());
+            if (response.getSendPayDate() != null) {
+                vo.setGmtPayment(response.getSendPayDate().toString());
+            }
+            return vo;
+
+        } catch (AlipayApiException ex) {
+            throw new BusinessException(400, "查询交易状态失败: " + ex.getMessage());
+        }
+    }
+
+    /** 获取企业对应的已开通当面付订单 */
+    private FacetofaceOrderEntity getSuccessOrder(String enterpriseId) {
+        FacetofaceOrderEntity order = mapper.selectOne(
+                new LambdaQueryWrapper<FacetofaceOrderEntity>()
+                        .eq(FacetofaceOrderEntity::getEnterpriseId, enterpriseId)
+                        .eq(FacetofaceOrderEntity::getOrderStatus, FacetofaceOrderStatus.SUCCESS.getValue())
+                        .orderByDesc(FacetofaceOrderEntity::getId)
+                        .last("LIMIT 1"));
+        if (order == null) {
+            throw new BusinessException(400, "该企业尚未开通当面付或开通未成功");
+        }
+        if (StrUtil.isBlank(order.getAppAuthToken())) {
+            throw new BusinessException(400, "该企业的当面付授权令牌缺失,请重新开通");
+        }
+        return order;
+    }
+
     // ========== private ==========
 
     private FacetofaceOrderEntity requireOrder(Long id) {