Skip to content

Commit

Permalink
feat - SPD-132-SPD-133-SPD-146 - Add select/deselect all button, remo…
Browse files Browse the repository at this point in the history
…ve delete button in sales page, Added some validation in add product
  • Loading branch information
Seaaaannnnn committed Jun 28, 2024
1 parent a66736f commit 7d261a1
Show file tree
Hide file tree
Showing 4 changed files with 281 additions and 92 deletions.
34 changes: 15 additions & 19 deletions src/add_product.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$name = $_POST['name'] ?? null;
$category = $_POST['category'] ?? null;
$servingType = $_POST['servingType'] ?? null;
$flavorSize = $_POST['flavorSize'] ?? null;
$servingType = !empty($_POST['servingType']) ? $_POST['servingType'] : null;
$flavorSize = !empty($_POST['flavorSize']) ? $_POST['flavorSize'] : null;
$price = $_POST['price'] ?? null;
$image = $_FILES['image'] ?? null;

if ($name && $category && $price) { // Removed image check here, see below
if ($name && $category && $price) {
// Determine the table based on the category type
$categoryLower = strtolower($category);
if (strpos($categoryLower, 'drink') !== false || in_array($categoryLower, ['froyo', 'coffee & blended'])) {
Expand All @@ -23,14 +23,14 @@
$variationTable = 'drink_variation';
$servingField = 'type';
$flavorField = 'size';
$idField = 'drink_id'; // Add this line for dynamic ID field
$idField = 'drink_id';
} else {
$categoryTable = 'food_item';
$categoryField = 'food_category';
$variationTable = 'food_variation';
$servingField = 'serving';
$flavorField = 'flavor';
$idField = 'food_id'; // Add this line for dynamic ID field
$idField = 'food_id';
}

// Check if the product already exists
Expand Down Expand Up @@ -89,23 +89,19 @@
}
}

