138 lines
5.3 KiB
PHP
138 lines
5.3 KiB
PHP
<?php
|
|
|
|
namespace Modules\EcommerceFinance\Repositories;
|
|
|
|
use Modules\EcommerceFinance\Services\UpstreamReadOnlyQuery;
|
|
use RuntimeException;
|
|
use Throwable;
|
|
|
|
/**
|
|
* 商品成本使用的基础料号 → 内部商品编码映射。
|
|
*
|
|
* 只读取条码打印导入记录的固定字段;数据库账号和连接参数由系统设置中的
|
|
* product_barcode_catalog 来源提供,不进入仓库或业务数据。
|
|
*/
|
|
class ProductMaterialBarcodeMappingRepository
|
|
{
|
|
public const SOURCE_KEY = 'product_barcode_catalog';
|
|
|
|
/**
|
|
* 「91.C数字.数字」是条码映射库里的基础料号,后面的规格尾缀不参与查询。
|
|
*/
|
|
public static function normalizeMaterialCode(string $code): ?string
|
|
{
|
|
$code = mb_strtoupper(trim($code));
|
|
if (preg_match('/^(91\.C\d+\.\d+)(?:-.*)?$/i', $code, $matches) !== 1) {
|
|
return null;
|
|
}
|
|
|
|
return $matches[1];
|
|
}
|
|
|
|
/**
|
|
* @param list<string> $materialCodes
|
|
* @return array{
|
|
* unique:array<string,string>,
|
|
* ambiguous:array<string,list<string>>,
|
|
* missing:list<string>,
|
|
* source_rows:int
|
|
* }
|
|
*/
|
|
public function resolve(array $materialCodes, ?UpstreamReadOnlyQuery $query = 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);
|
|
$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 '
|
|
. "TRIM(updates->>'materialNo') AS material_no, "
|
|
. 'COALESCE(NULLIF(BTRIM("normalizedSku"), \'\'), NULLIF(BTRIM("skuCode"), \'\')) AS sku_code '
|
|
. 'FROM public."BarcodePrintImportRecord" '
|
|
. "WHERE TRIM(updates->>'materialNo') IN ({$placeholders}) "
|
|
. 'AND COALESCE(NULLIF(BTRIM("normalizedSku"), \'\'), NULLIF(BTRIM("skuCode"), \'\')) IS NOT NULL'
|
|
. '), barcode_matches AS ('
|
|
. 'SELECT DISTINCT material_skus.material_no, '
|
|
. "NULLIF(BTRIM(product_rows.updates->>'barcode'), '') AS barcode "
|
|
. '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"
|
|
. ') '
|
|
. 'SELECT barcode_matches.material_no, barcode_matches.barcode AS mapped_sku '
|
|
. 'FROM barcode_matches '
|
|
. 'UNION '
|
|
. 'SELECT material_skus.material_no, material_skus.sku_code '
|
|
. 'FROM material_skus '
|
|
. 'WHERE NOT EXISTS ('
|
|
. 'SELECT 1 FROM barcode_matches '
|
|
. 'WHERE barcode_matches.material_no = material_skus.material_no'
|
|
. ')',
|
|
$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;
|
|
}
|
|
$candidates[$materialCode][$mappedSku] = true;
|
|
}
|
|
}
|
|
} catch (Throwable $exception) {
|
|
throw new RuntimeException(
|
|
'91 基础料号条码映射读取失败,请检查商品条码映射库只读连接:' . $exception->getMessage(),
|
|
0,
|
|
$exception,
|
|
);
|
|
}
|
|
|
|
$unique = [];
|
|
$ambiguous = [];
|
|
$missing = [];
|
|
foreach ($materialCodes as $materialCode) {
|
|
$mappedSkus = array_keys($candidates[$materialCode] ?? []);
|
|
sort($mappedSkus, SORT_STRING);
|
|
if (count($mappedSkus) === 1) {
|
|
$unique[$materialCode] = $mappedSkus[0];
|
|
} elseif (count($mappedSkus) > 1) {
|
|
$ambiguous[$materialCode] = $mappedSkus;
|
|
} else {
|
|
$missing[] = $materialCode;
|
|
}
|
|
}
|
|
|
|
return [
|
|
'unique' => $unique,
|
|
'ambiguous' => $ambiguous,
|
|
'missing' => $missing,
|
|
'source_rows' => $sourceRows,
|
|
];
|
|
}
|
|
}
|