fix: fix bug in rebalanace, stale session values being read
This commit is contained in:
6
.env
6
.env
@@ -31,9 +31,9 @@ EMAIL_FROM="SkyMoney Budget <no-reply@skymoneybudget.com>"
|
||||
EMAIL_BOUNCE_FROM=bounces@skymoneybudget.com
|
||||
EMAIL_REPLY_TO=support@skymoneybudget.com
|
||||
|
||||
UPDATE_NOTICE_VERSION=8
|
||||
UPDATE_NOTICE_TITLE="Rebalance tools and onboarding fixes"
|
||||
UPDATE_NOTICE_BODY="This release adds a dedicated Rebalance page for variable budgets with apply-time safeguard confirmations, plus onboarding fixed-expense submission and money input improvements."
|
||||
UPDATE_NOTICE_VERSION=9
|
||||
UPDATE_NOTICE_TITLE="Rebalance tool bug correction"
|
||||
UPDATE_NOTICE_BODY="Fixed bug issue where available budget value is stale in user sessions and wont read updated value properly."
|
||||
ALLOW_INSECURE_AUTH_FOR_DEV=false
|
||||
JWT_ISSUER=skymoney-api
|
||||
JWT_AUDIENCE=skymoney-web
|
||||
|
||||
@@ -3417,6 +3417,20 @@ async function ensureBudgetSession(app: any, userId: string, fallbackAvailableCe
|
||||
});
|
||||
}
|
||||
|
||||
async function ensureBudgetSessionAvailableSynced(
|
||||
app: any,
|
||||
userId: string,
|
||||
availableCents: number
|
||||
) {
|
||||
const normalizedAvailableCents = BigInt(Math.max(0, Math.trunc(availableCents)));
|
||||
const session = await ensureBudgetSession(app, userId, Number(normalizedAvailableCents));
|
||||
if ((session.availableCents ?? 0n) === normalizedAvailableCents) return session;
|
||||
return app.prisma.budgetSession.update({
|
||||
where: { id: session.id },
|
||||
data: { availableCents: normalizedAvailableCents },
|
||||
});
|
||||
}
|
||||
|
||||
app.post("/variable-categories", mutationRateLimit, async (req, reply) => {
|
||||
const parsed = CatBody.safeParse(req.body);
|
||||
if (!parsed.success) {
|
||||
@@ -3555,11 +3569,11 @@ app.get("/variable-categories/manual-rebalance", async (req, reply) => {
|
||||
select: { id: true, name: true, percent: true, isSavings: true, balanceCents: true },
|
||||
});
|
||||
const totalBalance = cats.reduce((s, c) => s + Number(c.balanceCents ?? 0n), 0);
|
||||
const session = await ensureBudgetSession(app, userId, totalBalance);
|
||||
await ensureBudgetSessionAvailableSynced(app, userId, totalBalance);
|
||||
|
||||
return reply.send({
|
||||
ok: true,
|
||||
availableCents: Number(session.availableCents ?? 0n),
|
||||
availableCents: totalBalance,
|
||||
categories: cats.map((c) => ({ ...c, balanceCents: Number(c.balanceCents ?? 0n) })),
|
||||
});
|
||||
});
|
||||
@@ -3579,8 +3593,8 @@ app.post("/variable-categories/manual-rebalance", async (req, reply) => {
|
||||
if (cats.length === 0) return reply.code(400).send({ ok: false, code: "NO_CATEGORIES" });
|
||||
|
||||
const totalBalance = cats.reduce((s, c) => s + Number(c.balanceCents ?? 0n), 0);
|
||||
const session = await ensureBudgetSession(app, userId, totalBalance);
|
||||
const availableCents = Number(session.availableCents ?? 0n);
|
||||
const availableCents = totalBalance;
|
||||
await ensureBudgetSessionAvailableSynced(app, userId, availableCents);
|
||||
|
||||
const targetMap = new Map<string, number>();
|
||||
for (const t of parsed.data.targets) {
|
||||
|
||||
@@ -44,6 +44,37 @@ describe("manual rebalance", () => {
|
||||
await seedBasics();
|
||||
});
|
||||
|
||||
it("uses live category balances when session availableCents is stale", async () => {
|
||||
await prisma.budgetSession.updateMany({
|
||||
where: { userId: U },
|
||||
data: { availableCents: 1234n },
|
||||
});
|
||||
|
||||
const getRes = await request(app.server)
|
||||
.get("/variable-categories/manual-rebalance")
|
||||
.set("x-user-id", U);
|
||||
|
||||
expect(getRes.statusCode).toBe(200);
|
||||
expect(getRes.body?.availableCents).toBe(10_000);
|
||||
|
||||
const cats = await prisma.variableCategory.findMany({ where: { userId: U }, orderBy: { priority: "asc" } });
|
||||
const targets = cats.map((c) => ({ id: c.id, targetCents: 2500 })); // 4 * 2500 = 10000
|
||||
const postRes = await request(app.server)
|
||||
.post("/variable-categories/manual-rebalance")
|
||||
.set("x-user-id", U)
|
||||
.send({ targets });
|
||||
|
||||
expect(postRes.statusCode).toBe(200);
|
||||
expect(postRes.body?.availableCents).toBe(10_000);
|
||||
|
||||
const session = await prisma.budgetSession.findFirst({
|
||||
where: { userId: U },
|
||||
orderBy: { periodStart: "desc" },
|
||||
select: { availableCents: true },
|
||||
});
|
||||
expect(Number(session?.availableCents ?? 0n)).toBe(10_000);
|
||||
});
|
||||
|
||||
it("rebalances when sums match available", async () => {
|
||||
const cats = await prisma.variableCategory.findMany({ where: { userId: U }, orderBy: { priority: "asc" } });
|
||||
const targets = cats.map((c) => ({ id: c.id, targetCents: 2500 })); // 4 * 2500 = 10000
|
||||
|
||||
Reference in New Issue
Block a user