mirror of
https://github.com/renee-png/acmcc.git
synced 2026-06-21 01:40:01 +00:00
Bills: editing a paid bill saves and keeps its payment in sync
Editing a paid bill now updates the linked payment along with the bill: when the amount changes and the bill has a single bill payment, the bank transaction, the check, and the paid amount are all updated to the new total. The whole save is wrapped in error handling and the bill_items insert is now error-checked, so any failure surfaces a clear toast instead of silently appearing to 'not save'. Also refreshes the transactions/accounts caches after a bill edit. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -46,6 +46,7 @@ export default function AccountingBillsPage() {
|
||||
const parseFn = parseBill;
|
||||
const [open, setOpen] = useState(false);
|
||||
const [editId, setEditId] = useState<string | null>(null);
|
||||
const [editBill, setEditBill] = useState<any | null>(null);
|
||||
const [search, setSearch] = useState("");
|
||||
const [statusFilter, setStatusFilter] = useState<string>("all");
|
||||
const [autoOnly, setAutoOnly] = useState(false);
|
||||
@@ -130,7 +131,7 @@ export default function AccountingBillsPage() {
|
||||
const total = +(subtotal + tax).toFixed(2);
|
||||
|
||||
const resetForm = () => {
|
||||
setEditId(null);
|
||||
setEditId(null); setEditBill(null);
|
||||
setVendorId(""); setNumber(""); setDueDate(""); setTaxPct(0); setNotes("");
|
||||
setItems([{ description: "", quantity: 1, rate: 0, account_id: null }]);
|
||||
setFile(null); setFilePreview(null); setUploadedUrl(null);
|
||||
@@ -139,6 +140,7 @@ export default function AccountingBillsPage() {
|
||||
|
||||
const openEdit = async (b: any) => {
|
||||
setEditId(b.id);
|
||||
setEditBill(b);
|
||||
// The dropdown is keyed by public vendor id; map the stored accounting
|
||||
// vendor back to its source public vendor when one exists.
|
||||
let pubVendorId = "";
|
||||
@@ -261,6 +263,7 @@ export default function AccountingBillsPage() {
|
||||
const save = async (keepOpen = false) => {
|
||||
if (!number.trim()) return toast.error("Bill number required");
|
||||
if (!vendorId) return toast.error("Select a vendor (Pay to) before saving");
|
||||
try {
|
||||
let attachmentUrl = uploadedUrl;
|
||||
if (file && !attachmentUrl) attachmentUrl = await uploadFileObj(file);
|
||||
|
||||
@@ -291,8 +294,27 @@ export default function AccountingBillsPage() {
|
||||
}).eq("id", editId);
|
||||
if (error) return toast.error(error.message);
|
||||
await accounting.from("bill_items").delete().eq("bill_id", editId);
|
||||
await accounting.from("bill_items").insert(itemRows(editId));
|
||||
toast.success("Bill updated");
|
||||
const { error: biErr } = await accounting.from("bill_items").insert(itemRows(editId));
|
||||
if (biErr) return toast.error(biErr.message);
|
||||
|
||||
// Keep an already-paid bill's payment in sync with the edited amount. When
|
||||
// the total changed and the bill has a single linked bill payment, update
|
||||
// that payment (bank transaction + check) and the paid amount to match.
|
||||
const wasPaid = Number(editBill?.paid_amount ?? 0) > 0;
|
||||
const amountChanged = Math.abs(Number(editBill?.total ?? 0) - total) > 0.005;
|
||||
if (wasPaid && amountChanged) {
|
||||
const { data: pays } = await accounting.from("transactions").select("id").eq("bill_id", editId);
|
||||
if ((pays?.length ?? 0) === 1) {
|
||||
await accounting.from("transactions").update({ amount: total }).eq("bill_id", editId);
|
||||
await accounting.from("checks").update({ amount: total }).eq("source_bill_id", editId);
|
||||
await accounting.from("bills").update({ paid_amount: total, status: total > 0 ? "paid" : "open" }).eq("id", editId);
|
||||
toast.success("Bill and payment updated");
|
||||
} else {
|
||||
toast.warning("Bill updated — it has split/partial payments, so review the payment(s) manually.");
|
||||
}
|
||||
} else {
|
||||
toast.success("Bill updated");
|
||||
}
|
||||
} else {
|
||||
const { data: bill, error } = await accounting.from("bills").insert({
|
||||
company_id: cid, vendor_id: acctVendorId, number,
|
||||
@@ -308,6 +330,11 @@ export default function AccountingBillsPage() {
|
||||
resetForm();
|
||||
if (!keepOpen) setOpen(false);
|
||||
qc.invalidateQueries({ queryKey: ["bills", cid] });
|
||||
qc.invalidateQueries({ queryKey: ["transactions", cid] });
|
||||
qc.invalidateQueries({ queryKey: ["accounts", cid] });
|
||||
} catch (e: any) {
|
||||
toast.error(e?.message ?? "Failed to save bill");
|
||||
}
|
||||
};
|
||||
|
||||
// ── Read-only bill detail view ──
|
||||
|
||||
Reference in New Issue
Block a user