yeg
2026-09-15 207799855341eee5c7db68b4e38f4544d526a38a
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
package com.talentcard.server.business.merchant;
 
import com.alibaba.fastjson.JSON;
import com.talentcard.server.business.DatabaseRows;
import com.talentcard.server.business.payment.huifu.HuifuOnboardingProgressGateway;
import com.talentcard.server.common.BusinessException;
import com.talentcard.server.common.ErrorCode;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;
 
/** Six independent evidence-backed stages; provider calls never hold application row locks. */
@Service
public class MerchantOnboardingProgressService {
    public static final String RECOVERY_HUIFU_ID = "6666000241335656";
    private static final Map<String,String> LABELS = new LinkedHashMap<>();
    static {
        LABELS.put("basic", "基础审核"); LABELS.put("wechat", "微信支付");
        LABELS.put("appId", "人才端绑定"); LABELS.put("realname", "实名与授权");
        LABELS.put("delay", "延迟入账"); LABELS.put("settlement", "自动结算");
    }
    private final JdbcTemplate jdbc;
    private final HuifuOnboardingProgressGateway gateway;
    public MerchantOnboardingProgressService(JdbcTemplate jdbc, HuifuOnboardingProgressGateway gateway) { this.jdbc=jdbc; this.gateway=gateway; }
 
    public boolean supports(Map<String,Object> application) { return RECOVERY_HUIFU_ID.equals(text(application.get("providerHuifuId"))); }
 
    public Map<String,Object> refresh(Long applicationId, boolean retry) {
        Map<String,Object> application=application(applicationId);
        if (!supports(application)) throw new BusinessException(ErrorCode.CONFLICT,"This recovery is limited to the designated existing merchant");
        jdbc.update("insert ignore into merchant_onboarding_progress(application_id,stages_json) values (?, '{}')", applicationId);
        String owner=UUID.randomUUID().toString();
        if(jdbc.update("update merchant_onboarding_progress set sync_owner=?,sync_until=date_add(now(),interval 5 minute) where application_id=? and (sync_owner is null or sync_until<now())", owner, applicationId)==0) return view(application);
        try {
            Map<String,Object> response=gateway.queryApplication(text(application.get("providerHuifuId")), text(application.get("providerApplyNo")));
            if (!"00000000".equals(text(response.get("resp_code")))) {
                String error=queryError(response);
                jdbc.update("update merchant_onboarding_progress set sync_error=? where application_id=? and sync_owner=?",error,applicationId,owner);
            } else {
                Map<String,Object> stages = savedStages(applicationId);
                String audit=text(response.get("apply_status"));
                if ("Y".equals(audit) && "S".equals(text(response.get("reg_status")))) stages.put("basic", "confirmed");
                else if (!"confirmed".equals(stages.get("basic"))) stages.put("basic",List.of("N","F").contains(audit) ? "failed" : "pending");
                jdbc.update("update merchant_onboarding_progress set stages_json=?,last_synced_at=now(),sync_error='' where application_id=? and sync_owner=?",JSON.toJSONString(stages),applicationId,owner);
                Map<String,Object> capabilities=gateway.queryCapabilities(text(application.get("providerHuifuId")));
                if (capabilities != null && "00000000".equals(text(capabilities.get("resp_code")))) {
                    if (capabilities.containsKey("delay_flag") && capabilities.containsKey("forced_delay_flag")) {
                        stages.put("delay", "Y".equals(capabilities.get("delay_flag")) && "N".equals(capabilities.get("forced_delay_flag")) ? "confirmed" : "missing");
                    } else {
                        jdbc.update("update merchant_onboarding_progress set sync_error=? where application_id=? and sync_owner=?","汇付返回缺少延迟配置字段,已保留最后有效状态",applicationId,owner);
                    }
                    jdbc.update("update merchant_onboarding_progress set stages_json=? where application_id=? and sync_owner=?",JSON.toJSONString(stages),applicationId,owner);
                } else {
                    jdbc.update("update merchant_onboarding_progress set sync_error=? where application_id=? and sync_owner=?",queryError(capabilities),applicationId,owner);
                }
                jdbc.update("update merchant_onboarding_progress set last_synced_at=now() where application_id=? and sync_owner=?",applicationId,owner);
            }
        } catch (RuntimeException exception) {
            jdbc.update("update merchant_onboarding_progress set sync_error=? where application_id=? and sync_owner=?","查询结果暂未确认,已保留最后有效进度,请稍后刷新",applicationId,owner);
        } finally {
            jdbc.update("update merchant_onboarding_progress set sync_owner=null,sync_until=null where application_id=? and sync_owner=?",applicationId,owner);
        }
        return view(application(applicationId));
    }
 
    public Map<String,Object> view(Map<String,Object> application) {
        Map<String,Object> result=new LinkedHashMap<>();
        result.put("id",text(application.get("id"))); result.put("applicationNo",text(application.get("applicationNo")));
        result.put("status","pending"); result.put("subjectType",text(application.get("subjectType")));
        result.put("submittedAt",text(application.get("createdAt"))); result.put("retryable",false);
        result.put("refreshable",true); result.put("lastSyncedAt",""); result.put("syncError","");
        List<Map<String,Object>> saved=rows("select * from merchant_onboarding_progress where application_id=?",application.get("id"));
        Map<String,Object> stages=new LinkedHashMap<>();
        if (!saved.isEmpty()) {
            stages=JSON.parseObject(text(saved.get(0).get("stagesJson")), Map.class);
            result.put("lastSyncedAt",text(saved.get(0).get("lastSyncedAt")));
            result.put("syncError",text(saved.get(0).get("syncError")));
        }
        List<Map<String,Object>> progress=new ArrayList<>();
        for (var entry:LABELS.entrySet()) progress.add(Map.of("key",entry.getKey(),"label",entry.getValue(),"status",text(stages.getOrDefault(entry.getKey(),"unknown")),"reason","尚未取得通道生效证据"));
        result.put("stages",progress); result.put("reason","请刷新进度,核实原申请与各项能力");
        return result;
    }
 
    private Map<String,Object> application(Long id) {
        List<Map<String,Object>> records=rows("select * from merchant_onboarding_application where id=? and initial_bank_card_id is not null",id);
        if(records.isEmpty()) throw new BusinessException(ErrorCode.NOT_FOUND,"Onboarding application not found");
        return records.get(0);
    }
    @SuppressWarnings("unchecked")
    private Map<String,Object> savedStages(Long id) {
        return JSON.parseObject(jdbc.queryForObject("select stages_json from merchant_onboarding_progress where application_id=?",String.class,id),Map.class);
    }
    private List<Map<String,Object>> rows(String sql,Object... args) { return DatabaseRows.normalize(jdbc.queryForList(sql,args)); }
    private static String text(Object value) { return value==null ? "" : String.valueOf(value); }
    private static String queryError(Map<String,Object> response) {
        return response != null && "20002".equals(text(response.get("resp_code")))
                ? "汇付查询权限不足(20002),请联系平台运营核实接口权限"
                : "汇付查询未成功,请稍后刷新或联系平台运营";
    }
}