diff --git a/app/Console/Commands/VerifyQccEnterprisePackInfo.php b/app/Console/Commands/VerifyQccEnterprisePackInfo.php new file mode 100644 index 0000000..ca3d6a9 --- /dev/null +++ b/app/Console/Commands/VerifyQccEnterprisePackInfo.php @@ -0,0 +1,102 @@ +argument('company_id')); + if (!$company) { + $this->error('企业不存在。'); + return self::FAILURE; + } + + $account = $company->qccAccount; + if (!$account || $account->status !== CompanyQccAccount::STATUS_SELECTED) { + $status = $account ? $account->status : 'none'; + $this->error("企业必须处于候选状态(selected),当前状态:{$status}。"); + return self::FAILURE; + } + + if (empty(trim((string) $company->credit_code))) { + $this->error('企业缺少统一社会信用代码,无法调用 packInfo。'); + return self::FAILURE; + } + + $requestRef = sprintf('pack-info-cli-%d-%s', $company->id, now()->format('YmdHisv')); + $this->info("开始调用 packInfo:{$company->company_name}({$company->credit_code})"); + $this->line("请求引用:{$requestRef}"); + + try { + $response = (new QccCallService())->call( + $company, + 'enterprise-pack-info-cli', + $requestRef, + fn () => (new YuanheRepository())->enterprisePackInfo([ + 'creditCode' => $company->credit_code, + 'enterpriseName' => $company->company_name, + ]), + fn (array $result) => array_key_exists('code', $result) && (int) $result['code'] === 0, + fn (array $result) => !array_key_exists('code', $result) + ? '元禾 packInfo 响应缺少业务状态码 code' + : false + ); + } catch (Throwable $exception) { + $this->error($exception->getMessage()); + if ($exception instanceof YuanhePackInfoException) { + $this->table( + ['HTTP 状态', 'Content-Type', '响应字节数'], + [[ + $exception->httpStatus ?? '(无响应)', + $exception->contentType ?? '(未提供)', + $exception->rawResponse === null ? 0 : strlen($exception->rawResponse), + ]] + ); + if ($this->option('raw') && $exception->rawResponse !== null) { + $this->line('原始响应:'); + $this->line($exception->rawResponse); + } + } + $this->line('调用后的企业户状态:' . $account->fresh()->status); + return self::FAILURE; + } + + $freshAccount = $account->fresh(); + $this->table( + ['元禾 code', '元禾 msg', '调用后状态', '首次成功引用'], + [[ + $response['code'] ?? '(缺失)', + $response['msg'] ?? '', + $freshAccount->status, + $freshAccount->first_success_ref ?? '', + ]] + ); + + if ($this->option('raw')) { + $this->line(json_encode($response, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT)); + } + + if (($response['code'] ?? null) !== 0 && ($response['code'] ?? null) !== '0') { + $this->warn('元禾未返回明确成功(code !== 0);企业保持候选状态。'); + return self::FAILURE; + } + + $this->info('元禾返回明确成功,企业已标记为已占额。'); + return self::SUCCESS; + } +} diff --git a/app/Exceptions/YuanhePackInfoException.php b/app/Exceptions/YuanhePackInfoException.php new file mode 100644 index 0000000..135344c --- /dev/null +++ b/app/Exceptions/YuanhePackInfoException.php @@ -0,0 +1,18 @@ +baseUrl . '/master-service/openapi/businessCollege/enterprise/packInfo'; + $header = $this->getHeader(); + + $ch = curl_init(); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + curl_setopt($ch, CURLOPT_URL, $url); + curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 3); + curl_setopt($ch, CURLOPT_TIMEOUT, 3); + curl_setopt($ch, CURLOPT_HTTPHEADER, $header); + curl_setopt($ch, CURLOPT_POST, true); + curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($params, JSON_UNESCAPED_UNICODE)); + if (stripos($url, 'https://') !== false) { + curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); + curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); + curl_setopt($ch, CURLOPT_SSLVERSION, 1); + } + + $raw = curl_exec($ch); + $curlError = curl_error($ch); + $httpStatus = (int) curl_getinfo($ch, CURLINFO_RESPONSE_CODE); + $contentType = curl_getinfo($ch, CURLINFO_CONTENT_TYPE) ?: null; + curl_close($ch); + + if ($raw === false) { + throw new YuanhePackInfoException( + '元禾 packInfo 网络调用失败:' . ($curlError ?: '未知 cURL 错误'), + $httpStatus ?: null, + $contentType + ); + } + + $result = json_decode($raw, true); + if (!is_array($result)) { + throw new YuanhePackInfoException( + '元禾 packInfo 响应不是有效 JSON 对象:' . json_last_error_msg(), + $httpStatus ?: null, + $contentType, + $raw + ); + } + + return $result; + } + /** * 数据推送 */