diff --git a/modules/EcommerceFinance/Services/AccountLedgerRemarkMap.php b/modules/EcommerceFinance/Services/AccountLedgerRemarkMap.php index b7853f5f..a84d9e25 100644 --- a/modules/EcommerceFinance/Services/AccountLedgerRemarkMap.php +++ b/modules/EcommerceFinance/Services/AccountLedgerRemarkMap.php @@ -285,8 +285,11 @@ class AccountLedgerRemarkMap if ($platform === null || $platform === '') { continue; } - if (isset($map[$platform][$item])) { - return $map[$platform][$item]; + // 先按原样匹配,再按「去掉 wx 前缀」的账单项目匹配(淘系部分行带 wx 前缀) + foreach ($this->itemLookupKeys($item) as $candidate) { + if (isset($map[$platform][$candidate])) { + return $map[$platform][$candidate]; + } } } @@ -324,27 +327,62 @@ class AccountLedgerRemarkMap /** 同平台同账单项目的「财务备注」;没有规则或财务备注为空时返回 null(由调用方回落)。 */ private function accountMappingRemark(string $platform, string $item, array $businessRemarks, string $goodsName): ?string { - $rules = $this->accountMappingIndex()[$this->normalizeKey($platform)][$this->normalizeKey($item)] ?? []; - if ($rules === []) { - return null; + $index = $this->accountMappingIndex(); + $platformKey = $this->normalizeKey($platform); + + // 先按原样匹配,再按「去掉 wx 前缀」的账单项目匹配(科目映射表里部分项目不带 wx 前缀) + foreach ($this->itemLookupKeys($item) as $candidate) { + $rules = $index[$platformKey][$this->normalizeKey($candidate)] ?? []; + if ($rules === []) { + continue; + } + + if (count($rules) === 1) { + $remark = trim((string) ($rules[0]['memo'] ?? '')); + if ($remark !== '') { + return $remark; + } + + continue; + } + + // 同一账单项目有多条规则时,用映射表自己的匹配器(按商品名称/业务备注关键词取最具体的) + try { + $result = app(AccountMappingMatcher::class)->match($platform, $candidate, $businessRemarks, $goodsName); + } catch (Throwable) { + $result = null; + } + + $remark = trim((string) ($result['rule']['memo'] ?? '')); + if ($remark !== '') { + return $remark; + } } - if (count($rules) === 1) { - $remark = trim((string) ($rules[0]['memo'] ?? '')); + return null; + } - return $remark === '' ? null : $remark; + /** + * 账单项目的查找候选:原样优先,其次去掉 wx 前缀。 + * + * 淘系同一笔费用在不同页签/导出里会出现带 wx 前缀(wx基础软件服务费)与不带前缀(基础软件服务费)两种写法, + * 按口径应当是同一个总账备注;去掉前缀后再查一次即可命中同一批规则。 + * + * @return list + */ + private function itemLookupKeys(string $item): array + { + $item = trim($item); + $keys = [$item]; + + if ($item !== '' && stripos($item, 'wx') === 0) { + $withoutPrefix = ltrim(mb_substr($item, 2)); + if ($withoutPrefix !== '') { + $keys[] = $withoutPrefix; + } } - // 同一账单项目有多条规则时,用映射表自己的匹配器(按商品名称/业务备注关键词取最具体的) - try { - $result = app(AccountMappingMatcher::class)->match($platform, $item, $businessRemarks, $goodsName); - } catch (Throwable) { - return null; - } - - $remark = trim((string) ($result['rule']['memo'] ?? '')); - - return $remark === '' ? null : $remark; + return array_values(array_unique($keys)); } private function normalizeKey(string $value): string