CaiWuXiTong/app/Console/Commands/SyncDingWorklogs.php

105 lines
4.2 KiB
PHP

<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use Modules\EcommerceFinance\Exceptions\DingTalkWorklogException;
use Modules\EcommerceFinance\Repositories\DingWorklogMirrorRepository;
use Modules\EcommerceFinance\Services\DingTalkWorklogClient;
use Throwable;
class SyncDingWorklogs extends Command
{
protected $signature = 'business-mirror:sync-ding-worklogs
{--days= : 回看天数,默认使用配置值}
{--template= : 日志模板名称,默认使用配置值}';
protected $description = '同步钉钉财务日报到日志统计镜像';
public function handle(
DingTalkWorklogClient $client,
DingWorklogMirrorRepository $repository,
): int {
if (! (bool) config('dingtalk.worklog.enabled', true)) {
return self::SUCCESS;
}
if (! $repository->available()) {
$this->error('日志统计镜像表尚未建立,请先执行数据库迁移。');
return self::FAILURE;
}
if (! $client->isConfigured()) {
$repository->recordFailure('dingtalk_credentials_missing');
$this->error('钉钉应用凭据未配置。');
return self::FAILURE;
}
$days = max((int) ($this->option('days') ?: config('dingtalk.worklog.lookback_days', 35)), 1);
$template = trim((string) ($this->option('template') ?: config('dingtalk.worklog.template_name', '财务日报')));
$to = now();
$from = $to->copy()->subDays($days)->startOfDay();
try {
$result = $client->listReports($from, $to, $template);
$now = now();
$rows = [];
foreach ($result['reports'] as $report) {
if (! is_array($report)) {
continue;
}
$submittedRaw = $report['create_time']
?? $report['created_at']
?? $report['submit_time']
?? null;
if ($submittedRaw === null || $submittedRaw === '') {
continue;
}
try {
$submittedAt = DingWorklogMirrorRepository::submittedAt($submittedRaw);
} catch (Throwable) {
continue;
}
$statisticsDate = DingWorklogMirrorRepository::statisticsDate($submittedAt);
$rows[] = [
'report_id' => DingWorklogMirrorRepository::reportId($report),
'template_name' => mb_substr(trim((string) ($report['template_name'] ?? $template)), 0, 191),
'creator_userid' => mb_substr(trim((string) ($report['creator_userid'] ?? $report['creator_id'] ?? '')), 0, 128),
'creator_name' => mb_substr(trim((string) ($report['creator_name'] ?? $report['creator_nick'] ?? '')), 0, 191),
'submitted_at' => $submittedAt->toDateTimeString(),
'statistics_date' => $statisticsDate->toDateString(),
'remark' => trim((string) ($report['remark'] ?? '')),
'raw_payload' => json_encode($report, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES),
'synced_at' => $now,
'created_at' => $now,
'updated_at' => $now,
];
}
$upserted = $repository->upsertReports($rows);
$repository->recordSuccess($upserted, $template, $from, $to);
$this->info(sprintf(
'钉钉日志同步完成:读取 %d 页,写入/更新 %d 条。',
$result['pages'],
$upserted,
));
return self::SUCCESS;
} catch (DingTalkWorklogException $exception) {
$repository->recordFailure($exception->errorCode);
report($exception);
$this->error($exception->getMessage());
return self::FAILURE;
} catch (Throwable $exception) {
$repository->recordFailure('dingtalk_worklog_sync_failed');
report($exception);
$this->error('钉钉日志同步失败,详细原因已记录到受保护日志。');
return self::FAILURE;
}
}
}