From 6c14b2436fae0c563fad83d834677d42e1a92c4e Mon Sep 17 00:00:00 2001 From: Flatlogic Bot Date: Thu, 18 Dec 2025 09:40:37 +0000 Subject: [PATCH] 2.0 --- add_shipment_details.php | 74 +++++ admin/add_dealer.php | 52 ++++ admin/delete_dealer.php | 47 ++++ admin/edit_dealer.php | 68 +++++ admin/import_products.php | 61 +++++ admin/index.php | 23 ++ admin/manage_dealers.php | 47 ++++ admin/reports.php | 113 ++++++++ api/get_product_details.php | 32 +++ assets/css/custom.css | 23 ++ assets/vm-shot-2025-12-09T05-39-13-528Z.jpg | Bin 0 -> 24872 bytes cart.php | 180 ++++++++++++ db/migration_001_warranty.php | 19 ++ db/migration_002_products.php | 18 ++ db/migration_003_dealers.php | 18 ++ db/migration_004_sold_serials.php | 22 ++ db/migration_005_alter_warranty.php | 22 ++ db/migration_006_users.php | 21 ++ db/migration_007_alter_products.php | 15 + db/migration_008_service_requests.php | 24 ++ db/migration_009_service_request_comments.php | 21 ++ db/migration_010_add_is_admin_to_users.php | 11 + ..._011_add_file_path_to_service_requests.php | 11 + ...gration_012_create_notifications_table.php | 22 ++ ...on_013_add_user_id_to_service_requests.php | 13 + ...igration_014_create_product_categories.php | 19 ++ ...gration_015_alter_products_add_details.php | 20 ++ db/migration_016_create_orders_table.php | 21 ++ db/migration_017_create_order_items_table.php | 23 ++ db/migration_018_add_dealer_kpis.php | 17 ++ ...ration_019_add_paid_amount_to_invoices.php | 14 + db/migration_020_add_dealer_id_to_orders.php | 38 +++ db/migration_021_fix_orders_dealer_id.php | 26 ++ db/seed_data.php | 74 +++++ db/seed_invoices.php | 59 ++++ delete_shipment_details.php | 36 +++ edit_shipment_details.php | 87 ++++++ includes/footer.php | 11 + includes/header.php | 100 +++++++ index.php | 256 ++++++++---------- invoice_details.php | 105 +++++++ invoices.php | 80 ++++++ login.php | 58 ++++ logout.php | 6 + notifications.php | 46 ++++ order_details.php | 78 ++++++ orders.php | 72 +++++ post_payment.php | 46 ++++ products.php | 122 +++++++++ profile.php | 95 +++++++ service_request_details.php | 249 +++++++++++++++++ service_requests.php | 227 ++++++++++++++++ targets.php | 74 +++++ update_service_request_status.php | 30 ++ warranty_registration.php | 226 ++++++++++++++++ 55 files changed, 3126 insertions(+), 146 deletions(-) create mode 100644 add_shipment_details.php create mode 100644 admin/add_dealer.php create mode 100644 admin/delete_dealer.php create mode 100644 admin/edit_dealer.php create mode 100644 admin/import_products.php create mode 100644 admin/index.php create mode 100644 admin/manage_dealers.php create mode 100644 admin/reports.php create mode 100644 api/get_product_details.php create mode 100644 assets/css/custom.css create mode 100644 assets/vm-shot-2025-12-09T05-39-13-528Z.jpg create mode 100644 cart.php create mode 100644 db/migration_001_warranty.php create mode 100644 db/migration_002_products.php create mode 100644 db/migration_003_dealers.php create mode 100644 db/migration_004_sold_serials.php create mode 100644 db/migration_005_alter_warranty.php create mode 100644 db/migration_006_users.php create mode 100644 db/migration_007_alter_products.php create mode 100644 db/migration_008_service_requests.php create mode 100644 db/migration_009_service_request_comments.php create mode 100644 db/migration_010_add_is_admin_to_users.php create mode 100644 db/migration_011_add_file_path_to_service_requests.php create mode 100644 db/migration_012_create_notifications_table.php create mode 100644 db/migration_013_add_user_id_to_service_requests.php create mode 100644 db/migration_014_create_product_categories.php create mode 100644 db/migration_015_alter_products_add_details.php create mode 100644 db/migration_016_create_orders_table.php create mode 100644 db/migration_017_create_order_items_table.php create mode 100644 db/migration_018_add_dealer_kpis.php create mode 100644 db/migration_019_add_paid_amount_to_invoices.php create mode 100644 db/migration_020_add_dealer_id_to_orders.php create mode 100644 db/migration_021_fix_orders_dealer_id.php create mode 100644 db/seed_data.php create mode 100644 db/seed_invoices.php create mode 100644 delete_shipment_details.php create mode 100644 edit_shipment_details.php create mode 100644 includes/footer.php create mode 100644 includes/header.php create mode 100644 invoice_details.php create mode 100644 invoices.php create mode 100644 login.php create mode 100644 logout.php create mode 100644 notifications.php create mode 100644 order_details.php create mode 100644 orders.php create mode 100644 post_payment.php create mode 100644 products.php create mode 100644 profile.php create mode 100644 service_request_details.php create mode 100644 service_requests.php create mode 100644 targets.php create mode 100644 update_service_request_status.php create mode 100644 warranty_registration.php diff --git a/add_shipment_details.php b/add_shipment_details.php new file mode 100644 index 0000000..3ea76d2 --- /dev/null +++ b/add_shipment_details.php @@ -0,0 +1,74 @@ +prepare($sql); + $stmt->execute([$request_id, $carrier, $tracking_number, $shipment_date]); + + header('Location: service_request_details.php?id=' . $request_id); + exit; + + } catch (PDOException $e) { + die("Database error: " . $e->getMessage()); + } +} + +?> + +
+
+
+
+

Add Shipment Details

+
+
+
+ +
+ + +
+
+ + +
+
+ + +
+ + Cancel +
+
+
+
+
+ + diff --git a/admin/add_dealer.php b/admin/add_dealer.php new file mode 100644 index 0000000..3d3c979 --- /dev/null +++ b/admin/add_dealer.php @@ -0,0 +1,52 @@ +prepare("INSERT INTO dealers (name, email) VALUES (?, ?)"); + if ($stmt->execute([$name, $email])) { + $success = 'Dealer added successfully.'; + } else { + $error = 'Failed to add dealer.'; + } + } +} +?> + +
+

Add Dealer

+ +
+ + +
+ +
+
+ + +
+
+ + +
+ +
+
+ + diff --git a/admin/delete_dealer.php b/admin/delete_dealer.php new file mode 100644 index 0000000..f756694 --- /dev/null +++ b/admin/delete_dealer.php @@ -0,0 +1,47 @@ +prepare("DELETE FROM dealers WHERE id = ?"); + $stmt->execute([$dealer_id]); + } + header('Location: manage_dealers.php'); + exit; +} + +$stmt = $pdo->prepare("SELECT * FROM dealers WHERE id = ?"); +$stmt->execute([$dealer_id]); +$dealer = $stmt->fetch(); + +if (!$dealer) { + header('Location: manage_dealers.php'); + exit; +} +?> + +
+

Delete Dealer

+

Are you sure you want to delete the dealer ""?

+
+ + No, Cancel +
+
+ + diff --git a/admin/edit_dealer.php b/admin/edit_dealer.php new file mode 100644 index 0000000..04a0497 --- /dev/null +++ b/admin/edit_dealer.php @@ -0,0 +1,68 @@ +prepare("UPDATE dealers SET name = ?, email = ? WHERE id = ?"); + if ($stmt->execute([$name, $email, $dealer_id])) { + $success = 'Dealer updated successfully.'; + } else { + $error = 'Failed to update dealer.'; + } + } +} + +$stmt = $pdo->prepare("SELECT * FROM dealers WHERE id = ?"); +$stmt->execute([$dealer_id]); +$dealer = $stmt->fetch(); + +if (!$dealer) { + header('Location: manage_dealers.php'); + exit; +} +?> + +
+

