From da0815949e02b27db5b1611f98b32a1ef89193af Mon Sep 17 00:00:00 2001 From: Flatlogic Bot Date: Sun, 12 Oct 2025 05:26:53 +0000 Subject: [PATCH] finavo --- assets/css/custom.css | 55 ++++ customer.php | 227 +++++++++++++ dashboard.php | 90 ++++++ db/migrate.php | 38 +++ db/migrations/000_create_migrations_table.sql | 5 + db/migrations/001_create_users_table.sql | 11 + db/migrations/002_create_customers_table.sql | 16 + db/migrations/003_create_quotations_table.sql | 13 + db/migrations/004_create_invoices_table.sql | 12 + includes/auth.php | 8 + includes/footer.php | 4 + includes/header.php | 12 + includes/sidebar.php | 11 + index.php | 151 +-------- invoices.php | 297 ++++++++++++++++++ login.php | 151 +++++++++ logout.php | 7 + quotations.php | 284 +++++++++++++++++ 18 files changed, 1244 insertions(+), 148 deletions(-) create mode 100644 assets/css/custom.css create mode 100644 customer.php create mode 100644 dashboard.php create mode 100644 db/migrate.php create mode 100644 db/migrations/000_create_migrations_table.sql create mode 100644 db/migrations/001_create_users_table.sql create mode 100644 db/migrations/002_create_customers_table.sql create mode 100644 db/migrations/003_create_quotations_table.sql create mode 100644 db/migrations/004_create_invoices_table.sql create mode 100644 includes/auth.php create mode 100644 includes/footer.php create mode 100644 includes/header.php create mode 100644 includes/sidebar.php create mode 100644 invoices.php create mode 100644 login.php create mode 100644 logout.php create mode 100644 quotations.php diff --git a/assets/css/custom.css b/assets/css/custom.css new file mode 100644 index 0000000..9fc00b2 --- /dev/null +++ b/assets/css/custom.css @@ -0,0 +1,55 @@ +/* Login Page Styles */ +body.login-page { + background-color: #f8f9fa; +} + +.login-container { + margin-top: 100px; +} + +/* Dashboard Styles */ +#wrapper { + display: flex; +} + +#sidebar-wrapper { + min-height: 100vh; + margin-left: -15rem; + transition: margin .25s ease-out; +} + +#sidebar-wrapper .sidebar-heading { + padding: 0.875rem 1.25rem; + font-size: 1.2rem; +} + +#sidebar-wrapper .list-group { + width: 15rem; +} + +#page-content-wrapper { + min-width: 100vw; +} + +body.sb-sidenav-toggled #wrapper #sidebar-wrapper { + margin-left: 0; +} + +@media (min-width: 768px) { + #sidebar-wrapper { + margin-left: 0; + } + + #page-content-wrapper { + min-width: 0; + width: 100%; + } + + body.sb-sidenav-toggled #wrapper #sidebar-wrapper { + margin-left: -15rem; + } +} + +#sidebarToggle { + border-radius: 0.25rem; +} \ No newline at end of file diff --git a/customer.php b/customer.php new file mode 100644 index 0000000..9559a4a --- /dev/null +++ b/customer.php @@ -0,0 +1,227 @@ +prepare("DELETE FROM customers WHERE id = ?"); + $stmt->execute([$delete_id]); + header("Location: customer.php"); + exit; +} + +// Handle form submission for adding a new customer +if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['add_customer'])) { + $companyName = $_POST['companyName'] ?? ''; + $contactPerson = $_POST['contactPerson'] ?? ''; + $email = $_POST['email'] ?? ''; + $phone = $_POST['phone'] ?? ''; + + if (!empty($companyName)) { + $pdo = db(); + $stmt = $pdo->prepare("INSERT INTO customers (companyName, contactPerson, email, phone) VALUES (?, ?, ?, ?)"); + $stmt->execute([$companyName, $contactPerson, $email, $phone]); + header("Location: customer.php"); + exit; + } +} + +// Handle form submission for updating a customer +if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['update_customer'])) { + $id = $_POST['customer_id']; + $companyName = $_POST['companyName'] ?? ''; + $contactPerson = $_POST['contactPerson'] ?? ''; + $email = $_POST['email'] ?? ''; + $phone = $_POST['phone'] ?? ''; + + if (!empty($id) && !empty($companyName)) { + $pdo = db(); + $stmt = $pdo->prepare("UPDATE customers SET companyName = ?, contactPerson = ?, email = ?, phone = ? WHERE id = ?"); + $stmt->execute([$companyName, $contactPerson, $email, $phone, $id]); + header("Location: customer.php"); + exit; + } +} + +// Fetch all customers +$pdo = db(); +$stmt = $pdo->query("SELECT * FROM customers ORDER BY createdAt DESC"); +$customers = $stmt->fetchAll(); + +include 'includes/header.php'; +?> +
+ + +
+ + + + +
+
+

Customers

+
+ +
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
#Company NameContact PersonEmailPhoneActions
No customers found.
+ + +
+
+
+
+
+ + + + + + + + + + diff --git a/dashboard.php b/dashboard.php new file mode 100644 index 0000000..acc63c7 --- /dev/null +++ b/dashboard.php @@ -0,0 +1,90 @@ +query($customers_query); +$total_customers = $customers_result->fetch_assoc()['total_customers']; + +// Fetch total quotations +$quotations_query = "SELECT COUNT(*) as total_quotations FROM quotations"; +$quotations_result = db()->query($quotations_query); +$total_quotations = $quotations_result->fetch_assoc()['total_quotations']; + +// Fetch total invoices +$invoices_query = "SELECT COUNT(*) as total_invoices FROM invoices"; +$invoices_result = db()->query($invoices_query); +$total_invoices = $invoices_result->fetch_assoc()['total_invoices']; +?> +
+ + +
+ + + + +
+

Dashboard

+

Welcome to your accounting dashboard.

+
+
+
+
Total Customers
+ +
+
+
+
+
Total Invoices
+ +
+
+
+
+
Quotations Sent
+ +
+
+
+
+
Overdue Invoices
+ +
+
+
+
+
+
+ + \ No newline at end of file diff --git a/db/migrate.php b/db/migrate.php new file mode 100644 index 0000000..cd90019 --- /dev/null +++ b/db/migrate.php @@ -0,0 +1,38 @@ +exec(file_get_contents($migrations_dir . '/000_create_migrations_table.sql')); + + $ran_migrations_stmt = $pdo->query("SELECT migration FROM migrations"); + $ran_migrations = $ran_migrations_stmt->fetchAll(PDO::FETCH_COLUMN); + + $migration_files = glob($migrations_dir . '/*.sql'); + sort($migration_files); + + foreach ($migration_files as $file) { + $migration_name = basename($file); + if ($migration_name === '000_create_migrations_table.sql') { + continue; + } + + if (!in_array($migration_name, $ran_migrations)) { + echo "Running migration: $migration_name...\n"; + $sql = file_get_contents($file); + $pdo->exec($sql); + + $stmt = $pdo->prepare("INSERT INTO migrations (migration) VALUES (?)"); + $stmt->execute([$migration_name]); + echo "Success.\n"; + } else { + echo "Migration already ran: $migration_name.\n"; + } + } +} + +run_migrations(); + diff --git a/db/migrations/000_create_migrations_table.sql b/db/migrations/000_create_migrations_table.sql new file mode 100644 index 0000000..d8fde3f --- /dev/null +++ b/db/migrations/000_create_migrations_table.sql @@ -0,0 +1,5 @@ +CREATE TABLE IF NOT EXISTS `migrations` ( + `id` INT AUTO_INCREMENT PRIMARY KEY, + `migration` VARCHAR(255) NOT NULL UNIQUE, + `createdAt` DATETIME DEFAULT CURRENT_TIMESTAMP +); \ No newline at end of file diff --git a/db/migrations/001_create_users_table.sql b/db/migrations/001_create_users_table.sql new file mode 100644 index 0000000..7d2d1b4 --- /dev/null +++ b/db/migrations/001_create_users_table.sql @@ -0,0 +1,11 @@ +CREATE TABLE IF NOT EXISTS `users` ( + `id` INT AUTO_INCREMENT PRIMARY KEY, + `username` VARCHAR(255) NOT NULL UNIQUE, + `email` VARCHAR(255) NOT NULL UNIQUE, + `password` VARCHAR(255) NOT NULL, + `role` ENUM('Admin', 'Finance', 'Sales', 'Manager') NOT NULL, + `isActive` BOOLEAN DEFAULT TRUE, + `lastLogin` DATETIME, + `createdAt` DATETIME DEFAULT CURRENT_TIMESTAMP, + `updatedAt` DATETIME ON UPDATE CURRENT_TIMESTAMP +); \ No newline at end of file diff --git a/db/migrations/002_create_customers_table.sql b/db/migrations/002_create_customers_table.sql new file mode 100644 index 0000000..6dfd572 --- /dev/null +++ b/db/migrations/002_create_customers_table.sql @@ -0,0 +1,16 @@ +CREATE TABLE IF NOT EXISTS `customers` ( + `id` INT AUTO_INCREMENT PRIMARY KEY, + `companyName` VARCHAR(255) NOT NULL, + `contactPerson` VARCHAR(255), + `email` VARCHAR(255), + `phone` VARCHAR(255), + `address` TEXT, + `billingAddress` TEXT, + `taxId` VARCHAR(255), + `paymentTerms` INT DEFAULT 30, + `currency` VARCHAR(10) DEFAULT 'USD', + `notes` TEXT, + `createdBy` INT, + `createdAt` DATETIME DEFAULT CURRENT_TIMESTAMP, + FOREIGN KEY (`createdBy`) REFERENCES `users`(`id`) ON DELETE SET NULL +); \ No newline at end of file diff --git a/db/migrations/003_create_quotations_table.sql b/db/migrations/003_create_quotations_table.sql new file mode 100644 index 0000000..6d7b7f2 --- /dev/null +++ b/db/migrations/003_create_quotations_table.sql @@ -0,0 +1,13 @@ +CREATE TABLE IF NOT EXISTS `quotations` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `customer_id` int(11) NOT NULL, + `quotation_number` varchar(255) NOT NULL, + `quotation_date` date NOT NULL, + `total_amount` decimal(10,2) NOT NULL, + `status` varchar(50) NOT NULL DEFAULT 'Draft', + `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + PRIMARY KEY (`id`), + KEY `customer_id` (`customer_id`), + CONSTRAINT `quotations_ibfk_1` FOREIGN KEY (`customer_id`) REFERENCES `customers` (`id`) ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; diff --git a/db/migrations/004_create_invoices_table.sql b/db/migrations/004_create_invoices_table.sql new file mode 100644 index 0000000..9fbaea5 --- /dev/null +++ b/db/migrations/004_create_invoices_table.sql @@ -0,0 +1,12 @@ +CREATE TABLE IF NOT EXISTS `invoices` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `customer_id` int(11) NOT NULL, + `invoice_date` date NOT NULL, + `due_date` date NOT NULL, + `total` decimal(10,2) NOT NULL, + `status` varchar(20) NOT NULL DEFAULT 'Draft', + `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + PRIMARY KEY (`id`), + KEY `customer_id` (`customer_id`), + CONSTRAINT `invoices_ibfk_1` FOREIGN KEY (`customer_id`) REFERENCES `customers` (`id`) ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; diff --git a/includes/auth.php b/includes/auth.php new file mode 100644 index 0000000..256f5d1 --- /dev/null +++ b/includes/auth.php @@ -0,0 +1,8 @@ + \ No newline at end of file diff --git a/includes/footer.php b/includes/footer.php new file mode 100644 index 0000000..7cf63f8 --- /dev/null +++ b/includes/footer.php @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/includes/header.php b/includes/header.php new file mode 100644 index 0000000..c724779 --- /dev/null +++ b/includes/header.php @@ -0,0 +1,12 @@ + + + + + + K Design Accounting + + + + + +
\ No newline at end of file diff --git a/includes/sidebar.php b/includes/sidebar.php new file mode 100644 index 0000000..dfa0c83 --- /dev/null +++ b/includes/sidebar.php @@ -0,0 +1,11 @@ + + diff --git a/index.php b/index.php index 7205f3d..e9553eb 100644 --- a/index.php +++ b/index.php @@ -1,150 +1,5 @@ - - - - - - New Style - - - - - - - - - - - - - - - - - - - - - -
-
-

