requireLogin(); $page_title = 'Sales Management'; $success_message = ''; $error_message = ''; // Handle form submissions if ($_SERVER['REQUEST_METHOD'] == 'POST' && isset($_POST['action'])) { if ($_POST['action'] == 'record_sale') { $sale_date = $_POST['sale_date'] ?? ''; $customer_name = trim($_POST['customer_name'] ?? ''); $customer_phone = trim($_POST['customer_phone'] ?? ''); $payment_status = $_POST['payment_status'] ?? 'paid'; $payment_method = $_POST['payment_method'] ?? 'cash'; $notes = trim($_POST['notes'] ?? ''); // Get line items from individual form fields $products = $_POST['product_id'] ?? []; $quantities = $_POST['quantity'] ?? []; $unit_prices = $_POST['unit_price'] ?? []; $line_totals = $_POST['line_total'] ?? []; // Validation if (empty($sale_date)) { $error_message = 'Sale date is required.'; } elseif (empty($products) || !is_array($products)) { $error_message = 'At least one product/service must be added.'; } else { // Build line items array $line_items = []; $total_amount = 0; for ($i = 0; $i < count($products); $i++) { if (!empty($products[$i]) && !empty($quantities[$i]) && isset($unit_prices[$i]) && isset($line_totals[$i])) { $product_id = intval($products[$i]); $quantity = floatval($quantities[$i]); $unit_price = floatval($unit_prices[$i]); $line_total = floatval($line_totals[$i]); if ($product_id > 0 && $quantity > 0 && $unit_price >= 0 && $line_total >= 0) { $line_items[] = [ 'product_id' => $product_id, 'quantity' => $quantity, 'unit_price' => $unit_price, 'line_total' => $line_total ]; $total_amount += $line_total; } } } if (empty($line_items)) { $error_message = 'At least one valid product/service must be added.'; } elseif ($total_amount <= 0) { $error_message = 'Total amount must be greater than zero.'; } else { try { // Generate bill number $bill_number = 'BILL' . date('YmdHis') . rand(100, 999); // Start transaction $pdo->beginTransaction(); // Insert sale $stmt = $pdo->prepare(" INSERT INTO sales (bill_number, sale_date, customer_name, customer_phone, total_amount, payment_status, payment_method, notes, created_by) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?) "); $stmt->execute([ $bill_number, $sale_date, $customer_name, $customer_phone, $total_amount, $payment_status, $payment_method, $notes, $_SESSION['user_id'] ]); $sale_id = $pdo->lastInsertId(); // Insert line items $stmt = $pdo->prepare(" INSERT INTO sales_items (sale_id, product_service_id, quantity, unit_price, line_total) VALUES (?, ?, ?, ?, ?) "); foreach ($line_items as $item) { $stmt->execute([ $sale_id, $item['product_id'], $item['quantity'], $item['unit_price'], $item['line_total'] ]); } $pdo->commit(); $_SESSION['success_message'] = 'Sale recorded successfully! Bill: ' . $bill_number; // Redirect to prevent form resubmission header("Location: sales.php"); exit(); } catch (Exception $e) { $pdo->rollBack(); $error_message = 'Error recording sale: ' . $e->getMessage(); } } } } elseif ($_POST['action'] == 'delete_sale') { $sale_id = intval($_POST['sale_id'] ?? 0); if ($sale_id > 0) { try { $pdo->beginTransaction(); // Delete sales items first $stmt = $pdo->prepare("DELETE FROM sales_items WHERE sale_id = ?"); $stmt->execute([$sale_id]); // Delete sale $stmt = $pdo->prepare("DELETE FROM sales WHERE id = ?"); $result = $stmt->execute([$sale_id]); if ($result) { $pdo->commit(); $_SESSION['success_message'] = 'Sale deleted successfully.'; } else { $pdo->rollBack(); $_SESSION['error_message'] = 'Failed to delete sale.'; } } catch (Exception $e) { $pdo->rollBack(); $_SESSION['error_message'] = 'Error deleting sale: ' . $e->getMessage(); } } header("Location: sales.php"); exit(); } } // Fetch products/services try { $stmt = $pdo->prepare(" SELECT ps.*, u.unit_name, u.unit_symbol FROM products_services ps JOIN units u ON ps.unit_id = u.id WHERE ps.status = 'active' ORDER BY ps.name "); $stmt->execute(); $products_services = $stmt->fetchAll(PDO::FETCH_ASSOC); } catch (PDOException $e) { $products_services = []; } // Fetch sales with filters $filter_date_from = $_GET['filter_date_from'] ?? ''; $filter_date_to = $_GET['filter_date_to'] ?? ''; $where_clause = "1=1"; $params = []; if (!empty($filter_date_from)) { $where_clause .= " AND s.sale_date >= ?"; $params[] = $filter_date_from; } if (!empty($filter_date_to)) { $where_clause .= " AND s.sale_date <= ?"; $params[] = $filter_date_to; } try { // Get sales stats $stmt = $pdo->prepare(" SELECT COUNT(*) as total_sales, COALESCE(SUM(total_amount), 0) as total_revenue, COALESCE(SUM(CASE WHEN payment_status = 'paid' THEN total_amount ELSE 0 END), 0) as paid_amount FROM sales s WHERE $where_clause "); $stmt->execute($params); $stats = $stmt->fetch(PDO::FETCH_ASSOC); // Get sales records $stmt = $pdo->prepare(" SELECT s.*, u.full_name as created_by_name FROM sales s JOIN users u ON s.created_by = u.id WHERE $where_clause ORDER BY s.created_at DESC LIMIT 50 "); $stmt->execute($params); $sales = $stmt->fetchAll(PDO::FETCH_ASSOC); // Get line items for each sale foreach ($sales as &$sale) { $stmt = $pdo->prepare(" SELECT si.*, ps.name as product_name, u.unit_symbol FROM sales_items si JOIN products_services ps ON si.product_service_id = ps.id JOIN units u ON ps.unit_id = u.id WHERE si.sale_id = ? "); $stmt->execute([$sale['id']]); $sale['items'] = $stmt->fetchAll(PDO::FETCH_ASSOC); } } catch (PDOException $e) { $stats = ['total_sales' => 0, 'total_revenue' => 0, 'paid_amount' => 0]; $sales = []; $error_message = 'Error fetching sales data.'; } include 'includes/header.php'; ?>
Total Sales
Total Revenue
Paid Amount

Record New Sale

Please create products or services first.

Products/Services

Grand Total: ₹0.00

Filter Sales

Clear

Sales Records

No Sales Found

Record your first sale using the form above.

Bill# Date Items Total Customer Payment Action
: @ ₹ =

-

Notes: