master^2
weizong song 6 days ago
parent 0689d65756
commit ee1912e173

@ -0,0 +1,102 @@
<?php
namespace App\Console\Commands;
use App\Exceptions\YuanhePackInfoException;
use App\Models\Company;
use App\Models\CompanyQccAccount;
use App\Repositories\YuanheRepository;
use App\Services\QccCallService;
use Illuminate\Console\Command;
use Throwable;
class VerifyQccEnterprisePackInfo extends Command
{
protected $signature = 'qcc:verify-pack-info
{company_id : 已纳入候选池的本地企业 ID}
{--raw : 输出元禾完整响应 JSON}';
protected $description = '调用一次元禾企业户聚合接口 packInfo验证企业户占额状态流转';
public function handle(): int
{
$company = Company::find($this->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;
}
}

@ -0,0 +1,18 @@
<?php
namespace App\Exceptions;
use RuntimeException;
class YuanhePackInfoException extends RuntimeException
{
public function __construct(
string $message,
public readonly ?int $httpStatus = null,
public readonly ?string $contentType = null,
public readonly ?string $rawResponse = null,
?\Throwable $previous = null
) {
parent::__construct($message, 0, $previous);
}
}

@ -2,6 +2,7 @@
namespace App\Repositories;
use App\Exceptions\YuanhePackInfoException;
use App\Models\AppointmentConfig;
use App\Models\Course;
use App\Models\ThirdAppointmentLog;
@ -80,6 +81,58 @@ class YuanheRepository
}
}
/**
* 查询企业户聚合信息。
*
* 此方法保留元禾响应外层的 code/data/msg/status供调用方判定一次
* 企业户调用是否明确成功;不要像 companyInfo 一样仅返回 data。
*/
public function enterprisePackInfo(array $params): array
{
$url = $this->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;
}
/**
* 数据推送
*/

Loading…
Cancel
Save