105 lines
4.2 KiB
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;
|
|
}
|
|
}
|
|
}
|