CaiWuXiTong/modules/EcommerceFinance/View/DingWorklogStatisticsPageData.php

132 lines
5.4 KiB
PHP

<?php
namespace Modules\EcommerceFinance\View;
use Illuminate\Http\Request;
use Illuminate\Support\Carbon;
use Modules\EcommerceFinance\Repositories\DingWorklogMirrorRepository;
use Modules\EcommerceFinance\Services\DingWorklogPenaltyCalculator;
use Throwable;
class DingWorklogStatisticsPageData
{
public function __construct(
private readonly DingWorklogMirrorRepository $repository,
private readonly DingWorklogPenaltyCalculator $penaltyCalculator,
) {}
public function page(Request $request): array
{
$latestStatisticsDate = now()->hour < 12
? now()->subDay()->startOfDay()
: now()->startOfDay();
$from = $this->date($request->query('from'))
?? $latestStatisticsDate->copy()->subDays(13);
$to = $this->date($request->query('to')) ?? $latestStatisticsDate->copy();
if ($from->greaterThan($to)) {
[$from, $to] = [$to, $from];
}
if ($from->diffInDays($to) > 90) {
$from = $to->copy()->subDays(90);
}
$state = $this->repository->available() ? $this->repository->state() : null;
$errorCode = trim((string) ($state['last_error_code'] ?? ''));
$syncState = match (true) {
! $this->repository->available() => 'unavailable',
$errorCode !== '' => 'failed',
$state === null => 'pending',
($state['status'] ?? '') === 'running' => 'syncing',
($state['status'] ?? '') === 'succeeded' => 'succeeded',
default => 'pending',
};
$permissionRequired = DingWorklogMirrorRepository::isPermissionError($errorCode);
$daily = [];
$selectedDate = $this->date($request->query('date'))?->toDateString();
$submissions = [];
$penalty = ['start_date' => null, 'end_date' => null, 'members' => []];
$penaltyError = null;
if ($this->repository->available()) {
try {
$daily = $this->repository->dailySummary($from->toDateString(), $to->toDateString());
$selectedDate ??= $daily[0]['statistics_date'] ?? $latestStatisticsDate->toDateString();
$submissions = array_map(static fn (object $row): array => [
'report_id' => (string) $row->report_id,
'template_name' => (string) ($row->template_name ?? ''),
'creator_userid' => (string) ($row->creator_userid ?? ''),
'creator_name' => (string) ($row->creator_name ?? ''),
'submitted_at' => (string) $row->submitted_at,
'statistics_date' => (string) $row->statistics_date,
], $this->repository->submissionsForDate($selectedDate));
} catch (Throwable $exception) {
report($exception);
$syncState = 'failed';
$errorCode = 'dingtalk_worklog_read_failed';
}
try {
$penalty = $this->penaltyCalculator->summary(
$from->toDateString(),
$to->toDateString(),
now(),
);
} catch (Throwable $exception) {
report($exception);
$penaltyError = '日志漏写扣分暂时无法计算。';
}
}
$currentDate = $latestStatisticsDate->toDateString();
$current = collect($daily)->firstWhere('statistics_date', $currentDate) ?? [
'statistics_date' => $currentDate,
'submission_count' => 0,
'submitter_count' => 0,
'first_submitted_at' => null,
'last_submitted_at' => null,
];
return [
'view' => 'business.pages.other.log-statistics',
'worklogFilters' => [
'from' => $from->toDateString(),
'to' => $to->toDateString(),
'date' => $selectedDate,
],
'worklogState' => [
'state' => $syncState,
'error_code' => $errorCode ?: null,
'permission_required' => $permissionRequired,
'permission_apply_url' => $permissionRequired ? $this->repository->permissionApplyUrl() : null,
'status' => $state['status'] ?? null,
'last_attempted_at' => $state['last_attempted_at'] ?? null,
'last_succeeded_at' => $state['last_succeeded_at'] ?? null,
'mirror_row_count' => (int) ($state['mirror_row_count'] ?? 0),
],
'worklogCurrent' => $current,
'worklogDaily' => $daily,
'worklogSubmissions' => $submissions,
'worklogPenalty' => $penalty,
'worklogPenaltyError' => $penaltyError,
'worklogDays' => (int) $from->diffInDays($to) + 1,
'worklogTotalSubmissions' => array_sum(array_column($daily, 'submission_count')),
'worklogTemplateName' => (string) config('dingtalk.worklog.display_name', '财务日报 / 日志'),
'worklogCutoffAt' => $latestStatisticsDate->copy()->addDay()->setTime(12, 0)->toDateTimeString(),
];
}
private function date(mixed $value): ?Carbon
{
$value = trim((string) $value);
if (preg_match('/^\d{4}-\d{2}-\d{2}$/', $value) !== 1) {
return null;
}
try {
return Carbon::createFromFormat('!Y-m-d', $value)->startOfDay();
} catch (Throwable) {
return null;
}
}
}