*/ public function page(): array { $rows = $this->store->listRows( PayablesFinalActions::DATASET_PREFIX . 'supplier:' . self::DATASET, (int) (company_id() ?: 1), ); $negativeRows = []; foreach ($rows as $row) { $balance = $this->number($row['supplier_balance'] ?? null) ?? 0.0; $shouldPay = $this->number($row['should_pay'] ?? null) ?? 0.0; $estimatedPrice = $this->number($row['estimated_price'] ?? null) ?? 0.0; $alertAmount = $balance - $shouldPay + $estimatedPrice; if ($alertAmount >= 0) { continue; } $row['supplier_balance'] = $balance; $row['_negative_alert_amount'] = round($alertAmount, 2); $negativeRows[] = $row; } usort($negativeRows, static function (array $left, array $right): int { return strcmp( (string) ($right['summary_month'] ?? ''), (string) ($left['summary_month'] ?? ''), ) ?: strnatcasecmp( (string) ($left['supplier'] ?? ''), (string) ($right['supplier'] ?? ''), ); }); $months = []; foreach ($negativeRows as $row) { $month = trim((string) ($row['summary_month'] ?? '')); if (preg_match('/^\d{4}-\d{2}$/', $month) === 1) { $months[$month] = true; } } $months = array_keys($months); rsort($months); $requestedMonth = trim((string) request()->query('month', '')); $month = in_array($requestedMonth, $months, true) ? $requestedMonth : ''; if ($month !== '') { $negativeRows = array_values(array_filter( $negativeRows, static fn (array $row): bool => (string) ($row['summary_month'] ?? '') === $month, )); } $supplierNames = []; foreach ($negativeRows as $row) { $supplier = trim((string) ($row['supplier'] ?? '')); if ($supplier !== '') { $supplierNames[$supplier] = true; } } $supplierNames = array_keys($supplierNames); sort($supplierNames, SORT_NATURAL | SORT_FLAG_CASE); $supplierQuery = mb_substr(trim((string) request()->query('supplier', '')), 0, 191); if ($supplierQuery !== '') { $needle = mb_strtolower($supplierQuery); $negativeRows = array_values(array_filter( $negativeRows, static function (array $row) use ($needle): bool { $haystack = mb_strtolower(implode("\n", [ (string) ($row['supplier'] ?? ''), (string) ($row['company'] ?? ''), ])); return str_contains($haystack, $needle); }, )); } $supplierCounts = []; foreach ($negativeRows as $row) { $key = trim((string) ($row['company'] ?? '')) . "\0" . trim((string) ($row['supplier'] ?? '')); $supplierCounts[$key] = true; } $total = count($negativeRows); $pages = max((int) ceil($total / self::PER_PAGE), 1); $page = min(max((int) request()->query('page', 1), 1), $pages); $pageRows = array_slice($negativeRows, ($page - 1) * self::PER_PAGE, self::PER_PAGE); $pageSupplierNames = array_values(array_unique(array_filter( array_map( static fn (array $row): string => trim((string) ($row['supplier'] ?? '')), $pageRows, ), static fn (string $name): bool => $name !== '', ))); $purchasersBySupplier = []; if ($pageSupplierNames !== []) { try { foreach ($this->supplierManagement->suppliersByNames($pageSupplierNames) as $supplier) { $name = trim((string) ($supplier->scmname ?? '')); $buyer = trim((string) ($supplier->buyer ?? '')); if ($name !== '' && $buyer !== '') { $purchasersBySupplier[$name][$buyer] = true; } } } catch (Throwable $exception) { report($exception); } } $purchasersBySupplier = array_map( static fn (array $buyers): string => implode('、', array_keys($buyers)), $purchasersBySupplier, ); $items = array_map( static function (array $row) use ($purchasersBySupplier): object { $supplier = trim((string) ($row['supplier'] ?? '')); $row['purchaser'] = $purchasersBySupplier[$supplier] ?? ''; return (object) $row; }, $pageRows, ); $negativeAlertFields = []; $fields = collect($this->registry->fields( PayablesFinalRegistry::SECTION_SUPPLIER, self::DATASET, ))->map( static fn (array $definition, string $name): array => ['name' => $name] + $definition, )->values()->all(); foreach ($fields as $field) { $negativeAlertFields[] = $field; if (($field['name'] ?? '') === 'negative_reason') { $negativeAlertFields[] = ['name' => 'purchaser', 'label' => '采购', 'type' => 'text']; } } return [ 'view' => 'business.pages.negative-alerts.supplier-negative-alert', 'negativeAlertFields' => $negativeAlertFields, 'negativeAlertRows' => new LengthAwarePaginator( $items, $total, self::PER_PAGE, $page, [ 'path' => request()->url(), 'query' => request()->except('page'), ], ), 'negativeAlertMonths' => $months, 'negativeAlertMonth' => $month, 'negativeAlertSupplier' => $supplierQuery, 'negativeAlertSupplierNames' => $supplierNames, 'negativeAlertSupplierCount' => count($supplierCounts), 'negativeAlertTotal' => $total, 'negativeAlertSourceUrl' => route('business.pages.show', [ 'section' => 'supplier-payables-final', 'page' => 'supplier-payables-report', ]), ]; } private function number(mixed $value): ?float { if ($value === null || trim((string) $value) === '') { return null; } $normalized = str_replace([',', ',', ' '], '', trim((string) $value)); return is_numeric($normalized) ? (float) $normalized : null; } }