账单明细:财务备注/财务类型筛选按平台限定,修同项目跨平台串行(优惠收入带出冲减收入)

This commit is contained in:
yueyang 2026-10-09 10:36:27 +08:00
parent a0faaa116b
commit cfdda94da8

View File

@ -737,22 +737,10 @@ class BillingDetailsPageData
$conditions[] = '(' . implode(' OR ', $haystack) . ')';
}
if ($filters['type'] !== []) {
$allowed = $this->itemsForTypes($filters['type']);
if ($allowed === []) {
$conditions[] = '1 = 0';
} else {
// 与页面带出财务备注/类型时一致:wx 前缀的账单项目按去前缀后的名称归类。
// 项目名以字面量内联:MySQL 对字面量 IN 列表会排序后二分查找,
// 参数化 IN 会逐行线性比对,161 个项目 × 130 万行会退化到 30 秒以上。
$conditions[] = $this->normalizedItemSql() . ' IN (' . $this->literals($allowed) . ')';
}
$conditions[] = $this->platformItemCondition('category', $filters['type'], $label);
}
if (($filters['remark'] ?? []) !== []) {
// 财务备注筛选:与财务类型同一口径,先落回「账单项目」集合再下推 SQL。
$allowed = $this->itemsForRemarks($filters['remark']);
$conditions[] = $allowed === []
? '1 = 0'
: $this->normalizedItemSql() . ' IN (' . $this->literals($allowed) . ')';
$conditions[] = $this->platformItemCondition('memo', $filters['remark'], $label);
}
$dateBind = $dateCol === 'bill_date'
@ -902,6 +890,57 @@ class BillingDetailsPageData
return "(CASE WHEN bill_item LIKE 'wx%' THEN LTRIM(SUBSTRING(bill_item, 3)) ELSE bill_item END)";
}
/**
* 「财务类型 / 财务备注」→ 按平台限定的 SQL 条件。
*
* 同一账单项目在不同平台可能挂不同的财务备注/类型,只按项目名过滤会把其它平台的同名项目一起带出来,
* 所以这里再按店铺前缀限定平台;项目名仍以字面量内联,避免参数化 IN 在千万行上退化成线性比对。
*
* @param string $field category(财务类型)或 memo(财务备注)
* @param list<string> $values
*/
private function platformItemCondition(string $field, array $values, string $branchLabel): string
{
$wanted = array_flip($values);
$byPlatform = [];
foreach ($this->rules() as $key => $rule) {
$value = (string) ($rule[$field] ?? '');
if ($value === '' || ! isset($wanted[$value])) {
continue;
}
[$platform, $item] = array_pad(explode('|', $key, 2), 2, '');
if ($platform === '' || $item === '') {
continue;
}
$byPlatform[$platform][$item] = true;
}
$branchPlatforms = self::BRANCH_PLATFORMS[$branchLabel] ?? [];
$parts = [];
foreach ($byPlatform as $platform => $items) {
if ($branchPlatforms !== [] && ! in_array($platform, $branchPlatforms, true)) {
continue;
}
$parts[] = '(' . $this->storePrefixCondition($platform) . ' AND '
. $this->normalizedItemSql() . ' IN (' . $this->literals(array_keys($items)) . '))';
}
return $parts === [] ? '1 = 0' : '(' . implode(' OR ', $parts) . ')';
}
/** 科目映射表平台 → 对应的店铺名前缀条件(阿里巴巴含新佰广1688 / 淘工厂等)。 */
private function storePrefixCondition(string $platform): string
{
$parts = [];
foreach (self::PLATFORM_PREFIX as $prefix => $mapped) {
if ($mapped === $platform) {
$parts[] = 'store_name LIKE ' . $this->likeLiteral($prefix);
}
}
return $parts === [] ? '1 = 1' : '(' . implode(' OR ', $parts) . ')';
}
/**
* 取与查询区间有交集的账期的 active_generation(与 JD / 抖音账单页仓储同一口径)。
*