// Insert into variations table
if ($servingType || $flavorSize) {
$sql = "INSERT INTO $variationTable ($idField, $servingField, $flavorField, price) VALUES (?, ?, ?, ?)";
$stmt = $db->prepare($sql);
if ($stmt) {
$stmt->bind_param("issd", $productId, $servingType, $flavorSize, $price);
if ($stmt->execute()) {
$response['success'] = true;
} else {
$response['message'] = 'Failed to insert product variations: ' . $stmt->error;
}
$stmt->close();
// Always insert the price, even if servingType and flavorSize are not provided
$sql = "INSERT INTO $variationTable ($idField, $servingField, $flavorField, price) VALUES (?, ?, ?, ?)";
$stmt = $db->prepare($sql);
if ($stmt) {
$stmt->bind_param("issd", $productId, $servingType, $flavorSize, $price);
if ($stmt->execute()) {
$response['success'] = true;
} else {
$response['message'] = 'Failed to prepare variation insertion statement: ' . $db->error;
$response['message'] = 'Failed to insert product variations: ' . $stmt->error;
}
$stmt->close();
} else {
$response['success'] = true;
$response['message'] = 'Failed to prepare variation insertion statement: ' . $db->error;
}
} else {
$response['message'] = 'Name, category, and price are required';
Expand Down
166 changes: 108 additions & 58 deletions src/javascript/billing.js
Original file line number Diff line number Diff line change
Expand Up @@ -222,71 +222,122 @@ $(document).ready(function () {
function generatePrintableContent(tenderedAmount) {
const processedBy = currentUser;
const orderDetails = {
items: [],
subtotal: parseFloat($("#subtotalValue").text().replace(/,/g, "")),
discount: parseFloat($("#discountInput").val()),
grandTotal: parseFloat($("#grandTotalValue").text()),
tenderedAmount: tenderedAmount,
items: [],
subtotal: parseFloat($("#subtotalValue").text().replace(/,/g, "")),
discountPercentage: parseFloat($("#discountInput").val()) || 0, // Set to 0 if NaN
grandTotal: parseFloat($("#grandTotalValue").text()),
tenderedAmount: tenderedAmount,
};

const change = tenderedAmount - orderDetails.grandTotal;
const discountAmount = orderDetails.subtotal * (orderDetails.discountPercentage / 100);

$("#orderCart tr").each(function () {
const cells = $(this).find("td");
orderDetails.items.push({
productName: cells.eq(1).find(".text-capitalize").text().trim(),
quantity: cells.eq(0).find("p").text().trim().slice(1),
price: parseFloat(
cells
.eq(2)
.find(".text-carbon-grey")
.text()
.trim()
.replace(/[^\d.]/g, "")
),
});
const cells = $(this).find("td");
orderDetails.items.push({
productName: cells.eq(1).find(".text-capitalize").text().trim(),
quantity: cells.eq(0).find("p").text().trim().slice(1),
price: parseFloat(
cells
.eq(2)
.find(".text-carbon-grey")
.text()
.trim()
.replace(/[^\d.]/g, "")
),
});
});

return `
<html>
<head>
<title>Receipt</title>
</head>
<body>
<div style="text-align: center;">
<html>
<head>
<title>Receipt</title>
<style>
@media print {
.receipt {
width: auto;
margin: 0 auto;
padding: 10px;
}
.table, .table tr, .table th, .table td {
page-break-inside: avoid;
}
}
html, body {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
display: flex;
justify-content: center;
align-items: center;
font-family: Arial, sans-serif;
background-color: #f8f8f8;
}
.receipt {
width: 80mm; /* Width of a typical thermal paper */
padding: 10px;
box-sizing: border-box;
background-color: white;
page-break-inside: avoid;
}
.center-text {
text-align: center;
}
.table {
width: 100%;
border-collapse: collapse;
page-break-inside: avoid;
}
.table th, .table td {
border-bottom: 1px dashed #000;
padding: 5px 0;
text-align: center;
page-break-inside: avoid;
}
.table th {
border-top: 1px dashed #000;
}
.table .text-end {
text-align: right;
}
.roboto-mono {
font-family: 'Roboto Mono', monospace;
}
h4, h5, p {
margin: 5px 0;
}
</style>
</head>
<body>
<div class="receipt">
<div class="center-text">
<div style="display: flex; align-items: center; justify-content: center;">
<img src="images/logo-removebg-preview.png" alt="Sweet Avenue Logo" style="max-width: 75px; margin-right: 10px;">
<div style="display: flex; flex-direction: column; align-items: flex-start;">
<h4 style="margin: 0;"><strong>SWEET AVENUE</strong></h4>
<h5 style="margin: 0;"><strong>COFFEE • BAKESHOP</strong></h5>
<h4><strong>SWEET AVENUE</strong></h4>
<h5><strong>COFFEE • BAKESHOP</strong></h5>
</div>
</div>
<br>
<p class="roboto-mono"><b>${new Date().toLocaleString()}</b></p>
<hr>
</div>
<table class="table table-borderless text-center" style="margin-bottom: 20px;">
<table class="table">
<thead>
<tr>
<th style="text-align: center;">Product</th>
<th style="text-align: center;">Quantity</th>
<th style="text-align: center;">Price</th>
<th>Product</th>
<th>Quantity</th>
<th>Price</th>
</tr>
</thead>
<tbody class="roboto-mono">
${orderDetails.items
.map(
(item) => `
<tr>
<td class="center-text">${capitalizeEachWord(
item.productName
)}</td>
<td style="text-align: center;">${
item.quantity
}</td>
<td style="text-align: center;">₱${item.price.toFixed(
2
)}</td>
<td>${capitalizeEachWord(item.productName)}</td>
<td>${item.quantity}</td>
<td>₱${item.price.toFixed(2)}</td>
</tr>
`
)
Expand All @@ -295,30 +346,29 @@ $(document).ready(function () {
</table>
<hr>
<div class="roboto-mono">
<p><strong>Subtotal:</strong> ₱${orderDetails.subtotal.toFixed(
2
)}</p>
<p><strong>Discount:</strong> ${orderDetails.discount.toFixed(
2
)} %</p>
<p><strong>Grand Total:</strong> ₱${orderDetails.grandTotal.toFixed(
2
)}</p>
<p><strong>Tendered Amount:</strong> ₱${orderDetails.tenderedAmount.toFixed(
2
)}</p>
<p><strong>Subtotal:</strong> ₱${orderDetails.subtotal.toFixed(2)}</p>
<p><strong>Discount Percentage:</strong> ${orderDetails.discountPercentage.toFixed(2)} %</p>
<p><strong>Discount Amount:</strong> - ₱${discountAmount.toFixed(2)}</p>
<p><strong>Grand Total:</strong> ₱${orderDetails.grandTotal.toFixed(2)}</p>
<p><strong>Tendered Amount:</strong> ₱${orderDetails.tenderedAmount.toFixed(2)}</p>
<p><strong>Change:</strong> ₱${change.toFixed(2)}</p>
</div>
<hr>
<p class="roboto-mono"><strong>Processed by: ${processedBy}</strong></p><br><br>'
<p class="roboto-mono"><strong>Processed by: ${processedBy}</strong></p>
<p class="roboto-mono"><strong>Wifi Password: Sweet_Avenue123</strong></p><br><br>
<hr>
<div class="text-center roboto-mono">
<div class="center-text roboto-mono">
<p>Thank you for your patronage. We’d love to see you again soon. You're always welcome here!</p>
</div>
</body>
</html>
`;
}
</div>
</body>
</html>
`;
}

function capitalizeEachWord(str) {
return str.replace(/\b\w/g, char => char.toUpperCase());
}

// Calculate grand total
function calculateGrandTotal() {
Expand Down
30 changes: 17 additions & 13 deletions src/product.php
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ function getCategories($db, $table) {
food_variation fv ON fi.id = fv.food_id";
$result = $db->query($query);
while($row = $result->fetch_assoc()) {
echo "<tr data-id='".$row['id']."' data-variation-id='".$row['variation_id']."' class='text-capitalize text-truncate fw-semibold'>";
echo "<tr data-id='".$row['id']."' data-variation-id='".$row['variation_id']."' data-product-type='food' class='text-capitalize text-truncate fw-semibold'>";
echo "<td class='text-carbon-grey fw-medium font-14'><input type='checkbox' class='product-checkbox' data-product-id='" . $row['id'] . "' data-variation-id='" . $row['variation_id'] . "'></td>";
echo "<td class='text-carbon-grey fw-medium font-14'><img src='" . $row['Image'] . "' alt='Product Image' style='max-width: 50px; max-height: 50px; border-radius: 50%;'></td>";
echo "<td class='text-carbon-grey fw-medium font-14'>".$row['Name']."</td>";
Expand Down Expand Up @@ -157,7 +157,7 @@ function getCategories($db, $table) {
drink_variation dv ON di.id = dv.drink_id";
$result = $db->query($query);
while($row = $result->fetch_assoc()) {
echo "<tr data-id='".$row['id']."' data-variation-id='".$row['variation_id']."' class='text-capitalize text-truncate fw-semibold'>";
echo "<tr data-id='".$row['id']."' data-variation-id='".$row['variation_id']."'data-product-type='drink' class='text-capitalize text-truncate fw-semibold'>";
echo "<td class='text-carbon-grey fw-medium font-14'><input type='checkbox' class='product-checkbox' data-product-id='" . $row['id'] . "' data-variation-id='" . $row['variation_id'] . "'></td>";
echo "<td class='text-carbon-grey fw-medium font-14'><img src='" . $row['Image'] . "' alt='Product Image' style='max-width: 50px; max-height: 50px; border-radius: 50%;'></td>";
echo "<td class='text-carbon-grey fw-medium font-14'>".$row['Name']."</td>";
Expand Down Expand Up @@ -228,8 +228,8 @@ function getCategories($db, $table) {
</div>
<form id="addProductForm" enctype="multipart/form-data">
<div class="mb-3">
<label for="image" class="form-label">Image</label>
<input type="file" class="form-control" id="image" name="image" accept=".jpg, .jpeg, .png, .svg">
<label for="image" class="form-label">Image<span style="color: red;"> *</span></label>
<input type="file" class="form-control" id="image" name="image" accept=".jpg, .jpeg, .png, .svg" required>
</div>
<div class="mb-3">
<label for="name" class="form-label">Name<span style="color: red;"> *</span></label>
Expand All @@ -251,7 +251,7 @@ function getCategories($db, $table) {
<input type="text" class="form-control" id="servingType" name="servingType">
</div>
<div class="mb-3">
<label for="flavorSize" class="form-label">Flavor/Size</label>
<label for="flavorSize" class="form-label">Flavor/Size<span style="color: red;">(It must have a size if you're adding a product to a drink category.) </span></label>
<input type="text" class="form-control" id="flavorSize" name="flavorSize">
</div>
<div class="mb-3">
Expand Down Expand Up @@ -476,7 +476,7 @@ function resetCategoryForm() {
}
});

document.getElementById('saveChangesBtn').addEventListener('click', addNewProduct);
//document.getElementById('saveChangesBtn').addEventListener('click', addNewProduct);
$('#addProductModal').on('hidden.bs.modal', function () {
resetForm();
});
Expand Down Expand Up @@ -506,8 +506,14 @@ function addNewProduct() {
var category = document.getElementById('category').value.trim();
var priceInput = document.getElementById('price');
var price = priceInput.value.trim();
var imageInput = document.getElementById('image');
var image = imageInput.value.trim();

// Validate form fields
if (!image) {
showError('Image is required.');
return;
}
if (!name) {
showError('Name is required.');
return;
Expand Down Expand Up @@ -553,6 +559,7 @@ function showError(message) {
document.getElementById('errorMessage').innerText = message;
document.getElementById('errorContainer').style.display = 'block';
}

function resetForm() {
document.getElementById('addProductForm').reset();
document.getElementById('errorContainer').style.display = 'none';
Expand All @@ -569,13 +576,15 @@ function resetForm() {
$('#drink').DataTable();

// Capture product data when a row is clicked
$('body').on('click', '.product-checkbox', function() {
$('body').on('click', '.product-checkbox', function() {
var productId = $(this).closest('tr').data('id'); // Fetch the product ID from the data attribute of the closest <tr> element
var variationId = $(this).closest('tr').data('variation-id'); // Fetch the variation ID from the data attribute of the closest <tr> element
var productType = $(this).closest('tr').data('product-type'); // Fetch the product type (drink or food)
var row = $(this).closest('tr');
selectedProduct = {
id: productId,
variationId: variationId,
productType: productType,
image: row.find('img').attr('src'),
name: row.find('td:eq(2)').text().trim(),
category: row.find('td:eq(3)').text().trim(),
Expand All @@ -585,7 +594,6 @@ function resetForm() {
};
});

// Populate the edit modal with the selected product data
$('#editProductModal').on('show.bs.modal', function () {
if (!selectedProduct) {
$('#noProductSelectedModal').modal('show');
Expand All @@ -600,16 +608,12 @@ function resetForm() {
$('#editPrice').val(selectedProduct.price);
$('#productId').val(selectedProduct.id);
$('#variationId').val(selectedProduct.variationId); // Set variationId in the hidden input field
$('#productType').val(selectedProduct.productType); // Set productType in the hidden input field

// Clear previous error messages
$('#editErrorContainer').hide().text('');
$('#priceError').hide();
});

// Handle save changes for editing product
$('#saveChangesEditBtn').on('click', function() {
saveChangesEdit();
});
});

function saveChangesEdit() {
Expand Down
Loading

0 comments on commit 7d261a1

Please sign in to comment.