beginTransaction(); $type = $_POST['type'] ?? 'sale'; $table = ($type === 'purchase') ? 'purchases' : 'invoices'; $item_table = ($type === 'purchase') ? 'purchase_items' : 'invoice_items'; $cust_supplier_col = ($type === 'purchase') ? 'supplier_id' : 'customer_id'; $fk_col = ($type === 'purchase') ? 'purchase_id' : 'invoice_id'; $rawCustomerId = $_POST['customer_id'] ?? ''; $cust_id = ($type === 'sale' && ($rawCustomerId === '' || $rawCustomerId === null)) ? null : (int)$rawCustomerId; $inv_date = $_POST['invoice_date'] ?: date('Y-m-d'); $due_date = $_POST['due_date'] ?: null; $status = $_POST['status'] ?? 'pending'; $pay_type = $_POST['payment_type'] ?? 'cash'; $items = $_POST['item_ids'] ?? []; if (empty($items)) { throw new Exception("Please add at least one item."); } $qtys = $_POST['quantities'] ?? []; $prices = $_POST['prices'] ?? []; $total_subtotal = 0; $total_vat = 0; foreach ($items as $i => $item_id) { if (!$item_id) continue; $qty = normalize_quantity($qtys[$i] ?? 0); $price = (float)$prices[$i]; $subtotal = $qty * $price; $stmtVat = $db->prepare("SELECT vat_rate FROM stock_items WHERE id = ?"); $stmtVat->execute([$item_id]); $vatRate = (float)$stmtVat->fetchColumn(); $vatAmount = $subtotal * ($vatRate / 100); $total_subtotal += $subtotal; $total_vat += $vatAmount; } $total_with_vat = $total_subtotal + $total_vat; $paid = (float)($_POST['paid_amount'] ?? 0); if ($status === 'paid') $paid = $total_with_vat; $stmt = $db->prepare("INSERT INTO $table ($cust_supplier_col, invoice_date, due_date, status, payment_type, total_amount, vat_amount, total_with_vat, paid_amount) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)"); $stmt->execute([$cust_id, $inv_date, $due_date, $status, $pay_type, $total_subtotal, $total_vat, $total_with_vat, $paid]); $inv_id = $db->lastInsertId(); if (db_column_exists($table, 'outlet_id')) { $db->prepare("UPDATE $table SET outlet_id = ? WHERE id = ?")->execute([current_outlet_id(), $inv_id]); } $items_for_journal = []; foreach ($items as $i => $item_id) { if (!$item_id) continue; $qty = normalize_quantity($qtys[$i] ?? 0); $price = (float)$prices[$i]; $subtotal = $qty * $price; $stmtVat = $db->prepare("SELECT vat_rate FROM stock_items WHERE id = ?"); $stmtVat->execute([$item_id]); $vatRate = (float)$stmtVat->fetchColumn(); $vatAmount = $subtotal * ($vatRate / 100); $db->prepare("INSERT INTO $item_table ($fk_col, item_id, quantity, unit_price, vat_amount, total_price) VALUES (?, ?, ?, ?, ?, ?)")->execute([$inv_id, $item_id, $qty, $price, $vatAmount, $subtotal]); // Update stock $change = ($type === 'sale') ? -$qty : $qty; update_stock($item_id, $change); $items_for_journal[] = ['id' => $item_id, 'qty' => $qty]; } // Accounting if ($type === 'sale') { recordSaleJournal($inv_id, $total_with_vat, $inv_date, $items_for_journal, $total_vat); } else { // For purchases, you might have recordPurchaseJournal, but let's check if it exists if (function_exists('recordPurchaseJournal')) { recordPurchaseJournal($inv_id, $total_with_vat, $inv_date, $items_for_journal, $total_vat); } } $db->commit(); $wablasNotice = ''; if ($type === 'sale' && function_exists('wablasQueueInvoiceNotification')) { $wablasQueue = wablasQueueInvoiceNotification((int)$inv_id); $wablasNotice = (string)($wablasQueue['notice'] ?? ''); } $_SESSION['trigger_invoice_modal'] = true; $_SESSION['show_invoice_id'] = (int)$inv_id; $_SESSION['show_invoice_page'] = ($type === 'purchase') ? 'purchases' : 'sales'; $msg = ($type === 'purchase' ? "Purchase" : "Invoice") . " #$inv_id created!" . $wablasNotice; redirectWithMessage($msg, page_url($type === 'purchase' ? 'purchases' : 'sales')); } catch (Exception $e) { $db->rollBack(); $message = "Error: " . $e->getMessage(); } } if (isset($_POST['edit_invoice'])) { $db = db(); try { $db->beginTransaction(); $id = (int)$_POST['invoice_id']; $type = ($page === 'purchases') ? 'purchase' : 'sale'; $table = ($type === 'purchase') ? 'purchases' : 'invoices'; $item_table = ($type === 'purchase') ? 'purchase_items' : 'invoice_items'; $cust_supplier_col = ($type === 'purchase') ? 'supplier_id' : 'customer_id'; $fk_col = ($type === 'purchase') ? 'purchase_id' : 'invoice_id'; $rawCustomerId = $_POST['customer_id'] ?? ''; $cust_id = ($type === 'sale' && ($rawCustomerId === '' || $rawCustomerId === null)) ? null : (int)$rawCustomerId; $date = $_POST['invoice_date'] ?: date('Y-m-d'); $due_date = $_POST['due_date'] ?: null; $status = $_POST['status'] ?? 'pending'; $pay_type = $_POST['payment_type'] ?? 'cash'; $items = $_POST['item_ids'] ?? []; $qtys = $_POST['quantities'] ?? []; $prices = $_POST['prices'] ?? []; $total_subtotal = 0; $total_vat = 0; foreach ($items as $i => $item_id) { if (!$item_id) continue; $qty = normalize_quantity($qtys[$i] ?? 0); $price = (float)$prices[$i]; $subtotal = $qty * $price; $stmtVat = $db->prepare("SELECT vat_rate FROM stock_items WHERE id = ?"); $stmtVat->execute([$item_id]); $vatRate = (float)$stmtVat->fetchColumn(); $vatAmount = $subtotal * ($vatRate / 100); $total_subtotal += $subtotal; $total_vat += $vatAmount; } $total_with_vat = $total_subtotal + $total_vat; $paid = (float)($_POST['paid_amount'] ?? 0); if ($status === 'paid') $paid = $total_with_vat; $db->prepare("UPDATE $table SET $cust_supplier_col = ?, invoice_date = ?, due_date = ?, status = ?, payment_type = ?, total_amount = ?, vat_amount = ?, total_with_vat = ?, paid_amount = ? WHERE id = ?") ->execute([$cust_id, $date, $due_date, $status, $pay_type, $total_subtotal, $total_vat, $total_with_vat, $paid, $id]); if (db_column_exists($table, 'outlet_id')) { $db->prepare("UPDATE $table SET outlet_id = COALESCE(outlet_id, ?) WHERE id = ?")->execute([current_outlet_id(), $id]); } // Revert stock for old items $stmtOld = $db->prepare("SELECT item_id, quantity FROM $item_table WHERE $fk_col = ?"); $stmtOld->execute([$id]); $oldItems = $stmtOld->fetchAll(); foreach ($oldItems as $old) { $change = ($type === 'sale') ? normalize_quantity($old['quantity'] ?? 0) : -normalize_quantity($old['quantity'] ?? 0); update_stock($old['item_id'], $change); } // Delete old items $db->prepare("DELETE FROM $item_table WHERE $fk_col = ?")->execute([$id]); // Insert new items and update stock foreach ($items as $i => $item_id) { if (!$item_id) continue; $qty = normalize_quantity($qtys[$i] ?? 0); $price = (float)$prices[$i]; $subtotal = $qty * $price; $stmtVat = $db->prepare("SELECT vat_rate FROM stock_items WHERE id = ?"); $stmtVat->execute([$item_id]); $vatRate = (float)$stmtVat->fetchColumn(); $vatAmount = $subtotal * ($vatRate / 100); $db->prepare("INSERT INTO $item_table ($fk_col, item_id, quantity, unit_price, vat_amount, total_price) VALUES (?, ?, ?, ?, ?, ?)")->execute([$id, $item_id, $qty, $price, $vatAmount, $subtotal]); $change = ($type === 'sale') ? -$qty : $qty; update_stock($item_id, $change); } $db->commit(); $msg = ($type === 'purchase' ? "Purchase" : "Invoice") . " updated successfully!"; redirectWithMessage($msg, page_url($type === 'purchase' ? 'purchases' : 'sales')); } catch (Exception $e) { $db->rollBack(); $message = "Error: " . $e->getMessage(); } }