connection = $database->connection( (string) config('upstream_mirrors.connection', 'business_mirror') ); } public function scope(): string { $scope = trim((string) config( 'upstream_mirrors.ding_process_details.scope', self::DEFAULT_SCOPE, )); return $scope !== '' ? $scope : self::DEFAULT_SCOPE; } public function datasetKey(): string { return self::DATASET_PREFIX . $this->scope(); } public function ready(): bool { $schema = Schema::connection($this->connection->getName()); if (! $schema->hasTable('ding_process_detail_mirror') || ! $schema->hasTable('business_mirror_table_states')) { return false; } $state = $this->state(); return $state !== null && ($state['initial_completed_at'] ?? null) !== null; } /** @return array|null */ public function state(): ?array { if (! Schema::connection($this->connection->getName())->hasTable('business_mirror_table_states')) { return null; } $row = $this->connection->table('business_mirror_table_states') ->where('dataset_key', $this->datasetKey()) ->first(); return $row === null ? null : (array) $row; } /** * @param array $filters * @return array{ * data:list, * total:int, * summary:array{rows:int,approvals:int,amount_total:float,bank_amount_total:float}, * status:string, * last_synced_at:?string, * scope:string * } */ public function paginate(array $filters, int $page, int $perPage): array { if (! $this->ready()) { throw new RuntimeException('ding_process_detail_mirror_not_ready'); } $page = max($page, 1); $perPage = min(max($perPage, 1), 100); $query = $this->filteredQuery($filters); $total = (clone $query)->count(); $summary = [ 'rows' => $total, 'approvals' => (clone $query)->distinct()->count('business_id'), 'amount_total' => (float) ((clone $query)->sum('amount') ?? 0), 'bank_amount_total' => (float) ((clone $query)->sum('bank_amount') ?? 0), ]; $data = $query ->orderByDesc('business_month') ->orderByDesc('business_id') ->orderBy('line_no') ->forPage($page, $perPage) ->get() ->all(); $state = $this->state(); return [ 'data' => $data, 'total' => $total, 'summary' => $summary, 'status' => (string) ($state['status'] ?? 'unknown'), 'last_synced_at' => isset($state['last_succeeded_at']) ? (string) $state['last_succeeded_at'] : null, 'scope' => $this->scope(), ]; } /** @return array{months:list,document_types:list,statuses:list} */ public function filterOptions(): array { if (! Schema::connection($this->connection->getName())->hasTable('ding_process_detail_mirror')) { return ['months' => [], 'document_types' => [], 'statuses' => []]; } $base = $this->connection->table('ding_process_detail_mirror') ->where('source_scope', $this->scope()); return [ 'months' => (clone $base) ->whereNotNull('business_month') ->where('business_month', '!=', '') ->distinct() ->orderByDesc('business_month') ->pluck('business_month') ->map(static function (mixed $value): string { $month = (string) $value; return preg_match('/^\d{6}$/', $month) === 1 ? substr($month, 0, 4) . '-' . substr($month, 4, 2) : $month; }) ->all(), 'document_types' => (clone $base) ->whereNotNull('document_type') ->where('document_type', '!=', '') ->distinct() ->orderBy('document_type') ->pluck('document_type') ->map(static fn (mixed $value): string => (string) $value) ->all(), 'statuses' => (clone $base) ->whereNotNull('status') ->where('status', '!=', '') ->distinct() ->orderBy('status') ->pluck('status') ->map(static fn (mixed $value): string => (string) $value) ->all(), ]; } /** @param array $filters */ public function exportCount(array $filters): int { if (! Schema::connection($this->connection->getName())->hasTable('ding_process_detail_mirror')) { return 0; } return (int) $this->filteredQuery($filters)->count(); } /** * @param array $filters * @return \Generator> */ public function exportRows(array $filters): \Generator { $query = $this->filteredQuery($filters) ->orderByDesc('business_month') ->orderByDesc('business_id') ->orderBy('line_no'); foreach ($query->cursor() as $row) { yield (array) $row; } } /** @param array $filters */ private function filteredQuery(array $filters): Builder { $query = $this->connection->table('ding_process_detail_mirror') ->where('source_scope', $this->scope()); $month = trim((string) ($filters['month'] ?? '')); if (preg_match('/^\d{4}-\d{2}$/', $month) === 1) { $query->where('business_month', str_replace('-', '', $month)); } foreach ([ 'document_type' => 'document_type', 'status' => 'status', ] as $filter => $column) { $value = trim((string) ($filters[$filter] ?? '')); if ($value !== '') { $query->where($column, $value); } } foreach ([ 'business_id' => 'business_id', 'originator_name' => 'originator_name', 'keyword' => 'purpose', ] as $filter => $column) { $value = mb_substr(trim((string) ($filters[$filter] ?? '')), 0, 100); if ($value !== '') { $query->where($column, 'like', '%' . $value . '%'); } } return $query; } }