Browse Source

feat(alipay): 支持律师进件并回写支付宝二级商户ID

- 添加type字段区分商户和律师进件主体类型
- 实现applySmidToLawyer方法处理律师进件SMID回写逻辑
- 新增settledetailinfo设置用于支付宝结算信息配置
- 修改controller接口接受type参数传递进件主体类型
- 更新service层方法签名支持type参数传递
- 添加常量定义支付主体类型(商户和律师)
- 优化订单查询响应体解析逻辑返回完整JSON对象
- 实现lawyeruser实体和mapper的数据访问功能
- 添加订单ID一致性校验防止错误数据匹配
- 完善日志记录便于问题排查和调试追踪
fcw 5 days ago
parent
commit
c69a1d23e7

+ 7 - 0
alien-entity/src/main/java/shop/alien/entity/store/AlipayZftCreateRecord.java

@@ -56,6 +56,13 @@ public class AlipayZftCreateRecord {
     @TableField("order_id")
     private String orderId;
 
+    /**
+     * 进件主体:0 商户,1 律师(律师进件时按 law_firm 与 merchant_name 匹配回写律师表)。
+     */
+    @ApiModelProperty("类型")
+    @TableField("type")
+    private String type;
+
     @ApiModelProperty(value = "删除标记, 0:未删除, 1:已删除")
     @TableField("delete_flag")
     @TableLogic

+ 72 - 18
alien-job/src/main/java/shop/alien/job/store/AlipayJob.java

@@ -16,8 +16,10 @@ import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.lang3.StringUtils;
 import org.springframework.stereotype.Component;
 import shop.alien.entity.store.AlipayZftCreateRecord;
+import shop.alien.entity.store.LawyerUser;
 import shop.alien.entity.store.StoreInfo;
 import shop.alien.mapper.AlipayZftCreateRecordMapper;
+import shop.alien.mapper.LawyerUserMapper;
 import shop.alien.store.service.StoreInfoService;
 
 import java.util.List;
@@ -27,10 +29,17 @@ import java.util.List;
 @RequiredArgsConstructor
 public class AlipayJob {
 
+    /** 进件主体:商户 */
+    private static final String PAYMENT_SUBJECT_MERCHANT = "0";
+    /** 进件主体:律师 */
+    private static final String PAYMENT_SUBJECT_LAWYER = "1";
+
     private final AlipayZftCreateRecordMapper alipayZftCreateRecordMapper;
 
     private final StoreInfoService storeInfoService;
 
+    private final LawyerUserMapper lawyerUserMapper;
+
     /**
      * 查询支付宝二级商户进件结果,并从响应中回写门店 smid。
      */
@@ -66,38 +75,84 @@ public class AlipayJob {
             }
 
             String body = response.getBody();
-            String smid = extractSmidFromZftOrderQueryBody(body);
+            JSONObject firstOrder = firstOrderInZftOrderQueryBody(body);
+            String smid = firstOrder == null ? null : firstOrder.getString("smid");
             if (StringUtils.isBlank(smid)) {
                 log.debug("order.query 未解析到 smid orderId={}", orderId);
                 continue;
             }
 
-            Integer storeId = record.getStoreId();
-            if (storeId == null) {
-                log.debug("进件记录无 storeId,跳过回写 orderId={}", orderId);
-                continue;
+            String paymentSubject = record.getType() == null ? PAYMENT_SUBJECT_MERCHANT : record.getType();
+            if (PAYMENT_SUBJECT_LAWYER.equals(paymentSubject)) {
+                applySmidToLawyer(record, smid, firstOrder);
+            } else {
+                Integer storeId = record.getStoreId();
+                if (storeId == null) {
+                    log.debug("进件记录无 storeId,跳过回写 orderId={}", orderId);
+                    continue;
+                }
+
+                StoreInfo storeInfo = storeInfoService.getById(storeId);
+                if (storeInfo == null) {
+                    log.warn("门店不存在 storeId={} orderId={}", storeId, orderId);
+                    continue;
+                }
+
+                if (smid.equals(storeInfo.getAlipaySmid())) {
+                    continue;
+                }
+
+                storeInfo.setAlipaySmid(smid);
+                storeInfoService.updateById(storeInfo);
+                log.info("已回写门店 alipay_smid storeId={} orderId={}", storeId, orderId);
             }
+        }
+    }
 
-            StoreInfo storeInfo = storeInfoService.getById(storeId);
-            if (storeInfo == null) {
-                log.warn("门店不存在 storeId={} orderId={}", storeId, orderId);
+    /**
+     * 律师进件:law_firm 与进件 merchant_name 一致,且 zfb_secondary_merchant_account 为空时写入 smid。
+     * 若响应中带 order_id,则与进件记录 order_id 校验一致后再回写。
+     */
+    private void applySmidToLawyer(AlipayZftCreateRecord record, String smid, JSONObject firstOrder) {
+        String orderId = record.getOrderId();
+        String respOrderId = firstOrder != null ? firstOrder.getString("order_id") : null;
+        if (StringUtils.isNotBlank(respOrderId) && StringUtils.isNotBlank(orderId)
+                && !orderId.trim().equals(respOrderId.trim())) {
+            log.warn("order.query 返回 order_id 与进件记录不一致 recordOrderId={} respOrderId={}", orderId, respOrderId);
+            return;
+        }
+
+        String merchantName = record.getMerchantName();
+        if (StringUtils.isBlank(merchantName)) {
+            log.debug("律师进件记录无 merchant_name,跳过回写 orderId={}", orderId);
+            return;
+        }
+
+        LambdaQueryWrapper<LawyerUser> w = new LambdaQueryWrapper<>();
+        w.eq(LawyerUser::getLawFirm, merchantName.trim());
+        List<LawyerUser> lawyers = lawyerUserMapper.selectList(w);
+        if (lawyers == null || lawyers.isEmpty()) {
+            log.warn("未找到 law_firm 与 merchant_name 匹配的律师用户 merchantName={} orderId={}", merchantName, orderId);
+            return;
+        }
+
+        for (LawyerUser lawyer : lawyers) {
+            if (lawyer == null) {
                 continue;
             }
-
-            if (smid.equals(storeInfo.getAlipaySmid())) {
+            if (StringUtils.isNotBlank(lawyer.getZfbSecondaryMerchantAccount())) {
                 continue;
             }
-
-            storeInfo.setAlipaySmid(smid);
-            storeInfoService.updateById(storeInfo);
-            log.info("已回写门店 alipay_smid storeId={} orderId={}", storeId, orderId);
+            lawyer.setZfbSecondaryMerchantAccount(smid);
+            lawyerUserMapper.updateById(lawyer);
+            log.info("已回写律师 zfb_secondary_merchant_account lawyerUserId={} orderId={}", lawyer.getId(), orderId);
         }
     }
 
     /**
-     * 从 ant.merchant.expand.indirect.zftorder.query 响应 body 中取 orders 首条的 smid。
+     * 从 ant.merchant.expand.indirect.zftorder.query 响应 body 中取 orders 首条对象
      */
-    private static String extractSmidFromZftOrderQueryBody(String body) {
+    private static JSONObject firstOrderInZftOrderQueryBody(String body) {
         if (StringUtils.isBlank(body)) {
             return null;
         }
@@ -111,8 +166,7 @@ public class AlipayJob {
             if (orders == null || orders.isEmpty()) {
                 return null;
             }
-            JSONObject first = orders.getJSONObject(0);
-            return first == null ? null : first.getString("smid");
+            return orders.getJSONObject(0);
         } catch (Exception e) {
             log.warn("解析 zftorder.query 响应 body 失败: {}", e.getMessage());
             return null;

+ 3 - 2
alien-store/src/main/java/shop/alien/store/controller/AlipayZftOnboardingController.java

@@ -48,9 +48,10 @@ public class AlipayZftOnboardingController {
             + "或顶层 external_id 等与 extraBiz 合并;app_auth_token、notify_url、app_id 等同 curl 公共参数")
     @PostMapping("/create")
     public R<String> create(@RequestBody AntMerchantExpandIndirectZftCreateModel request,
-                            @RequestParam(value = "storeId", required = false) Integer storeId) throws AlipayApiException {
+                            @RequestParam(value = "storeId", required = false) Integer storeId,
+                            @RequestParam(value = "type", required = false) String type) throws AlipayApiException {
         log.info("AlipayZftOnboardingController.create storeId={}", storeId);
-        return alipayZftOnboardingService.zftCreate(request, storeId);
+        return alipayZftOnboardingService.zftCreate(request, storeId, type);
     }
 
     @ApiOperationSupport(order = 3)

+ 1 - 1
alien-store/src/main/java/shop/alien/store/service/AlipayZftOnboardingService.java

@@ -21,7 +21,7 @@ public interface AlipayZftOnboardingService {
     /**
      * ant.merchant.expand.indirect.zft.create — 二级商户标准进件(结构化必填:external_id、merchant_type、name、alias_name、mcc、service)
      */
-    R<String> zftCreate(AntMerchantExpandIndirectZftCreateModel request, Integer storeId) throws AlipayApiException;
+    R<String> zftCreate(AntMerchantExpandIndirectZftCreateModel request, Integer storeId, String type) throws AlipayApiException;
 
     /**
      * ant.merchant.expand.indirect.zft.simplecreate — 二级商户免证照进件(SDK setBizModel)

+ 2 - 1
alien-store/src/main/java/shop/alien/store/service/impl/AlipayZftOnboardingServiceImpl.java

@@ -52,7 +52,7 @@ public class AlipayZftOnboardingServiceImpl implements AlipayZftOnboardingServic
     }
 
     @Override
-    public R<String> zftCreate(AntMerchantExpandIndirectZftCreateModel request1, Integer storeId) throws AlipayApiException {
+    public R<String> zftCreate(AntMerchantExpandIndirectZftCreateModel request1, Integer storeId, String type) throws AlipayApiException {
         // 初始化SDK
         AlipayClient alipayClient = new DefaultAlipayClient(getAlipayConfig());
 
@@ -250,6 +250,7 @@ public class AlipayZftOnboardingServiceImpl implements AlipayZftOnboardingServic
 
         Date now = new Date();
         AlipayZftCreateRecord record = new AlipayZftCreateRecord();
+        record.setType(type);
         record.setStoreId(storeId);
         record.setExternalId(request1 != null ? request1.getExternalId() : null);
         record.setMerchantName(request1 != null ? request1.getName() : null);

+ 9 - 0
alien-store/src/main/java/shop/alien/store/strategy/payment/impl/AlipayPartnerPaymentStrategyImpl.java

@@ -65,6 +65,15 @@ public class AlipayPartnerPaymentStrategyImpl implements PaymentStrategy {
         // 【关键】设置二级商户信息(直付通必传)
         model.setSubMerchant(subMerchant);
 
+        SettleInfo settleInfo = new SettleInfo();
+        SettleDetailInfo settleDetailInfo = new SettleDetailInfo();
+        settleDetailInfo.setTransIn("defaultSettle");
+        settleDetailInfo.setAmount(total.toString());
+        List<SettleDetailInfo>  settleDetailInfos = new ArrayList<>();
+        settleDetailInfos.add(settleDetailInfo);
+        settleInfo.setSettleDetailInfos(settleDetailInfos);
+        model.setSettleInfo(settleInfo);
+
         // 设置产品码
 //        model.setProductCode("QUICK_MSECURITY_PAY");