Analyzing your requirements and generating your website…

-
- Loading… -
-

AI is collecting your requirements and applying the first changes.

-

This page will update automatically as the plan is implemented.

-

Runtime: PHP — UTC

-
-
-
- Page updated: (UTC) -
- - +header('Location: dashboard.php'); +exit(); diff --git a/invoices.php b/invoices.php new file mode 100644 index 0000000..d6305a1 --- /dev/null +++ b/invoices.php @@ -0,0 +1,297 @@ +prepare("DELETE FROM invoices WHERE id = ?"); + $stmt->execute([$delete_id]); + header("Location: invoices.php"); + exit; +} + +// Handle Add Invoice +if ($_SERVER["REQUEST_METHOD"] == "POST" && isset($_POST['add_invoice'])) { + $customer_id = $_POST['customer_id']; + $invoice_date = $_POST['invoice_date']; + $due_date = $_POST['due_date']; + $total = $_POST['total']; + $status = $_POST['status']; + + try { + $sql = "INSERT INTO invoices (customer_id, invoice_date, due_date, total, status) VALUES (:customer_id, :invoice_date, :due_date, :total, :status)"; + $stmt = db()->prepare($sql); + $stmt->execute([ + ':customer_id' => $customer_id, + ':invoice_date' => $invoice_date, + ':due_date' => $due_date, + ':total' => $total, + ':status' => $status + ]); + header("Location: invoices.php"); + exit(); + } catch (PDOException $e) { + $error_message = "Error adding invoice: " . $e->getMessage(); + } +} + +// Handle form submission for updating an invoice +if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['update_invoice'])) { + $id = $_POST['invoice_id']; + $customer_id = $_POST['customer_id']; + $invoice_date = $_POST['invoice_date']; + $due_date = $_POST['due_date']; + $total = $_POST['total']; + $status = $_POST['status']; + + if (!empty($id)) { + $pdo = db(); + $stmt = $pdo->prepare("UPDATE invoices SET customer_id = ?, invoice_date = ?, due_date = ?, total = ?, status = ? WHERE id = ?"); + $stmt->execute([$customer_id, $invoice_date, $due_date, $total, $status, $id]); + header("Location: invoices.php"); + exit; + } +} + +// Fetch invoices and customers +try { + $invoices_stmt = db()->query("SELECT i.*, c.companyName as customer_name FROM invoices i JOIN customers c ON i.customer_id = c.id ORDER BY i.invoice_date DESC"); + $invoices = $invoices_stmt->fetchAll(PDO::FETCH_ASSOC); + + $customers_stmt = db()->query("SELECT id, companyName FROM customers ORDER BY companyName ASC"); + $customers = $customers_stmt->fetchAll(PDO::FETCH_ASSOC); +} catch (PDOException $e) { + $error_message = "Error fetching data: " . $e->getMessage(); + $invoices = []; + $customers = []; +} + +include 'includes/header.php'; +?> + +
+ + +
+ + + + +
+
+