Edit Dealer

+ +
+ + +
+ +
+
+ + +
+
+ + +
+ +
+
+ + diff --git a/admin/import_products.php b/admin/import_products.php new file mode 100644 index 0000000..b656e39 --- /dev/null +++ b/admin/import_products.php @@ -0,0 +1,61 @@ +beginTransaction(); + + try { + $stmt = $pdo->prepare("INSERT INTO products (name, model_number, description, image_url, price, category_id, features, sample_type, measurement_parameters, result_speed) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"); + + fgetcsv($handle); // Skip header row + + while (($data = fgetcsv($handle, 1000, ",")) !== FALSE) { + //Pad the array with nulls if it doesn't have enough elements + $data = array_pad($data, 10, null); + $stmt->execute($data); + } + + $pdo->commit(); + $message = "
Products imported successfully.
"; + } catch (Exception $e) { + $pdo->rollBack(); + $message = "
Error importing products: " . $e->getMessage() . "
"; + } + + fclose($handle); + } else { + $message = "
Error opening the CSV file.
"; + } +} +?> + +

Import Products from CSV

+ + + +

Upload a CSV file with the following columns: `name`, `model_number`, `description`, `image_url`, `price`, `category_id`, `features`, `sample_type`, `measurement_parameters`, `result_speed`.

+

The `category_id` should correspond to an existing ID in the `product_categories` table.

+ +
+
+ + +
+ +
+ +

Back to Admin

+ + diff --git a/admin/index.php b/admin/index.php new file mode 100644 index 0000000..bd1bf7d --- /dev/null +++ b/admin/index.php @@ -0,0 +1,23 @@ + + +
+

Admin Panel

+

Welcome to the admin panel. Here you can manage users, products, and other settings.

+ Manage Dealers + Reports + Import Products +
+ + \ No newline at end of file diff --git a/admin/manage_dealers.php b/admin/manage_dealers.php new file mode 100644 index 0000000..204c6b5 --- /dev/null +++ b/admin/manage_dealers.php @@ -0,0 +1,47 @@ +query("SELECT * FROM dealers"); +$dealers = $stmt->fetchAll(); + +?> + +
+

Manage Dealers

+ Add Dealer + + + + + + + + + + + + + + + + + + + +
IDNameEmailActions
+ Edit + Delete +
+
+ + \ No newline at end of file diff --git a/admin/reports.php b/admin/reports.php new file mode 100644 index 0000000..6f66c23 --- /dev/null +++ b/admin/reports.php @@ -0,0 +1,113 @@ +query("SELECT id, name FROM dealers ORDER BY name ASC"); +$dealers = $stmt_dealers->fetchAll(); + +// Get filter values +$status_filter = $_GET['status'] ?? ''; +$dealer_filter = $_GET['dealer_id'] ?? ''; + +$sql = "SELECT sr.*, p.name as product_name, d.name as dealer_name + FROM service_requests sr + JOIN products p ON sr.product_id = p.id + JOIN dealers d ON sr.dealer_id = d.id"; + +$where_clauses = []; +$params = []; + +if (!empty($status_filter)) { + $where_clauses[] = "sr.status = ?"; + $params[] = $status_filter; +} + +if (!empty($dealer_filter)) { + $where_clauses[] = "sr.dealer_id = ?"; + $params[] = $dealer_filter; +} + +if (!empty($where_clauses)) { + $sql .= " WHERE " . implode(" AND ", $where_clauses); +} + +$sql .= " ORDER BY sr.created_at DESC"; + +$stmt = $pdo->prepare($sql); +$stmt->execute($params); +$service_requests = $stmt->fetchAll(); + +?> + +
+

Service Request Report

+ +
+
+
+
+ + +
+
+
+
+ + +
+
+
+
+ + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
IDDealerProductSerialStatusDate
+
+ + diff --git a/api/get_product_details.php b/api/get_product_details.php new file mode 100644 index 0000000..19caed5 --- /dev/null +++ b/api/get_product_details.php @@ -0,0 +1,32 @@ +prepare( + "SELECT p.name, p.model_number, p.part_number, p.description, p.image_url + FROM products p + JOIN sold_serials ss ON p.id = ss.product_id + WHERE ss.id = ?" + ); + $stmt->execute([$sold_serial_id]); + $product = $stmt->fetch(); + + if ($product) { + header('Content-Type: application/json'); + echo json_encode($product); + } else { + header("HTTP/1.0 404 Not Found"); + echo json_encode(['error' => 'Product not found']); + } + } catch (PDOException $e) { + header("HTTP/1.0 500 Internal Server Error"); + echo json_encode(['error' => 'Database error: ' . $e->getMessage()]); + } +} else { + header("HTTP/1.0 400 Bad Request"); + echo json_encode(['error' => 'No serial ID provided']); +} diff --git a/assets/css/custom.css b/assets/css/custom.css new file mode 100644 index 0000000..508e463 --- /dev/null +++ b/assets/css/custom.css @@ -0,0 +1,23 @@ +body { + background-color: #f8f9fa; +} + +.navbar { + box-shadow: 0 2px 4px rgba(0,0,0,.1); +} + +.card { + border-radius: 0.375rem; + box-shadow: 0 4px 6px rgba(0,0,0,.05); +} + +.btn-primary { + background-color: #0d6efd; + border: none; +} + +.footer { + position: absolute; + bottom: 0; + width: 100%; +} \ No newline at end of file diff --git a/assets/vm-shot-2025-12-09T05-39-13-528Z.jpg b/assets/vm-shot-2025-12-09T05-39-13-528Z.jpg new file mode 100644 index 0000000000000000000000000000000000000000..c206cea3d20df9046da9a451e636f742ed1e05f1 GIT binary patch literal 24872 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 0) { + if (isset($_SESSION['cart'][$product_id])) { + $_SESSION['cart'][$product_id] += $quantity; + } else { + $_SESSION['cart'][$product_id] = $quantity; + } + } + } + header('Location: products.php'); + exit; + + case 'update': + if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['quantities'])) { + foreach ($_POST['quantities'] as $product_id => $quantity) { + $quantity = (int)$quantity; + if ($quantity > 0) { + $_SESSION['cart'][$product_id] = $quantity; + } else { + unset($_SESSION['cart'][$product_id]); + } + } + } + header('Location: cart.php'); + exit; + + case 'place_order': + if ($_SERVER['REQUEST_METHOD'] === 'POST' && !empty($_SESSION['cart'])) { + + + $total_amount = 0; + $cart_products = []; + + $product_ids = array_keys($_SESSION['cart']); + if (empty($product_ids)) { + header('Location: cart.php'); + exit; + } + + $sql = "SELECT * FROM products WHERE id IN (" . implode(',', array_fill(0, count($product_ids), '?')) . ")"; + $stmt = $pdo->prepare($sql); + $stmt->execute($product_ids); + $products_array = $stmt->fetchAll(PDO::FETCH_ASSOC); + $products = []; + foreach ($products_array as $product) { + $products[$product['id']] = $product; + } + + // Debug: Dump products array + // var_dump($products); + + foreach ($_SESSION['cart'] as $product_id => $quantity) { + if (isset($products[$product_id])) { + $product = $products[$product_id]; + $price = $product['price'] ?? 0; + $total_amount += $price * $quantity; + $cart_products[] = ['product' => $product, 'quantity' => $quantity]; + } + } + + // Debug: Dump total amount + // var_dump($total_amount); + + if ($total_amount > 0) { + $pdo->beginTransaction(); + try { + $sql = 'INSERT INTO orders (user_id, total_amount, status) VALUES (?, ?, ?)'; + $stmt = $pdo->prepare($sql); + $stmt->execute([$_SESSION['user_id'], $total_amount, 'Pending']); + $order_id = $pdo->lastInsertId(); + + $sql = 'INSERT INTO order_items (order_id, product_id, quantity, price) VALUES (?, ?, ?, ?)'; + $stmt = $pdo->prepare($sql); + foreach ($cart_products as $item) { + // Use the price from the database, not the one from the session/cart loop + $product_price = $products[$item['product']['id']]['price'] ?? 0; + $stmt->execute([$order_id, $item['product']['id'], $item['quantity'], $product_price]); + } + + $pdo->commit(); + $_SESSION['cart'] = []; + header('Location: order_details.php?id=' . $order_id); + exit; + } catch (Exception $e) { + $pdo->rollBack(); + // Debug: Log exception + error_log($e->getMessage()); + header('Location: cart.php?error=place_order_failed'); + exit; + } + } else { + header('Location: cart.php?error=zero_total'); + exit; + } + } + header('Location: cart.php'); + exit; +} + +// Display Cart +$cart_items = []; +$total_price = 0; + +if (!empty($_SESSION['cart'])) { + $product_ids = array_keys($_SESSION['cart']); + $sql = "SELECT * FROM products WHERE id IN (" . implode(',', array_fill(0, count($product_ids), '?')) . ")"; + $stmt = $pdo->prepare($sql); + $stmt->execute($product_ids); + $products = $stmt->fetchAll(); + + foreach ($products as $product) { + $product_id = $product['id']; + $quantity = $_SESSION['cart'][$product_id]; + $price = $product['price'] ?? 0; + $cart_items[] = ['product' => $product, 'quantity' => $quantity, 'price' => $price]; + $total_price += $price * $quantity; + } +} +?> + +

Shopping Cart

+ + +
Your cart is empty.
+ +
+ + + + + + + + + + + + + + + + + + + +
ProductPriceQuantityTotal
$ + + $
+
+ +

Total: $

+
+
+
+ +
+ + + \ No newline at end of file diff --git a/db/migration_001_warranty.php b/db/migration_001_warranty.php new file mode 100644 index 0000000..565b482 --- /dev/null +++ b/db/migration_001_warranty.php @@ -0,0 +1,19 @@ +exec($sql); + echo "Table 'warranty_registrations' created successfully." . PHP_EOL; +} catch (PDOException $e) { + die("DB ERROR: " . $e->getMessage()); +} +?> \ No newline at end of file diff --git a/db/migration_002_products.php b/db/migration_002_products.php new file mode 100644 index 0000000..39ebf1f --- /dev/null +++ b/db/migration_002_products.php @@ -0,0 +1,18 @@ +exec($sql); + echo "Table 'products' created successfully." . PHP_EOL; +} catch (PDOException $e) { + die("DB ERROR: " . $e->getMessage()); +} diff --git a/db/migration_003_dealers.php b/db/migration_003_dealers.php new file mode 100644 index 0000000..51ac424 --- /dev/null +++ b/db/migration_003_dealers.php @@ -0,0 +1,18 @@ +exec($sql); + echo "Table 'dealers' created successfully." . PHP_EOL; +} catch (PDOException $e) { + die("DB ERROR: " . $e->getMessage()); +} diff --git a/db/migration_004_sold_serials.php b/db/migration_004_sold_serials.php new file mode 100644 index 0000000..ebfa848 --- /dev/null +++ b/db/migration_004_sold_serials.php @@ -0,0 +1,22 @@ +exec($sql); + echo "Table 'sold_serials' created successfully." . PHP_EOL; +} catch (PDOException $e) { + die("DB ERROR: " . $e->getMessage()); +} diff --git a/db/migration_005_alter_warranty.php b/db/migration_005_alter_warranty.php new file mode 100644 index 0000000..b6125fd --- /dev/null +++ b/db/migration_005_alter_warranty.php @@ -0,0 +1,22 @@ +exec($sql_add_column); + + // Add foreign key constraint + $sql_add_fk = "ALTER TABLE warranty_registrations ADD CONSTRAINT fk_sold_serial FOREIGN KEY (sold_serial_id) REFERENCES sold_serials(id) ON DELETE SET NULL"; + $pdo->exec($sql_add_fk); + + echo "Table 'warranty_registrations' modified successfully." . PHP_EOL; + +} catch (PDOException $e) { + // Check if column already exists to avoid fatal error on re-run + if (strpos($e->getMessage(), 'Duplicate column name') === false) { + die("DB ERROR: " . $e->getMessage()); + } + echo "Column 'sold_serial_id' already exists in 'warranty_registrations'." . PHP_EOL; +} diff --git a/db/migration_006_users.php b/db/migration_006_users.php new file mode 100644 index 0000000..7deea75 --- /dev/null +++ b/db/migration_006_users.php @@ -0,0 +1,21 @@ +exec($sql); + echo "Migration for users table applied successfully." . PHP_EOL; +} catch (PDOException $e) { + die("Migration failed: " . $e->getMessage()); +} diff --git a/db/migration_007_alter_products.php b/db/migration_007_alter_products.php new file mode 100644 index 0000000..3574772 --- /dev/null +++ b/db/migration_007_alter_products.php @@ -0,0 +1,15 @@ +exec($sql); + echo "Migration to add description and image_url to products table applied successfully." . PHP_EOL; +} catch (PDOException $e) { + die("Migration failed: " . $e->getMessage()); +} diff --git a/db/migration_008_service_requests.php b/db/migration_008_service_requests.php new file mode 100644 index 0000000..5aa9b12 --- /dev/null +++ b/db/migration_008_service_requests.php @@ -0,0 +1,24 @@ +exec($sql); + echo "Migration for service_requests table applied successfully." . PHP_EOL; +} catch (PDOException $e) { + die("Migration failed: " . $e->getMessage()); +} diff --git a/db/migration_009_service_request_comments.php b/db/migration_009_service_request_comments.php new file mode 100644 index 0000000..0e8028a --- /dev/null +++ b/db/migration_009_service_request_comments.php @@ -0,0 +1,21 @@ +exec($sql); + echo "Migration for service_request_comments table applied successfully." . PHP_EOL; +} catch (PDOException $e) { + die("Migration failed: " . $e->getMessage()); +} diff --git a/db/migration_010_add_is_admin_to_users.php b/db/migration_010_add_is_admin_to_users.php new file mode 100644 index 0000000..68ba199 --- /dev/null +++ b/db/migration_010_add_is_admin_to_users.php @@ -0,0 +1,11 @@ +exec($sql); + echo "Migration to add is_admin to users table applied successfully." . PHP_EOL; +} catch (PDOException $e) { + die("Migration failed: " . $e->getMessage()); +} diff --git a/db/migration_011_add_file_path_to_service_requests.php b/db/migration_011_add_file_path_to_service_requests.php new file mode 100644 index 0000000..3392ab1 --- /dev/null +++ b/db/migration_011_add_file_path_to_service_requests.php @@ -0,0 +1,11 @@ +exec($sql); + echo "Migration to add file_path to service_requests table applied successfully." . PHP_EOL; +} catch (PDOException $e) { + die("Migration failed: " . $e->getMessage()); +} diff --git a/db/migration_012_create_notifications_table.php b/db/migration_012_create_notifications_table.php new file mode 100644 index 0000000..9feb3a9 --- /dev/null +++ b/db/migration_012_create_notifications_table.php @@ -0,0 +1,22 @@ +exec($sql); + echo "Migration for notifications table applied successfully." . PHP_EOL; +} catch (PDOException $e) { + die("Migration failed: " . $e->getMessage()); +} diff --git a/db/migration_013_add_user_id_to_service_requests.php b/db/migration_013_add_user_id_to_service_requests.php new file mode 100644 index 0000000..3e15806 --- /dev/null +++ b/db/migration_013_add_user_id_to_service_requests.php @@ -0,0 +1,13 @@ +exec($sql); + $sql_fk = "ALTER TABLE service_requests ADD FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE"; + $pdo->exec($sql_fk); + echo "Migration to add user_id to service_requests table applied successfully." . PHP_EOL; +} catch (PDOException $e) { + die("Migration failed: " . $e->getMessage()); +} diff --git a/db/migration_014_create_product_categories.php b/db/migration_014_create_product_categories.php new file mode 100644 index 0000000..f458534 --- /dev/null +++ b/db/migration_014_create_product_categories.php @@ -0,0 +1,19 @@ +exec($sql); + echo "Table 'product_categories' created successfully." . PHP_EOL; +} catch (PDOException $e) { + die("Error creating table: " . $e->getMessage()); +} +?> \ No newline at end of file diff --git a/db/migration_015_alter_products_add_details.php b/db/migration_015_alter_products_add_details.php new file mode 100644 index 0000000..5cad415 --- /dev/null +++ b/db/migration_015_alter_products_add_details.php @@ -0,0 +1,20 @@ +exec($sql); + echo "Table 'products' altered successfully." . PHP_EOL; +} catch (PDOException $e) { + die("Error altering table: " . $e->getMessage()); +} +?> \ No newline at end of file diff --git a/db/migration_016_create_orders_table.php b/db/migration_016_create_orders_table.php new file mode 100644 index 0000000..f23ef7e --- /dev/null +++ b/db/migration_016_create_orders_table.php @@ -0,0 +1,21 @@ +exec($sql); + echo "Table 'orders' created successfully." . PHP_EOL; +} catch (PDOException $e) { + die("Error creating table: " . $e->getMessage()); +} +?> \ No newline at end of file diff --git a/db/migration_017_create_order_items_table.php b/db/migration_017_create_order_items_table.php new file mode 100644 index 0000000..92350dc --- /dev/null +++ b/db/migration_017_create_order_items_table.php @@ -0,0 +1,23 @@ +exec($sql); + echo "Table 'order_items' created successfully." . PHP_EOL; +} catch (PDOException $e) { + die("Error creating table: " . $e->getMessage()); +} +?> \ No newline at end of file diff --git a/db/migration_018_add_dealer_kpis.php b/db/migration_018_add_dealer_kpis.php new file mode 100644 index 0000000..3c66cbd --- /dev/null +++ b/db/migration_018_add_dealer_kpis.php @@ -0,0 +1,17 @@ +exec($sql); + echo "Table 'dealers' updated successfully." . PHP_EOL; +} catch (PDOException $e) { + die("DB ERROR: " . $e->getMessage()); +} diff --git a/db/migration_019_add_paid_amount_to_invoices.php b/db/migration_019_add_paid_amount_to_invoices.php new file mode 100644 index 0000000..c159ee3 --- /dev/null +++ b/db/migration_019_add_paid_amount_to_invoices.php @@ -0,0 +1,14 @@ +exec($sql); + echo "Table 'invoices' updated successfully." . PHP_EOL; +} catch (PDOException $e) { + die("DB ERROR: " . $e->getMessage()); +} diff --git a/db/migration_020_add_dealer_id_to_orders.php b/db/migration_020_add_dealer_id_to_orders.php new file mode 100644 index 0000000..5b8e096 --- /dev/null +++ b/db/migration_020_add_dealer_id_to_orders.php @@ -0,0 +1,38 @@ +exec("SET FOREIGN_KEY_CHECKS=0;"); + + $sql = <<exec($sql); + + $sql_update = <<exec($sql_update); + + $sql_alter = <<exec($sql_alter); + + $sql_fk = <<exec($sql_fk); + + $pdo->exec("SET FOREIGN_KEY_CHECKS=1;"); + + echo "Table 'orders' updated successfully." . PHP_EOL; +} catch (PDOException $e) { + die("DB ERROR: " . $e->getMessage()); +} diff --git a/db/migration_021_fix_orders_dealer_id.php b/db/migration_021_fix_orders_dealer_id.php new file mode 100644 index 0000000..8ff1bee --- /dev/null +++ b/db/migration_021_fix_orders_dealer_id.php @@ -0,0 +1,26 @@ +exec("SET FOREIGN_KEY_CHECKS=0;"); + + $sql_update = <<exec($sql_update); + + $sql_fk = <<exec($sql_fk); + + $pdo->exec("SET FOREIGN_KEY_CHECKS=1;"); + + echo "Table 'orders' fixed successfully." . PHP_EOL; +} catch (PDOException $e) { + die("DB ERROR: " . $e->getMessage()); +} diff --git a/db/seed_data.php b/db/seed_data.php new file mode 100644 index 0000000..7bfc366 --- /dev/null +++ b/db/seed_data.php @@ -0,0 +1,74 @@ +exec("SET FOREIGN_KEY_CHECKS = 0;"); + $pdo->exec("TRUNCATE TABLE order_items;"); + $pdo->exec("TRUNCATE TABLE orders;"); + $pdo->exec("TRUNCATE TABLE notifications;"); + $pdo->exec("TRUNCATE TABLE service_request_comments;"); + $pdo->exec("TRUNCATE TABLE service_requests;"); + $pdo->exec("TRUNCATE TABLE sold_serials;"); + $pdo->exec("TRUNCATE TABLE warranty_registrations;"); + $pdo->exec("TRUNCATE TABLE users;"); + $pdo->exec("TRUNCATE TABLE dealers;"); + $pdo->exec("TRUNCATE TABLE products;"); + $pdo->exec("TRUNCATE TABLE product_categories;"); + $pdo->exec("SET FOREIGN_KEY_CHECKS = 1;"); + + echo "Tables truncated successfully.\n"; + + // Seed Dealers + $dealers = [ + ['Dealer One', 'contact1@dealerone.com'], + ['Dealer Two', 'contact2@dealertwo.com'], + ]; + $stmt = $pdo->prepare("INSERT INTO dealers (name, email) VALUES (?, ?)"); + foreach ($dealers as $dealer) { + $stmt->execute($dealer); + } + echo "Dealers seeded successfully.\n"; + + // Get Dealer One ID + $stmt = $pdo->prepare("SELECT id FROM dealers WHERE name = ?"); + $stmt->execute(['Dealer One']); + $dealer1_id = $stmt->fetchColumn(); + + // Seed Users + $users = [ + ['dealer', password_hash('password', PASSWORD_DEFAULT), $dealer1_id, 0], + ['admin', password_hash('admin', PASSWORD_DEFAULT), null, 1], + ]; + $stmt = $pdo->prepare("INSERT INTO users (username, password_hash, dealer_id, is_admin) VALUES (?, ?, ?, ?)"); + foreach ($users as $user) { + $stmt->execute($user); + } + echo "Users seeded successfully.\n"; + + // Seed Product Categories + $categories = ['Analyzers', 'Reagents', 'Consumables']; + $stmt = $pdo->prepare("INSERT INTO product_categories (name) VALUES (?)"); + foreach ($categories as $category) { + $stmt->execute([$category]); + } + echo "Product categories seeded successfully.\n"; + + // Seed Products + $products = [ + ['Sensa-100 Analyzer', 'SENSA-100', 'Advanced blood gas analyzer.', 'assets/images/products/sensa-100.jpg', 1, 15000.00, 'features of Sensa-100'], + ['Sensa-200 Electrolyte Analyzer', 'SENSA-200', 'Automated electrolyte analysis.', 'assets/images/products/sensa-200.jpg', 1, 25000.00, 'features of Sensa-200'], + ['Blood Gas Reagent Kit', 'REAGENT-BG', 'Reagent kit for Sensa-100.', 'assets/images/products/reagent-bg.jpg', 2, 500.00, 'features of Reagent-BG'], + ['Replacement Electrode', 'CONSUME-ELECTRODE', 'Replacement electrode for analyzers.', 'assets/images/products/electrode.jpg', 3, 250.00, 'features of Electrode'] + ]; + $stmt = $pdo->prepare("INSERT INTO products (name, model_number, description, image_url, category_id, price, features) VALUES (?, ?, ?, ?, ?, ?, ?)"); + foreach ($products as $product) { + $stmt->execute($product); + } + echo "Products seeded successfully.\n"; + +} catch (PDOException $e) { + die("DB ERROR: " . $e->getMessage()); +} diff --git a/db/seed_invoices.php b/db/seed_invoices.php new file mode 100644 index 0000000..26e00c7 --- /dev/null +++ b/db/seed_invoices.php @@ -0,0 +1,59 @@ +query("SELECT id, dealer_id FROM users WHERE dealer_id IS NOT NULL AND dealer_id != 0 LIMIT 1"); + $user = $stmt->fetch(); + + if (!$user) { + // Create a dealer + $stmt = $pdo->prepare("INSERT INTO dealers (name, email) VALUES (?, ?)"); + $stmt->execute(['Dummy Dealer', 'dummy@dealer.com']); + $dealer_id = $pdo->lastInsertId(); + + // Create a user + $stmt = $pdo->prepare("INSERT INTO users (dealer_id, username, password_hash) VALUES (?, ?, ?)"); + $stmt->execute([$dealer_id, 'dummyuser', password_hash('password', PASSWORD_DEFAULT)]); + $user_id = $pdo->lastInsertId(); + } else { + $user_id = $user['id']; + $dealer_id = $user['dealer_id']; + } + + // Check for orders + $stmt = $pdo->prepare("SELECT id FROM orders WHERE user_id = ? LIMIT 5"); + $stmt->execute([$user_id]); + $orders = $stmt->fetchAll(PDO::FETCH_COLUMN); + + if (count($orders) < 5) { + // Create some orders if there aren't enough + $stmt = $pdo->prepare("INSERT INTO orders (user_id, dealer_id, total_amount, status) VALUES (?, ?, ?, ?)"); + for ($i = 0; $i < 5; $i++) { + $total_amount = rand(100, 1000); + $stmt->execute([$user_id, $dealer_id, $total_amount, 'Completed']); + } + $stmt = $pdo->prepare("SELECT id FROM orders WHERE user_id = ? LIMIT 5"); + $stmt->execute([$user_id]); + $orders = $stmt->fetchAll(PDO::FETCH_COLUMN); + } + + $stmt = $pdo->prepare("INSERT INTO invoices (dealer_id, order_id, invoice_date, due_date, total_amount, status, paid_amount) VALUES (?, ?, ?, ?, ?, ?, ?)"); + + foreach ($orders as $order_id) { + $invoice_date = date('Y-m-d', strtotime('-' . rand(1, 30) . ' days')); + $due_date = date('Y-m-d', strtotime($invoice_date . ' +30 days')); + $total_amount = rand(100, 1000); + $paid_amount = rand(0, $total_amount); + $status = ($paid_amount == $total_amount) ? 'paid' : 'pending'; + + $stmt->execute([$dealer_id, $order_id, $invoice_date, $due_date, $total_amount, $status, $paid_amount]); + } + + echo "Dummy invoices created successfully." . PHP_EOL; + +} catch (PDOException $e) { + die("DB ERROR: " . $e->getMessage()); +} \ No newline at end of file diff --git a/delete_shipment_details.php b/delete_shipment_details.php new file mode 100644 index 0000000..5085278 --- /dev/null +++ b/delete_shipment_details.php @@ -0,0 +1,36 @@ +prepare("SELECT service_request_id FROM shipment_details WHERE id = ?"); + $stmt_get_id->execute([$shipment_id]); + $service_request_id = $stmt_get_id->fetchColumn(); + + if ($service_request_id) { + $stmt_delete = $pdo->prepare("DELETE FROM shipment_details WHERE id = ?"); + $stmt_delete->execute([$shipment_id]); + header("Location: service_request_details.php?id=$service_request_id"); + } else { + header('Location: service_requests.php'); + } + exit; + +} catch (PDOException $e) { + die("Database error: " . $e->getMessage()); +} diff --git a/edit_shipment_details.php b/edit_shipment_details.php new file mode 100644 index 0000000..cca2574 --- /dev/null +++ b/edit_shipment_details.php @@ -0,0 +1,87 @@ +prepare("SELECT * FROM shipment_details WHERE id = ?"); + $stmt->execute([$shipment_id]); + $shipment = $stmt->fetch(); + + if (!$shipment) { + header('Location: service_requests.php'); + exit; + } + + $service_request_id = $shipment['service_request_id']; + + if ($_SERVER['REQUEST_METHOD'] === 'POST') { + $carrier = trim($_POST['carrier']); + $tracking_number = trim($_POST['tracking_number']); + $shipment_date = trim($_POST['shipment_date']); + + if (empty($carrier) || empty($tracking_number) || empty($shipment_date)) { + $error_message = "All fields are required."; + } else { + $stmt_update = $pdo->prepare( + "UPDATE shipment_details SET carrier = ?, tracking_number = ?, shipment_date = ? WHERE id = ?" + ); + $stmt_update->execute([$carrier, $tracking_number, $shipment_date, $shipment_id]); + + header("Location: service_request_details.php?id=$service_request_id"); + exit; + } + } +} catch (PDOException $e) { + die("Database error: " . $e->getMessage()); +} +?> + +
+
+
+
+

