Some checks failed
Docker Deploy / build-and-push (push) Has been cancelled
63 lines
1.6 KiB
TypeScript
63 lines
1.6 KiB
TypeScript
import { db } from "../db";
|
|
import { invoices, invoiceItems } from "../db/schema";
|
|
import { eq } from "drizzle-orm";
|
|
|
|
/**
|
|
* Recalculates the subtotal, tax amount, and total for a specific invoice
|
|
* based on its items and tax rate.
|
|
*/
|
|
export async function recalculateInvoiceTotals(invoiceId: string) {
|
|
// Fetch invoice to get tax rate
|
|
const invoice = await db
|
|
.select()
|
|
.from(invoices)
|
|
.where(eq(invoices.id, invoiceId))
|
|
.get();
|
|
|
|
if (!invoice) return;
|
|
|
|
// Fetch all items
|
|
const items = await db
|
|
.select()
|
|
.from(invoiceItems)
|
|
.where(eq(invoiceItems.invoiceId, invoiceId))
|
|
.all();
|
|
|
|
// Calculate totals
|
|
// Note: amounts are in cents
|
|
const subtotal = items.reduce((acc, item) => acc + item.amount, 0);
|
|
|
|
// Calculate discount
|
|
const discountType = invoice.discountType || "percentage";
|
|
const discountValue = invoice.discountValue || 0;
|
|
let discountAmount = 0;
|
|
|
|
if (discountType === "percentage") {
|
|
discountAmount = Math.round(subtotal * (discountValue / 100));
|
|
} else {
|
|
// Fixed amount is assumed to be in cents
|
|
discountAmount = Math.round(discountValue);
|
|
}
|
|
|
|
// Ensure discount doesn't exceed subtotal
|
|
discountAmount = Math.max(0, Math.min(discountAmount, subtotal));
|
|
|
|
const taxableAmount = subtotal - discountAmount;
|
|
|
|
const taxRate = invoice.taxRate || 0;
|
|
const taxAmount = Math.round(taxableAmount * (taxRate / 100));
|
|
|
|
const total = taxableAmount + taxAmount;
|
|
|
|
// Update invoice
|
|
await db
|
|
.update(invoices)
|
|
.set({
|
|
subtotal,
|
|
discountAmount,
|
|
taxAmount,
|
|
total,
|
|
})
|
|
.where(eq(invoices.id, invoiceId));
|
|
}
|