484 lines
16 KiB
PHP
484 lines
16 KiB
PHP
<?php
|
|
// Start session if not already started
|
|
if (session_status() === PHP_SESSION_NONE) {
|
|
session_start();
|
|
}
|
|
|
|
// Include the main database connection
|
|
include('../../routes/db_conn.php');
|
|
|
|
// Check for database connection
|
|
if (!isset($conn) || $conn->connect_error) {
|
|
error_log("Database connection failed: " . ($conn ? $conn->connect_error : "Connection not established"));
|
|
die("Database connection failed. Please try again later.");
|
|
}
|
|
|
|
// Set error reporting for debugging
|
|
error_reporting(E_ALL);
|
|
ini_set('display_errors', 1);
|
|
ini_set('log_errors', 1);
|
|
ini_set('error_log', '../../logs/php-errors.log');
|
|
|
|
// Check if user is logged in, redirect to login page if not
|
|
if (!isset($_SESSION['user_id']) || !isset($_SESSION['role'])) {
|
|
// Check if this is an AJAX request
|
|
if (!empty($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest') {
|
|
// Return JSON error for AJAX requests
|
|
header('Content-Type: application/json');
|
|
echo json_encode(['success' => false, 'message' => 'Session expired. Please login again.', 'redirect' => '/ayula-store/views/login/']);
|
|
exit;
|
|
} else {
|
|
// Redirect for regular requests
|
|
header('Location: /ayula-store/views/login/');
|
|
exit;
|
|
}
|
|
}
|
|
|
|
// Set variables for use throughout the application
|
|
$userRole = $_SESSION['role'] ?? ''; // 'user' or 'admin'
|
|
$username = $_SESSION['username'] ?? 'Unknown User';
|
|
$isAdmin = ($userRole === 'admin');
|
|
|
|
/**
|
|
* Get all products or filter by product type and/or search query
|
|
*
|
|
* @param int|null $typeId Optional product type ID to filter by
|
|
* @param string|null $searchQuery Optional search term to filter product names
|
|
* @return array List of products
|
|
*/
|
|
function getProducts($typeId = null, $searchQuery = null) {
|
|
global $conn;
|
|
|
|
try {
|
|
$sql = "SELECT b.*, j.nama_jenis
|
|
FROM barang_kasir b
|
|
JOIN jenis_barang j ON b.id_jenis = j.id_jenis
|
|
WHERE 1=1";
|
|
|
|
$params = [];
|
|
$types = "";
|
|
|
|
// Add type filter if specified
|
|
if ($typeId) {
|
|
$sql .= " AND b.id_jenis = ?";
|
|
$params[] = $typeId;
|
|
$types .= "i"; // integer parameter
|
|
}
|
|
|
|
// Add search filter if specified
|
|
if ($searchQuery && !empty($searchQuery)) {
|
|
$sql .= " AND (b.nama_barang LIKE ? OR b.kode_barang LIKE ?)";
|
|
$params[] = "%" . $searchQuery . "%";
|
|
$params[] = "%" . $searchQuery . "%";
|
|
$types .= "ss"; // two string parameters
|
|
}
|
|
|
|
$sql .= " ORDER BY b.nama_barang ASC";
|
|
|
|
$stmt = mysqli_prepare($conn, $sql);
|
|
|
|
if (!$stmt) {
|
|
error_log("Query preparation failed: " . mysqli_error($conn));
|
|
return [];
|
|
}
|
|
|
|
// Bind parameters dynamically if we have any
|
|
if (!empty($params)) {
|
|
$bindParams = array(&$stmt, &$types);
|
|
foreach($params as $key => $value) {
|
|
$bindParams[] = &$params[$key];
|
|
}
|
|
call_user_func_array('mysqli_stmt_bind_param', $bindParams);
|
|
}
|
|
|
|
$executed = mysqli_stmt_execute($stmt);
|
|
|
|
if (!$executed) {
|
|
error_log("Query execution failed: " . mysqli_stmt_error($stmt));
|
|
mysqli_stmt_close($stmt);
|
|
return [];
|
|
}
|
|
|
|
$result = mysqli_stmt_get_result($stmt);
|
|
|
|
$products = [];
|
|
while ($row = mysqli_fetch_assoc($result)) {
|
|
$products[] = $row;
|
|
}
|
|
|
|
mysqli_stmt_close($stmt);
|
|
return $products;
|
|
} catch (Exception $e) {
|
|
error_log("Exception in getProducts: " . $e->getMessage());
|
|
return [];
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get product details by ID
|
|
*
|
|
* @param int $productId The product ID
|
|
* @return array|null Product details or null if not found
|
|
*/
|
|
function getProductById($productId) {
|
|
global $conn;
|
|
|
|
try {
|
|
$stmt = mysqli_prepare($conn, "SELECT b.*, j.nama_jenis
|
|
FROM barang_kasir b
|
|
LEFT JOIN jenis_barang j ON b.id_jenis = j.id_jenis
|
|
WHERE b.id_barangK = ?");
|
|
|
|
if (!$stmt) {
|
|
error_log("Query preparation failed: " . mysqli_error($conn));
|
|
return null;
|
|
}
|
|
|
|
mysqli_stmt_bind_param($stmt, "i", $productId);
|
|
$executed = mysqli_stmt_execute($stmt);
|
|
|
|
if (!$executed) {
|
|
error_log("Query execution failed: " . mysqli_stmt_error($stmt));
|
|
mysqli_stmt_close($stmt);
|
|
return null;
|
|
}
|
|
|
|
$result = mysqli_stmt_get_result($stmt);
|
|
$product = mysqli_fetch_assoc($result);
|
|
mysqli_stmt_close($stmt);
|
|
|
|
return $product;
|
|
} catch (Exception $e) {
|
|
error_log("Exception in getProductById: " . $e->getMessage());
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get all product types (jenis_barang)
|
|
*
|
|
* @return array List of product types
|
|
*/
|
|
function getProductTypes() {
|
|
global $conn;
|
|
|
|
try {
|
|
$query = "SELECT * FROM jenis_barang ORDER BY nama_jenis";
|
|
$result = mysqli_query($conn, $query);
|
|
|
|
if (!$result) {
|
|
error_log("Query failed: " . mysqli_error($conn));
|
|
return [];
|
|
}
|
|
|
|
$types = [];
|
|
while ($row = mysqli_fetch_assoc($result)) {
|
|
$types[] = $row;
|
|
}
|
|
|
|
return $types;
|
|
} catch (Exception $e) {
|
|
error_log("Exception in getProductTypes: " . $e->getMessage());
|
|
return [];
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Create a new transaction
|
|
*
|
|
* @param array $items Array of items with product_id and quantity
|
|
* @param float $total Total amount
|
|
* @param float $cashAmount Cash amount received from customer
|
|
* @param float $changeAmount Change amount to be returned to customer
|
|
* @return array Result with success status and transaction ID
|
|
*/
|
|
function createTransaction($items, $total, $cashAmount = 0, $changeAmount = 0) {
|
|
global $conn;
|
|
|
|
if (empty($items)) {
|
|
return [
|
|
'success' => false,
|
|
'message' => 'No items in cart'
|
|
];
|
|
}
|
|
|
|
$totalItems = array_sum(array_column($items, 'quantity'));
|
|
|
|
// Generate transaction code (e.g., TRX-20250416-001)
|
|
$transactionCode = 'TRX-' . date('Ymd') . '-' . rand(100, 999);
|
|
|
|
// Begin transaction
|
|
mysqli_begin_transaction($conn);
|
|
|
|
try {
|
|
// Insert into transaksi table with cash_amount and change_amount
|
|
$stmt = mysqli_prepare($conn, "INSERT INTO transaksi (kode_transaksi, total_item, total, metode_pembayaran, cash_amount, change_amount) VALUES (?, ?, ?, 'Cash', ?, ?)");
|
|
|
|
if (!$stmt) {
|
|
throw new Exception("Failed to prepare transaction statement: " . mysqli_error($conn));
|
|
}
|
|
|
|
mysqli_stmt_bind_param($stmt, "siddd", $transactionCode, $totalItems, $total, $cashAmount, $changeAmount);
|
|
$executed = mysqli_stmt_execute($stmt);
|
|
|
|
if (!$executed) {
|
|
throw new Exception("Failed to execute transaction statement: " . mysqli_stmt_error($stmt));
|
|
}
|
|
|
|
// Get the ID of the transaction just created
|
|
$transactionId = mysqli_insert_id($conn);
|
|
|
|
if (!$transactionId) {
|
|
throw new Exception("Failed to get transaction ID");
|
|
}
|
|
|
|
// Insert each item into detail_transaksi
|
|
foreach ($items as $item) {
|
|
$product = getProductById($item['product_id']);
|
|
|
|
if (!$product) {
|
|
throw new Exception("Product not found: ID=" . $item['product_id']);
|
|
}
|
|
|
|
$itemTotal = $product['harga'] * $item['quantity'];
|
|
|
|
$stmt = mysqli_prepare($conn, "INSERT INTO detail_transaksi (id_transaksi, id_barangK, jumlah, harga_satuan, total_harga) VALUES (?, ?, ?, ?, ?)");
|
|
|
|
if (!$stmt) {
|
|
throw new Exception("Failed to prepare detail statement: " . mysqli_error($conn));
|
|
}
|
|
|
|
mysqli_stmt_bind_param($stmt, "iiddd", $transactionId, $item['product_id'], $item['quantity'], $product['harga'], $itemTotal);
|
|
$executed = mysqli_stmt_execute($stmt);
|
|
|
|
if (!$executed) {
|
|
throw new Exception("Failed to execute detail statement: " . mysqli_stmt_error($stmt));
|
|
}
|
|
|
|
// Update inventory (reduce stock)
|
|
$stmt = mysqli_prepare($conn, "UPDATE barang_kasir SET stok = stok - ? WHERE id_barangK = ? AND stok >= ?");
|
|
|
|
if (!$stmt) {
|
|
throw new Exception("Failed to prepare stock update statement: " . mysqli_error($conn));
|
|
}
|
|
|
|
mysqli_stmt_bind_param($stmt, "iii", $item['quantity'], $item['product_id'], $item['quantity']);
|
|
$executed = mysqli_stmt_execute($stmt);
|
|
|
|
if (!$executed) {
|
|
throw new Exception("Failed to execute stock update statement: " . mysqli_stmt_error($stmt));
|
|
}
|
|
|
|
// Check if stock was actually updated (prevents overselling)
|
|
if (mysqli_affected_rows($conn) == 0) {
|
|
throw new Exception("Insufficient stock for product: " . $product['nama_barang']);
|
|
}
|
|
}
|
|
|
|
// Commit transaction
|
|
mysqli_commit($conn);
|
|
|
|
return [
|
|
'success' => true,
|
|
'transaction_id' => $transactionId,
|
|
'transaction_code' => $transactionCode,
|
|
'cash_amount' => $cashAmount,
|
|
'change_amount' => $changeAmount
|
|
];
|
|
} catch (Exception $e) {
|
|
// Rollback in case of error
|
|
mysqli_rollback($conn);
|
|
error_log("Transaction failed: " . $e->getMessage());
|
|
return [
|
|
'success' => false,
|
|
'message' => $e->getMessage()
|
|
];
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get transaction by ID
|
|
*
|
|
* @param int $transactionId The transaction ID
|
|
* @return array|null Transaction details or null if not found
|
|
*/
|
|
function getTransactionById($transactionId) {
|
|
global $conn;
|
|
|
|
try {
|
|
// Get transaction details
|
|
$stmt = mysqli_prepare($conn, "SELECT * FROM transaksi WHERE id_transaksi = ?");
|
|
|
|
if (!$stmt) {
|
|
error_log("Query preparation failed: " . mysqli_error($conn));
|
|
return null;
|
|
}
|
|
|
|
mysqli_stmt_bind_param($stmt, "i", $transactionId);
|
|
$executed = mysqli_stmt_execute($stmt);
|
|
|
|
if (!$executed) {
|
|
error_log("Query execution failed: " . mysqli_stmt_error($stmt));
|
|
mysqli_stmt_close($stmt);
|
|
return null;
|
|
}
|
|
|
|
$result = mysqli_stmt_get_result($stmt);
|
|
$transaction = mysqli_fetch_assoc($result);
|
|
|
|
if (!$transaction) {
|
|
return null;
|
|
}
|
|
|
|
// Get transaction items
|
|
$stmt = mysqli_prepare($conn, "
|
|
SELECT dt.*, b.nama_barang, b.kode_barang, j.nama_jenis
|
|
FROM detail_transaksi dt
|
|
JOIN barang_kasir b ON dt.id_barangK = b.id_barangK
|
|
JOIN jenis_barang j ON b.id_jenis = j.id_jenis
|
|
WHERE dt.id_transaksi = ?
|
|
");
|
|
|
|
if (!$stmt) {
|
|
error_log("Query preparation failed: " . mysqli_error($conn));
|
|
return $transaction; // Return transaction without items
|
|
}
|
|
|
|
mysqli_stmt_bind_param($stmt, "i", $transactionId);
|
|
$executed = mysqli_stmt_execute($stmt);
|
|
|
|
if (!$executed) {
|
|
error_log("Query execution failed: " . mysqli_stmt_error($stmt));
|
|
mysqli_stmt_close($stmt);
|
|
return $transaction; // Return transaction without items
|
|
}
|
|
|
|
$result = mysqli_stmt_get_result($stmt);
|
|
|
|
$items = [];
|
|
while ($row = mysqli_fetch_assoc($result)) {
|
|
$items[] = $row;
|
|
}
|
|
|
|
$transaction['items'] = $items;
|
|
|
|
return $transaction;
|
|
} catch (Exception $e) {
|
|
error_log("Exception in getTransactionById: " . $e->getMessage());
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get recent transactions
|
|
*
|
|
* @param int $limit Maximum number of transactions to return
|
|
* @return array List of recent transactions
|
|
*/
|
|
function getRecentTransactions($limit = 10) {
|
|
global $conn;
|
|
|
|
try {
|
|
$query = "SELECT * FROM transaksi ORDER BY created_at DESC LIMIT " . intval($limit);
|
|
$result = mysqli_query($conn, $query);
|
|
|
|
if (!$result) {
|
|
error_log("Query failed: " . mysqli_error($conn));
|
|
return [];
|
|
}
|
|
|
|
$transactions = [];
|
|
while ($row = mysqli_fetch_assoc($result)) {
|
|
$transactions[] = $row;
|
|
}
|
|
|
|
return $transactions;
|
|
} catch (Exception $e) {
|
|
error_log("Exception in getRecentTransactions: " . $e->getMessage());
|
|
return [];
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get current user information
|
|
*
|
|
* @return array|null User details or null if not found
|
|
*/
|
|
function getCurrentUser() {
|
|
global $conn;
|
|
|
|
try {
|
|
if (isset($_SESSION['user_id'])) {
|
|
$stmt = mysqli_prepare($conn, "SELECT id_kasir, username, role, phone FROM kasir WHERE id_kasir = ?");
|
|
|
|
if (!$stmt) {
|
|
error_log("Query preparation failed: " . mysqli_error($conn));
|
|
return null;
|
|
}
|
|
|
|
mysqli_stmt_bind_param($stmt, "i", $_SESSION['user_id']);
|
|
$executed = mysqli_stmt_execute($stmt);
|
|
|
|
if (!$executed) {
|
|
error_log("Query execution failed: " . mysqli_stmt_error($stmt));
|
|
mysqli_stmt_close($stmt);
|
|
return null;
|
|
}
|
|
|
|
$result = mysqli_stmt_get_result($stmt);
|
|
$user = mysqli_fetch_assoc($result);
|
|
mysqli_stmt_close($stmt);
|
|
|
|
return $user;
|
|
}
|
|
return null;
|
|
} catch (Exception $e) {
|
|
error_log("Exception in getCurrentUser: " . $e->getMessage());
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get product by barcode (kode_barang)
|
|
*
|
|
* @param string $barcode The product barcode
|
|
* @return array|null Product details or null if not found
|
|
*/
|
|
function getProductByBarcode($barcode) {
|
|
global $conn;
|
|
|
|
try {
|
|
$stmt = mysqli_prepare($conn, "SELECT b.*, j.nama_jenis FROM barang_kasir b
|
|
LEFT JOIN jenis_barang j ON b.id_jenis = j.id_jenis
|
|
WHERE b.kode_barang = ?");
|
|
if (!$stmt) {
|
|
error_log("Query preparation failed: " . mysqli_error($conn));
|
|
return null;
|
|
}
|
|
|
|
mysqli_stmt_bind_param($stmt, "s", $barcode);
|
|
$executed = mysqli_stmt_execute($stmt);
|
|
|
|
if (!$executed) {
|
|
error_log("Query execution failed: " . mysqli_stmt_error($stmt));
|
|
mysqli_stmt_close($stmt);
|
|
return null;
|
|
}
|
|
|
|
$result = mysqli_stmt_get_result($stmt);
|
|
$product = mysqli_fetch_assoc($result);
|
|
mysqli_stmt_close($stmt);
|
|
|
|
// Log untuk debugging
|
|
if ($product) {
|
|
error_log("Product found: ID=" . $product['id_barangK'] . ", Name=" . $product['nama_barang']);
|
|
} else {
|
|
error_log("Product not found for barcode: " . $barcode);
|
|
}
|
|
|
|
return $product;
|
|
} catch (Exception $e) {
|
|
error_log("Exception in getProductByBarcode: " . $e->getMessage());
|
|
return null;
|
|
}
|
|
} |