Edit Shipment Details

+
+
+ + + +
+
+ + +
+
+ + +
+
+ + +
+ + Cancel +
+
+
+
+
+ + diff --git a/includes/footer.php b/includes/footer.php new file mode 100644 index 0000000..68fbc16 --- /dev/null +++ b/includes/footer.php @@ -0,0 +1,11 @@ + + +
+
+ © 2025 Sensa Core. All rights reserved. +
+
+ + + + \ No newline at end of file diff --git a/includes/header.php b/includes/header.php new file mode 100644 index 0000000..c49265b --- /dev/null +++ b/includes/header.php @@ -0,0 +1,100 @@ + + + + + + + Sensa Core Dealer Portal + + + + + + + + +
diff --git a/index.php b/index.php index 7205f3d..0a96ed4 100644 --- a/index.php +++ b/index.php @@ -1,150 +1,114 @@ prepare("SELECT COUNT(*) FROM service_requests WHERE dealer_id = ? AND status = 'pending'"); + $stmt_pending_requests->execute([$dealer_id]); + $pending_requests_count = $stmt_pending_requests->fetchColumn(); + + // Fetch unactivated warranties + $stmt_unactivated_warranties = $pdo->prepare("SELECT COUNT(*) FROM sold_serials WHERE dealer_id = ? AND is_activated = FALSE"); + $stmt_unactivated_warranties->execute([$dealer_id]); + $unactivated_warranties_count = $stmt_unactivated_warranties->fetchColumn(); + + // Fetch total products + $stmt_products = $pdo->query("SELECT COUNT(*) FROM products"); + $products_count = $stmt_products->fetchColumn(); + +} catch (PDOException $e) { + // For simplicity, we'll just display 0 if there's a db error. + $pending_requests_count = 0; + $unactivated_warranties_count = 0; + $products_count = 0; + $open_invoices_count = 0; + $total_due = 0; +} + +// Fetch open invoices summary +try { + $user_id = $_SESSION['user_id']; + $is_admin = $_SESSION['is_admin'] ?? false; + + $sql = "SELECT COUNT(*) as count, SUM(total_amount) as total FROM invoices WHERE status = 'open'"; + $params = []; + + if (!$is_admin) { + $sql .= " AND dealer_id = ?"; + $params[] = $user_id; + } + + $stmt_invoices = $pdo->prepare($sql); + $stmt_invoices->execute($params); + $invoices_summary = $stmt_invoices->fetch(); + $open_invoices_count = $invoices_summary['count'] ?? 0; + $total_due = $invoices_summary['total'] ?? 0; +} catch (PDOException $e) { + $open_invoices_count = 0; + $total_due = 0; +} -$phpVersion = PHP_VERSION; -$now = date('Y-m-d H:i:s'); ?> - - - - - - 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

