From 1cbc8312a6cbbfc09e97deda222de969121ea71e Mon Sep 17 00:00:00 2001 From: qiuxiang <394405259@qq.com> Date: Wed, 7 Oct 2026 15:24:58 +0800 Subject: [PATCH] =?UTF-8?q?=E5=BA=97=E9=93=BA=E6=94=B6=E6=AC=BE=E8=B4=A6?= =?UTF-8?q?=E6=88=B7=E8=B4=A6=E5=8D=95=EF=BC=9A=E6=80=BB=E8=B4=A6=E5=A4=87?= =?UTF-8?q?=E6=B3=A8=E4=BC=98=E5=85=88=E5=8F=96=E3=80=8C=E7=A7=91=E7=9B=AE?= =?UTF-8?q?=E6=98=A0=E5=B0=84=E8=A1=A8=E3=80=8D=E7=9A=84=E8=B4=A2=E5=8A=A1?= =?UTF-8?q?=E5=A4=87=E6=B3=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 账单项目在「科目映射表」里能匹到(同平台+同项目)时,总账备注取该规则的「财务备注」; 多规则时按业务备注/商品名称关键词取最具体的一条;匹不到则保留原有总账备注映射。规则按平台+项目预索引,避免逐行扫全表。 --- .../Services/AccountLedgerRemarkMap.php | 135 +++++++++++++++++- 1 file changed, 132 insertions(+), 3 deletions(-) diff --git a/modules/EcommerceFinance/Services/AccountLedgerRemarkMap.php b/modules/EcommerceFinance/Services/AccountLedgerRemarkMap.php index 2c93405c..2cecbefb 100644 --- a/modules/EcommerceFinance/Services/AccountLedgerRemarkMap.php +++ b/modules/EcommerceFinance/Services/AccountLedgerRemarkMap.php @@ -17,6 +17,9 @@ class AccountLedgerRemarkMap { public const CACHE_KEY = 'ec_account_ledger_remarks_map_v1'; + /** 「平台 + 账单项目」→ 科目映射表规则(请求内缓存,避免逐行扫描全部规则)。 */ + private ?array $accountMappingIndex = null; + /** 页签默认平台(店铺名没有平台前缀时使用)。 */ private const TAB_PLATFORM = [ 'taobao-alipay' => '淘宝', @@ -241,20 +244,44 @@ class AccountLedgerRemarkMap return $tabPlatform; } - /** 查总账备注;没有匹配返回 null。 */ - public function remark(?string $storeName, ?string $tabPlatform, ?string $billItem): ?string + /** + * 查总账备注;没有匹配返回 null。 + * + * 取值顺序: + * ①「财务规则 › 科目映射表」里同平台同账单项目的「财务备注」(匹配器按业务备注/商品名称关键词取最具体的一条) + * ② 上面没匹到时,回落到本表(账单项目 → 总账备注)原有的口径 + */ + public function remark( + ?string $storeName, + ?string $tabPlatform, + ?string $billItem, + array $businessRemarks = [], + string $goodsName = '', + ): ?string { $item = trim((string) $billItem); if ($item === '') { return null; } + $platforms = [$this->platform($storeName, $tabPlatform), $tabPlatform]; + + foreach ($platforms as $platform) { + if ($platform === null || $platform === '') { + continue; + } + $fromRule = $this->accountMappingRemark($platform, $item, $businessRemarks, $goodsName); + if ($fromRule !== null) { + return $fromRule; + } + } + $map = $this->map(); if ($map === []) { return null; } - foreach ([$this->platform($storeName, $tabPlatform), $tabPlatform] as $platform) { + foreach ($platforms as $platform) { if ($platform === null || $platform === '') { continue; } @@ -266,6 +293,59 @@ class AccountLedgerRemarkMap return null; } + /** 科目映射表按「平台 + 账单项目」预索引,避免逐行扫全部规则。 */ + private function accountMappingIndex(): array + { + if ($this->accountMappingIndex !== null) { + return $this->accountMappingIndex; + } + + $index = []; + try { + foreach (app(AccountMappingStore::class)->all() as $rule) { + if (! is_array($rule)) { + continue; + } + $platform = trim((string) ($rule['platform'] ?? '')); + $item = trim((string) ($rule['item'] ?? '')); + if ($platform === '' || $item === '') { + continue; + } + $index[$platform][$item][] = $rule; + } + } catch (Throwable) { + $index = []; + } + + return $this->accountMappingIndex = $index; + } + + /** 同平台同账单项目的「财务备注」;没有规则或财务备注为空时返回 null(由调用方回落)。 */ + private function accountMappingRemark(string $platform, string $item, array $businessRemarks, string $goodsName): ?string + { + $rules = $this->accountMappingIndex()[$platform][$item] ?? []; + if ($rules === []) { + return null; + } + + if (count($rules) === 1) { + $remark = trim((string) ($rules[0]['memo'] ?? '')); + + return $remark === '' ? null : $remark; + } + + // 同一账单项目有多条规则时,用映射表自己的匹配器(按商品名称/业务备注关键词取最具体的) + try { + $result = app(AccountMappingMatcher::class)->match($platform, $item, $businessRemarks, $goodsName); + } catch (Throwable) { + return null; + } + + $remark = trim((string) ($result['rule']['memo'] ?? '')); + + return $remark === '' ? null : $remark; + } + /** * 给一行账单补上 payload.ledger_remark(内部字段名 ledger_remark)。 * @@ -279,6 +359,8 @@ class AccountLedgerRemarkMap $row['store_name'] ?? null, $tabPlatform, $row['bill_item'] ?? null, + $this->businessRemarks($row), + $this->goodsName($row), ); if ($remark === null) { return $row; @@ -293,6 +375,53 @@ class AccountLedgerRemarkMap return $row; } + /** + * 账单上的业务备注(用于科目映射表的「业务备注关键词」条件)。 + * + * @param array $row + * @return list + */ + private function businessRemarks(array $row): array + { + $payload = is_array($row['payload'] ?? null) ? $row['payload'] : []; + + $values = [ + $row['custom_remark'] ?? null, + $row['finance_remark'] ?? null, + $payload['second_remark'] ?? null, + $payload['business_description'] ?? null, + $payload['move_summary'] ?? null, + $payload['settle_remark'] ?? null, + $payload['tx_remark'] ?? null, + $payload['cost_name'] ?? null, + ]; + + $remarks = []; + foreach ($values as $value) { + $text = trim((string) $value); + if ($text !== '') { + $remarks[] = $text; + } + } + + return $remarks; + } + + /** 商品名称(用于科目映射表的「商品名称关键词」条件)。 */ + private function goodsName(array $row): string + { + $payload = is_array($row['payload'] ?? null) ? $row['payload'] : []; + + foreach (['goods_name', 'product_name', 'goods_title'] as $key) { + $value = trim((string) ($payload[$key] ?? '')); + if ($value !== '') { + return $value; + } + } + + return ''; + } + /** * @param iterable> $rows * @return \Generator>