feat: add billing and organization workflows

This commit is contained in:
2026-06-24 13:53:52 +01:00
parent 4fd81c923b
commit 44bfb083f9
97 changed files with 10966 additions and 2044 deletions
@@ -5,7 +5,7 @@ import { db } from '$lib/server/db';
import { invoices, clients } from '$lib/server/db/schema';
import { loadOrganizationContext } from '$lib/server/organizations';
import { archiveSchema } from '$lib/schemas/shared.schema';
import { invoiceCreateSchema, invoiceEditSchema } from '$lib/schemas/invoices.schema';
import { invoiceEditSchema } from '$lib/schemas/invoices.schema';
import type { Actions, PageServerLoad } from './$types';
async function loadOptions(organizationId: string) {
@@ -51,48 +51,18 @@ export const load: PageServerLoad = async ({ locals, params }) => {
}
})),
options: await loadOptions(activeOrganizationId),
createForm: await superValidate({ clientId: params.id }, zod4(invoiceCreateSchema), {
id: 'invoices-create'
editForm: await superValidate(zod4(invoiceEditSchema), {
id: 'invoices-edit',
errors: false
}),
editForm: await superValidate(zod4(invoiceEditSchema), { id: 'invoices-edit' }),
archiveForm: await superValidate(zod4(archiveSchema), { id: 'invoices-archive' })
archiveForm: await superValidate(zod4(archiveSchema), {
id: 'invoices-archive',
errors: false
})
};
};
export const actions: Actions = {
create: async ({ locals, params, request }) => {
const { activeOrganizationId } = await loadOrganizationContext(locals);
const formData = await request.formData();
formData.set('clientId', params.id);
const form = await superValidate(formData, zod4(invoiceCreateSchema), {
id: 'invoices-create'
});
if (!form.valid) return message(form, 'Check the highlighted fields.', { status: 400 });
try {
await db.insert(invoices).values({
id: crypto.randomUUID(),
organizationId: activeOrganizationId,
clientId: form.data.clientId,
invoiceNumber: form.data.invoiceNumber,
issueDate: form.data.issueDate,
dueDate: form.data.dueDate,
status: form.data.status,
subtotalGbp: form.data.subtotalGbp,
taxGbp: form.data.taxGbp,
totalGbp: form.data.totalGbp,
notes: form.data.notes || null,
updatedAt: new Date(),
createdAt: new Date()
});
} catch {
return message(form, 'Unable to create invoice.', { status: 400 });
}
return message(form, 'Invoice created.');
},
edit: async ({ locals, params, request }) => {
const { activeOrganizationId } = await loadOrganizationContext(locals);
const formData = await request.formData();