feat: Implement query and reply functionality for Dispatch and Sales teams
This commit is contained in:
parent
348f175175
commit
929c1ba4df
@ -7,7 +7,8 @@ function setup_database($pdo) {
|
|||||||
email VARCHAR(255) NOT NULL UNIQUE,
|
email VARCHAR(255) NOT NULL UNIQUE,
|
||||||
password VARCHAR(255) NOT NULL,
|
password VARCHAR(255) NOT NULL,
|
||||||
role ENUM('Admin', 'Sales Rep', 'Dispatch') NOT NULL,
|
role ENUM('Admin', 'Sales Rep', 'Dispatch') NOT NULL,
|
||||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
|
||||||
)");
|
)");
|
||||||
|
|
||||||
$pdo->exec("CREATE TABLE IF NOT EXISTS orders (
|
$pdo->exec("CREATE TABLE IF NOT EXISTS orders (
|
||||||
@ -16,6 +17,8 @@ function setup_database($pdo) {
|
|||||||
order_date DATE NOT NULL,
|
order_date DATE NOT NULL,
|
||||||
order_text TEXT NOT NULL,
|
order_text TEXT NOT NULL,
|
||||||
status ENUM('Pending', 'Query', 'Query Replied', 'Shipped', 'Cancelled') NOT NULL DEFAULT 'Pending',
|
status ENUM('Pending', 'Query', 'Query Replied', 'Shipped', 'Cancelled') NOT NULL DEFAULT 'Pending',
|
||||||
|
query_text TEXT DEFAULT NULL,
|
||||||
|
reply_text TEXT DEFAULT NULL,
|
||||||
sales_rep_id INT NOT NULL,
|
sales_rep_id INT NOT NULL,
|
||||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||||
|
|||||||
40
index.php
40
index.php
@ -15,20 +15,35 @@ $shipped_orders_month_count = 0;
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
// --- Fetch Dashboard Counts ---
|
// --- Fetch Dashboard Counts ---
|
||||||
$conditions = '';
|
$base_conditions_arr = [];
|
||||||
$params = [];
|
$params = [];
|
||||||
|
|
||||||
if ($user_role === 'Sales Rep') {
|
if ($user_role === 'Sales Rep') {
|
||||||
$conditions = " WHERE sales_rep_id = :user_id";
|
$base_conditions_arr[] = "sales_rep_id = :user_id";
|
||||||
$params[':user_id'] = $user_id;
|
$params[':user_id'] = $user_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pending Orders Count
|
// Pending Orders Count
|
||||||
$stmt = $pdo->prepare("SELECT COUNT(*) FROM orders " . $conditions . " AND status = 'Pending'");
|
$pending_orders_conditions_arr = $base_conditions_arr;
|
||||||
|
$pending_orders_conditions_arr[] = "status = 'Pending'";
|
||||||
|
|
||||||
|
$pending_orders_where_clause = '';
|
||||||
|
if (!empty($pending_orders_conditions_arr)) {
|
||||||
|
$pending_orders_where_clause = " WHERE " . implode(" AND ", $pending_orders_conditions_arr);
|
||||||
|
}
|
||||||
|
$stmt = $pdo->prepare("SELECT COUNT(*) FROM orders " . $pending_orders_where_clause);
|
||||||
$stmt->execute($params);
|
$stmt->execute($params);
|
||||||
$pending_orders_count = $stmt->fetchColumn();
|
$pending_orders_count = $stmt->fetchColumn();
|
||||||
|
|
||||||
// Pending Replies Count (Orders with status 'Query' or 'Query Replied')
|
// Pending Replies Count (Orders with status 'Query' or 'Query Replied')
|
||||||
$stmt = $pdo->prepare("SELECT COUNT(*) FROM orders " . $conditions . " AND (status = 'Query' OR status = 'Query Replied')");
|
$pending_replies_conditions_arr = $base_conditions_arr;
|
||||||
|
$pending_replies_conditions_arr[] = "(status = 'Query' OR status = 'Query Replied')";
|
||||||
|
|
||||||
|
$pending_replies_where_clause = '';
|
||||||
|
if (!empty($pending_replies_conditions_arr)) {
|
||||||
|
$pending_replies_where_clause = " WHERE " . implode(" AND ", $pending_replies_conditions_arr);
|
||||||
|
}
|
||||||
|
$stmt = $pdo->prepare("SELECT COUNT(*) FROM orders " . $pending_replies_where_clause);
|
||||||
$stmt->execute($params);
|
$stmt->execute($params);
|
||||||
$pending_replies_count = $stmt->fetchColumn();
|
$pending_replies_count = $stmt->fetchColumn();
|
||||||
|
|
||||||
@ -36,12 +51,21 @@ try {
|
|||||||
$current_month_start = date('Y-m-01 00:00:00');
|
$current_month_start = date('Y-m-01 00:00:00');
|
||||||
$current_month_end = date('Y-m-t 23:59:59');
|
$current_month_end = date('Y-m-t 23:59:59');
|
||||||
|
|
||||||
$shipped_sql = "SELECT COUNT(*) FROM orders " . $conditions . " AND status = 'Shipped' AND created_at >= :start_date AND created_at <= :end_date";
|
$shipped_conditions_arr = $base_conditions_arr;
|
||||||
|
$shipped_conditions_arr[] = "status = 'Shipped'";
|
||||||
|
$shipped_conditions_arr[] = "created_at >= :start_date";
|
||||||
|
$shipped_conditions_arr[] = "created_at <= :end_date";
|
||||||
|
|
||||||
|
$shipped_where_clause = '';
|
||||||
$shipped_params = $params;
|
$shipped_params = $params;
|
||||||
$shipped_params[':start_date'] = $current_month_start;
|
$shipped_params[':start_date'] = $current_month_start;
|
||||||
$shipped_params[':end_date'] = $current_month_end;
|
$shipped_params[':end_date'] = $current_month_end;
|
||||||
|
|
||||||
$stmt = $pdo->prepare($shipped_sql);
|
if (!empty($shipped_conditions_arr)) {
|
||||||
|
$shipped_where_clause = " WHERE " . implode(" AND ", $shipped_conditions_arr);
|
||||||
|
}
|
||||||
|
|
||||||
|
$stmt = $pdo->prepare("SELECT COUNT(*) FROM orders " . $shipped_where_clause);
|
||||||
$stmt->execute($shipped_params);
|
$stmt->execute($shipped_params);
|
||||||
$shipped_orders_month_count = $stmt->fetchColumn();
|
$shipped_orders_month_count = $stmt->fetchColumn();
|
||||||
|
|
||||||
@ -133,9 +157,9 @@ try {
|
|||||||
<td><?php echo htmlspecialchars(substr($order['order_text'], 0, 50)); ?>...</td>
|
<td><?php echo htmlspecialchars(substr($order['order_text'], 0, 50)); ?>...</td>
|
||||||
<td><span class="badge bg-secondary"><?php echo htmlspecialchars($order['status']); ?></span></td>
|
<td><span class="badge bg-secondary"><?php echo htmlspecialchars($order['status']); ?></span></td>
|
||||||
<td>
|
<td>
|
||||||
<a href="#" class="btn btn-sm btn-outline-primary">View</a>
|
<a href="view_order.php?id=<?php echo $order['id']; ?>" class="btn btn-sm btn-outline-primary">View</a>
|
||||||
<?php if ($user_role === 'Sales Rep' && $order['sales_rep_id'] == $user_id): ?>
|
<?php if ($user_role === 'Sales Rep' && $order['sales_rep_id'] == $user_id): ?>
|
||||||
<a href="#" class="btn btn-sm btn-outline-secondary">Edit</a>
|
<a href="view_order.php?id=<?php echo $order['id']; ?>" class="btn btn-sm btn-outline-secondary">Edit</a>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|||||||
207
view_order.php
Normal file
207
view_order.php
Normal file
@ -0,0 +1,207 @@
|
|||||||
|
<?php
|
||||||
|
$page_title = 'View/Edit Order';
|
||||||
|
require_once __DIR__ . '/partials/header.php';
|
||||||
|
require_once __DIR__ . '/db/config.php';
|
||||||
|
|
||||||
|
$user_id = $_SESSION['user_id'];
|
||||||
|
$user_role = $_SESSION['user_role'];
|
||||||
|
$pdo = db();
|
||||||
|
$order = null;
|
||||||
|
$edit_mode = false;
|
||||||
|
$errors = [];
|
||||||
|
$success_message = '';
|
||||||
|
|
||||||
|
// Check if order ID is provided
|
||||||
|
if (isset($_GET['id']) && is_numeric($_GET['id'])) {
|
||||||
|
$order_id = $_GET['id'];
|
||||||
|
|
||||||
|
$stmt = $pdo->prepare("SELECT o.*, o.query_text, o.reply_text, u.name as sales_rep_name FROM orders o JOIN users u ON o.sales_rep_id = u.id WHERE o.id = :id");
|
||||||
|
$stmt->bindParam(':id', $order_id, PDO::PARAM_INT);
|
||||||
|
$stmt->execute();
|
||||||
|
$order = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
|
if (!$order) {
|
||||||
|
$errors[] = "Order not found.";
|
||||||
|
} else {
|
||||||
|
// Determine if user can edit this order
|
||||||
|
if ($user_role === 'Sales Rep' && $order['sales_rep_id'] == $user_id) {
|
||||||
|
$edit_mode = true;
|
||||||
|
} elseif ($user_role === 'Dispatch' || $user_role === 'Admin') {
|
||||||
|
$edit_mode = true; // Dispatch and Admin can always edit
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
error_log("Database error fetching order: " . $e->getMessage());
|
||||||
|
$errors[] = "Error loading order details. Please try again later.";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$errors[] = "No order ID provided.";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle form submission for updating order
|
||||||
|
if ($_SERVER['REQUEST_METHOD'] === 'POST' && $edit_mode && $order) {
|
||||||
|
$new_order_number = trim($_POST['order_number'] ?? '');
|
||||||
|
$new_order_date = trim($_POST['order_date'] ?? '');
|
||||||
|
$new_order_text = trim($_POST['order_text'] ?? '');
|
||||||
|
$new_status = trim($_POST['status'] ?? '');
|
||||||
|
$new_query_text = trim($_POST['query_text'] ?? '');
|
||||||
|
$new_reply_text = trim($_POST['reply_text'] ?? '');
|
||||||
|
|
||||||
|
// Preserve existing query/reply if not being updated by a specific status change
|
||||||
|
$query_to_save = $order['query_text'];
|
||||||
|
$reply_to_save = $order['reply_text'];
|
||||||
|
|
||||||
|
if ($new_status === 'Query' && empty($order['query_text'])) {
|
||||||
|
$query_to_save = $new_query_text;
|
||||||
|
} elseif ($new_status === 'Query Replied' && empty($order['reply_text'])) {
|
||||||
|
$reply_to_save = $new_reply_text;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (empty($new_order_number)) {
|
||||||
|
$errors[] = "Order number cannot be empty.";
|
||||||
|
}
|
||||||
|
if (empty($new_order_date)) {
|
||||||
|
$errors[] = "Order date cannot be empty.";
|
||||||
|
}
|
||||||
|
if (empty($new_order_text)) {
|
||||||
|
$errors[] = "Order text cannot be empty.";
|
||||||
|
}
|
||||||
|
if (empty($new_status)) {
|
||||||
|
$errors[] = "Status cannot be empty.";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (empty($errors)) {
|
||||||
|
try {
|
||||||
|
$stmt = $pdo->prepare("UPDATE orders SET order_number = :order_number, order_date = :order_date, order_text = :order_text, status = :status, query_text = :query_text, reply_text = :reply_text WHERE id = :id");
|
||||||
|
$stmt->bindParam(':order_number', $new_order_number);
|
||||||
|
$stmt->bindParam(':order_date', $new_order_date);
|
||||||
|
$stmt->bindParam(':order_text', $new_order_text);
|
||||||
|
$stmt->bindParam(':status', $new_status);
|
||||||
|
$stmt->bindParam(':query_text', $query_to_save);
|
||||||
|
$stmt->bindParam(':reply_text', $reply_to_save);
|
||||||
|
$stmt->bindParam(':id', $order_id, PDO::PARAM_INT);
|
||||||
|
$stmt->execute();
|
||||||
|
|
||||||
|
$success_message = "Order updated successfully!";
|
||||||
|
// Re-fetch order to display updated data
|
||||||
|
$stmt = $pdo->prepare("SELECT o.*, u.name as sales_rep_name FROM orders o JOIN users u ON o.sales_rep_id = u.id WHERE o.id = :id");
|
||||||
|
$stmt->bindParam(':id', $order_id, PDO::PARAM_INT);
|
||||||
|
$stmt->execute();
|
||||||
|
$order = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||||
|
} catch (PDOException $e) {
|
||||||
|
error_log("Database error updating order: " . $e->getMessage());
|
||||||
|
$errors[] = "Error updating order. Please try again later.";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
|
||||||
|
<div class="container mt-4">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-8 mx-auto">
|
||||||
|
<div class="card shadow-sm">
|
||||||
|
<div class="card-header bg-primary text-white">
|
||||||
|
<h1 class="card-title h4 mb-0"><?php echo htmlspecialchars($page_title); ?></h1>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<?php if (!empty($errors)): ?>
|
||||||
|
<div class="alert alert-danger">
|
||||||
|
<?php foreach ($errors as $error): ?>
|
||||||
|
<p class="mb-0"><?php echo htmlspecialchars($error); ?></p>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<?php if (!empty($success_message)): ?>
|
||||||
|
<div class="alert alert-success">
|
||||||
|
<?php echo htmlspecialchars($success_message); ?>
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<?php if ($order): ?>
|
||||||
|
<form method="POST">
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="order_number" class="form-label">Order Number</label>
|
||||||
|
<input type="text" class="form-control" id="order_number" name="order_number" value="<?php echo htmlspecialchars($order['order_number']); ?>" <?php echo $edit_mode ? '' : 'readonly'; ?>>
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="order_date" class="form-label">Order Date</label>
|
||||||
|
<input type="date" class="form-control" id="order_date" name="order_date" value="<?php echo htmlspecialchars($order['order_date']); ?>" <?php echo $edit_mode ? '' : 'readonly'; ?>>
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="order_text" class="form-label">Order Details</label>
|
||||||
|
<textarea class="form-control" id="order_text" name="order_text" rows="5" <?php echo $edit_mode ? '' : 'readonly'; ?>><?php echo htmlspecialchars($order['order_text']); ?></textarea>
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="sales_rep_name" class="form-label">Sales Rep</label>
|
||||||
|
<input type="text" class="form-control" id="sales_rep_name" value="<?php echo htmlspecialchars($order['sales_rep_name']); ?>" readonly>
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="status" class="form-label">Status</label>
|
||||||
|
<?php if ($edit_mode): ?>
|
||||||
|
<select class="form-select" id="status" name="status">
|
||||||
|
<?php $statuses = ['Pending', 'Query', 'Query Replied', 'Shipped', 'Cancelled']; ?>
|
||||||
|
<?php foreach ($statuses as $status_option): ?>
|
||||||
|
<option value="<?php echo htmlspecialchars($status_option); ?>" <?php echo ($order['status'] === $status_option) ? 'selected' : ''; ?>>
|
||||||
|
<?php echo htmlspecialchars($status_option); ?>
|
||||||
|
</option>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</select>
|
||||||
|
<?php else: ?>
|
||||||
|
<input type="text" class="form-control" id="status" name="status" value="<?php echo htmlspecialchars($order['status']); ?>" readonly>
|
||||||
|
<?php endif; ?>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-3" id="queryTextBox" style="display: none;">
|
||||||
|
<label for="query_text" class="form-label">Query</label>
|
||||||
|
<textarea class="form-control" id="query_text" name="query_text" rows="3" <?php echo ($order['query_text'] && $order['query_text'] !== '') ? 'readonly' : ''; ?>><?php echo htmlspecialchars($order['query_text'] ?? ''); ?></textarea>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-3" id="replyTextBox" style="display: none;">
|
||||||
|
<label for="reply_text" class="form-label">Query Reply</label>
|
||||||
|
<textarea class="form-control" id="reply_text" name="reply_text" rows="3" <?php echo ($order['reply_text'] && $order['reply_text'] !== '') ? 'readonly' : ''; ?>><?php echo htmlspecialchars($order['reply_text'] ?? ''); ?></textarea>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<?php if ($edit_mode): ?>
|
||||||
|
<button type="submit" class="btn btn-primary">Update Order</button>
|
||||||
|
<?php endif; ?>
|
||||||
|
<a href="index.php" class="btn btn-secondary">Back to Dashboard</a>
|
||||||
|
</form>
|
||||||
|
<?php else: ?>
|
||||||
|
<a href="index.php" class="btn btn-primary">Back to Dashboard</a>
|
||||||
|
<?php endif; ?>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
const statusSelect = document.getElementById('status');
|
||||||
|
const queryTextBox = document.getElementById('queryTextBox');
|
||||||
|
const replyTextBox = document.getElementById('replyTextBox');
|
||||||
|
|
||||||
|
function toggleTextBoxes() {
|
||||||
|
const currentStatus = statusSelect.value;
|
||||||
|
queryTextBox.style.display = 'none';
|
||||||
|
replyTextBox.style.display = 'none';
|
||||||
|
|
||||||
|
if (currentStatus === 'Query') {
|
||||||
|
queryTextBox.style.display = 'block';
|
||||||
|
} else if (currentStatus === 'Query Replied') {
|
||||||
|
replyTextBox.style.display = 'block';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initial call to set correct visibility on page load
|
||||||
|
toggleTextBoxes();
|
||||||
|
|
||||||
|
// Add event listener for status change
|
||||||
|
if (statusSelect) {
|
||||||
|
statusSelect.addEventListener('change', toggleTextBoxes);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<?php require_once __DIR__ . '/partials/footer.php'; ?>
|
||||||
Loading…
x
Reference in New Issue
Block a user