Convert per-project spent to base currency via account FX rate
Both the overview and budget page queries now multiply each approved expense amount by its account's fxRateToBase before summing. A -$434 USD expense on a USD account (rate 34.5) now contributes -14,973 THB to the total, not -434. Expenses with no account fall back to rate 1. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,23 +1,30 @@
|
|||||||
import type { PageServerLoad } from './$types';
|
import type { PageServerLoad } from './$types';
|
||||||
import { db } from '$lib/server/db/index.js';
|
import { db } from '$lib/server/db/index.js';
|
||||||
import { projects, expenses, sales, saleLineItems } from '$lib/server/db/schema.js';
|
import {
|
||||||
|
projects,
|
||||||
|
expenses,
|
||||||
|
sales,
|
||||||
|
saleLineItems,
|
||||||
|
companyAccounts
|
||||||
|
} from '$lib/server/db/schema.js';
|
||||||
import { eq, and, sql } from 'drizzle-orm';
|
import { eq, and, sql } from 'drizzle-orm';
|
||||||
|
|
||||||
export const load: PageServerLoad = async ({ parent }) => {
|
export const load: PageServerLoad = async ({ parent }) => {
|
||||||
const { company } = await parent();
|
const { company } = await parent();
|
||||||
|
|
||||||
// Get projects with spent amounts
|
// Get projects with spent amounts (converted to base currency via each expense's account fx rate)
|
||||||
const projectList = await db
|
const projectList = await db
|
||||||
.select({
|
.select({
|
||||||
id: projects.id,
|
id: projects.id,
|
||||||
name: projects.name,
|
name: projects.name,
|
||||||
allocatedBudget: projects.allocatedBudget,
|
allocatedBudget: projects.allocatedBudget,
|
||||||
isActive: projects.isActive,
|
isActive: projects.isActive,
|
||||||
spent: sql<string>`coalesce(sum(case when ${expenses.status} = 'approved' then ${expenses.amount} else 0 end), 0)`,
|
spent: sql<string>`coalesce(sum(case when ${expenses.status} = 'approved' then ${expenses.amount} * coalesce(${companyAccounts.fxRateToBase}, 1) else 0 end), 0)::text`,
|
||||||
pendingCount: sql<number>`count(case when ${expenses.status} = 'pending' then 1 end)::int`
|
pendingCount: sql<number>`count(case when ${expenses.status} = 'pending' then 1 end)::int`
|
||||||
})
|
})
|
||||||
.from(projects)
|
.from(projects)
|
||||||
.leftJoin(expenses, eq(expenses.projectId, projects.id))
|
.leftJoin(expenses, eq(expenses.projectId, projects.id))
|
||||||
|
.leftJoin(companyAccounts, eq(expenses.accountId, companyAccounts.id))
|
||||||
.where(eq(projects.companyId, company.id))
|
.where(eq(projects.companyId, company.id))
|
||||||
.groupBy(projects.id)
|
.groupBy(projects.id)
|
||||||
.orderBy(projects.name);
|
.orderBy(projects.name);
|
||||||
|
|||||||
@@ -9,7 +9,8 @@ import {
|
|||||||
expenses,
|
expenses,
|
||||||
companyLog,
|
companyLog,
|
||||||
sales,
|
sales,
|
||||||
saleLineItems
|
saleLineItems,
|
||||||
|
companyAccounts
|
||||||
} from '$lib/server/db/schema.js';
|
} from '$lib/server/db/schema.js';
|
||||||
import { and, eq, sql } from 'drizzle-orm';
|
import { and, eq, sql } from 'drizzle-orm';
|
||||||
import { requireCompanyRole } from '$lib/server/authorization.js';
|
import { requireCompanyRole } from '$lib/server/authorization.js';
|
||||||
@@ -24,10 +25,11 @@ export const load: PageServerLoad = async ({ parent, params }) => {
|
|||||||
id: projects.id,
|
id: projects.id,
|
||||||
name: projects.name,
|
name: projects.name,
|
||||||
allocatedBudget: projects.allocatedBudget,
|
allocatedBudget: projects.allocatedBudget,
|
||||||
spent: sql<string>`coalesce(sum(case when ${expenses.status} = 'approved' then ${expenses.amount} else 0 end), 0)`
|
spent: sql<string>`coalesce(sum(case when ${expenses.status} = 'approved' then ${expenses.amount} * coalesce(${companyAccounts.fxRateToBase}, 1) else 0 end), 0)::text`
|
||||||
})
|
})
|
||||||
.from(projects)
|
.from(projects)
|
||||||
.leftJoin(expenses, eq(expenses.projectId, projects.id))
|
.leftJoin(expenses, eq(expenses.projectId, projects.id))
|
||||||
|
.leftJoin(companyAccounts, eq(expenses.accountId, companyAccounts.id))
|
||||||
.where(eq(projects.companyId, params.companyId))
|
.where(eq(projects.companyId, params.companyId))
|
||||||
.groupBy(projects.id)
|
.groupBy(projects.id)
|
||||||
.orderBy(projects.name);
|
.orderBy(projects.name);
|
||||||
|
|||||||
Reference in New Issue
Block a user