reportRows(InputInvoiceReport::class); $outputRows = $this->reportRows(OutputInvoiceReport::class); if ($tab === 'summary') { $allRows = $this->summaryRows($inputRows, $outputRows); $filters = $this->summaryFilters(); $summaryRows = $this->filterSummaryRows($allRows, $filters); return [ 'view' => 'business.pages.invoice_reports', 'summaryRows' => $summaryRows, 'summaryTotals' => $this->summaryTotals($summaryRows), 'summaryFilters' => $filters, 'companyOptions' => $allRows->pluck('company_name') ->filter(static fn ($name): bool => (string) $name !== '') ->unique() ->sort() ->values(), 'taxpayerTypeOptions' => $allRows->pluck('taxpayer_type') ->filter(static fn ($type): bool => (string) $type !== '' && (string) $type !== '—') ->unique() ->sort() ->values(), ]; } return [ 'view' => 'business.pages.invoice_reports', 'items' => $tab === 'output' ? $outputRows : $inputRows, ]; } /** * 报表表在部分老环境可能尚未迁移,缺失时保持页面可用并展示空表。 * * @param class-string $model */ private function reportRows(string $model): Collection { try { return $model::query() ->orderBy('company_name') ->orderBy('id') ->get(); } catch (Throwable $exception) { report($exception); return collect(); } } private function summaryRows(Collection $inputRows, Collection $outputRows): Collection { $inputs = $inputRows->groupBy(fn ($row): string => trim((string) $row->company_name)); $outputs = $outputRows->groupBy(fn ($row): string => trim((string) $row->company_name)); $companyNames = $inputs->keys() ->merge($outputs->keys()) ->filter(static fn ($name): bool => $name !== '') ->unique() ->sort() ->values(); $taxpayerTypes = $this->taxpayerTypes($companyNames); return $companyNames->map(function (string $companyName) use ($inputs, $outputs, $taxpayerTypes): object { $inputRows = $inputs->get($companyName, collect()); $outputRows = $outputs->get($companyName, collect()); $inputAmount = $this->sumField($inputRows, 'input_total_amount'); $inputTax = $this->sumField($inputRows, 'input_total_tax'); $outputAmount = $this->sumField($outputRows, 'output_total_amount'); $outputTax = $this->sumField($outputRows, 'output_total_tax'); $ratio = $outputAmount > 0 ? $inputAmount / $outputAmount : null; return (object) [ 'company_name' => $companyName, 'taxpayer_type' => $taxpayerTypes->get($companyName, '—'), 'input_total_amount' => $inputAmount, 'input_total_tax' => $inputTax, 'output_total_amount' => $outputAmount, 'output_total_tax' => $outputTax, 'input_output_ratio' => $ratio, 'is_warning' => $ratio !== null && $ratio < 0.8, ]; }); } private function summaryTotals(Collection $rows): object { return (object) [ 'input_total_amount' => round((float) $rows->sum('input_total_amount'), 2), 'input_total_tax' => round((float) $rows->sum('input_total_tax'), 2), 'output_total_amount' => round((float) $rows->sum('output_total_amount'), 2), 'output_total_tax' => round((float) $rows->sum('output_total_tax'), 2), ]; } /** * @return array{company:string,taxpayer_type:string,warning:string} */ private function summaryFilters(): array { $warning = strtolower(trim((string) request()->query('warning', ''))); return [ 'company' => trim((string) request()->query('company', '')), 'taxpayer_type' => trim((string) request()->query('taxpayer_type', '')), 'warning' => in_array($warning, ['yes', 'no'], true) ? $warning : '', ]; } /** * @param array{company:string,taxpayer_type:string,warning:string} $filters */ private function filterSummaryRows(Collection $rows, array $filters): Collection { return $rows->filter(function (object $row) use ($filters): bool { if ($filters['company'] !== '' && $row->company_name !== $filters['company']) { return false; } if ($filters['taxpayer_type'] !== '' && $row->taxpayer_type !== $filters['taxpayer_type']) { return false; } if ($filters['warning'] === 'yes' && ! $row->is_warning) { return false; } if ($filters['warning'] === 'no' && $row->is_warning) { return false; } return true; })->values(); } /** * 纳税人类型取公司基础信息共享镜像;镜像未就绪或公司未登记时显示「—」。 */ private function taxpayerTypes(Collection $companyNames): Collection { $names = $companyNames ->map(static fn ($name): string => trim((string) $name)) ->filter(static fn (string $name): bool => $name !== '') ->unique() ->values() ->all(); if ($names === []) { return collect(); } try { $rows = app(\Modules\EcommerceFinance\Repositories\BusinessInformationMirrorRepository::class) ->allCompaniesForClassification(['_company_names' => $names]); return collect($rows) ->mapWithKeys(static fn (array $row): array => [ trim((string) ($row['company_name'] ?? '')) => trim((string) ($row['taxpayer_category'] ?? '')), ]) ->filter(static fn ($value, $key): bool => $key !== '' && (string) $value !== ''); } catch (Throwable $exception) { report($exception); return collect(); } } private function sumField(Collection $rows, string $field): float { return round($rows->sum(static fn ($row): float => (float) $row->{$field}), 2); } }