CaiWuXiTong/app/Console/Commands/PollEsignSignatures.php

141 lines
5.2 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
namespace App\Console\Commands;
use App\Models\Business\CourierAgreementSignature;
use App\Models\Business\CourierQuoteSignature;
use App\Services\Esign\EsignClient;
use App\Support\CourierAgreementSignatureService;
use App\Support\CourierQuoteSignatureService;
use Illuminate\Console\Command;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Log;
use Throwable;
class PollEsignSignatures extends Command
{
protected $signature = 'esign:poll-signatures
{--limit= : 本轮最多查询的签署流程数}
{--min-age= : 同一流程两次查询之间的最少秒数}';
protected $description = '在不使用回调地址时,定时查询 E 签宝流程状态并归档已签文件';
public function handle(
CourierQuoteSignatureService $quoteSignatures,
CourierAgreementSignatureService $agreementSignatures,
): int {
if (! (bool) config('services.esign.polling_enabled', false)) {
$this->components->info('E 签宝定时轮询未启用。');
return self::SUCCESS;
}
if (! EsignClient::configured()) {
$this->components->warn('E 签宝尚未正确配置,已跳过定时轮询。');
return self::SUCCESS;
}
$limit = min(max((int) ($this->option('limit')
?? config('services.esign.poll_batch_size', 25)), 1), 100);
$minAge = max((int) ($this->option('min-age')
?? config('services.esign.poll_min_age_seconds', 120)), 0);
$cutoff = now()->subSeconds($minAge);
$candidates = $this->candidates($limit, $cutoff);
$succeeded = 0;
$failed = 0;
foreach ($candidates as $candidate) {
$model = $candidate['model'];
try {
if ($candidate['type'] === 'quote') {
$quoteSignatures->synchronize($model, (int) ($model->updated_by ?: $model->created_by));
} else {
$agreementSignatures->synchronize($model, (int) ($model->updated_by ?: $model->created_by));
}
$succeeded++;
} catch (Throwable $exception) {
$failed++;
Log::warning('E 签宝签署流程定时查询失败。', [
'signature_type' => $candidate['type'],
'signature_id' => $model->getKey(),
'exception' => $exception::class,
]);
}
}
$this->components->info(sprintf(
'E 签宝轮询完成:候选 %d,成功 %d,失败 %d。',
$candidates->count(),
$succeeded,
$failed,
));
return $failed > 0 ? self::FAILURE : self::SUCCESS;
}
/** @return Collection<int,array{type:string,model:CourierQuoteSignature|CourierAgreementSignature}> */
private function candidates(int $limit, \DateTimeInterface $cutoff): Collection
{
$environment = strtolower(trim((string) config('services.esign.environment', 'sandbox')));
$quotes = CourierQuoteSignature::allCompanies()
->where('environment', $environment)
->whereNotNull('esign_sign_flow_id')
->where('esign_sign_flow_id', '<>', '')
->whereIn('status', [
CourierQuoteSignature::STATUS_SIGNING,
CourierQuoteSignature::STATUS_COMPLETED,
])
->where(fn (Builder $query) => $query
->whereNull('last_synced_at')
->orWhere('last_synced_at', '<=', $cutoff))
->orderByRaw('CASE WHEN last_synced_at IS NULL THEN 0 ELSE 1 END')
->orderBy('last_synced_at')
->orderBy('id')
->limit($limit)
->get()
->map(fn (CourierQuoteSignature $signature): array => [
'type' => 'quote',
'model' => $signature,
]);
$agreements = CourierAgreementSignature::allCompanies()
->disableCache()
->where('environment', $environment)
->whereNotNull('esign_sign_flow_id')
->where('esign_sign_flow_id', '<>', '')
->whereIn('status', [
CourierAgreementSignature::STATUS_SIGNING,
CourierAgreementSignature::STATUS_UNKNOWN,
CourierAgreementSignature::STATUS_COMPLETED,
])
->where(fn (Builder $query) => $query
->whereNull('last_synced_at')
->orWhere('last_synced_at', '<=', $cutoff))
->orderByRaw('CASE WHEN last_synced_at IS NULL THEN 0 ELSE 1 END')
->orderBy('last_synced_at')
->orderBy('id')
->limit($limit)
->get()
->map(fn (CourierAgreementSignature $signature): array => [
'type' => 'agreement',
'model' => $signature,
]);
return $quotes
->concat($agreements)
->sortBy(fn (array $candidate): string => sprintf(
'%020d:%s:%020d',
$candidate['model']->last_synced_at?->getTimestamp() ?? 0,
$candidate['type'],
$candidate['model']->getKey(),
))
->take($limit)
->values();
}
}