Files
chronus/src/pages/api/invoices/[id]/status.ts
Atridad Lahiji 12d59bb42f
All checks were successful
Docker Deploy / build-and-push (push) Successful in 3m57s
Refactored a bunch of shit
2026-02-09 01:49:19 -07:00

82 lines
1.9 KiB
TypeScript

import type { APIRoute } from "astro";
import { db } from "../../../../db";
import { invoices, members } from "../../../../db/schema";
import { eq, and } from "drizzle-orm";
export const POST: APIRoute = async ({
request,
redirect,
locals,
params,
}) => {
const user = locals.user;
if (!user) {
return redirect("/login");
}
const { id: invoiceId } = params;
if (!invoiceId) {
return new Response("Invoice ID required", { status: 400 });
}
const formData = await request.formData();
const status = formData.get("status") as string;
const validStatuses = [
"draft",
"sent",
"paid",
"void",
"accepted",
"declined",
];
if (!status || !validStatuses.includes(status)) {
return new Response("Invalid status", { status: 400 });
}
const invoice = await db
.select()
.from(invoices)
.where(eq(invoices.id, invoiceId))
.get();
if (!invoice) {
return new Response("Invoice not found", { status: 404 });
}
const membership = await db
.select()
.from(members)
.where(
and(
eq(members.userId, user.id),
eq(members.organizationId, invoice.organizationId)
)
)
.get();
if (!membership) {
return new Response("Unauthorized", { status: 401 });
}
// Destructive status changes require owner/admin
const destructiveStatuses = ["void"];
const isAdminOrOwner = membership.role === "owner" || membership.role === "admin";
if (destructiveStatuses.includes(status) && !isAdminOrOwner) {
return new Response("Only owners and admins can void invoices", { status: 403 });
}
try {
await db
.update(invoices)
.set({ status: status as any })
.where(eq(invoices.id, invoiceId));
return redirect(`/dashboard/invoices/${invoiceId}`);
} catch (error) {
console.error("Error updating invoice status:", error);
return new Response("Internal Server Error", { status: 500 });
}
};