+ +
+
+
+
+
Pending Service Requests
+

+ View Details +
+
-
-
- Page updated: (UTC) -
- - +
+
+
+
Unactivated Warranties
+

+ Register Now +
+
+
+
+
+
+
Total Products
+

+ Browse Catalog +
+
+
+
+
+
+
Open Invoices
+

+

Total Due: $

+ View Invoices +
+
+
+
+ + +
+
+

Sensa Core Dealer Portal

+

Welcome to the central hub for sales, service, and finance operations. Manage your orders, register warranties, and track service requests all in one place.

+
+
+ + + \ No newline at end of file diff --git a/invoice_details.php b/invoice_details.php new file mode 100644 index 0000000..5c48dac --- /dev/null +++ b/invoice_details.php @@ -0,0 +1,105 @@ +prepare($sql); + $stmt->execute([$invoice_id]); + $invoice = $stmt->fetch(); + + if (!$invoice) { + die('Invoice not found.'); + } + +} catch (PDOException $e) { + die("Database error: " . $e->getMessage()); +} +?> + +

Invoice Details #

+ +
+
Invoice Information
+
+

Invoice ID:

+

Order ID:

+

Invoice Date:

+

Due Date:

+

Total Amount: $

+

Status:

+
+
+ +
+
Payments
+
+ + + + + + + + + + prepare($sql); + $stmt->execute([$invoice_id]); + $payments = $stmt->fetchAll(); + $total_paid = 0; + foreach ($payments as $payment) { + $total_paid += $payment['amount']; + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + } + ?> + +
Payment DateAmountPayment Method
' . htmlspecialchars($payment['payment_date']) . '$' . htmlspecialchars(number_format($payment['amount'], 2)) . '' . htmlspecialchars($payment['payment_method']) . '
+

