71 lines
1.8 KiB
TypeScript
71 lines
1.8 KiB
TypeScript
import type { Prisma, PrismaClient } from "@prisma/client";
|
|
|
|
type BudgetSessionAccessor =
|
|
| Pick<PrismaClient, "budgetSession">
|
|
| Pick<Prisma.TransactionClient, "budgetSession">;
|
|
|
|
function normalizeAvailableCents(value: number): bigint {
|
|
if (!Number.isFinite(value)) return 0n;
|
|
return BigInt(Math.max(0, Math.trunc(value)));
|
|
}
|
|
|
|
export async function getLatestBudgetSession(
|
|
db: BudgetSessionAccessor,
|
|
userId: string
|
|
) {
|
|
return db.budgetSession.findFirst({
|
|
where: { userId },
|
|
orderBy: { periodStart: "desc" },
|
|
});
|
|
}
|
|
|
|
export async function ensureBudgetSession(
|
|
db: BudgetSessionAccessor,
|
|
userId: string,
|
|
fallbackAvailableCents = 0,
|
|
now = new Date()
|
|
) {
|
|
const existing = await getLatestBudgetSession(db, userId);
|
|
if (existing) return existing;
|
|
|
|
const start = new Date(
|
|
Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), 1, 0, 0, 0, 0)
|
|
);
|
|
const end = new Date(
|
|
Date.UTC(now.getUTCFullYear(), now.getUTCMonth() + 1, 1, 0, 0, 0, 0)
|
|
);
|
|
const normalizedAvailable = normalizeAvailableCents(fallbackAvailableCents);
|
|
|
|
return db.budgetSession.create({
|
|
data: {
|
|
userId,
|
|
periodStart: start,
|
|
periodEnd: end,
|
|
totalBudgetCents: normalizedAvailable,
|
|
allocatedCents: 0n,
|
|
fundedCents: 0n,
|
|
availableCents: normalizedAvailable,
|
|
},
|
|
});
|
|
}
|
|
|
|
export async function ensureBudgetSessionAvailableSynced(
|
|
db: BudgetSessionAccessor,
|
|
userId: string,
|
|
availableCents: number
|
|
) {
|
|
const normalizedAvailable = normalizeAvailableCents(availableCents);
|
|
const session = await ensureBudgetSession(
|
|
db,
|
|
userId,
|
|
Number(normalizedAvailable)
|
|
);
|
|
|
|
if ((session.availableCents ?? 0n) === normalizedAvailable) return session;
|
|
|
|
return db.budgetSession.update({
|
|
where: { id: session.id },
|
|
data: { availableCents: normalizedAvailable },
|
|
});
|
|
}
|