import com.talentcard.server.business.merchant.MerchantPaymentReadinessService;
import com.talentcard.server.business.payment.huifu.HuifuMerchantCapabilityGateway;
import com.talentcard.server.business.payment.huifu.HuifuMerchantCapabilityQueryCommand;
import com.talentcard.server.business.payment.huifu.HuifuPaymentProperties;
import java.io.IOException;
import java.io.Reader;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.transaction.support.TransactionTemplate;
/**
* 只读排查探针:这家商户「能不能收款」,本地能力快照说行不行,通道侧又是什么值。
*
*
口径与下单闸门同源:最终结论取 {@link MerchantPaymentReadinessService#readiness},本探针只负责把
* 它的输入摆出来(本地快照 <-> 通道真值),省得为了看懂一句「商户收款能力待确认」再去翻库。
*/
public class MerchantCapabilityProbe {
/** 公网 IP 只留主机段前两段:地址本身(端口+路径)就是攻击面。 */
private static final Pattern AUTHORITY_IPV4 = Pattern.compile("^(\\d{1,3})\\.(\\d{1,3})\\.\\d{1,3}\\.\\d{1,3}(:\\d+)?$");
/**
* 回答什么问题:给定商户 ID / 进件 ID / 汇付号,本地 {@code merchant_onboarding_application} 上的
* 能力快照({@code merchant_stat} / {@code auto_settle_status} / {@code cash_switch_status} /
* {@code cash_type} / {@code capability_verified_at})与通道 {@code v2/merchant/basicdata/query} 的
* 真值差在哪,以及按 {@code MerchantPaymentReadinessService} 的规则算出来现在能不能收款。
*
*
什么时候用它:下单被拒「商户收款能力待确认 / 取现能力不可用 / 子商户状态异常」,或者后台商户页
* 的收款按钮灰着——先看是本地快照过期,还是通道那边真的被关停了。
*
*
它不改任何状态:只 SELECT 与通道查询。特别地,它绝不调用
* {@code refresh} / {@code capability} / {@code refreshQuietly} / {@code merchantVerify}
* ——那四个都会把通道结果写回快照({@code update merchant_onboarding_application}),属于写操作;
* 要刷新快照请用后台的「立即核实」,那条路径有冷却与并发保护,探针不走它。
*
*
参数格式(全部从命令行传,缺参数直接打用法退出,不用任何默认值瞎猜):
*
* --db-url=<JDBC URL> --db-user=<用户> --db-password=<口令>
* 三者之一:--application-id=<进件ID> | --huifu-id=<斗拱商户号> | --merchant-id=<本地商户ID>
* [--store-id=<门店ID>] 判定「能不能收款」时按这个门店问;默认用命中进件自己的 store_id
* [--config=<汇付配置文件路径>] 不给就只查本地,且判定会退化成「跳过通道确认」那一档
* [--huifu-environment=test|prod]
*
*/
public static void main(String[] args) {
String dbUrl = required(args, "db-url");
String dbUser = required(args, "db-user");
String dbPassword = required(args, "db-password");
String applicationId = arg(args, "application-id");
String huifuId = arg(args, "huifu-id");
String merchantId = arg(args, "merchant-id");
if (blank(applicationId) && blank(huifuId) && blank(merchantId)) {
System.out.println("必须给一个定位方式:--application-id=<进件ID>、--huifu-id=<斗拱商户号> 或 --merchant-id=<本地商户ID>。");
usage();
}
String configPath = arg(args, "config");
HuifuPaymentProperties properties = blank(configPath)
? new HuifuPaymentProperties() : loadProperties(configPath, arg(args, "huifu-environment"));
warnIfProduction(blank(configPath), properties);
System.out.println("只读探针:只做 SELECT 与通道的商户信息查询。不发起支付、不关单、不退款、不交易确认、"
+ "不下发业务开通、不刷新能力快照、不改任何数据库行。");
System.out.println("数据库目标:" + maskHost(dbUrl));
DriverManagerDataSource dataSource = new DriverManagerDataSource(dbUrl, dbUser, dbPassword);
JdbcTemplate jdbc = new JdbcTemplate(dataSource);
List