[['交易单号', '交易订单'], ['差异', '金额']], self::PAGE_OTHER_SURCHARGE => [['交易单号', '交易订单'], ['金额']], self::PAGE_RETURN_FEE => [['交易订单', '交易单号'], ['结算金额', '金额']], ]; private const CACHE_MINUTES = 10; public function __construct(private readonly CourierPayableSummaryStore $store) {} /** * @param string $page self::PAGE_* 之一 * @return array 交易单号 => 金额(保留源文件里的原值字符串) */ public function map(int $companyId, string $page): array { if (! isset(self::PAGES[$page])) { return []; } $disk = Storage::disk('uploads'); $path = $this->store->path($companyId, $page); if (! $disk->exists($path)) { return []; } // 文件时间戳进缓存键:财务重新导入运费差后不用等缓存过期。 $key = sprintf('courier-payable-summary-map:v1:%s:%d:%d', $page, $companyId, (int) $disk->lastModified($path)); return Cache::remember($key, now()->addMinutes(self::CACHE_MINUTES), function () use ($companyId, $page): array { try { return $this->build($companyId, $page); } catch (Throwable $exception) { report($exception); return []; } }); } /** @return array */ private function build(int $companyId, string $page): array { $snapshot = $this->store->snapshot($companyId, $page); if ($snapshot === null) { return []; } [$orderHeaders, $valueHeaders] = self::PAGES[$page]; $headers = array_map(static fn ($value): string => trim((string) $value), (array) $snapshot['headers']); $orderColumn = $this->columnIndex($headers, $orderHeaders); $valueColumn = $this->columnIndex($headers, $valueHeaders); if ($orderColumn === null || $valueColumn === null) { return []; } $map = []; foreach ((array) $snapshot['rows'] as $row) { $orderNos = trim((string) ($row[$orderColumn] ?? '')); if ($orderNos === '') { continue; } $value = trim((string) ($row[$valueColumn] ?? '')); if ($value === '') { continue; } // 源表一个格子可能放多个交易单号(逗号分隔),逐个挂到同一个金额上。 foreach (explode(',', $orderNos) as $orderNo) { $orderNo = trim($orderNo); if ($orderNo !== '' && ! isset($map[$orderNo])) { $map[$orderNo] = $value; } } } return $map; } /** * 按表头名定位:候选顺序优先,每个候选先找完全相等的表头,再退化成包含匹配 * (例如「差异(结算运费-提供成本运费)」只能靠包含匹配)。 * * @param list $needles */ private function columnIndex(array $headers, array $needles): ?int { foreach ($needles as $needle) { foreach ($headers as $index => $header) { if ($header === $needle) { return (int) $index; } } } foreach ($needles as $needle) { foreach ($headers as $index => $header) { if ($header !== '' && mb_strpos($header, $needle) !== false) { return (int) $index; } } } return null; } }