fix(merchant): 修正存量商户微信补开的请求组装与审核中判定
2026-09-15 对指定存量商户 6666000241335656 做真实补开时逐项撞出来的缺陷:
前两次请求被通道拒绝、第三次受理。修复后应用自己发出的请求与探针逐字相同。
- media_mer_common_flag 从顶层移进 online_media_info_list 元素。它是媒介元素的字段,
放顶层会被拒:`基础参数校验失败:【media_merCommon_flag-媒介主体与商户主体是否一致】不能为空,或格式非法`。
之前那次「补上顶层字段」的修复从未真正生效——当时没有可用权限去验证它。
- 线上三个场景一起开(4 线上公众号/5 线上小程序/12 线上反扫),原先只发场景 5,
另外两条支付路径在通道侧就没有配置。场景 12 在汇付费率规则表里没有独立行,与 4/5 共用同一线上规则。
- 企业微信开通使用 fee_rule_id(cid)代替 mcc:官方《微信费率规则ID》表里企业线上只有 756 一条,
细分行业含「就业信息平台/其他信息服务平台」;费率默认由 0.60 改为 0.70。
- 去掉 use_chains_flag=3。它要求上级本身有商户级微信配置,而我们的上级是渠道商
(查询返回 huifuId不存在),实测被拒:`失败:复用交易信息,上级商户号为空`。
不下发该字段时,子商户在渠道 00016904 下取得自己的微信子商户号。
- 运营媒介改为按 merchant-online-media-name 下发、默认留空:文档写明它只在开通快捷/网银/
余额支付Pro/分账/大额转账/代扣时才需要,且声明 media_mer_common_flag=N 会连带索要
授权或开发证明材料,而平台是一个小程序服务多个商户。
- 回执把 90000000(审核中)计入已受理,与两个进件网关的判定保持一致。真实补开返回的正是它,
照原判定会被记成 business_open_status=failed,两端页面会把已开好的商户显示成失败。
验证:真实补开受理(apply_no=2026091530554624),三个场景 wx_conf_status=S、入驻成功,
delay_flag 由 N 变 Y,人才端 AppID 绑定读回成功。定向测试 29 项全绿;全量 198 项仅
docs/agents/testing.md 所列的 3 项基线失败,无新增。
| | |
| | | import com.talentcard.server.common.ErrorCode; |
| | | import java.time.LocalDate; |
| | | import java.time.format.DateTimeFormatter; |
| | | import java.util.ArrayList; |
| | | import java.util.LinkedHashMap; |
| | | import java.util.List; |
| | | import java.util.Map; |
| | |
| | | return new HuifuMerchantBusinessOpenGateway(properties).buildRequest(requestNo, huifuId, shortName, mcc, individualMerchant); |
| | | } |
| | | |
| | | /** |
| | | * 线上微信业务场景:4=线上公众号、5=线上小程序、12=线上反扫。 |
| | | * |
| | | * <p>三个场景一起开:平台的小程序、H5 公众号与反扫共用同一个子商户号,只开小程序会让另外两条 |
| | | * 支付路径在通道侧没有配置。汇付《微信费率规则ID》表里场景 12 没有独立行,它与 4/5 共用同一条 |
| | | * 线上规则——参考商户 {@code 6666000226048687} 线上三场景费率同为 0.70% 且真实生效。 |
| | | */ |
| | | private static final List<String> ONLINE_WECHAT_SCENES = List.of("4", "5", "12"); |
| | | |
| | | private Map<String, Object> buildRequest(String requestNo, String huifuId, String shortName, String mcc, boolean individualMerchant) { |
| | | String feeRuleId = properties.getMerchantWechatFeeRuleId(); |
| | | List<Map<String, Object>> wechatList = new ArrayList<>(); |
| | | for (String scene : ONLINE_WECHAT_SCENES) { |
| | | Map<String, Object> wechat = new LinkedHashMap<>(); |
| | | wechat.put("pay_scene", "5"); |
| | | wechat.put("pay_scene", scene); |
| | | // 企业微信业务使用汇付确认的 fee_rule_id;仅在未配置规则 ID 时兼容旧的 mcc 路径。 |
| | | // 不得把参考商户的规则 ID 猜测套用到其它行业。 |
| | | if (!properties.getMerchantWechatFeeRuleId().isBlank()) { |
| | | wechat.put("fee_rule_id", properties.getMerchantWechatFeeRuleId()); |
| | | if (!feeRuleId.isBlank()) { |
| | | wechat.put("fee_rule_id", feeRuleId); |
| | | } else { |
| | | // mcc:文档注明「个体工商户、小微商户必填」——个人主体属于小微商户,所以必须带上。 |
| | | wechat.put("mcc", mcc); |
| | | } |
| | | wechat.put("fee_rate", properties.getMerchantWechatFeeRate().trim()); |
| | | // 最低收取手续费留空:通道按不设最低收费处理,详情查询读回 fee_min_amt=0.00 |
| | | // (参考商户线上三场景实测就是 0.00)。该字段可选且写明「大于 0」,不要主动送 0。 |
| | | // 实名认证由通道在业务开通成功后另行发起;取 N 表示本次不发起。 |
| | | // 改成 Y 之前要先确认实名所需的材料(含 F22/F24 照片)已就绪。 |
| | | wechat.put("is_check_real_name", "N"); |
| | |
| | | wechat.put("wx_real_name_info", JSON.toJSONString(realName)); |
| | | } |
| | | } |
| | | |
| | | Map<String, Object> media = new LinkedHashMap<>(); |
| | | media.put("media_type", "S3"); |
| | | media.put("media_name", properties.getMerchantOnlineMediaName().trim()); |
| | | wechatList.add(wechat); |
| | | } |
| | | |
| | | Map<String, Object> agreement = new LinkedHashMap<>(); |
| | | agreement.put("agreement_type", "3"); |
| | |
| | | request.put("huifu_id", huifuId); |
| | | request.put("upper_huifu_id", properties.getOnboardingUpperHuifuId().trim()); |
| | | request.put("short_name", shortName); |
| | | request.put("wx_conf_list", JSON.toJSONString(List.of(wechat))); |
| | | request.put("wx_conf_list", JSON.toJSONString(wechatList)); |
| | | request.put("online_busi_type", properties.getMerchantOnlineBusinessType().trim()); |
| | | // 运营媒介只在开通快捷/网银/余额支付Pro/分账/大额转账/代扣时才需要,本网关只开线上微信, |
| | | // 因此默认不下发。要下发就把 merchant-online-media-name 配上;注意声明 |
| | | // media_mer_common_flag=N(媒介主体与商户主体不一致)时,通道会一并索要授权或开发证明材料。 |
| | | String mediaName = properties.getMerchantOnlineMediaName().trim(); |
| | | if (!mediaName.isBlank()) { |
| | | Map<String, Object> media = new LinkedHashMap<>(); |
| | | media.put("media_type", "S3"); |
| | | media.put("media_name", mediaName); |
| | | putIfPresent(media, "media_mer_common_flag", properties.getMerchantMediaSubjectSame()); |
| | | request.put("online_media_info_list", JSON.toJSONString(List.of(media))); |
| | | // 运营媒介主体与商户主体是否一致。平台用一个运营媒介为众多子商户开通,主体天然不一致, |
| | | // 而且它是顶层必填——不传会被通道拒(实测报「media_merCommon_flag…不能为空,或格式非法」)。 |
| | | putIfPresent(request, "media_mer_common_flag", properties.getMerchantMediaSubjectSame()); |
| | | } |
| | | request.put("agreement_info", JSON.toJSONString(agreement)); |
| | | // 进件时就把延迟入账能力配好:先付钱后核销的订单必须把钱留在通道「待确认」, |
| | | // 核销确认后才分配给商户。forced_delay_flag 保持关闭——支付即核销的到店消费订单不该被延迟。 |
| | |
| | | |
| | | private void ensureConfigured() { |
| | | if (!properties.isEnabled()) throw new BusinessException(ErrorCode.CONFLICT, "Huifu payment is disabled"); |
| | | if (blank(properties.getSystemId()) || blank(properties.getProductId()) || blank(properties.getOnboardingUpperHuifuId()) || blank(properties.getMerchantWechatFeeRate()) || blank(properties.getMerchantOnlineBusinessType()) || blank(properties.getMerchantOnlineMediaName()) || blank(properties.getMerchantAgreementUrl()) || blank(properties.getPrivateKey()) || blank(properties.getPlatformPublicKey())) throw new BusinessException(ErrorCode.CONFLICT, "Huifu merchant business opening configuration is incomplete"); |
| | | if (blank(properties.getSystemId()) || blank(properties.getProductId()) || blank(properties.getOnboardingUpperHuifuId()) || blank(properties.getMerchantWechatFeeRate()) || blank(properties.getMerchantOnlineBusinessType()) || blank(properties.getMerchantAgreementUrl()) || blank(properties.getPrivateKey()) || blank(properties.getPlatformPublicKey())) throw new BusinessException(ErrorCode.CONFLICT, "Huifu merchant business opening configuration is incomplete"); |
| | | } |
| | | |
| | | private void initializeSdk() throws Exception { |
| | |
| | | String code = value(data, "sub_resp_code", "resp_code", "code"); |
| | | return new Result(success(code), value(data, "apply_no", "applyNo"), code, value(data, "sub_resp_desc", "resp_desc", "message")); |
| | | } |
| | | private static boolean success(String code) { return "00000000".equals(code) || "00000100".equals(code) || "10000".equals(code) || "0".equals(code) || "SUCCESS".equalsIgnoreCase(code); } |
| | | // 90000000 = 审核中:业务开通已被受理、微信子商户号当场就入驻成功,但整张申请单仍在审核。 |
| | | // 它与两个进件网关的判定保持一致;漏掉它会把一次成功受理记成 business_open_status=failed。 |
| | | private static boolean success(String code) { return "00000000".equals(code) || "00000100".equals(code) || "90000000".equals(code) || "10000".equals(code) || "0".equals(code) || "SUCCESS".equalsIgnoreCase(code); } |
| | | private static String value(Map<String, Object> data, String... keys) { for (String key : keys) if (data.get(key) != null) return String.valueOf(data.get(key)).trim(); return ""; } |
| | | } |
| | | } |
| | |
| | | /** |
| | | * 商户业务开通的 {@code use_chains_flag}:是否用上级(渠道商)的微信商户号发起交易。 |
| | | * |
| | | * <p>我们是平台自有的一个小程序服务多个商户,没有实现「微信特约商户进件」给每个商户单独 |
| | | * 申请微信商户号,所以保持 {@code 3}——仅微信、复用上级商户号。留空则不下发该字段, |
| | | * 由商户使用自己的微信商户号。 |
| | | * <p>留空(默认)即不下发该字段,子商户会在渠道下拿到自己的微信子商户号。 |
| | | * 不要下发 {@code 3}:那是「复用上级微信商户号」,要求上级本身有商户级微信配置,而我们的上级是 |
| | | * 渠道商(没有商户级配置,查询返回「huifuId不存在」),实测会被通道拒: |
| | | * 「失败:复用交易信息,上级商户号为空」。 |
| | | */ |
| | | private String merchantUseChainsFlag = "3"; |
| | | private String merchantUseChainsFlag = ""; |
| | | private String merchantWechatFeeRate = "0.60"; |
| | | /** |
| | | * 企业微信业务开通使用的汇付费率规则 ID。企业场景应优先填写该值, |
| | |
| | | # 进件只做「渠道商 → 普通商户」两级:不再用 head_office_flag=0 + head_huifu_id 把商户 |
| | | # 建成平台自己的下级商户。实测那条路没有收益(建完照样 20002 数据权限认证失败), |
| | | # 还会按总部客群类型索要 F725/F726/F727 材料。 |
| | | # 商户业务开通是否复用上级(渠道商)的微信商户号:3=仅微信;留空=不下发该字段。 |
| | | merchant-use-chains-flag: ${HUIFU_MERCHANT_USE_CHAINS_FLAG:3} |
| | | merchant-wechat-fee-rate: ${HUIFU_MERCHANT_WECHAT_FEE_RATE:0.60} |
| | | # 企业微信开通应填写汇付按实际行业确认的规则 ID;留空时沿用 mcc 兼容路径。 |
| | | merchant-wechat-fee-rule-id: ${HUIFU_MERCHANT_WECHAT_FEE_RULE_ID:} |
| | | # 是否复用上级(渠道商)的微信商户号:1=微信+支付宝,2=不使用,3=仅微信,4=支付宝;留空=不下发。 |
| | | # 渠道商 6666000220591054 本身没有商户级微信配置(查询返回「huifuId不存在」),实测下发 3 会被拒: |
| | | # 「失败:复用交易信息,上级商户号为空」。不下发时,子商户在渠道 00016904 下拿到自己的微信 |
| | | # 子商户号(实测 sub_mer_id=W15737921333057628112,sub_mer_name 即商户注册名)。 |
| | | merchant-use-chains-flag: ${HUIFU_MERCHANT_USE_CHAINS_FLAG:} |
| | | merchant-wechat-fee-rate: ${HUIFU_MERCHANT_WECHAT_FEE_RATE:0.70} |
| | | # 企业微信业务的费率规则号(cid)。756 是汇付《微信费率规则ID》表里「企业 + fee_type=01(线上)」 |
| | | # 唯一的一条规则,细分行业含「就业信息平台/其他信息服务平台」,与本平台业务对应; |
| | | # 场景 12 在该表没有独立行,与线上公众号/小程序共用这一条。留空则退回 mcc 兼容路径。 |
| | | merchant-wechat-fee-rule-id: ${HUIFU_MERCHANT_WECHAT_FEE_RULE_ID:756} |
| | | merchant-online-business-type: ${HUIFU_MERCHANT_ONLINE_BUSINESS_TYPE:H5311L} |
| | | merchant-online-media-name: ${HUIFU_MERCHANT_ONLINE_MEDIA_NAME:东区人才卡} |
| | | # 运营媒介主体与商户主体是否一致。平台用一个运营媒介给众多子商户开通,主体天然不一致。 |
| | | # 这是商户业务开通的顶层必填,缺了会被通道拒(实测报 media_merCommon_flag 不能为空)。 |
| | | # 运营媒介(online_media_info_list)。文档写明它只在开通快捷/网银/余额支付Pro/分账/ |
| | | # 大额转账/代扣时才需要,且是「基本信息入驻接口」的必填项,不是「商户业务开通」的必填项; |
| | | # 本平台只开线上微信,所以默认留空即不下发。要下发时再配媒介名称。 |
| | | merchant-online-media-name: ${HUIFU_MERCHANT_ONLINE_MEDIA_NAME:} |
| | | # 媒介主体与商户主体是否一致;它是 online_media_info_list 的**元素字段**,不是顶层参数。 |
| | | # 声明 N(不一致)时通道会一并索要授权或开发证明材料,因此不下发媒介时它也用不上。 |
| | | merchant-media-subject-same: ${HUIFU_MERCHANT_MEDIA_SUBJECT_SAME:N} |
| | | # 小微经营类型,个人商户开通微信业务时必填;三种取值都要求 F22 门头照 + F24 内景照。 |
| | | merchant-micro-business-type: ${HUIFU_MERCHANT_MICRO_BUSINESS_TYPE:MICRO_TYPE_ONLINE} |
| | |
| | | |
| | | import static org.assertj.core.api.Assertions.assertThat; |
| | | |
| | | import java.util.ArrayList; |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | |
| | |
| | | * <p>以汇付《商户业务开通》(v2.merchant.busi.open) 的请求规则为准逐项核对后发现两处缺口: |
| | | * |
| | | * <ul> |
| | | * <li>{@code media_mer_common_flag}(顶层):运营媒介主体与商户主体是否一致。平台用一个运营媒介 |
| | | * 给众多子商户开通,主体天然不一致。实测缺它会被拒: |
| | | * 「【media_merCommon_flag-媒介主体与商户主体是否一致】不能为空,或格式非法」。</li> |
| | | * <li>{@code media_mer_common_flag}({@code online_media_info_list} 的元素字段):运营媒介主体与商户主体 |
| | | * 是否一致。平台用一个运营媒介给众多子商户开通,主体天然不一致,取 N。它属于媒介**元素**而不是顶层参数, |
| | | * 放顶层会被拒:「【media_merCommon_flag-媒介主体与商户主体是否一致】不能为空,或格式非法」。</li> |
| | | * <li>{@code micro_biz_type}(wx_conf_list 元素内的 wx_real_name_info):个人商户开通微信业务必填, |
| | | * 且三种取值都要求 F22 店铺门头照 + F24 店铺内景照。</li> |
| | | * </ul> |
| | |
| | | } |
| | | |
| | | @Test |
| | | void theMediaSubjectFlagIsAlwaysSent() { |
| | | void theMediaSubjectFlagIsInsideTheMediaElement() { |
| | | Map<String, Object> request = request(false); |
| | | |
| | | // 平台媒介主体与商户主体不一致,取 N;关键是必须出现,否则通道判参数非法。 |
| | | assertThat(request).containsEntry("media_mer_common_flag", "N"); |
| | | // 平台媒介主体与商户主体不一致,取 N。它是 online_media_info_list 的**元素字段**, |
| | | // 不是顶层参数——放顶层会被通道判「不能为空,或格式非法」。 |
| | | assertThat(request).doesNotContainKey("media_mer_common_flag"); |
| | | |
| | | Map<String, Object> media = onlineMedia(request); |
| | | assertThat(media).containsEntry("media_mer_common_flag", "N"); |
| | | } |
| | | |
| | | /** |
| | | * 运营媒介只在开通快捷/网银/余额支付Pro/分账/大额转账/代扣时才需要,本平台只开线上微信, |
| | | * 默认不下发;不下发媒介,通道也就不会再索要「授权或开发证明材料」。 |
| | | */ |
| | | @Test |
| | | void aBlankMediaNameKeepsTheMediaDeclarationOutOfTheRequest() { |
| | | HuifuPaymentProperties properties = properties(); |
| | | properties.setMerchantOnlineMediaName(" "); |
| | | |
| | | Map<String, Object> request = HuifuMerchantBusinessOpenGateway.buildRequestForTest( |
| | | properties, "BO-TEST-1", "6666000241390821", "阳野", "5812", false); |
| | | |
| | | assertThat(request).doesNotContainKey("online_media_info_list"); |
| | | } |
| | | |
| | | @Test |
| | |
| | | Map<String, Object> request = request(true); |
| | | |
| | | List<Map<String, Object>> wechat = wechatConfig(request); |
| | | assertThat(wechat).hasSize(1); |
| | | // 个人主体属于小微商户,mcc 也是必填。 |
| | | assertThat(wechat.get(0)).containsKeys("mcc", "wx_real_name_info"); |
| | | assertThat(wechat).hasSize(3); |
| | | // 个人主体属于小微商户,mcc 也是必填;三个线上场景都要带。 |
| | | assertThat(wechat).allSatisfy(entry -> assertThat(entry).containsKeys("mcc", "wx_real_name_info")); |
| | | |
| | | // 层级:micro_biz_type 在 wx_real_name_info 这个嵌套 jsonObject 里,不在元素顶层。 |
| | | assertThat(wechat.get(0)).doesNotContainKey("micro_biz_type"); |
| | |
| | | Map<String, Object> request = request(false); |
| | | |
| | | List<Map<String, Object>> wechat = wechatConfig(request); |
| | | assertThat(wechat.get(0)).doesNotContainKey("wx_real_name_info"); |
| | | assertThat(wechat).allSatisfy(entry -> assertThat(entry).doesNotContainKey("wx_real_name_info")); |
| | | } |
| | | |
| | | @Test |
| | |
| | | List<Map<String, Object>> wechat = wechatConfig(HuifuMerchantBusinessOpenGateway.buildRequestForTest( |
| | | properties, "BO-TEST-RULE", "6666000241335656", "成都喜望科技", "7372", false)); |
| | | |
| | | assertThat(wechat.get(0)).containsEntry("fee_rule_id", "756"); |
| | | assertThat(wechat.get(0)).doesNotContainKey("mcc"); |
| | | assertThat(wechat).allSatisfy(entry -> { |
| | | assertThat(entry).containsEntry("fee_rule_id", "756"); |
| | | assertThat(entry).doesNotContainKey("mcc"); |
| | | }); |
| | | } |
| | | |
| | | /** |
| | | * 线上公众号、小程序、反扫三个场景一起开。只开小程序会让另外两条支付路径在通道侧缺配置, |
| | | * 而平台的小程序、H5 公众号与反扫共用同一个子商户号。 |
| | | */ |
| | | @Test |
| | | void theOnlineWeChatScenesAreOpenedTogether() { |
| | | List<Map<String, Object>> wechat = wechatConfig(request(false)); |
| | | |
| | | List<String> scenes = new ArrayList<>(); |
| | | for (Map<String, Object> entry : wechat) scenes.add(String.valueOf(entry.get("pay_scene"))); |
| | | assertThat(scenes).containsExactly("4", "5", "12"); |
| | | |
| | | assertThat(wechat).allSatisfy(entry -> { |
| | | assertThat(entry).containsEntry("fee_rate", "0.60"); |
| | | // 最低收取手续费可选、文档写明「大于 0」:留空让通道按不设最低收费处理, |
| | | // 详情查询读回 fee_min_amt=0.00(参考商户线上三场景实测即 0.00),不要主动送 0。 |
| | | assertThat(entry).doesNotContainKey("fee_min_amt"); |
| | | // 不填子渠道号即入驻到渠道默认配置的微信渠道号下。 |
| | | assertThat(entry).doesNotContainKey("pay_channel_id"); |
| | | }); |
| | | } |
| | | |
| | | /** |
| | |
| | | private List<Map<String, Object>> wechatConfig(Map<String, Object> request) { |
| | | return JSON.parseObject(String.valueOf(request.get("wx_conf_list")), List.class); |
| | | } |
| | | |
| | | @SuppressWarnings("unchecked") |
| | | private Map<String, Object> onlineMedia(Map<String, Object> request) { |
| | | List<Map<String, Object>> media = |
| | | JSON.parseObject(String.valueOf(request.get("online_media_info_list")), List.class); |
| | | assertThat(media).hasSize(1); |
| | | return media.get(0); |
| | | } |
| | | } |
| New file |
| | |
| | | package com.talentcard.server.business.payment.huifu; |
| | | |
| | | import static org.assertj.core.api.Assertions.assertThat; |
| | | |
| | | import java.util.Map; |
| | | |
| | | import org.junit.jupiter.api.Test; |
| | | |
| | | /** |
| | | * 商户业务开通的回执判定。 |
| | | * |
| | | * <p>{@code 90000000=审核中} 表示申请已被受理(微信子商户号当场就入驻成功),整张申请单仍在审核, |
| | | * 它与两个进件网关的判定一致。漏掉它会把一次成功受理记成 {@code business_open_status=failed}, |
| | | * 两端页面就会把已经开好的商户显示成失败。 |
| | | */ |
| | | class HuifuBusinessOpenResultTests { |
| | | |
| | | @Test |
| | | void aSubmittedApplicationUnderReviewCountsAsAccepted() { |
| | | HuifuMerchantBusinessOpenGateway.Result result = HuifuMerchantBusinessOpenGateway.Result.from( |
| | | Map.of("resp_code", "90000000", "resp_desc", "审核中", "apply_no", "2026091530554624")); |
| | | |
| | | assertThat(result.accepted()).isTrue(); |
| | | assertThat(result.applyNo()).isEqualTo("2026091530554624"); |
| | | assertThat(result.code()).isEqualTo("90000000"); |
| | | } |
| | | |
| | | @Test |
| | | void aRejectedApplicationIsNotAccepted() { |
| | | HuifuMerchantBusinessOpenGateway.Result result = HuifuMerchantBusinessOpenGateway.Result.from( |
| | | Map.of("resp_code", "00000001", "resp_desc", "基础参数校验失败")); |
| | | |
| | | assertThat(result.accepted()).isFalse(); |
| | | assertThat(result.applyNo()).isEmpty(); |
| | | } |
| | | } |
| | |
| | | } |
| | | |
| | | /** |
| | | * 商户自己没有微信商户号(我们没实现「微信特约商户进件」),开通时仍然复用上级商户号发起交易, |
| | | * 否则子商户根本没有可用的微信商户号。留空该配置即不下发字段。 |
| | | * 默认不下发 {@code use_chains_flag}:子商户在渠道下取得自己的微信子商户号。 |
| | | * |
| | | * <p>下发 {@code 3}(复用上级微信商户号)曾是默认值,但上级是渠道商、没有商户级微信配置, |
| | | * 通道会拒:「失败:复用交易信息,上级商户号为空」。2026-09-15 的真实补开在不带该字段时被受理, |
| | | * 线上公众号/小程序/反扫三场景各自入驻成功并返回自己的 {@code sub_mer_id}。 |
| | | */ |
| | | @Test |
| | | void businessOpenReusesTheSuperiorWeChatMerchantNumber() { |
| | | void businessOpenLeavesTheUseChainsFlagOutByDefault() { |
| | | Map<String, Object> request = HuifuMerchantBusinessOpenGateway.buildRequestForTest( |
| | | properties(), "BO-TEST-1", "6666000241335656", "成都喜望科技", "5812", false); |
| | | |
| | | assertThat(request).containsEntry("use_chains_flag", "3"); |
| | | assertThat(request).doesNotContainKey("use_chains_flag"); |
| | | } |
| | | |
| | | @Test |
| | | void aBlankUseChainsFlagKeepsTheFieldOutOfTheRequest() { |
| | | void aConfiguredUseChainsFlagIsSentAsIs() { |
| | | HuifuPaymentProperties properties = properties(); |
| | | properties.setMerchantUseChainsFlag(" "); |
| | | properties.setMerchantUseChainsFlag("3"); |
| | | |
| | | Map<String, Object> request = HuifuMerchantBusinessOpenGateway.buildRequestForTest( |
| | | properties, "BO-TEST-1", "6666000241335656", "成都喜望科技", "5812", false); |
| | | |
| | | assertThat(request).doesNotContainKey("use_chains_flag"); |
| | | assertThat(request).containsEntry("use_chains_flag", "3"); |
| | | } |
| | | |
| | | private static HuifuPaymentProperties properties() { |