CaiWuXiTong/modules/EcommerceFinance/Services/AccessoryReshipMatcher.php

61 lines
2.8 KiB
PHP

<?php
namespace Modules\EcommerceFinance\Services;
/** 配件只处理第一个条码;成品逐个完整条码匹配。金额使用分,避免浮点累计。 */
class AccessoryReshipMatcher
{
public const WAREHOUSE = '常州简尚家居有限公司';
public static function barcode(string $value): string
{
$first = trim(explode(',', $value)[0]);
$position = strrpos($first, '-');
return $position === false ? $first : substr($first, 0, $position);
}
public static function cents(mixed $value): ?int
{
if (!preg_match('/^\d+(?:\.\d+)?$/', trim((string) $value))) {
return null;
}
[$whole, $decimal] = array_pad(explode('.', trim((string) $value), 2), 2, '');
return (int) $whole * 100 + (int) substr(str_pad($decimal, 2, '0'), 0, 2) + (strlen($decimal) > 2 && (int) $decimal[2] >= 5 ? 1 : 0);
}
public function match(array $accessories, iterable $originals): array
{
$index = [];
foreach ($originals as $original) {
if (trim((string) ($original['warehouse_name'] ?? '')) === self::WAREHOUSE || trim((string) ($original['express_no'] ?? '')) === '') continue;
$trade = trim((string) ($original['trade_no'] ?? ''));
if ($trade === '') continue;
foreach (explode(',', (string) ($original['barcode'] ?? '')) as $barcode) {
$barcode = trim($barcode);
if ($barcode === '') continue;
$key = json_encode([$trade, $barcode]);
$identity = json_encode([$original['express_no'], $original['express_name1'] ?? '', substr((string) $original['ship_time'], 0, 7)]);
$index[$key][$identity] = [
'express_no' => $original['express_no'],
'courier' => ($original['express_name1'] ?? '') ?: ($original['express_name2'] ?? ''),
'month' => substr((string) $original['ship_time'], 0, 7),
];
}
}
$result = [];
foreach ($accessories as $row) {
$barcode = self::barcode((string) ($row['barcode'] ?? ''));
$trade = trim((string) ($row['trade_no'] ?? ''));
$matches = ($barcode !== '' && $trade !== '') ? array_values($index[json_encode([$trade, $barcode])] ?? []) : [];
$row['normalized_barcode'] = $barcode;
$row['matches'] = $matches;
$row['status'] = $matches === [] ? 'unmatched' : 'matched';
$row['freight_cents'] = self::cents($row['freight'] ?? null);
// 多候选仍属于可扣款;保持一条补发记录,运费不随候选数量放大。
$row['deduction_cents'] = $matches === [] ? 0 : $row['freight_cents'];
$result[] = $row;
}
return $result;
}
}