153 lines
5.5 KiB
PHP
153 lines
5.5 KiB
PHP
<?php
|
||
|
||
namespace Modules\EcommerceFinance\View;
|
||
|
||
use Illuminate\Http\Request;
|
||
use Illuminate\Pagination\LengthAwarePaginator;
|
||
use Modules\EcommerceFinance\Repositories\DingProcessDetailMirrorRepository;
|
||
use Throwable;
|
||
|
||
class ProcessDetailsPageData
|
||
{
|
||
public const PER_PAGE_OPTIONS = [50, 100, 200];
|
||
|
||
public const DEFAULT_PER_PAGE = 50;
|
||
|
||
public function __construct(
|
||
private readonly DingProcessDetailMirrorRepository $repository,
|
||
) {}
|
||
|
||
public static function normalizePerPage(mixed $value): int
|
||
{
|
||
$perPage = (int) $value;
|
||
|
||
return in_array($perPage, self::PER_PAGE_OPTIONS, true)
|
||
? $perPage
|
||
: self::DEFAULT_PER_PAGE;
|
||
}
|
||
|
||
/** @return array{0:string,1:string} */
|
||
public static function normalizePaidDateRange(
|
||
mixed $start,
|
||
mixed $end,
|
||
mixed $legacyDate = '',
|
||
): array {
|
||
$start = self::normalizeFilterDate($start);
|
||
$end = self::normalizeFilterDate($end);
|
||
if ($start === '' && $end === '') {
|
||
$legacyDate = self::normalizeFilterDate($legacyDate);
|
||
$start = $legacyDate;
|
||
$end = $legacyDate;
|
||
}
|
||
if ($start !== '' && $end !== '' && $start > $end) {
|
||
[$start, $end] = [$end, $start];
|
||
}
|
||
|
||
return [$start, $end];
|
||
}
|
||
|
||
/** @return array<string,mixed> */
|
||
public function page(Request $request): array
|
||
{
|
||
$filters = $this->filters($request);
|
||
$page = max((int) $request->query('page', 1), 1);
|
||
$perPage = self::normalizePerPage($request->query('per_page'));
|
||
$paginationQuery = array_filter(
|
||
[...$filters, 'per_page' => $perPage],
|
||
static fn (mixed $value): bool => $value !== '' && $value !== null,
|
||
);
|
||
|
||
try {
|
||
$options = $this->repository->filterOptions($filters);
|
||
if ($filters['payment_state'] !== ''
|
||
&& ! in_array($filters['payment_state'], $options['payment_states'], true)) {
|
||
$filters['payment_state'] = '';
|
||
unset($paginationQuery['payment_state']);
|
||
}
|
||
$result = $this->repository->paginate($filters, $page, $perPage);
|
||
|
||
return [
|
||
'processRows' => new LengthAwarePaginator(
|
||
$result['data'],
|
||
$result['total'],
|
||
$perPage,
|
||
$page,
|
||
['path' => $request->url(), 'query' => $paginationQuery],
|
||
),
|
||
'filters' => $filters,
|
||
'summary' => $result['summary'],
|
||
'documentTypes' => $options['document_types'],
|
||
'statuses' => $options['statuses'],
|
||
'paymentStates' => $options['payment_states'],
|
||
'mirrorStatus' => $result['status'],
|
||
'mirrorSyncedAt' => $result['last_synced_at'],
|
||
'mirrorStale' => $result['sync_stale'] ?? false,
|
||
'mirrorStaleAfterMinutes' => $result['sync_stale_after_minutes'] ?? 15,
|
||
'scope' => $result['scope'],
|
||
'error' => null,
|
||
];
|
||
} catch (Throwable $exception) {
|
||
report($exception);
|
||
|
||
return [
|
||
'processRows' => new LengthAwarePaginator([], 0, $perPage, $page, [
|
||
'path' => $request->url(),
|
||
'query' => $paginationQuery,
|
||
]),
|
||
'filters' => $filters,
|
||
'summary' => [
|
||
'rows' => 0,
|
||
'approvals' => 0,
|
||
'amount_total' => 0.0,
|
||
'bank_amount_total' => 0.0,
|
||
],
|
||
'documentTypes' => [],
|
||
'statuses' => [],
|
||
'paymentStates' => [],
|
||
'mirrorStatus' => 'unavailable',
|
||
'mirrorSyncedAt' => null,
|
||
'mirrorStale' => false,
|
||
'mirrorStaleAfterMinutes' => 15,
|
||
'scope' => $this->repository->scope(),
|
||
'error' => 'OA流程镜像尚未完成导入,请稍后重试。',
|
||
];
|
||
}
|
||
}
|
||
|
||
/** @return array<string,string> */
|
||
private function filters(Request $request): array
|
||
{
|
||
$status = trim((string) $request->query('status', ''));
|
||
[$paidStart, $paidEnd] = self::normalizePaidDateRange(
|
||
$request->query('paid_start'),
|
||
$request->query('paid_end'),
|
||
$request->query('paid_date'),
|
||
);
|
||
$paymentState = DingProcessDetailMirrorRepository::normalizePaymentStateFilter(
|
||
$request->query('payment_state'),
|
||
);
|
||
|
||
return [
|
||
'paid_start' => $paidStart,
|
||
'paid_end' => $paidEnd,
|
||
'document_type' => mb_substr(trim((string) $request->query('document_type', '')), 0, 100),
|
||
'status' => mb_substr($status, 0, 20),
|
||
'payment_state' => $paymentState,
|
||
'business_id' => mb_substr(trim((string) $request->query('business_id', '')), 0, 32),
|
||
'originator_name' => mb_substr(trim((string) $request->query('originator_name', '')), 0, 100),
|
||
'keyword' => mb_substr(trim((string) $request->query('keyword', '')), 0, 100),
|
||
];
|
||
}
|
||
|
||
private static function normalizeFilterDate(mixed $value): string
|
||
{
|
||
$date = trim((string) $value);
|
||
if (preg_match('/^(\d{4})-(\d{2})-(\d{2})$/', $date, $parts) !== 1
|
||
|| ! checkdate((int) $parts[2], (int) $parts[3], (int) $parts[1])) {
|
||
return '';
|
||
}
|
||
|
||
return $date;
|
||
}
|
||
}
|