61 lines
2.8 KiB
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;
|
|
}
|
|
}
|