187 lines
9.1 KiB
PHP
187 lines
9.1 KiB
PHP
<?php
|
|
// Shared Sales/Purchases create/update handlers extracted from index.php
|
|
// to reduce regression risk while preserving the existing behavior.
|
|
// Invoices
|
|
if (isset($_POST['add_invoice'])) {
|
|
$db = db();
|
|
try {
|
|
$db->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';
|
|
|
|
$cust_id = (int)$_POST['customer_id'];
|
|
$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 = (float)$qtys[$i];
|
|
$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 = (float)$qtys[$i];
|
|
$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';
|
|
|
|
$cust_id = (int)$_POST['customer_id'];
|
|
$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 = (float)$qtys[$i];
|
|
$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') ? (float)$old['quantity'] : -(float)$old['quantity'];
|
|
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 = (float)$qtys[$i];
|
|
$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(); }
|
|
}
|