From 4b20014812362f185f8f111b91dd0f542470c1ae Mon Sep 17 00:00:00 2001 From: Flatlogic Bot Date: Mon, 16 Feb 2026 09:18:06 +0000 Subject: [PATCH] Autosave: 20260216-091806 --- db/migrations/20260216_add_invoices.sql | 20 + .../20260216_update_invoices_payment.sql | 1 + index.php | 698 +++++++++++++++++- 3 files changed, 692 insertions(+), 27 deletions(-) create mode 100644 db/migrations/20260216_add_invoices.sql create mode 100644 db/migrations/20260216_update_invoices_payment.sql diff --git a/db/migrations/20260216_add_invoices.sql b/db/migrations/20260216_add_invoices.sql new file mode 100644 index 0000000..6cbcc7c --- /dev/null +++ b/db/migrations/20260216_add_invoices.sql @@ -0,0 +1,20 @@ +CREATE TABLE IF NOT EXISTS invoices ( + id INT AUTO_INCREMENT PRIMARY KEY, + customer_id INT, + invoice_date DATE NOT NULL, + type ENUM('sale', 'purchase') NOT NULL, + total_amount DECIMAL(15, 2) DEFAULT 0.00, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + FOREIGN KEY (customer_id) REFERENCES customers(id) ON DELETE SET NULL +); + +CREATE TABLE IF NOT EXISTS invoice_items ( + id INT AUTO_INCREMENT PRIMARY KEY, + invoice_id INT NOT NULL, + item_id INT NOT NULL, + quantity DECIMAL(15, 2) NOT NULL, + unit_price DECIMAL(15, 2) NOT NULL, + total_price DECIMAL(15, 2) NOT NULL, + FOREIGN KEY (invoice_id) REFERENCES invoices(id) ON DELETE CASCADE, + FOREIGN KEY (item_id) REFERENCES stock_items(id) ON DELETE CASCADE +); diff --git a/db/migrations/20260216_update_invoices_payment.sql b/db/migrations/20260216_update_invoices_payment.sql new file mode 100644 index 0000000..8b8e26d --- /dev/null +++ b/db/migrations/20260216_update_invoices_payment.sql @@ -0,0 +1 @@ +ALTER TABLE invoices ADD COLUMN payment_type ENUM('cash', 'credit') DEFAULT 'cash' AFTER type; \ No newline at end of file diff --git a/index.php b/index.php index f1f46a9..b622a5b 100644 --- a/index.php +++ b/index.php @@ -4,6 +4,15 @@ require_once 'db/config.php'; // Handle POST Requests $message = ''; +if ($_SERVER['REQUEST_METHOD'] === 'GET' && isset($_GET['action']) && $_GET['action'] === 'search_items') { + header('Content-Type: application/json'); + $q = $_GET['q'] ?? ''; + $stmt = db()->prepare("SELECT id, name_en, name_ar, sku, sale_price, purchase_price, stock_quantity FROM stock_items WHERE name_en LIKE ? OR name_ar LIKE ? OR sku LIKE ? LIMIT 10"); + $stmt->execute(["%$q%", "%$q%", "%$q%"]); + echo json_encode($stmt->fetchAll()); + exit; +} + if ($_SERVER['REQUEST_METHOD'] === 'POST') { if (isset($_POST['add_customer'])) { $name = $_POST['name'] ?? ''; @@ -186,6 +195,122 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') { } } + if (isset($_POST['import_customers']) || isset($_POST['import_suppliers'])) { + $type = isset($_POST['import_customers']) ? 'customer' : 'supplier'; + if (isset($_FILES['excel_file']) && $_FILES['excel_file']['error'] === UPLOAD_ERR_OK) { + $file = $_FILES['excel_file']['tmp_name']; + $handle = fopen($file, 'r'); + $header = fgetcsv($handle); + $count = 0; + while (($row = fgetcsv($handle)) !== FALSE) { + if (count($row) < 4) continue; + $name = trim($row[0]); + $email = trim($row[1]); + $phone = trim($row[2]); + $balance = (float)trim($row[3]); + if ($name) { + $stmt = db()->prepare("INSERT INTO customers (name, email, phone, balance, type) VALUES (?, ?, ?, ?, ?)"); + $stmt->execute([$name, $email, $phone, $balance, $type]); + $count++; + } + } + fclose($handle); + $message = "$count " . ($type === 'customer' ? 'customers' : 'suppliers') . " imported successfully!"; + } + } + + if (isset($_POST['import_categories'])) { + if (isset($_FILES['excel_file']) && $_FILES['excel_file']['error'] === UPLOAD_ERR_OK) { + $file = $_FILES['excel_file']['tmp_name']; + $handle = fopen($file, 'r'); + $header = fgetcsv($handle); + $count = 0; + while (($row = fgetcsv($handle)) !== FALSE) { + if (count($row) < 2) continue; + $name_en = trim($row[0]); + $name_ar = trim($row[1]); + if ($name_en && $name_ar) { + $stmt = db()->prepare("INSERT INTO stock_categories (name_en, name_ar) VALUES (?, ?)"); + $stmt->execute([$name_en, $name_ar]); + $count++; + } + } + fclose($handle); + $message = "$count categories imported successfully!"; + } + } + + if (isset($_POST['import_units'])) { + if (isset($_FILES['excel_file']) && $_FILES['excel_file']['error'] === UPLOAD_ERR_OK) { + $file = $_FILES['excel_file']['tmp_name']; + $handle = fopen($file, 'r'); + $header = fgetcsv($handle); + $count = 0; + while (($row = fgetcsv($handle)) !== FALSE) { + if (count($row) < 4) continue; + $name_en = trim($row[0]); + $name_ar = trim($row[1]); + $short_en = trim($row[2]); + $short_ar = trim($row[3]); + if ($name_en && $name_ar) { + $stmt = db()->prepare("INSERT INTO stock_units (name_en, name_ar, short_name_en, short_name_ar) VALUES (?, ?, ?, ?)"); + $stmt->execute([$name_en, $name_ar, $short_en, $short_ar]); + $count++; + } + } + fclose($handle); + $message = "$count units imported successfully!"; + } + } + + if (isset($_POST['add_invoice'])) { + $customer_id = $_POST['customer_id'] ?: null; + $invoice_date = $_POST['invoice_date'] ?: date('Y-m-d'); + $type = $_POST['type'] ?? 'sale'; // 'sale' or 'purchase' + $payment_type = $_POST['payment_type'] ?? 'cash'; + $item_ids = $_POST['item_ids'] ?? []; + $quantities = $_POST['quantities'] ?? []; + $prices = $_POST['prices'] ?? []; + + if (!empty($item_ids)) { + $db = db(); + $db->beginTransaction(); + try { + $total_amount = 0; + foreach ($item_ids as $index => $item_id) { + $total_amount += (float)$quantities[$index] * (float)$prices[$index]; + } + + $stmt = $db->prepare("INSERT INTO invoices (customer_id, invoice_date, type, payment_type, total_amount) VALUES (?, ?, ?, ?, ?)"); + $stmt->execute([$customer_id, $invoice_date, $type, $payment_type, $total_amount]); + $invoice_id = $db->lastInsertId(); + + foreach ($item_ids as $index => $item_id) { + $qty = (float)$quantities[$index]; + $price = (float)$prices[$index]; + $total_price = $qty * $price; + + $stmt = $db->prepare("INSERT INTO invoice_items (invoice_id, item_id, quantity, unit_price, total_price) VALUES (?, ?, ?, ?, ?)"); + $stmt->execute([$invoice_id, $item_id, $qty, $price, $total_price]); + + // Update stock level + if ($type === 'sale') { + $stmt = $db->prepare("UPDATE stock_items SET stock_quantity = stock_quantity - ? WHERE id = ?"); + } else { + $stmt = $db->prepare("UPDATE stock_items SET stock_quantity = stock_quantity + ? WHERE id = ?"); + } + $stmt->execute([$qty, $item_id]); + } + + $db->commit(); + $message = ucfirst($type) . " invoice created successfully!"; + } catch (Exception $e) { + $db->rollBack(); + $message = "Error creating invoice: " . $e->getMessage(); + } + } + } + if (isset($_POST['add_payment_method'])) { $name_en = $_POST['name_en'] ?? ''; $name_ar = $_POST['name_ar'] ?? ''; @@ -250,6 +375,17 @@ switch ($page) { case 'payment_methods': $data['payment_methods'] = db()->query("SELECT * FROM payment_methods ORDER BY id DESC")->fetchAll(); break; + case 'sales': + case 'purchases': + $type = ($page === 'sales') ? 'sale' : 'purchase'; + $data['invoices'] = db()->query("SELECT v.*, c.name as customer_name + FROM invoices v + LEFT JOIN customers c ON v.customer_id = c.id + WHERE v.type = '$type' + ORDER BY v.id DESC")->fetchAll(); + $data['items_list'] = db()->query("SELECT id, name_en, name_ar, sale_price, purchase_price, stock_quantity FROM stock_items ORDER BY name_en ASC")->fetchAll(); + $data['customers_list'] = db()->query("SELECT id, name FROM customers WHERE type = '" . ($type === 'sale' ? 'customer' : 'supplier') . "' ORDER BY name ASC")->fetchAll(); + break; default: $data['customers'] = db()->query("SELECT * FROM customers WHERE type = 'customer' ORDER BY id DESC LIMIT 5")->fetchAll(); // Dashboard stats @@ -273,44 +409,91 @@ $projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? 'Accounting System'; - + + @@ -441,9 +629,14 @@ $projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? 'Accounting System';
Management
- +
+ + +
@@ -522,9 +715,14 @@ $projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? 'Accounting System';
Stock Categories
- +
+ + +
@@ -552,9 +750,14 @@ $projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? 'Accounting System';
Stock Units
- +
+ + +
@@ -778,6 +981,194 @@ $projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? 'Accounting System';
+ +
+
+
+ +
+
+ + + + + + + + + + + + prepare("SELECT ii.*, i.name_en, i.name_ar + FROM invoice_items ii + JOIN stock_items i ON ii.item_id = i.id + WHERE ii.invoice_id = ?"); + $items->execute([$inv['id']]); + $inv['items'] = $items->fetchAll(PDO::FETCH_ASSOC); + ?> + + + + + + + + + +
Invoice #DateTotal AmountActions
INV-$ + +
+
+
+ + + + + + +
@@ -1043,6 +1434,122 @@ $projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? 'Accounting System';
+ + + + + + + + + + + +