fix(ledger): 补全 getEffectivePrice 复合查询条件,修复历史价格跨资产串联 Bug

This commit is contained in:
kennethcheng 2026-04-30 13:42:51 +08:00
parent 91e7485259
commit b131400aa9
2 changed files with 13 additions and 4 deletions

View File

@ -168,3 +168,8 @@
- 修复 `reconstructPortfolioHistory` 主循环while 条件与 `dateStr` 生成均改用 `formatDateString(currentDate)`,确保与 `getTodayInShanghai()` 返回格式完全一致。 - 修复 `reconstructPortfolioHistory` 主循环while 条件与 `dateStr` 生成均改用 `formatDateString(currentDate)`,确保与 `getTodayInShanghai()` 返回格式完全一致。
- 在资产遍历循环中增加兜底防御逻辑:当 `getEffectivePrice` 返回 null 时,使用 `assetLatestPriceMap` 中缓存的 `latestPrice` 作为兜底价格,避免价格变量为 undefined 或沿用上一资产的值;同时修正了 `totalCostCny``priceStr` 为空时不应累加的 Bug。 - 在资产遍历循环中增加兜底防御逻辑:当 `getEffectivePrice` 返回 null 时,使用 `assetLatestPriceMap` 中缓存的 `latestPrice` 作为兜底价格,避免价格变量为 undefined 或沿用上一资产的值;同时修正了 `totalCostCny``priceStr` 为空时不应累加的 Bug。
- 在 `allAssets` 查询中新增 `latestPrice` 字段,构建 `assetLatestPriceMap` 供兜底逻辑使用。 - 在 `allAssets` 查询中新增 `latestPrice` 字段,构建 `assetLatestPriceMap` 供兜底逻辑使用。
## 修复 getEffectivePrice 引擎中 Drizzle ORM 缺失 and(eq(assetId)) 的致命逻辑漏网
- 修复 `getEffectivePrice` 引擎中 Drizzle ORM 查询条件未使用 `and()` 复合操作符的致命逻辑漏网,确保历史断点结转价格精准匹配单一资产。
- 在 `src/actions/snapshots.ts` 顶部从 `drizzle-orm` 引入 `and` 操作符,将 `getEffectivePrice``where` 子句从两个独立的 `.where()` 链式调用重构为 `and(eq(assetPricesHistory.assetId, assetId), lte(assetPricesHistory.date, dateStr))` 的显式复合条件。
- 修复后 `assetId` 条件与日期条件被绝对锁定在同一个 `AND` 逻辑块中,彻底杜绝了周末等非交易日历史节点价格跨资产串联的荒谬市值问题(如海尔被错误匹配 BTC 价格导致 3700 万市值)。

View File

@ -3,7 +3,7 @@
import { db } from '@/db'; import { db } from '@/db';
import { portfolioSnapshots, transactions, assetPricesHistory, assets, exchangeRates } from '@/db/schema'; import { portfolioSnapshots, transactions, assetPricesHistory, assets, exchangeRates } from '@/db/schema';
import { getPortfolioPositions } from './portfolio'; import { getPortfolioPositions } from './portfolio';
import { asc, desc, eq, gte, lte, sql } from 'drizzle-orm'; import { and, asc, desc, eq, gte, lte, sql } from 'drizzle-orm';
import Big from 'big.js'; import Big from 'big.js';
function formatDateString(date: Date): string { function formatDateString(date: Date): string {
@ -194,8 +194,12 @@ export async function getEffectivePrice(
price: assetPricesHistory.price, price: assetPricesHistory.price,
}) })
.from(assetPricesHistory) .from(assetPricesHistory)
.where(eq(assetPricesHistory.assetId, assetId)) .where(
.where(lte(assetPricesHistory.date, dateStr)) and(
eq(assetPricesHistory.assetId, assetId),
lte(assetPricesHistory.date, dateStr)
)
)
.orderBy(desc(assetPricesHistory.date)) .orderBy(desc(assetPricesHistory.date))
.limit(1); .limit(1);