$materialCodes * @return array{ * unique:array, * ambiguous:array>, * missing:list, * source_rows:int * } */ public function resolve( array $materialCodes, ?UpstreamReadOnlyQuery $query = null, ?callable $enabledSkuLookup = null, ): array { $normalized = []; foreach ($materialCodes as $code) { $materialCode = self::normalizeMaterialCode((string) $code); if ($materialCode !== null) { $normalized[$materialCode] = true; } } $materialCodes = array_keys($normalized); sort($materialCodes, SORT_STRING); if ($materialCodes === []) { return [ 'unique' => [], 'ambiguous' => [], 'missing' => [], 'source_rows' => 0, ]; } $query ??= new UpstreamReadOnlyQuery(self::SOURCE_KEY, 15); $enabledSkuLookup ??= static fn (array $skuCodes): array => app( ProductCatalogMirrorRepository::class, )->enabledNormalSkuCodes($skuCodes); /** @var array> $candidates */ $candidates = []; $sourceRows = 0; try { foreach (array_chunk($materialCodes, 200) as $chunk) { $placeholders = implode(', ', array_fill(0, count($chunk), '?')); $rows = $query->select( 'WITH material_skus AS (' . 'SELECT DISTINCT ' . "UPPER(BTRIM(updates->>'materialNo')) AS material_no, " . 'COALESCE(NULLIF(BTRIM("normalizedSku"), \'\'), NULLIF(BTRIM("skuCode"), \'\')) AS sku_code ' . 'FROM public."BarcodePrintImportRecord" ' . "WHERE UPPER(BTRIM(updates->>'materialNo')) IN ({$placeholders}) " . 'AND COALESCE(NULLIF(BTRIM("normalizedSku"), \'\'), NULLIF(BTRIM("skuCode"), \'\')) IS NOT NULL' . '), barcode_matches AS (' . 'SELECT DISTINCT material_skus.material_no, ' . "UPPER(NULLIF(BTRIM(product_rows.updates->>'barcode'), '')) AS mapped_sku, " . 'product_rows."createdAt" AS import_record_created_at ' . 'FROM material_skus ' . 'JOIN public."BarcodePrintImportRecord" product_rows ' . 'ON COALESCE(NULLIF(BTRIM(product_rows."normalizedSku"), \'\'), ' . 'NULLIF(BTRIM(product_rows."skuCode"), \'\')) = material_skus.sku_code ' . "WHERE NULLIF(BTRIM(product_rows.updates->>'barcode'), '') IS NOT NULL" . '), barcode_candidates AS (' . 'SELECT barcode_matches.material_no, barcode_matches.mapped_sku, ' . 'COALESCE(archive."createdAt", barcode_matches.import_record_created_at) ' . 'AS candidate_created_at ' . 'FROM barcode_matches ' . 'LEFT JOIN public."SupplyChainProductArchive" archive ' . 'ON UPPER(BTRIM(archive.barcode)) = barcode_matches.mapped_sku ' . '), base_sku_candidates AS (' . 'SELECT material_skus.material_no, ' . 'UPPER(BTRIM(material_skus.sku_code)) AS mapped_sku, ' . 'archive."createdAt" AS candidate_created_at ' . 'FROM material_skus ' . 'LEFT JOIN public."SupplyChainProductArchive" archive ' . 'ON UPPER(BTRIM(archive.sku::text)) = UPPER(BTRIM(material_skus.sku_code)) ' . 'WHERE NOT EXISTS (' . 'SELECT 1 FROM barcode_matches ' . 'WHERE barcode_matches.material_no = material_skus.material_no' . ')' . ') ' . 'SELECT material_no, mapped_sku, candidate_created_at ' . 'FROM barcode_candidates ' . 'UNION ' . 'SELECT material_no, mapped_sku, candidate_created_at ' . 'FROM base_sku_candidates', $chunk, ); foreach ($rows as $row) { $sourceRows++; $materialCode = self::normalizeMaterialCode((string) ($row['material_no'] ?? '')); $mappedSku = mb_strtoupper(trim((string) ($row['mapped_sku'] ?? ''))); if ($materialCode === null || $mappedSku === '') { continue; } $createdAt = trim((string) ( $row['candidate_created_at'] ?? $row['import_record_created_at'] ?? '' )); if ( ! isset($candidates[$materialCode][$mappedSku]) || $createdAt > $candidates[$materialCode][$mappedSku] ) { $candidates[$materialCode][$mappedSku] = $createdAt; } } } } catch (Throwable $exception) { throw new RuntimeException( '91 基础料号条码映射读取失败,请检查商品条码映射库只读连接:' . $exception->getMessage(), 0, $exception, ); } $candidateSkus = []; foreach ($candidates as $mappedCandidates) { foreach (array_keys($mappedCandidates) as $mappedSku) { $candidateSkus[(string) $mappedSku] = true; } } ksort($candidateSkus, SORT_STRING); try { $enabledSkus = $enabledSkuLookup(array_keys($candidateSkus)); } catch (Throwable $exception) { throw new RuntimeException( '91 基础料号普通商品状态读取失败:' . $exception->getMessage(), 0, $exception, ); } $unique = []; $ambiguous = []; $missing = []; foreach ($materialCodes as $materialCode) { $mappedCandidates = array_filter( $candidates[$materialCode] ?? [], static fn (string $createdAt, string $mappedSku): bool => isset($enabledSkus[$mappedSku]), ARRAY_FILTER_USE_BOTH, ); if ($mappedCandidates === []) { $missing[] = $materialCode; continue; } $latestCreatedAt = max(array_values($mappedCandidates)); $mappedSkus = []; foreach ($mappedCandidates as $mappedSku => $createdAt) { if ($createdAt === $latestCreatedAt) { $mappedSkus[] = (string) $mappedSku; } } sort($mappedSkus, SORT_STRING); if (count($mappedSkus) === 1) { $unique[$materialCode] = $mappedSkus[0]; } else { $ambiguous[$materialCode] = $mappedSkus; } } return [ 'unique' => $unique, 'ambiguous' => $ambiguous, 'missing' => $missing, 'source_rows' => $sourceRows, ]; } }