Total Paid: $

+

Amount Due: $

+
+
+ + +
+
Post a Payment
+
+
+ +
+ + +
+
+ + +
+ +
+
+
+ + + \ No newline at end of file diff --git a/invoices.php b/invoices.php new file mode 100644 index 0000000..bccaa73 --- /dev/null +++ b/invoices.php @@ -0,0 +1,80 @@ +prepare($sql); + $stmt->execute($params); + $invoices = $stmt->fetchAll(); + +} catch (PDOException $e) { + die("Database error: " . $e->getMessage()); +} +?> + +

Invoices

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Invoice IDOrder IDInvoice DateDue DateTotal AmountPaid AmountBalanceAge of InvoiceStatusActions
$$$diff($invoice_date)->days; + echo $age . ' days'; + ?> + View Details +
+ + \ No newline at end of file diff --git a/login.php b/login.php new file mode 100644 index 0000000..0870a7a --- /dev/null +++ b/login.php @@ -0,0 +1,58 @@ +prepare("SELECT * FROM users WHERE username = ?"); + $stmt->execute([$username]); + $user = $stmt->fetch(); + + if ($user && password_verify($password, $user['password_hash'])) { + $_SESSION['user_id'] = $user['id']; + $_SESSION['dealer_id'] = $user['dealer_id']; + $_SESSION['is_admin'] = $user['is_admin']; + header('Location: index.php'); + exit; + } else { + $error = 'Invalid username or password.'; + } + } +} +?> + +
+
+
+
+
+

