diff --git a/db/migrations/20260220_add_due_date_to_invoices.sql b/db/migrations/20260220_add_due_date_to_invoices.sql new file mode 100644 index 0000000..15587fc --- /dev/null +++ b/db/migrations/20260220_add_due_date_to_invoices.sql @@ -0,0 +1,4 @@ +-- Migration: Add due_date to invoices +-- Created at: 2026-02-20 + +ALTER TABLE invoices ADD COLUMN due_date DATE DEFAULT NULL; diff --git a/index.php b/index.php index 68f1b42..a3c6393 100644 --- a/index.php +++ b/index.php @@ -128,6 +128,20 @@ function can(string $permission): bool { return is_array($perms) && in_array($permission, $perms); } +function getPurchaseAlerts() { + if (($_SESSION['user_role_name'] ?? '') !== 'Administrator' && ($_SESSION['user_permissions'] ?? '') !== 'all') return []; + $db = db(); + $stmt = $db->query("SELECT i.id, i.due_date, i.total_with_vat, c.name as supplier_name + FROM invoices i + LEFT JOIN customers c ON i.customer_id = c.id + WHERE i.type = 'purchase' + AND i.status != 'paid' + AND i.due_date IS NOT NULL + AND i.due_date <= DATE_ADD(CURDATE(), INTERVAL 7 DAY) + ORDER BY i.due_date ASC"); + return $stmt->fetchAll(PDO::FETCH_ASSOC); +} + // Missing helper functions function getLoyaltyMultiplier($tier) { switch (strtolower((string)$tier)) { @@ -639,6 +653,7 @@ function getPromotionalPrice($item) { $type = $_POST['type'] ?? 'sale'; $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'; @@ -669,8 +684,8 @@ function getPromotionalPrice($item) { $paid = (float)($_POST['paid_amount'] ?? 0); if ($status === 'paid') $paid = $total_with_vat; - $stmt = $db->prepare("INSERT INTO invoices (customer_id, type, invoice_date, status, payment_type, total_amount, vat_amount, total_with_vat, paid_amount) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)"); - $stmt->execute([$cust_id, $type, $inv_date, $status, $pay_type, $total_subtotal, $total_vat, $total_with_vat, $paid]); + $stmt = $db->prepare("INSERT INTO invoices (customer_id, type, invoice_date, due_date, status, payment_type, total_amount, vat_amount, total_with_vat, paid_amount) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"); + $stmt->execute([$cust_id, $type, $inv_date, $due_date, $status, $pay_type, $total_subtotal, $total_vat, $total_with_vat, $paid]); $inv_id = $db->lastInsertId(); $items_for_journal = []; @@ -922,6 +937,7 @@ function getPromotionalPrice($item) { $id = (int)$_POST['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'; @@ -951,8 +967,8 @@ function getPromotionalPrice($item) { $paid = (float)($_POST['paid_amount'] ?? 0); if ($status === 'paid') $paid = $total_with_vat; - $db->prepare("UPDATE invoices SET customer_id = ?, invoice_date = ?, status = ?, payment_type = ?, total_amount = ?, vat_amount = ?, total_with_vat = ?, paid_amount = ? WHERE id = ?") - ->execute([$cust_id, $date, $status, $pay_type, $total_subtotal, $total_vat, $total_with_vat, $paid, $id]); + $db->prepare("UPDATE invoices SET customer_id = ?, 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]); // Revert stock for old items $stmtOld = $db->prepare("SELECT ii.item_id, ii.quantity, i.type FROM invoice_items ii JOIN invoices i ON ii.invoice_id = i.id WHERE ii.invoice_id = ?"); @@ -2733,6 +2749,40 @@ $projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? 'Accounting System';