From a058f6109834e29435f5ce4aa19a43d67d07c060 Mon Sep 17 00:00:00 2001
From: yeg <1347747024@qq.com>
Date: 星期五, 18 九月 2026 15:52:59 +0800
Subject: [PATCH] fix(onboarding): 结算银行卡卡号面从未落库,历史进件重提时补齐
---
talent-card-server/src/main/java/com/talentcard/server/business/merchant/MerchantSettlementService.java | 33 ++++++++++++++++++++++-----------
1 files changed, 22 insertions(+), 11 deletions(-)
diff --git a/talent-card-server/src/main/java/com/talentcard/server/business/merchant/MerchantSettlementService.java b/talent-card-server/src/main/java/com/talentcard/server/business/merchant/MerchantSettlementService.java
index 73f3a6f..0a217dd 100644
--- a/talent-card-server/src/main/java/com/talentcard/server/business/merchant/MerchantSettlementService.java
+++ b/talent-card-server/src/main/java/com/talentcard/server/business/merchant/MerchantSettlementService.java
@@ -144,7 +144,7 @@
if (!repeated.isEmpty()) return onboarding(repeated.get(0));
List<Map<String, Object>> active = rows("select * from merchant_onboarding_application where merchant_id = ? and store_id = ? and initial_bank_card_id is not null and status in ('pending','approved') order by id desc limit 1", principal.merchantId(), principal.storeId());
if (!active.isEmpty() && onboardingProgressService.supports(active.get(0))) {
- supplyMissingStorePhotos(active.get(0), request);
+ supplyMissingOnboardingMaterials(active.get(0), request);
return onboarding(active.get(0));
}
if (!active.isEmpty() && !retryable(active.get(0))) return onboarding(active.get(0));
@@ -181,7 +181,7 @@
String no = BusinessIdGenerator.next("MO");
String certificateValidityType = certificateValidityType(request.subjectCertificateValidityType());
String certificateBeginDate = certificateBeginDate(request.subjectCertificateBeginDate());
- jdbc.update("insert into merchant_onboarding_application(merchant_id, store_id, application_no, subject_type, subject_name, credit_code, license_validity_type, license_begin_date, license_end_date, subject_id_no_masked, subject_id_no_encrypted, subject_cert_validity_type, subject_cert_begin_date, subject_cert_end_date, registered_region, registered_province_code, registered_city_code, registered_district_code, registered_address, merchant_name, merchant_short_name, company_type, business_license_url, established_date, registered_capital, legal_id_front_url, legal_id_back_url, legal_certificate_address, legal_mobile, administrator_email, contact_name, contact_mobile, store_header_url, store_indoor_url, idempotency_key) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", principal.merchantId(), principal.storeId(), no, request.subjectType(), request.subjectName().trim(), clean(request.creditCode()), certificateValidityType(request.licenseValidityType()), certificateBeginDate(request.licenseBeginDate()), certificateEndDate(request.licenseEndDate()), maskId(request.subjectIdNumber()), sensitiveDataCrypto.encrypt(clean(request.subjectIdNumber()).toUpperCase()), certificateValidityType, certificateBeginDate, certificateEndDate(request.subjectCertificateEndDate()), clean(request.registeredRegion()), clean(request.registeredProvinceCode()), clean(request.registeredCityCode()), clean(request.registeredDistrictCode()), clean(request.registeredAddress()), clean(request.merchantName()), clean(request.merchantShortName()), clean(request.companyType()), clean(request.businessLicenseUrl()), clean(request.establishedDate()), clean(request.registeredCapital()), clean(request.legalIdFrontUrl()), clean(request.legalIdBackUrl()), clean(request.legalCertificateAddress()), clean(request.legalMobile()), clean(request.administratorEmail()), request.contactName().trim(), request.contactMobile().trim(), clean(request.storeHeaderUrl()), clean(request.storeIndoorUrl()), key.trim());
+ jdbc.update("insert into merchant_onboarding_application(merchant_id, store_id, application_no, subject_type, subject_name, credit_code, license_validity_type, license_begin_date, license_end_date, subject_id_no_masked, subject_id_no_encrypted, subject_cert_validity_type, subject_cert_begin_date, subject_cert_end_date, registered_region, registered_province_code, registered_city_code, registered_district_code, registered_address, merchant_name, merchant_short_name, company_type, business_license_url, established_date, registered_capital, legal_id_front_url, legal_id_back_url, settlement_card_front_url, legal_certificate_address, legal_mobile, administrator_email, contact_name, contact_mobile, store_header_url, store_indoor_url, idempotency_key) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", principal.merchantId(), principal.storeId(), no, request.subjectType(), request.subjectName().trim(), clean(request.creditCode()), certificateValidityType(request.licenseValidityType()), certificateBeginDate(request.licenseBeginDate()), certificateEndDate(request.licenseEndDate()), maskId(request.subjectIdNumber()), sensitiveDataCrypto.encrypt(clean(request.subjectIdNumber()).toUpperCase()), certificateValidityType, certificateBeginDate, certificateEndDate(request.subjectCertificateEndDate()), clean(request.registeredRegion()), clean(request.registeredProvinceCode()), clean(request.registeredCityCode()), clean(request.registeredDistrictCode()), clean(request.registeredAddress()), clean(request.merchantName()), clean(request.merchantShortName()), clean(request.companyType()), clean(request.businessLicenseUrl()), clean(request.establishedDate()), clean(request.registeredCapital()), clean(request.legalIdFrontUrl()), clean(request.legalIdBackUrl()), clean(request.settlementCardFrontUrl()), clean(request.legalCertificateAddress()), clean(request.legalMobile()), clean(request.administratorEmail()), request.contactName().trim(), request.contactMobile().trim(), clean(request.storeHeaderUrl()), clean(request.storeIndoorUrl()), key.trim());
String cardNumber = request.bankCardNumber().trim();
String cardKey = key.trim() + ":initial";
if (cardKey.length() > 128) cardKey = cardKey.substring(0, 128);
@@ -209,21 +209,32 @@
}
/**
- * 存量个人进件缺门店照片时,允许商户在重新提交里补上。
+ * 存量个人进件缺门店照片、或缺结算银行卡卡号面时,允许商户在重新提交里补上。
*
* <p>门店照片是个人(小微)主体开通微信支付与发起微信实名的硬材料,而分阶段模型下重复提交
* **不会新建进件**(也就不会在通道上多出一家商户),商户端因此没有别的补图入口——真实开发库里
* 已经有拿到汇付商户号的个人进件,就是这个形态。
*
- * <p>只补空着的那两项,已有值不覆盖;进件、银行卡与通道申请一律不动。
+ * <p>结算卡卡号面在这一列补进 INSERT 之前**从来没落过库**(2026-09-18 工单),历史记录全是空值,
+ * 库里也没有别的地方能还原它。所以这里一并补上——这是已提交进件唯一的补救入口。
+ *
+ * <p>只补空着的那几项,已有值不覆盖;进件、银行卡与通道申请一律不动。
*/
- private void supplyMissingStorePhotos(Map<String, Object> application, MerchantOnboardingRequest request) {
- if (request == null || !"individual".equalsIgnoreCase(clean(application.get("subjectType")))) return;
- if (clean(application.get("storeHeaderUrl")).isBlank() && !blank(request.storeHeaderUrl())) {
- jdbc.update("update merchant_onboarding_application set store_header_url=? where id=?", request.storeHeaderUrl().trim(), application.get("id"));
+ private void supplyMissingOnboardingMaterials(Map<String, Object> application, MerchantOnboardingRequest request) {
+ if (request == null) return;
+ Object id = application.get("id");
+ // 门店照片只有个人主体才有,企业主体不提交这两项,沿用原来的判定。
+ if ("individual".equalsIgnoreCase(clean(application.get("subjectType")))) {
+ if (clean(application.get("storeHeaderUrl")).isBlank() && !blank(request.storeHeaderUrl())) {
+ jdbc.update("update merchant_onboarding_application set store_header_url=? where id=?", request.storeHeaderUrl().trim(), id);
+ }
+ if (clean(application.get("storeIndoorUrl")).isBlank() && !blank(request.storeIndoorUrl())) {
+ jdbc.update("update merchant_onboarding_application set store_indoor_url=? where id=?", request.storeIndoorUrl().trim(), id);
+ }
}
- if (clean(application.get("storeIndoorUrl")).isBlank() && !blank(request.storeIndoorUrl())) {
- jdbc.update("update merchant_onboarding_application set store_indoor_url=? where id=?", request.storeIndoorUrl().trim(), application.get("id"));
+ // 这里不另判主体类型:企业主体(非个体工商户)客户端本来就把这一项传空串,blank 会挡住。
+ if (clean(application.get("settlementCardFrontUrl")).isBlank() && !blank(request.settlementCardFrontUrl())) {
+ jdbc.update("update merchant_onboarding_application set settlement_card_front_url=? where id=?", request.settlementCardFrontUrl().trim(), id);
}
}
@@ -610,7 +621,7 @@
boolean mccRequired = individual || "个体工商户".equals(clean(application.get("companyType")));
// 个人(小微)商户的门店照片必须随业务开通一起交上去。缺图就直接收口成失败、
// 不发这次请求:发出去也只会被通道驳回,还会在通道侧留下一条缺材料的申请。
- // 商户在进件页补上照片重新提交即可(见 supplyMissingStorePhotos),下次刷新会带材料重发。
+ // 商户在进件页补上照片重新提交即可(见 supplyMissingOnboardingMaterials),下次刷新会带材料重发。
String storeHeaderFileId = "";
String storeIndoorFileId = "";
if (individual) {
--
Gitblit v1.7.1