| | |
| | | // 个人主体属于小微商户,mcc 也是必填;三个线上场景都要带。 |
| | | assertThat(wechat).allSatisfy(entry -> assertThat(entry).containsKeys("mcc", "wx_real_name_info")); |
| | | |
| | | // 层级:micro_biz_type 在 wx_real_name_info 这个嵌套 jsonObject 里,不在元素顶层。 |
| | | // 层级与形态:micro_biz_type 在 wx_real_name_info 这个**嵌套 jsonObject** 里,不在元素顶层, |
| | | // 也不能是 JSON 字符串。官方字段目录里该字段类型是 `Object`(对照 wx_conf_list[] 本身才是 |
| | | // `String` 的 jsonArray字符串)——双重编码发出去通道会回「wx_conf_list格式错误」。 |
| | | assertThat(wechat.get(0)).doesNotContainKey("micro_biz_type"); |
| | | Map<String, Object> realName = JSON.parseObject(String.valueOf(wechat.get(0).get("wx_real_name_info")), Map.class); |
| | | assertThat(wechat.get(0).get("wx_real_name_info")).isInstanceOf(Map.class); |
| | | Map<String, Object> realName = JSON.parseObject(JSON.toJSONString(wechat.get(0).get("wx_real_name_info")), Map.class); |
| | | assertThat(realName).containsEntry("micro_biz_type", "MICRO_TYPE_ONLINE"); |
| | | } |
| | | |
| | |
| | | assertThat(wechat).allSatisfy(entry -> assertThat(entry).doesNotContainKey("wx_real_name_info")); |
| | | } |
| | | |
| | | /** |
| | | * 个人(小微)商户填了 {@code micro_biz_type},就欠这两张门店照片:官方在 micro_biz_type |
| | | * 的说明里写明「需要提供 F22:店铺门头照图片;F24:店铺内景图片,补充资料填写在 |
| | | * extended_material_list 对象中」。原先只有 micro_biz_type、没有材料,开通是缺材料提交。 |
| | | */ |
| | | @Test |
| | | void anIndividualMerchantCarriesTheStorePhotosAsExtendedMaterial() { |
| | | Map<String, Object> request = HuifuMerchantBusinessOpenGateway.buildRequestForTest( |
| | | properties(), "BO-TEST-MATERIAL", "6666000241390821", "阳野", "5812", true, true, "file-f22", "file-f24"); |
| | | |
| | | List<Map<String, Object>> materials = |
| | | JSON.parseObject(String.valueOf(request.get("extended_material_list")), List.class); |
| | | assertThat(materials).hasSize(2); |
| | | assertThat(materials.get(0)).containsEntry("file_type", "F22").containsEntry("file_id", "file-f22"); |
| | | assertThat(materials.get(1)).containsEntry("file_type", "F24").containsEntry("file_id", "file-f24"); |
| | | } |
| | | |
| | | /** 门店照片缺一张就只发一张:宁可让通道明确报缺哪一项,也不要塞占位图顶上。 */ |
| | | @Test |
| | | void aMissingStorePhotoIsNotReplacedByAPlaceholder() { |
| | | Map<String, Object> request = HuifuMerchantBusinessOpenGateway.buildRequestForTest( |
| | | properties(), "BO-TEST-MATERIAL-1", "6666000241390821", "阳野", "5812", true, true, "file-f22", ""); |
| | | |
| | | List<Map<String, Object>> materials = |
| | | JSON.parseObject(String.valueOf(request.get("extended_material_list")), List.class); |
| | | assertThat(materials).hasSize(1); |
| | | assertThat(materials.get(0)).containsEntry("file_type", "F22"); |
| | | } |
| | | |
| | | /** 企业主体没有这项材料要求,不要凭空给企业商户加附件。 */ |
| | | @Test |
| | | void anEnterpriseMerchantCarriesNoExtendedMaterial() { |
| | | Map<String, Object> request = HuifuMerchantBusinessOpenGateway.buildRequestForTest( |
| | | properties(), "BO-TEST-MATERIAL-2", "6666000241390821", "成都喜望科技", "5812", false, false, "file-f22", "file-f24"); |
| | | |
| | | assertThat(request).doesNotContainKey("extended_material_list"); |
| | | } |
| | | |
| | | /** |
| | | * 个体工商户走企业进件接口,所以不是「个人主体」,但官方把「个体工商户、小微商户」并列为 |
| | | * {@code mcc} 必填的一类。配了 {@code fee_rule_id} 也不能把 mcc 省掉——官方请求示例里 |
| | | * {@code mcc} 与 {@code fee_rule_id} 本来就出现在同一个元素里。 |
| | | * |
| | | * <p>原先这条判断写在 {@code fee_rule_id} 的 else 分支里,平台配了规则号 756 之后 |
| | | * 小微/个体工商户的 mcc 永远发不出去,业务开通被通道回 {@code wx_conf_list格式错误}。 |
| | | * |
| | | * <p>费率规则号也要换成该主体类型的那一个:同表「线上、类型 01」下个体工商户是 761。 |
| | | */ |
| | | @Test |
| | | void anIndividualBusinessCarriesTheMccAndItsOwnFeeRule() { |
| | | HuifuPaymentProperties properties = properties(); |
| | | properties.setMerchantWechatFeeRuleId("756"); |
| | | |
| | | List<Map<String, Object>> wechat = wechatConfig(HuifuMerchantBusinessOpenGateway.buildRequestForTest( |
| | | properties, "BO-TEST-INDV", "6666000241390821", "阳野餐饮店", "5812", false, true, "", "")); |
| | | |
| | | assertThat(wechat).hasSize(3); |
| | | assertThat(wechat).allSatisfy(entry -> { |
| | | assertThat(entry).containsEntry("fee_rule_id", "761"); |
| | | assertThat(entry).containsEntry("mcc", "5812"); |
| | | }); |
| | | } |
| | | |
| | | /** |
| | | * 个人(小微)主体的费率规则号必须换成小微那一行。官方的《微信费率规则ID》对照表按 |
| | | * 「支付场景 × 业务开通类型 × 主体类型」定位 CID:线上(场景 4/5、类型 01)下企业是 756、 |
| | | * 小微是 775。拿企业的 756 发给小微,通道回的是「微信费率规则号填写不正确,请检查!」—— |
| | | * 2026-09-16 真实个人商户实测(该次报文的格式已经正确,纯粹是号选错)。 |
| | | */ |
| | | @Test |
| | | void aMicroMerchantUsesTheMicroFeeRuleNotTheEnterpriseOne() { |
| | | HuifuPaymentProperties properties = properties(); |
| | | properties.setMerchantWechatFeeRuleId("756"); |
| | | |
| | | List<Map<String, Object>> wechat = wechatConfig(HuifuMerchantBusinessOpenGateway.buildRequestForTest( |
| | | properties, "BO-TEST-MICRO", "6666000241804122", "阳野", "5812", true)); |
| | | |
| | | assertThat(wechat).allSatisfy(entry -> |
| | | assertThat(entry).containsEntry("fee_rule_id", "775").containsEntry("mcc", "5812")); |
| | | } |
| | | |
| | | @Test |
| | | void anEnterpriseCanUseAProviderConfirmedFeeRuleInsteadOfMcc() { |
| | | HuifuPaymentProperties properties = properties(); |