75 lines
2.2 KiB
TypeScript
75 lines
2.2 KiB
TypeScript
import { and, eq } from 'drizzle-orm';
|
|
import { useDb } from '~~/server/database/client';
|
|
import { expenseParticipants, expenses } from '~~/server/database/schema';
|
|
|
|
export default defineEventHandler(async (event) => {
|
|
const slug = getRouterParam(event, 'slug')!;
|
|
const id = Number(getRouterParam(event, 'id'));
|
|
await getPotOrThrow(slug);
|
|
|
|
const body = await readBody(event);
|
|
const description =
|
|
typeof body?.description === 'string' ? body.description.trim() : '';
|
|
const amountCents = Number(body?.amountCents);
|
|
const payerId = Number(body?.payerId);
|
|
const participantIds: number[] = Array.isArray(body?.participantIds)
|
|
? body.participantIds.map(Number)
|
|
: [];
|
|
|
|
if (!description) {
|
|
throw createError({
|
|
statusCode: 400,
|
|
statusMessage: 'description is required',
|
|
});
|
|
}
|
|
if (!Number.isInteger(amountCents) || amountCents <= 0) {
|
|
throw createError({
|
|
statusCode: 400,
|
|
statusMessage: 'amountCents must be a positive integer',
|
|
});
|
|
}
|
|
if (participantIds.length === 0) {
|
|
throw createError({
|
|
statusCode: 400,
|
|
statusMessage: 'at least one participant must be selected',
|
|
});
|
|
}
|
|
|
|
const potParticipants = await getParticipants(slug);
|
|
const validIds = new Set(potParticipants.map((p) => p.id));
|
|
if (
|
|
!validIds.has(payerId) ||
|
|
participantIds.some((pid) => !validIds.has(pid))
|
|
) {
|
|
throw createError({
|
|
statusCode: 400,
|
|
statusMessage:
|
|
'payerId and participantIds must reference participants of this Pot',
|
|
});
|
|
}
|
|
|
|
const db = useDb(event);
|
|
const [existing] = await db
|
|
.select()
|
|
.from(expenses)
|
|
.where(and(eq(expenses.id, id), eq(expenses.potSlug, slug)));
|
|
if (!existing) {
|
|
throw createError({ statusCode: 404, statusMessage: 'Expense not found' });
|
|
}
|
|
|
|
await db
|
|
.update(expenses)
|
|
.set({ description, amountCents, payerId })
|
|
.where(eq(expenses.id, id));
|
|
await db
|
|
.delete(expenseParticipants)
|
|
.where(eq(expenseParticipants.expenseId, id));
|
|
await db
|
|
.insert(expenseParticipants)
|
|
.values(
|
|
participantIds.map((participantId) => ({ expenseId: id, participantId })),
|
|
);
|
|
|
|
return { id, description, amountCents, payerId, participantIds };
|
|
});
|