Dealer Login

+ +
+ +
+
+ + +
+
+ + +
+ +
+
+
+
+
+
+ + diff --git a/logout.php b/logout.php new file mode 100644 index 0000000..95db42c --- /dev/null +++ b/logout.php @@ -0,0 +1,6 @@ +prepare("UPDATE notifications SET is_read = 1 WHERE user_id = ?"); + $stmt->execute([$user_id]); + header('Location: notifications.php'); + exit; +} + +$stmt = $pdo->prepare("SELECT * FROM notifications WHERE user_id = ? ORDER BY created_at DESC"); +$stmt->execute([$user_id]); +$notifications = $stmt->fetchAll(); + +?> + +
+

Notifications

+
+ +
+
    + +
  • + +

    + +
    +
  • + + +
  • You have no notifications.
  • + +
+
+ + diff --git a/order_details.php b/order_details.php new file mode 100644 index 0000000..b794ff8 --- /dev/null +++ b/order_details.php @@ -0,0 +1,78 @@ +prepare($sql); +$stmt->execute([$order_id, $_SESSION['user_id']]); +$order = $stmt->fetch(); + +if (!$order) { + header('Location: orders.php'); + exit; +} + +// Fetch order items +$sql = " + SELECT oi.*, p.name as product_name + FROM order_items oi + JOIN products p ON oi.product_id = p.id + WHERE oi.order_id = ? +"; +$stmt = $pdo->prepare($sql); +$stmt->execute([$order_id]); +$order_items = $stmt->fetchAll(); + +?> + +

Order Details #

+ +
+
+
Order Summary
+

Total Amount: $

+

Status:

+

Date:

+
+
+ +

Items in this Order

+ + + + + + + + + + + + + + + + + + + + +
ProductQuantityPriceTotal
$$
+ +Back to Orders + + diff --git a/orders.php b/orders.php new file mode 100644 index 0000000..1a8abfb --- /dev/null +++ b/orders.php @@ -0,0 +1,72 @@ +prepare($sql); +$stmt->execute($params); +$orders = $stmt->fetchAll(); + +?> + +

My Orders

+ + + + +
+ You have no orders with the status ''. +
+ + + + + + + + + + + + + + + + + + + + + + +
Order IDTotal AmountStatusDate
#$View Details
+ + + diff --git a/post_payment.php b/post_payment.php new file mode 100644 index 0000000..bb666ca --- /dev/null +++ b/post_payment.php @@ -0,0 +1,46 @@ +prepare($sql); + $stmt->execute([$invoice_id, $payment_date, $amount, $payment_method]); + + // Update invoice status if fully paid + $sql = "SELECT i.total_amount, SUM(p.amount) as total_paid FROM invoices i LEFT JOIN payments p ON i.id = p.invoice_id WHERE i.id = ? GROUP BY i.id"; + $stmt = $pdo->prepare($sql); + $stmt->execute([$invoice_id]); + $invoice_data = $stmt->fetch(); + + if ($invoice_data['total_paid'] >= $invoice_data['total_amount']) { + $sql = "UPDATE invoices SET status = 'paid' WHERE id = ?"; + $stmt = $pdo->prepare($sql); + $stmt->execute([$invoice_id]); + } + + header('Location: invoice_details.php?id=' . $invoice_id); + exit; + + } catch (PDOException $e) { + die("Database error: " . $e->getMessage()); + } +} else { + header('Location: invoices.php'); + exit; +} +?> \ No newline at end of file diff --git a/products.php b/products.php new file mode 100644 index 0000000..0dd3884 --- /dev/null +++ b/products.php @@ -0,0 +1,122 @@ +query("SELECT * FROM product_categories ORDER BY name ASC"); + $categories = $category_stmt->fetchAll(); + + // Get filter parameters + $search = $_GET['search'] ?? ''; + $selected_category = $_GET['category'] ?? ''; + + // Build product query + $sql = "SELECT p.*, c.name AS category_name FROM products p LEFT JOIN product_categories c ON p.category_id = c.id"; + $params = []; + $where_clauses = []; + + if ($search) { + $where_clauses[] = "(p.name LIKE ? OR p.model_number LIKE ?)"; + $params[] = '%' . $search . '%'; + $params[] = '%' . $search . '%'; + } + + if ($selected_category) { + $where_clauses[] = "p.category_id = ?"; + $params[] = $selected_category; + } + + if (!empty($where_clauses)) { + $sql .= " WHERE " . implode(" AND ", $where_clauses); + } + + $sql .= " ORDER BY p.name ASC"; + + $stmt = $pdo->prepare($sql); + $stmt->execute($params); + $products = $stmt->fetchAll(); + +} catch (PDOException $e) { + die("Database error: " . $e->getMessage()); +} +?> + +

Product Catalog