Invoices

+
+ +
+
+ + +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
#CustomerInvoice DateDue DateAmountStatusActions
No invoices found.
INV-$ + + + + + +
+
+
+
+
+ + + + + + + + + + diff --git a/login.php b/login.php new file mode 100644 index 0000000..2e8ce72 --- /dev/null +++ b/login.php @@ -0,0 +1,151 @@ +query("SELECT id FROM users LIMIT 1"); + if ($stmt->rowCount() == 0) { + $default_email = "admin@example.com"; + $default_password = "password"; + $hashed_password = password_hash($default_password, PASSWORD_DEFAULT); + $default_username = "admin"; + $default_role = "Admin"; + + $insert_stmt = $pdo->prepare("INSERT INTO users (username, email, password, role) VALUES (:username, :email, :password, :role)"); + $insert_stmt->bindParam(':username', $default_username); + $insert_stmt->bindParam(':email', $default_email); + $insert_stmt->bindParam(':password', $hashed_password); + $insert_stmt->bindParam(':role', $default_role); + $insert_stmt->execute(); + } +} catch (PDOException $e) { + // Don't expose error details to the user + error_log("Error checking/creating default user: " . $e->getMessage()); +} + + +$email = $password = ""; +$email_err = $password_err = $login_err = ""; + +if ($_SERVER["REQUEST_METHOD"] == "POST") { + if (empty(trim($_POST["email"]))) { + $email_err = "Please enter email."; + } else { + $email = trim($_POST["email"]); + } + + if (empty(trim($_POST["password"]))) { + $password_err = "Please enter your password."; + } else { + $password = trim($_POST["password"]); + } + + if (empty($email_err) && empty($password_err)) { + $sql = "SELECT id, username, email, password, role FROM users WHERE email = :email"; + + if ($stmt = $pdo->prepare($sql)) { + $stmt->bindParam(":email", $param_email, PDO::PARAM_STR); + $param_email = $email; + + if ($stmt->execute()) { + if ($stmt->rowCount() == 1) { + if ($row = $stmt->fetch()) { + $id = $row["id"]; + $username = $row["username"]; + $hashed_password = $row["password"]; + $role = $row["role"]; + if (password_verify($password, $hashed_password)) { + session_start(); + + $_SESSION["loggedin"] = true; + $_SESSION["id"] = $id; + $_SESSION["username"] = $username; + $_SESSION["role"] = $role; + + header("location: dashboard.php"); + } else { + $login_err = "Invalid email or password."; + } + } + } else { + $login_err = "Invalid email or password."; + } + } else { + echo "Oops! Something went wrong. Please try again later."; + } + unset($stmt); + } + } + unset($pdo); +} +?> + + + + + + Login - K Design Accounting + + + + + +
+
+
+
+ +

K Design Accounting

+

Streamline your finances with elegance and precision.

+
+
+
+
+
+

Welcome Back

+ ' . $login_err . '
'; + } + ?> +
+
+ + + +
+
+ + + +
+
+
+ + +
+ Forgot password? +
+
+ +
+
+
+
+
+
+
+ + + \ No newline at end of file diff --git a/logout.php b/logout.php new file mode 100644 index 0000000..a6f0bcf --- /dev/null +++ b/logout.php @@ -0,0 +1,7 @@ + diff --git a/quotations.php b/quotations.php new file mode 100644 index 0000000..ef10c10 --- /dev/null +++ b/quotations.php @@ -0,0 +1,284 @@ +prepare("DELETE FROM quotations WHERE id = ?"); + $stmt->execute([$delete_id]); + header("Location: quotations.php"); + exit; +} + +// Handle form submission for adding a new quotation +if ($_SERVER["REQUEST_METHOD"] == "POST" && isset($_POST['add_quotation'])) { + $customer_id = $_POST['customer_id']; + $quotation_number = $_POST['quotation_number']; + $quotation_date = $_POST['quotation_date']; + $total_amount = $_POST['total_amount']; + + if (!empty($customer_id) && !empty($quotation_number) && !empty($quotation_date) && !empty($total_amount)) { + $pdo = db(); + $stmt = $pdo->prepare("INSERT INTO quotations (customer_id, quotation_number, quotation_date, total_amount) VALUES (?, ?, ?, ?)"); + $stmt->execute([$customer_id, $quotation_number, $quotation_date, $total_amount]); + } + header("Location: quotations.php"); + exit(); +} + +// Handle form submission for updating a quotation +if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['update_quotation'])) { + $id = $_POST['quotation_id']; + $customer_id = $_POST['customer_id']; + $quotation_number = $_POST['quotation_number']; + $quotation_date = $_POST['quotation_date']; + $total_amount = $_POST['total_amount']; + $status = $_POST['status']; + + if (!empty($id)) { + $pdo = db(); + $stmt = $pdo->prepare("UPDATE quotations SET customer_id = ?, quotation_number = ?, quotation_date = ?, total_amount = ?, status = ? WHERE id = ?"); + $stmt->execute([$customer_id, $quotation_number, $quotation_date, $total_amount, $status, $id]); + header("Location: quotations.php"); + exit; + } +} + +// Fetch all customers for the dropdown +$pdo = db(); +$customers_stmt = $pdo->query("SELECT id, companyName FROM customers ORDER BY companyName ASC"); +$customers = $customers_stmt->fetchAll(PDO::FETCH_ASSOC); + +// Fetch all quotations with customer names +$quotations_stmt = $pdo->query(" + SELECT + q.id, + q.customer_id, + q.quotation_number, + q.quotation_date, + q.total_amount, + q.status, + c.companyName AS customer_name + FROM quotations q + JOIN customers c ON q.customer_id = c.id + ORDER BY q.quotation_date DESC +"); +$quotations = $quotations_stmt->fetchAll(PDO::FETCH_ASSOC); + +include 'includes/header.php'; +?> + +
+ + +
+ + + + +
+
+

Quotations

+
+ +
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
#CustomerDateAmountStatusActions
No quotations found.
$ + + + + + +
+
+
+
+
+ + + + + + + + + +