253 lines
10 KiB
PHP
253 lines
10 KiB
PHP
<?php
|
|
require_once 'includes/header.php';
|
|
require_once 'db/config.php';
|
|
|
|
$message = '';
|
|
$error = '';
|
|
|
|
// Handle form submission
|
|
if (isset($_POST['save_readings'])) {
|
|
$date = $_POST['date'];
|
|
$prices = $_POST['prices'];
|
|
$readings = $_POST['readings'];
|
|
|
|
$pdo = db();
|
|
$pdo->beginTransaction();
|
|
|
|
try {
|
|
$stmt = $pdo->prepare(
|
|
"INSERT INTO daybook_readings (date, nozzle_id, opening_reading, closing_reading, price)
|
|
VALUES (?, ?, ?, ?, ?)"
|
|
);
|
|
|
|
// Fetch fuel types for nozzles
|
|
$nozzle_fuel_types = [];
|
|
$nozzles_stmt = $pdo->query("
|
|
SELECT n.id, ft.fuel_name
|
|
FROM nozzles n
|
|
JOIN pumps p ON n.pump_id = p.id
|
|
JOIN tanks t ON p.tank_id = t.id
|
|
JOIN fuel_types ft ON t.fuel_type_id = ft.id
|
|
");
|
|
while ($row = $nozzles_stmt->fetch(PDO::FETCH_ASSOC)) {
|
|
$nozzle_fuel_types[$row['id']] = $row['fuel_name'];
|
|
}
|
|
|
|
foreach ($readings as $reading) {
|
|
$nozzle_id = $reading['nozzle_id'];
|
|
$opening = $reading['opening'];
|
|
$closing = $reading['closing'];
|
|
|
|
if ($closing < $opening) {
|
|
throw new Exception("Closing reading cannot be less than opening reading for one of the nozzles.");
|
|
}
|
|
|
|
$fuel_name = $nozzle_fuel_types[$nozzle_id] ?? null;
|
|
if (!$fuel_name || !isset($prices[$fuel_name])) {
|
|
throw new Exception("Could not determine price for nozzle ID: $nozzle_id");
|
|
}
|
|
$price = $prices[$fuel_name];
|
|
|
|
$stmt->execute([$date, $nozzle_id, $opening, $closing, $price]);
|
|
}
|
|
|
|
$pdo->commit();
|
|
$message = "Daybook readings saved successfully!";
|
|
} catch (PDOException $e) {
|
|
$pdo->rollBack();
|
|
if ($e->errorInfo[1] == 1062) { // Duplicate entry
|
|
$error = "Error: Daybook readings for this date and nozzle already exist.";
|
|
} else {
|
|
$error = "Database error: " . $e->getMessage();
|
|
}
|
|
} catch (Exception $e) {
|
|
$pdo->rollBack();
|
|
$error = "Error: " . $e->getMessage();
|
|
}
|
|
}
|
|
|
|
|
|
// Fetch previous day's closing readings to suggest as opening readings
|
|
$previous_day_readings = [];
|
|
if (isset($_GET['date'])) {
|
|
$current_date = $_GET['date'];
|
|
$previous_date = date('Y-m-d', strtotime($current_date . ' -1 day'));
|
|
$stmt = db()->prepare("SELECT nozzle_id, closing_reading FROM daybook_readings WHERE date = ?");
|
|
$stmt->execute([$previous_date]);
|
|
$readings = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
|
foreach ($readings as $reading) {
|
|
$previous_day_readings[$reading['nozzle_id']] = $reading['closing_reading'];
|
|
}
|
|
}
|
|
|
|
// Fetch nozzles and their associated fuel types
|
|
$nozzles_stmt = db()->query("
|
|
SELECT n.id, n.nozzle_number, ft.fuel_name
|
|
FROM nozzles n
|
|
JOIN pumps p ON n.pump_id = p.id
|
|
JOIN tanks t ON p.tank_id = t.id
|
|
JOIN fuel_types ft ON t.fuel_type_id = ft.id
|
|
ORDER BY n.id
|
|
");
|
|
$nozzles = $nozzles_stmt->fetchAll(PDO::FETCH_ASSOC);
|
|
|
|
// Group nozzles by fuel type
|
|
$nozzles_by_fuel = [];
|
|
foreach ($nozzles as $nozzle) {
|
|
$nozzles_by_fuel[$nozzle['fuel_name']][] = $nozzle;
|
|
}
|
|
|
|
?>
|
|
|
|
<div class="container-fluid">
|
|
<h1 class="h3 mb-4 text-gray-800">Daily Daybook</h1>
|
|
|
|
<?php if ($message): ?>
|
|
<div class="alert alert-success"><?php echo $message; ?></div>
|
|
<?php endif; ?>
|
|
<?php if ($error): ?>
|
|
<div class="alert alert-danger"><?php echo $error; ?></div>
|
|
<?php endif; ?>
|
|
|
|
<div class="card shadow mb-4">
|
|
<div class="card-header py-3">
|
|
<h6 class="m-0 font-weight-bold text-primary">Enter Readings</h6>
|
|
</div>
|
|
<div class="card-body">
|
|
<form method="GET" action="daybook.php" class="form-inline mb-4">
|
|
<div class="form-group mr-2">
|
|
<label for="date" class="mr-2">Date:</label>
|
|
<input type="date" class="form-control" id="date" name="date" value="<?php echo isset($_GET['date']) ? htmlspecialchars($_GET['date']) : date('Y-m-d'); ?>" required>
|
|
</div>
|
|
<button type="submit" class="btn btn-primary">Load Readings</button>
|
|
</form>
|
|
|
|
<?php if (isset($_GET['date'])): ?>
|
|
<form method="POST" action="daybook.php">
|
|
<input type="hidden" name="date" value="<?php echo htmlspecialchars($_GET['date']); ?>">
|
|
|
|
<?php foreach ($nozzles_by_fuel as $fuel_name => $fuel_nozzles): ?>
|
|
<h5 class="mt-4"><?php echo htmlspecialchars($fuel_name); ?></h5>
|
|
<div class="form-group row">
|
|
<label for="price_<?php echo strtolower($fuel_name); ?>" class="col-sm-2 col-form-label">Price (per Ltr)</label>
|
|
<div class="col-sm-4">
|
|
<input type="number" step="0.01" class="form-control" id="price_<?php echo strtolower($fuel_name); ?>" name="prices[<?php echo htmlspecialchars($fuel_name); ?>]" required>
|
|
</div>
|
|
</div>
|
|
<div class="table-responsive">
|
|
<table class="table table-bordered" width="100%" cellspacing="0">
|
|
<thead>
|
|
<tr>
|
|
<th>Nozzle</th>
|
|
<th>Opening Reading</th>
|
|
<th>Closing Reading</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<?php foreach ($fuel_nozzles as $nozzle): ?>
|
|
<tr>
|
|
<td><?php echo htmlspecialchars($nozzle['nozzle_number']); ?></td>
|
|
<td>
|
|
<input type="hidden" name="readings[<?php echo $nozzle['id']; ?>][nozzle_id]" value="<?php echo $nozzle['id']; ?>">
|
|
<input type="number" step="0.01" class="form-control" name="readings[<?php echo $nozzle['id']; ?>][opening]" value="<?php echo $previous_day_readings[$nozzle['id']] ?? '0.00'; ?>" required>
|
|
</td>
|
|
<td>
|
|
<input type="number" step="0.01" class="form-control" name="readings[<?php echo $nozzle['id']; ?>][closing]" required>
|
|
</td>
|
|
</tr>
|
|
<?php endforeach; ?>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
<?php endforeach; ?>
|
|
<button type="submit" name="save_readings" class="btn btn-success">Save Readings</button>
|
|
</form>
|
|
|
|
<div id="sales_summary" class="mt-4"></div>
|
|
|
|
<?php endif; ?>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<?php require_once 'includes/footer.php'; ?>
|
|
|
|
<script>
|
|
document.addEventListener('DOMContentLoaded', function () {
|
|
const form = document.querySelector('form[method="POST"]');
|
|
if (!form) return;
|
|
|
|
const summaryContainer = document.getElementById('sales_summary');
|
|
|
|
function calculateSales() {
|
|
let totalSalesByFuel = {};
|
|
let grandTotalAmount = 0;
|
|
|
|
const readingInputs = form.querySelectorAll('input[name^="readings["]');
|
|
const prices = {};
|
|
document.querySelectorAll('input[name^="prices["]').forEach(priceInput => {
|
|
const fuelName = priceInput.name.match(/prices\[(.*)\]/)[1];
|
|
prices[fuelName] = parseFloat(priceInput.value) || 0;
|
|
});
|
|
|
|
const nozzlesByFuel = <?php echo json_encode($nozzles_by_fuel); ?>;
|
|
let salesSummaryHtml = '<h5 class="mt-4">Live Sales Summary</h5>';
|
|
|
|
for (const fuelName in nozzlesByFuel) {
|
|
if (nozzlesByFuel.hasOwnProperty(fuelName)) {
|
|
let fuelTotalSaleQty = 0;
|
|
let fuelTotalSaleAmount = 0;
|
|
|
|
nozzlesByFuel[fuelName].forEach(nozzle => {
|
|
const openingInput = form.querySelector(`input[name="readings[${nozzle.id}][opening]"]`);
|
|
const closingInput = form.querySelector(`input[name="readings[${nozzle.id}][closing]"]`);
|
|
|
|
const openingReading = parseFloat(openingInput.value) || 0;
|
|
const closingReading = parseFloat(closingInput.value) || 0;
|
|
const price = prices[fuelName] || 0;
|
|
|
|
if (closingReading >= openingReading) {
|
|
const saleQty = closingReading - openingReading;
|
|
const saleAmount = saleQty * price;
|
|
|
|
fuelTotalSaleQty += saleQty;
|
|
fuelTotalSaleAmount += saleAmount;
|
|
}
|
|
});
|
|
|
|
totalSalesByFuel[fuelName] = {
|
|
qty: fuelTotalSaleQty,
|
|
amount: fuelTotalSaleAmount
|
|
};
|
|
|
|
grandTotalAmount += fuelTotalSaleAmount;
|
|
}
|
|
}
|
|
|
|
salesSummaryHtml += '<div class="table-responsive"><table class="table table-bordered">' +
|
|
'<thead><tr><th>Fuel Type</th><th>Total Sale Qty (Ltr)</th><th>Total Sale Amount</th></tr></thead><tbody>';
|
|
|
|
for (const fuelName in totalSalesByFuel) {
|
|
if (totalSalesByFuel.hasOwnProperty(fuelName)) {
|
|
salesSummaryHtml += `<tr>
|
|
<td>${fuelName}</td>
|
|
<td>${totalSalesByFuel[fuelName].qty.toFixed(2)}</td>
|
|
<td>${totalSalesByFuel[fuelName].amount.toFixed(2)}</td>
|
|
</tr>`;
|
|
}
|
|
}
|
|
|
|
salesSummaryHtml += `</tbody><tfoot><tr>
|
|
<th colspan="2" class="text-right">Grand Total</th>
|
|
<th>${grandTotalAmount.toFixed(2)}</th>
|
|
</tr></tfoot></table></div>`;
|
|
|
|
summaryContainer.innerHTML = salesSummaryHtml;
|
|
}
|
|
|
|
form.addEventListener('input', calculateSales);
|
|
calculateSales(); // Initial calculation
|
|
});
|
|
</script>
|
|
|
|
<?php require_once 'includes/footer.php'; ?>
|