+ +
+
+
+ +
+
+ +
+
+ +
+
+
+ +
+ +
+

No products found.

+
+ + +
+
+ <?php echo htmlspecialchars($product['name']); ?> +
+
+

Price: $

+
Model:
+ +
Category:
+ +

+ + +

Features:

+ + +

Sample Type:

+ + +

Parameters:

+ + +

Result Speed:

+ +
+
+ +
+ + +
+
+
+
+
+
+ + +
+ + diff --git a/profile.php b/profile.php new file mode 100644 index 0000000..618fe01 --- /dev/null +++ b/profile.php @@ -0,0 +1,95 @@ +prepare("SELECT password_hash FROM users WHERE id = ?"); + $stmt->execute([$user_id]); + $user = $stmt->fetch(); + + if ($user && password_verify($current_password, $user['password_hash'])) { + $password_hash = password_hash($new_password, PASSWORD_DEFAULT); + $stmt = $pdo->prepare("UPDATE users SET password_hash = ? WHERE id = ?"); + if ($stmt->execute([$password_hash, $user_id])) { + $success = 'Password updated successfully.'; + } else { + $error = 'Failed to update password.'; + } + } else { + $error = 'Incorrect current password.'; + } + } +} + +$stmt = $pdo->prepare("SELECT * FROM users WHERE id = ?"); +$stmt->execute([$user_id]); +$user = $stmt->fetch(); + +?> + +
+

Profile

+
+
+
Your Information
+

Username:

+ + prepare("SELECT * FROM dealers WHERE id = ?"); + $stmt_dealer->execute([$user['dealer_id']]); + $dealer = $stmt_dealer->fetch(); + ?> +

Dealer:

+

Email:

