diff --git a/addons/shopro_huifu/command/QuerySplitConfig.php b/addons/shopro_huifu/command/QuerySplitConfig.php index 1ee4c74..337b483 100644 --- a/addons/shopro_huifu/command/QuerySplitConfig.php +++ b/addons/shopro_huifu/command/QuerySplitConfig.php @@ -79,8 +79,46 @@ class QuerySplitConfig extends Command $items = HuifuClient::parseSplitBillResult($data['split_bill_result'] ?? null); if ($items === []) { $output->writeln(''); - $output->writeln('[WARN] 未返回 split_bill_result:主商户可能未开通分账/延时分账,或 product 无权限'); - $output->writeln('可加 --json 查看完整应答'); + $output->writeln('[结论] split_bill_result 为空 = 汇付侧「分账配置申请」尚未生效(或未提交)'); + $output->writeln(' 这与支付查单 delay_acct_flag=Y(延时分账/延迟入账)不是同一开关。'); + $output->writeln(' 商城 confirm 带 acct_split_bunch 时,无生效分账配置 + 未绑定接收方 → 典型 22000002。'); + $output->writeln(''); + $output->writeln('应答顶层字段: ' . implode(', ', array_keys($data))); + $nested = HuifuClient::collectNestedKeys($data, ['rule_origin', 'div_flag', 'apply_ratio', 'delay_flag']); + if ($nested !== []) { + $output->writeln('嵌套扫描: ' . json_encode($nested, JSON_UNESCAPED_UNICODE)); + } + $output->writeln(''); + $output->writeln('--- 商户详情补充 (v2/merchant/basicdata/query + product_id) ---'); + $basic = $client->queryMerchantBasicdata($huifuId, true); + if ($basic['ok']) { + $bd = $basic['data'] ?? []; + $bCode = (string) ($bd['resp_code'] ?? ''); + $delay = (string) ($bd['delay_flag'] ?? ''); + $forced = (string) ($bd['forced_delay_flag'] ?? ''); + if ($delay !== '' || $forced !== '') { + $output->writeln('delay_flag(延迟入账): ' . ($delay !== '' ? $delay : '(未返回)')); + $output->writeln('forced_delay_flag: ' . ($forced !== '' ? $forced : '(未返回)')); + } else { + $scan = HuifuClient::collectNestedKeys($bd, ['delay_flag', 'forced_delay_flag', 'rule_origin', 'div_flag']); + if ($scan !== []) { + $output->writeln('详情嵌套: ' . json_encode($scan, JSON_UNESCAPED_UNICODE)); + } else { + $output->writeln('未读到 delay_flag(可 --json 看 basicdata 全文)'); + } + } + if ($bCode !== '' && $bCode !== '00000000') { + $output->writeln('basicdata resp_code=' . $bCode . ' ' . ($bd['resp_desc'] ?? '')); + } + } else { + $output->writeln('[SKIP] ' . $basic['message']); + } + $output->writeln(''); + $output->writeln('下一步(汇付实施/工单):'); + $output->writeln(' 1) v2/merchant/split/config 提交:rule_origin=01, div_flag=Y, apply_ratio≥业务比例(如30)'); + $output->writeln(' 2) 控台/接口绑定分账接收方 6666000245630872(进件通过 ≠ 分账关系已配)'); + $output->writeln(' 3) 生效后再跑本命令,应出现 rule_origin;新订单测分账,勿重试 unconfirm_amt=0 的旧单'); + $output->writeln('完整 JSON: php think shopro_huifu:query-split-config --json'); return 2; } diff --git a/addons/shopro_huifu/library/HuifuClient.php b/addons/shopro_huifu/library/HuifuClient.php index 3f52d1e..536d712 100644 --- a/addons/shopro_huifu/library/HuifuClient.php +++ b/addons/shopro_huifu/library/HuifuClient.php @@ -579,12 +579,85 @@ class HuifuClient $request->setHuifuId($huifuId); $request->setReqDate(date('Ymd')); $request->setReqSeqId('SPLQ' . date('YmdHis') . mt_rand(1000, 9999)); + $productId = trim((string) $this->config->get('product_id')); + if ($productId !== '') { + $request->setExtendInfo(['product_id' => $productId]); + } return $this->safeApiResult($this->postRequest($request)); } + /** + * 商户详细信息查询(传 product_id 时可含 delay_flag 等业务开通字段) + */ + public function queryMerchantBasicdata($huifuId = '', $withProductId = true) + { + $huifuId = trim((string) $huifuId); + if ($huifuId === '') { + $huifuId = trim((string) $this->config->get('huifu_id')); + } + if ($huifuId === '') { + return ['ok' => false, 'message' => '缺少 huifu_id', 'data' => null]; + } + + SdkLoader::requireRequest('V2MerchantBasicdataQueryRequest.php'); + $request = new \BsPaySdk\request\V2MerchantBasicdataQueryRequest(); + $request->setHuifuId($huifuId); + $request->setReqDate(date('Ymd')); + $request->setReqSeqId('MBDQ' . date('YmdHis') . mt_rand(1000, 9999)); + if ($withProductId) { + $productId = trim((string) $this->config->get('product_id')); + if ($productId !== '') { + $request->setExtendInfo(['product_id' => $productId]); + } + } + + return $this->safeApiResult($this->postRequest($request)); + } + + + + /** + * 在汇付应答中递归查找指定键(用于 split 配置可能在嵌套 JSON 字符串中) + * + * @return array + */ + public static function collectNestedKeys($payload, array $keys) + { + $found = []; + self::walkNestedPayload($payload, $keys, $found); + return $found; + } + + + + protected static function walkNestedPayload($node, array $keys, array &$found) + { + if (is_string($node)) { + $trim = trim($node); + if ($trim !== '' && ($trim[0] === '{' || $trim[0] === '[')) { + $decoded = json_decode($trim, true); + if (is_array($decoded)) { + self::walkNestedPayload($decoded, $keys, $found); + } + } + return; + } + if (!is_array($node)) { + return; + } + foreach ($node as $k => $v) { + if (in_array($k, $keys, true) && $v !== '' && $v !== null && !isset($found[$k])) { + $found[$k] = $v; + } + self::walkNestedPayload($v, $keys, $found); + } + } + + + /** * 解析 split_bill_result(可能是 array 或 JSON 字符串) *