Changes
Co-authored-by: renee-png <262607627+renee-png@users.noreply.github.com>
This commit is contained in:
co-authored by
renee-png
parent
a583e788ba
commit
6fa8e0fb63
@@ -41,6 +41,7 @@ export function GenerateInvoiceDialog({ open, onOpenChange, clientId, clientName
|
||||
const [taxPct, setTaxPct] = useState("0");
|
||||
const [dueDays, setDueDays] = useState("30");
|
||||
const [notes, setNotes] = useState("");
|
||||
const [isRetainer, setIsRetainer] = useState(false);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [saving, setSaving] = useState(false);
|
||||
|
||||
@@ -104,9 +105,53 @@ export function GenerateInvoiceDialog({ open, onOpenChange, clientId, clientName
|
||||
|
||||
const submit = async () => {
|
||||
if (!user?.id) return;
|
||||
if (selectedIds.length === 0) return toast.error("Select at least one case");
|
||||
if (selectedIds.length === 0 && !isRetainer) return toast.error("Select at least one case");
|
||||
setSaving(true);
|
||||
try {
|
||||
if (isRetainer) {
|
||||
// Retainer invoices have no time/expenses — create a single line item for the deposit.
|
||||
const yr = new Date().getFullYear();
|
||||
const num = `INV-${yr}-${Math.floor(1000 + Math.random() * 9000)}`;
|
||||
const due = new Date();
|
||||
due.setDate(due.getDate() + (Number(dueDays) || 30));
|
||||
const amt = Math.max(0, Number((document.getElementById("retainer-amount") as HTMLInputElement)?.value) || 0);
|
||||
if (amt <= 0) {
|
||||
setSaving(false);
|
||||
return toast.error("Enter a retainer amount");
|
||||
}
|
||||
const tax = +(amt * (Number(taxPct) || 0) / 100).toFixed(2);
|
||||
const { data: inv, error: ie } = await supabase
|
||||
.from("invoices")
|
||||
.insert({
|
||||
invoice_number: num,
|
||||
client_id: clientId,
|
||||
status: "draft",
|
||||
issue_date: new Date().toISOString().slice(0, 10),
|
||||
due_date: due.toISOString().slice(0, 10),
|
||||
subtotal: amt,
|
||||
tax,
|
||||
total: +(amt + tax).toFixed(2),
|
||||
notes: notes || "Retainer deposit",
|
||||
is_retainer: true,
|
||||
created_by: user.id,
|
||||
})
|
||||
.select("id, invoice_number")
|
||||
.single();
|
||||
if (ie || !inv) throw ie ?? new Error("Failed to create");
|
||||
await supabase.from("invoice_line_items").insert({
|
||||
invoice_id: inv.id,
|
||||
kind: "manual",
|
||||
description: "Retainer deposit into trust account",
|
||||
quantity: 1,
|
||||
rate: amt,
|
||||
amount: amt,
|
||||
sort_order: 0,
|
||||
});
|
||||
toast.success(`Retainer invoice ${inv.invoice_number} created`);
|
||||
onOpenChange(false);
|
||||
navigate({ to: "/invoices/$invoiceId", params: { invoiceId: inv.id } });
|
||||
return;
|
||||
}
|
||||
const { invoiceId, invoiceNumber } = await generateInvoiceForClient({
|
||||
clientId,
|
||||
caseIds: selectedIds,
|
||||
|
||||
Reference in New Issue
Block a user