+ +
+
+ +
+
+
Change Password
+ +
+ + +
+ +
+
+ + +
+
+ + +
+
+ + +
+ +
+
+
+
+ + diff --git a/service_request_details.php b/service_request_details.php new file mode 100644 index 0000000..5850fdb --- /dev/null +++ b/service_request_details.php @@ -0,0 +1,249 @@ +prepare( + "SELECT sr.* + FROM service_requests sr + WHERE sr.id = ? AND (sr.dealer_id = ? OR ?)" + ); + $stmt->execute([$request_id, $dealer_id, $_SESSION['is_admin']]); + $request = $stmt->fetch(); + + if (!$request) { + // Request not found or doesn't belong to the dealer + header('Location: service_requests.php'); + exit; + } + + // Fetch service request items + $stmt_items = $pdo->prepare( + "SELECT sri.serial_number, sri.issue_description, p.name as product_name + FROM service_request_items sri + JOIN products p ON sri.product_id = p.id + WHERE sri.service_request_id = ?" + ); + $stmt_items->execute([$request_id]); + $request_items = $stmt_items->fetchAll(); + + + // Handle comment submission + if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['comment'])) { + $comment = trim($_POST['comment']); + if (!empty($comment)) { + $stmt_insert_comment = $pdo->prepare( + "INSERT INTO service_request_comments (service_request_id, user_id, comment) VALUES (?, ?, ?)" + ); + $stmt_insert_comment->execute([$request_id, $_SESSION['user_id'], $comment]); + + // Create a notification + $current_user_id = $_SESSION['user_id']; + $request_owner_id = $request['user_id']; + + $message = "A new comment has been added to your service request #{$request_id}."; + + if ($current_user_id != $request_owner_id) { + // Notify the request owner + $stmt_notify = $pdo->prepare("INSERT INTO notifications (user_id, service_request_id, message) VALUES (?, ?, ?)"); + $stmt_notify->execute([$request_owner_id, $request_id, $message]); + } else { + // Notify all admins + $stmt_admins = $pdo->query("SELECT id FROM users WHERE is_admin = 1"); + $admins = $stmt_admins->fetchAll(PDO::FETCH_COLUMN); + $stmt_notify = $pdo->prepare("INSERT INTO notifications (user_id, service_request_id, message) VALUES (?, ?, ?)"); + foreach ($admins as $admin_id) { + if($admin_id != $current_user_id) { + $stmt_notify->execute([$admin_id, $request_id, $message]); + } + } + } + + // Redirect to the same page to prevent form resubmission + header("Location: service_request_details.php?id=$request_id"); + exit; + } + } + + // Fetch comments for the service request + $stmt_comments = $pdo->prepare( + "SELECT c.*, u.username + FROM service_request_comments c + JOIN users u ON c.user_id = u.id + WHERE c.service_request_id = ? + ORDER BY c.created_at ASC" + ); + $stmt_comments->execute([$request_id]); + $comments = $stmt_comments->fetchAll(); + +} catch (PDOException $e) { + die("Database error: " . $e->getMessage()); +} + +?> + + + +

Service Request Details

+ +
+
+
Request #
+ +
+
+
+
+

Submitted At:

+

Last Updated:

+
+
+
+
Products
+ + + + + + + + + + + + + + + + + +
Product NameSerial NumberIssue Description
+ +
+
Attached File
+

View Attached File

+ + + +
+
Update Status
+
+ +
+ + +
+
+ +
+
+ +
+
+
Shipment Details
+
+
+ prepare("SELECT * FROM shipment_details WHERE service_request_id = ?"); + $stmt_shipment->execute([$request_id]); + $shipments = $stmt_shipment->fetchAll(); + ?> + +

No shipment details available.

+ +

Only administrators and dealers can add shipment details.

+ + + + + + + + + + + + + + + + + + + + + + + + + +
CarrierTracking NumberShipment DateActions
+ Edit + Delete +
+ + +
+ + Add Shipment + +
+
+
+ +
+
+
Comments
+
+
+ +
+
+ +
+
+
+ +
+
+
+ + +

No comments yet.

+ +
+ +
+ + diff --git a/service_requests.php b/service_requests.php new file mode 100644 index 0000000..092ddc6 --- /dev/null +++ b/service_requests.php @@ -0,0 +1,227 @@ +query("SELECT id, name, model_number FROM products ORDER BY name ASC"); + $products = $stmt_products->fetchAll(); + + // Handle form submission + if ($_SERVER["REQUEST_METHOD"] == "POST") { + $submitted_products = $_POST['products'] ?? []; + $file_path = null; + + if (isset($_FILES['file_upload']) && $_FILES['file_upload']['error'] == UPLOAD_ERR_OK) { + $upload_dir = __DIR__ . '/uploads/'; + if (!is_dir($upload_dir)) { + mkdir($upload_dir, 0777, true); + } + + $file_name = uniqid('file_') . '_' . basename($_FILES['file_upload']['name']); + $target_file = $upload_dir . $file_name; + + if (move_uploaded_file($_FILES['file_upload']['tmp_name'], $target_file)) { + $file_path = 'uploads/' . $file_name; + } else { + $error_message = "Sorry, there was an error uploading your file."; + } + } + + if (empty($submitted_products)) { + $error_message = "Please add at least one product and provide an issue description."; + } else { + try { + $pdo->beginTransaction(); + + // Create the main service request + $sql_request = "INSERT INTO service_requests (dealer_id, user_id, file_path) VALUES (?, ?, ?)"; + $stmt_request = $pdo->prepare($sql_request); + $stmt_request->execute([$dealer_id, $_SESSION['user_id'], $file_path]); + $service_request_id = $pdo->lastInsertId(); + + // Add each product to the service_request_items table + $sql_item = "INSERT INTO service_request_items (service_request_id, product_id, serial_number, issue_description) VALUES (?, ?, ?, ?)"; + $stmt_item = $pdo->prepare($sql_item); + + foreach ($submitted_products as $product_data) { + $product_id = trim($product_data['product_id']); + $serial_number = trim($product_data['serial_number']); + $issue_description = trim($product_data['issue_description']); + if (!empty($product_id) && !empty($serial_number) && !empty($issue_description)) { + $stmt_item->execute([$service_request_id, $product_id, $serial_number, $issue_description]); + } + } + + $pdo->commit(); + $success_message = "Service request submitted successfully!"; + + } catch (PDOException $e) { + $pdo->rollBack(); + $error_message = "Failed to submit service request: " . $e->getMessage(); + } + } + } + + // Fetch existing service requests for the dealer + $stmt_requests = $pdo->prepare( + "SELECT sr.id, sr.status, sr.created_at, + GROUP_CONCAT(p.name SEPARATOR ', ') as product_names, + GROUP_CONCAT(sri.serial_number SEPARATOR ', ') as serial_numbers + FROM service_requests sr + LEFT JOIN service_request_items sri ON sr.id = sri.service_request_id + LEFT JOIN products p ON sri.product_id = p.id + WHERE sr.dealer_id = ? + GROUP BY sr.id + ORDER BY sr.created_at DESC" + ); + $stmt_requests->execute([$dealer_id]); + $service_requests = $stmt_requests->fetchAll(); + +} catch (PDOException $e) { + $error_message = "Database error: " . $e->getMessage(); +} + +?> + +
+
+
+
+

Submit a Service Request

+
+
+ +
+ + +
+ + +
+
+
+
+
+ + +
+
+ + +
+
+
+ + +
+
+
+ + +
+ + +
+ +
+
+
+
+
+
+
+

Your Service Requests

+
+
+ +

You have not submitted any service requests yet.

+ + + + + + + + + + + + + + + + + + + + + + + + +
Request IDProductsSerialsStatusDateActions
+ View Details +
+ +
+
+
+
+ + + + diff --git a/targets.php b/targets.php new file mode 100644 index 0000000..a34d3e8 --- /dev/null +++ b/targets.php @@ -0,0 +1,74 @@ +No dealer ID found in session."; + include_once 'includes/footer.php'; + exit(); +} + +$pdo = db(); +$stmt = $pdo->prepare("SELECT * FROM dealers WHERE id = ?"); +$stmt->execute([$dealer_id]); +$dealer = $stmt->fetch(); + +if (!$dealer) { + echo "
Dealer not found.
"; + include_once 'includes/footer.php'; + exit(); +} + +$target = $dealer['target'] ?? 0; +$achievement = $dealer['achievement'] ?? 0; +$credit_limit = $dealer['credit_limit'] ?? 0; +$credit_limit_utilisation = $dealer['credit_limit_utilisation'] ?? 0; + +$achievement_percentage = $target > 0 ? ($achievement / $target) * 100 : 0; +$credit_utilisation_percentage = $credit_limit > 0 ? ($credit_limit_utilisation / $credit_limit) * 100 : 0; +?> + +
+

Targets and Achievements

+
+
+
Targets
+

Your sales target for the current quarter is: $

+
+
+
+
+
Achievements
+

Your sales so far this quarter: $

+
+
%
+
+
+
+
+
+
Credit Limit
+

Your credit limit is: $

+
+
+
+
+
Credit Limit Utilisation
+

You have used: $

+
+
%
+
+
+
+
+ + \ No newline at end of file diff --git a/update_service_request_status.php b/update_service_request_status.php new file mode 100644 index 0000000..eb8d558 --- /dev/null +++ b/update_service_request_status.php @@ -0,0 +1,30 @@ +prepare($sql); + $stmt->execute([$status, $request_id]); + + header('Location: service_request_details.php?id=' . $request_id); + exit; + + } catch (PDOException $e) { + die("Database error: " . $e->getMessage()); + } +} else { + header('Location: service_requests.php'); + exit; +} +?> \ No newline at end of file diff --git a/warranty_registration.php b/warranty_registration.php new file mode 100644 index 0000000..012b932 --- /dev/null +++ b/warranty_registration.php @@ -0,0 +1,226 @@ +prepare( + "SELECT ss.id, ss.serial_number, p.name as product_name + FROM sold_serials ss + JOIN products p ON ss.product_id = p.id + WHERE ss.dealer_id = ? AND ss.is_activated = FALSE" + ); + $stmt->execute([$dealer_id]); + $unactivated_serials = $stmt->fetchAll(); + +} catch (PDOException $e) { + die("Database error: " . $e->getMessage()); +} + +$success_message = ''; +$error_message = ''; + +if ($_SERVER["REQUEST_METHOD"] == "POST") { + $sold_serial_id = trim($_POST['sold_serial_id']); + $end_customer_name = trim($_POST['end_customer_name']); + $end_customer_address = trim($_POST['end_customer_address']); + $dealer_invoice_date = trim($_POST['dealer_invoice_date']); + $dealer_invoice_no = trim($_POST['dealer_invoice_no']); + $installation_date = trim($_POST['installation_date']); + + if (empty($sold_serial_id) || empty($end_customer_name) || empty($end_customer_address) || empty($dealer_invoice_date) || empty($dealer_invoice_no) || empty($installation_date)) { + $error_message = "All fields are required."; + } else { + $target_dir = "uploads/invoices/"; + if (!is_dir($target_dir)) { + mkdir($target_dir, 0777, true); + } + $target_file = $target_dir . basename($_FILES["dealer_invoice"]["name"]); + $uploadOk = 1; + $imageFileType = strtolower(pathinfo($target_file,PATHINFO_EXTENSION)); + + // Check if file already exists + if (file_exists($target_file)) { + $error_message = "Sorry, file already exists."; + $uploadOk = 0; + } + + // Check file size + if ($_FILES["dealer_invoice"]["size"] > 500000) { + $error_message = "Sorry, your file is too large."; + $uploadOk = 0; + } + + // Allow certain file formats + if($imageFileType != "jpg" && $imageFileType != "png" && $imageFileType != "jpeg" + && $imageFileType != "gif" && $imageFileType != "pdf" ) { + $error_message = "Sorry, only JPG, JPEG, PNG, GIF & PDF files are allowed."; + $uploadOk = 0; + } + + if ($uploadOk == 0) { + $error_message = "Sorry, your file was not uploaded."; + // if everything is ok, try to upload file + } else { + if (move_uploaded_file($_FILES["dealer_invoice"]["tmp_name"], $target_file)) { + try { + $pdo = db(); + $pdo->beginTransaction(); + + // 1. Insert warranty registration + $sql = "INSERT INTO warranty_registrations (sold_serial_id, end_customer_name, end_customer_address, dealer_invoice_date, dealer_invoice_no, dealer_invoice_path, installation_date, serial_number) + SELECT ?, ?, ?, ?, ?, ?, ?, serial_number FROM sold_serials WHERE id = ?"; + $stmt = $pdo->prepare($sql); + $stmt->execute([$sold_serial_id, $end_customer_name, $end_customer_address, $dealer_invoice_date, $dealer_invoice_no, $target_file, $installation_date, $sold_serial_id]); + + // 2. Mark serial as activated + $sql_update = "UPDATE sold_serials SET is_activated = TRUE WHERE id = ?"; + $stmt_update = $pdo->prepare($sql_update); + $stmt_update->execute([$sold_serial_id]); + + $pdo->commit(); + + // Fetch serial number for display message + $stmt_sn = $pdo->prepare("SELECT serial_number FROM sold_serials WHERE id = ?"); + $stmt_sn->execute([$sold_serial_id]); + $serial_number = $stmt_sn->fetchColumn(); + + $success_message = "Warranty for serial number " . htmlspecialchars($serial_number) . " registered successfully!"; + + } catch (PDOException $e) { + $pdo->rollBack(); + $error_message = "Database error: " . $e->getMessage(); + } + } else { + $error_message = "Sorry, there was an error uploading your file."; + } + } + } +} + +require_once 'includes/header.php'; +?> + +
+
+
+
+

Device Warranty Registration

+
+
+

Register a device installation to activate the warranty. Please select a device serial number, enter the end customer's name, and the installation date.

+ + + + + + + + +
+
+ + + +
No devices are pending warranty activation.
+ +
+ + + +
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+ +
+
+
+
+
+ + + +