adding services

This commit is contained in:
Flatlogic Bot 2026-03-02 10:39:33 +00:00
parent 874d750960
commit ab23c4540e
4 changed files with 90 additions and 283 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

211
items.php
View File

@ -162,13 +162,12 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action'])) {
} elseif ($_POST['action'] === 'update_price') {
$item_id = $_POST['item_id'];
$service_id = $_POST['service_id'];
$variant_id = $_POST['variant_id'] ?: null;
$price = $_POST['price'];
$stmt = db()->prepare("INSERT INTO prices (branch_id, item_id, variant_id, service_id, price)
VALUES (?, ?, ?, ?, ?)
$stmt = db()->prepare("INSERT INTO prices (branch_id, item_id, service_id, price)
VALUES (?, ?, ?, ?)
ON DUPLICATE KEY UPDATE price = ?");
$stmt->execute([$branch_id, $item_id, $variant_id, $service_id, $price, $price]);
$stmt->execute([$branch_id, $item_id, $service_id, $price, $price]);
if (isset($_POST['ajax'])) {
header('Content-Type: application/json');
@ -178,35 +177,6 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action'])) {
header('Location: items.php?success=price_updated');
exit;
} elseif ($_POST['action'] === 'add_variant') {
$item_id = $_POST['item_id'];
$name_en = $_POST['variant_name_en'];
$name_ar = $_POST['variant_name_ar'];
$stmt = db()->prepare("INSERT INTO item_variants (item_id, name_en, name_ar) VALUES (?, ?, ?)");
$stmt->execute([$item_id, $name_en, $name_ar]);
header('Location: items.php?success=variant_added');
exit;
} elseif ($_POST['action'] === 'edit_variant') {
$id = $_POST['id'];
$name_en = $_POST['name_en'];
$name_ar = $_POST['name_ar'];
$stmt = db()->prepare("UPDATE item_variants SET name_en = ?, name_ar = ? WHERE id = ?");
$stmt->execute([$name_en, $name_ar, $id]);
if (isset($_POST['ajax'])) {
header('Content-Type: application/json');
echo json_encode(['success' => true]);
exit;
}
header('Location: items.php?success=variant_updated');
exit;
} elseif ($_POST['action'] === 'delete_variant') {
$id = $_POST['id'];
$stmt = db()->prepare("DELETE FROM item_variants WHERE id = ?");
$stmt->execute([$id]);
header('Location: items.php?success=variant_deleted');
exit;
}
}
@ -226,14 +196,7 @@ $stmt->execute([$branch_id]);
$prices_raw = $stmt->fetchAll();
$prices = [];
foreach ($prices_raw as $p) {
$v_key = $p['variant_id'] ?: 'default';
$prices[$p['item_id']][$v_key][$p['service_id']] = $p['price'];
}
$item_variants = db()->query("SELECT * FROM item_variants ORDER BY name_en ASC")->fetchAll();
$variants_by_item = [];
foreach ($item_variants as $v) {
$variants_by_item[$v['item_id']][] = $v;
$prices[$p['item_id']][$p['service_id']] = $p['price'];
}
?>
@ -268,7 +231,7 @@ foreach ($item_variants as $v) {
<th class="ps-4 py-3"><?= __('item') ?></th>
<th class="py-3"><?= __('category') ?></th>
<th class="py-3"><?= __('vat_percent') ?></th>
<th class="py-3"><?= __('variants_prices') ?? 'Pricing & Services' ?></th>
<th class="py-3"><?= __('pricing_services') ?? 'Pricing & Services' ?></th>
<th class="pe-4 py-3 text-end"><?= __('actions') ?></th>
</tr>
</thead>
@ -302,7 +265,7 @@ foreach ($item_variants as $v) {
<td><?= number_format($item['vat_percent'], 2) ?>%</td>
<td>
<button class="btn btn-sm btn-outline-info px-3" style="border-radius: 8px;" data-bs-toggle="modal" data-bs-target="#pricingModal<?= $item['id'] ?>">
<i class="bi bi-currency-dollar me-1"></i> <?= count($variants_by_item[$item['id']] ?? []) ?> <?= __('variants') ?> / <?= count($services) ?> <?= __('services') ?>
<i class="bi bi-currency-dollar me-1"></i> <?= count($services) ?> <?= __('services') ?>
</button>
</td>
<td class="pe-4 text-end">
@ -324,10 +287,10 @@ foreach ($item_variants as $v) {
<div class="d-flex">
<i class="bi bi-info-circle-fill me-3 fs-4"></i>
<div>
<h6 class="fw-bold mb-1">How to use Variants & Services?</h6>
<h6 class="fw-bold mb-1">How to manage Services?</h6>
<p class="mb-0 small">
<strong>Services:</strong> General actions like "Wash Only", "Urgent Wash", "Iron Only". Add them once and set prices for each item.<br>
<strong>Variants:</strong> Specific garment types or materials like "Silk Dress", "Wool Suit", or "Large Carpet". Use them if an item has different versions with unique pricing.
<strong>Services:</strong> Actions like "Wash Only", "Urgent Wash", "Iron Only". Add them using the <strong>Services</strong> button at the top, then set prices for each item in the table above.<br>
<em>Simplified:</em> We removed "Variants" to make it easier. Now you just define your services and set their prices for each item.
</p>
</div>
</div>
@ -535,64 +498,35 @@ foreach ($item_variants as $v) {
<!-- Pricing Modals -->
<?php foreach($items as $item): ?>
<div class="modal fade pricing-modal" id="pricingModal<?= $item['id'] ?>" tabindex="-1">
<div class="modal-dialog modal-xl modal-dialog-centered">
<div class="modal-dialog modal-lg modal-dialog-centered">
<div class="modal-content" style="border-radius: 25px;">
<div class="modal-header border-0 p-4">
<div>
<h5 class="modal-title fw-bold m-0"><?= __('pricing_management') ?></h5>
<h5 class="modal-title fw-bold m-0"><?= __('service_pricing') ?? 'Service Pricing' ?></h5>
<p class="text-muted m-0 small"><?= $lang === 'ar' ? $item['name_ar'] : $item['name_en'] ?></p>
</div>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body p-4 pt-0">
<!-- Add Variant Form -->
<div class="bg-light p-3 mb-4 d-flex align-items-end" style="border-radius: 15px;">
<form method="POST" class="row g-2 w-100">
<input type="hidden" name="action" value="add_variant">
<input type="hidden" name="item_id" value="<?= $item['id'] ?>">
<div class="col-md-4">
<label class="form-label small fw-bold mb-1"><?= __('variant_name_en') ?? 'Variant Name (e.g. Silk, Long, Small)' ?></label>
<input type="text" name="variant_name_en" class="form-control form-control-sm" required style="border-radius: 8px;">
</div>
<div class="col-md-4">
<label class="form-label small fw-bold mb-1"><?= __('variant_name_ar') ?? 'Variant Name (AR)' ?></label>
<input type="text" name="variant_name_ar" class="form-control form-control-sm" style="border-radius: 8px;">
</div>
<div class="col-md-4">
<button type="submit" class="btn btn-sm btn-primary w-100 py-2 fw-bold" style="border-radius: 8px;">
<i class="bi bi-plus-lg me-1"></i> <?= __('add_variant') ?>
</button>
</div>
</form>
</div>
<div class="table-responsive">
<table class="table table-hover align-middle">
<thead class="bg-light">
<tr class="small text-muted">
<th style="min-width: 200px;"><?= __('variant') ?></th>
<?php foreach($services as $s): ?>
<th class="text-center"><?= $lang === 'ar' ? $s['name_ar'] : $s['name_en'] ?></th>
<?php endforeach; ?>
<th class="text-end"><?= __('actions') ?></th>
<th style="min-width: 200px;"><?= __('service') ?></th>
<th class="text-center"><?= __('price') ?> (SAR)</th>
</tr>
</thead>
<tbody>
<!-- Default Variant -->
<tr>
<td class="fw-bold">
<div class="d-flex align-items-center">
<i class="bi bi-star-fill text-warning me-2"></i>
<?= __('default') ?>
</div>
</td>
<?php foreach($services as $service): ?>
<?php foreach($services as $service): ?>
<tr>
<td class="fw-bold">
<?= $lang === 'ar' ? $service['name_ar'] : $service['name_en'] ?>
</td>
<td class="text-center">
<div class="input-group input-group-sm justify-content-center mx-auto" style="width: 120px; position: relative;">
<div class="input-group input-group-sm justify-content-center mx-auto" style="width: 150px; position: relative;">
<input type="number" step="0.01" class="form-control text-center price-input"
value="<?= $prices[$item['id']]['default'][$service['id']] ?? 0.00 ?>"
value="<?= $prices[$item['id']][$service['id']] ?? 0.00 ?>"
data-item-id="<?= $item['id'] ?>"
data-variant-id=""
data-service-id="<?= $service['id'] ?>"
style="border-radius: 8px;">
<span class="input-group-text bg-transparent border-0 d-none success-indicator" style="position: absolute; right: -25px; top: 5px;">
@ -600,64 +534,13 @@ foreach ($item_variants as $v) {
</span>
</div>
</td>
<?php endforeach; ?>
<td class="text-end"></td>
</tr>
<!-- Custom Variants -->
<?php if(isset($variants_by_item[$item['id']])): ?>
<?php foreach($variants_by_item[$item['id']] as $variant): ?>
<tr>
<td>
<div class="row g-1 position-relative">
<div class="col-6">
<input type="text" class="form-control form-control-sm variant-name-input"
value="<?= $variant['name_en'] ?>"
data-variant-id="<?= $variant['id'] ?>"
data-field="name_en"
placeholder="EN"
style="border-radius: 6px;">
</div>
<div class="col-6">
<input type="text" class="form-control form-control-sm variant-name-input"
value="<?= $variant['name_ar'] ?>"
data-variant-id="<?= $variant['id'] ?>"
data-field="name_ar"
placeholder="AR"
style="border-radius: 6px; text-align: right;">
</div>
<span class="success-indicator d-none" style="position: absolute; right: -20px; top: 8px;">
<i class="bi bi-check-lg text-success"></i>
</span>
</div>
</td>
<?php foreach($services as $service): ?>
<td class="text-center">
<div class="input-group input-group-sm justify-content-center mx-auto" style="width: 120px; position: relative;">
<input type="number" step="0.01" class="form-control text-center price-input"
value="<?= $prices[$item['id']][$variant['id']][$service['id']] ?? 0.00 ?>"
data-item-id="<?= $item['id'] ?>"
data-variant-id="<?= $variant['id'] ?>"
data-service-id="<?= $service['id'] ?>"
style="border-radius: 8px;">
<span class="input-group-text bg-transparent border-0 d-none success-indicator" style="position: absolute; right: -25px; top: 5px;">
<i class="bi bi-check-lg text-success"></i>
</span>
</div>
</td>
<?php endforeach; ?>
<td class="text-end">
<button type="button" class="btn btn-sm btn-light text-danger" onclick="confirmDeleteVariant(<?= $variant['id'] ?>)" style="border-radius: 8px;">
<i class="bi bi-trash"></i>
</button>
</td>
</tr>
<?php endforeach; ?>
<?php endif; ?>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
<div class="alert alert-info py-2 small mt-3 mb-0" style="border-radius: 10px;">
<i class="bi bi-info-circle me-2"></i> Prices and variant names are saved automatically as you type.
<i class="bi bi-info-circle me-2"></i> Prices are saved automatically as you type.
</div>
</div>
</div>
@ -673,7 +556,7 @@ foreach ($item_variants as $v) {
<style>
.bg-soft-primary { background-color: rgba(13, 110, 253, 0.1); }
.price-input:focus, .variant-name-input:focus {
.price-input:focus {
border-color: #0d6efd;
box-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.1);
}
@ -761,15 +644,7 @@ function confirmDelete(type, id) {
}
}
function confirmDeleteVariant(id) {
if (confirm("<?= __('are_you_sure') ?>")) {
document.getElementById('deleteAction').value = 'delete_variant';
document.getElementById('deleteId').value = id;
document.getElementById('deleteForm').submit();
}
}
// AJAX logic for prices and variants
// AJAX logic for prices
document.querySelectorAll('.price-input').forEach(input => {
let timeout = null;
input.addEventListener('input', function() {
@ -780,7 +655,6 @@ document.querySelectorAll('.price-input').forEach(input => {
formData.append('action', 'update_price');
formData.append('ajax', '1');
formData.append('item_id', self.dataset.itemId);
formData.append('variant_id', self.dataset.variantId);
formData.append('service_id', self.dataset.serviceId);
formData.append('price', self.value);
@ -800,41 +674,8 @@ document.querySelectorAll('.price-input').forEach(input => {
});
});
document.querySelectorAll('.variant-name-input').forEach(input => {
let timeout = null;
input.addEventListener('input', function() {
clearTimeout(timeout);
const self = this;
timeout = setTimeout(async () => {
const row = self.closest('tr');
const enInput = row.querySelector('[data-field="name_en"]');
const arInput = row.querySelector('[data-field="name_ar"]');
const formData = new FormData();
formData.append('action', 'edit_variant');
formData.append('ajax', '1');
formData.append('id', self.dataset.variantId);
formData.append('name_en', enInput.value);
formData.append('name_ar', arInput.value);
try {
const response = await fetch('items.php', {
method: 'POST',
body: formData
});
const data = await response.json();
if (data.success) {
showIndicator(self);
}
} catch (error) {
console.error('Error updating variant:', error);
}
}, 500);
});
});
function showIndicator(input) {
const indicator = input.parentElement.querySelector('.success-indicator') || input.closest('td').querySelector('.success-indicator');
const indicator = input.parentElement.querySelector('.success-indicator');
if (indicator) {
indicator.classList.remove('d-none');
setTimeout(() => {

View File

@ -53,12 +53,10 @@ $title = 'order_details';
require_once __DIR__ . '/includes/header.php';
$stmt = db()->prepare("SELECT oi.*, i.name_en as item_en, i.name_ar as item_ar,
s.name_en as service_en, s.name_ar as service_ar,
v.name_en as variant_en, v.name_ar as variant_ar
s.name_en as service_en, s.name_ar as service_ar
FROM order_items oi
JOIN items i ON oi.item_id = i.id
JOIN services s ON oi.service_id = s.id
LEFT JOIN item_variants v ON oi.variant_id = v.id
WHERE oi.order_id = ?");
$stmt->execute([$order_id]);
$order_items = $stmt->fetchAll();
@ -71,10 +69,10 @@ $payments = $stmt->fetchAll();
<div class="row">
<div class="col-md-8">
<div class="card p-4 mb-4">
<div class="card p-4 mb-4" style="border-radius: 25px; border: none; shadow: 0 10px 30px rgba(0,0,0,0.05);">
<div class="d-flex justify-content-between align-items-center mb-4">
<h5 class="fw-bold mb-0"><?= __('order') ?> #<?= $order['order_number'] ?></h5>
<span class="badge bg-<?= getStatusColor($order['status']) ?> fs-6 px-3 py-2"><?= __($order['status']) ?></span>
<span class="badge bg-<?= getStatusColor($order['status']) ?> fs-6 px-3 py-2" style="border-radius: 12px;"><?= __($order['status']) ?></span>
</div>
<div class="table-responsive mb-4">
@ -97,56 +95,54 @@ $payments = $stmt->fetchAll();
?>
<tr>
<td>
<?= $lang === 'ar' ? ($item['item_ar'] ?: $item['item_en']) : $item['item_en'] ?>
<?php if($item['variant_id']): ?>
<br><small class="text-muted"><?= $lang === 'ar' ? $item['variant_ar'] : $item['variant_en'] ?></small>
<?php endif; ?>
<strong><?= $lang === 'ar' ? ($item['item_ar'] ?: $item['item_en']) : $item['item_en'] ?></strong>
</td>
<td><?= $lang === 'ar' ? ($item['service_ar'] ?: $item['service_en']) : $item['service_en'] ?></td>
<td><?= $item['quantity'] ?></td>
<td class="text-end"><?= number_format($item['unit_price'], 2) ?> SAR</td>
<td class="text-end"><?= number_format($item['vat_amount'] * $item['quantity'], 2) ?> SAR</td>
<td class="text-end"><?= number_format($item['subtotal'] + ($item['vat_amount'] * $item['quantity']), 2) ?> SAR</td>
<td class="text-end fw-bold"><?= number_format($item['subtotal'] + ($item['vat_amount'] * $item['quantity']), 2) ?> SAR</td>
</tr>
<?php endforeach; ?>
</tbody>
<tfoot>
<tr>
<th colspan="5" class="text-end"><?= __('subtotal') ?></th>
<th colspan="5" class="text-end text-muted small"><?= __('subtotal') ?></th>
<th class="text-end"><?= number_format($subtotal_sum, 2) ?> SAR</th>
</tr>
<tr>
<th colspan="5" class="text-end"><?= __('vat_total') ?? 'VAT Total' ?></th>
<th colspan="5" class="text-end text-muted small"><?= __('vat_total') ?? 'VAT Total' ?></th>
<th class="text-end"><?= number_format($order['vat_total'], 2) ?> SAR</th>
</tr>
<tr>
<th colspan="5" class="text-end"><?= __('total') ?></th>
<th class="text-end fs-5 text-primary"><?= number_format($order['total_price'], 2) ?> SAR</th>
<th colspan="5" class="text-end fs-5 fw-bold"><?= __('total') ?></th>
<th class="text-end fs-5 fw-bold text-primary"><?= number_format($order['total_price'], 2) ?> SAR</th>
</tr>
</tfoot>
</table>
</div>
<div class="row mt-4">
<div class="row mt-4 p-4 bg-light mx-1" style="border-radius: 20px;">
<div class="col-md-6">
<h6 class="fw-bold"><?= __('customer_details') ?></h6>
<p class="mb-1"><strong><?= $lang === 'ar' ? ($order['customer_name_ar'] ?: $order['customer_name_en']) : $order['customer_name_en'] ?></strong></p>
<h6 class="fw-bold text-muted small mb-3"><?= __('customer_details') ?></h6>
<p class="mb-1 fw-bold"><?= $lang === 'ar' ? ($order['customer_name_ar'] ?: $order['customer_name_en']) : $order['customer_name_en'] ?></p>
<p class="mb-1"><?= $order['customer_phone'] ?></p>
<p class="mb-0 text-muted"><?= $lang === 'ar' ? ($order['customer_address_ar'] ?: $order['customer_address_en']) : $order['customer_address_en'] ?></p>
<p class="mb-0 text-muted small"><?= $lang === 'ar' ? ($order['customer_address_ar'] ?: $order['customer_address_en']) : $order['customer_address_en'] ?></p>
</div>
<div class="col-md-6 text-md-end">
<h6 class="fw-bold"><?= __('order_date') ?></h6>
<p><?= date('d M Y, h:i A', strtotime($order['created_at'])) ?></p>
<div class="col-md-6 text-md-end mt-4 mt-md-0">
<h6 class="fw-bold text-muted small mb-3"><?= __('order_date') ?></h6>
<p class="mb-0 fw-bold"><?= date('d M Y', strtotime($order['created_at'])) ?></p>
<p class="mb-0 text-muted"><?= date('h:i A', strtotime($order['created_at'])) ?></p>
</div>
</div>
</div>
<div class="card p-4">
<div class="card p-4 border-0 shadow-sm mb-4" style="border-radius: 25px;">
<h5 class="fw-bold mb-4"><?= __('payments') ?></h5>
<div class="table-responsive">
<table class="table">
<table class="table table-sm">
<thead>
<tr>
<tr class="text-muted small">
<th><?= __('date') ?></th>
<th><?= __('method') ?></th>
<th class="text-end"><?= __('amount') ?></th>
@ -156,13 +152,13 @@ $payments = $stmt->fetchAll();
<?php foreach($payments as $p): ?>
<tr>
<td><?= date('d M Y, h:i A', strtotime($p['created_at'])) ?></td>
<td><?= __($p['payment_method']) ?></td>
<td class="text-end"><?= number_format($p['amount'], 2) ?> SAR</td>
<td><span class="badge bg-light text-dark px-3 py-2 rounded-pill"><?= __($p['payment_method']) ?></span></td>
<td class="text-end fw-bold"><?= number_format($p['amount'], 2) ?> SAR</td>
</tr>
<?php endforeach; ?>
<?php if (empty($payments)): ?>
<tr>
<td colspan="3" class="text-center text-muted"><?= __('no_payments') ?></td>
<td colspan="3" class="text-center text-muted py-4"><?= __('no_payments') ?></td>
</tr>
<?php endif; ?>
</tbody>
@ -172,52 +168,57 @@ $payments = $stmt->fetchAll();
</div>
<div class="col-md-4">
<div class="card p-4 mb-4">
<div class="card p-4 mb-4 border-0 shadow-sm" style="border-radius: 25px;">
<h5 class="fw-bold mb-4"><?= __('actions') ?></h5>
<form method="POST" class="mb-4">
<input type="hidden" name="action" value="update_status">
<label class="form-label small text-muted"><?= __('update_status') ?></label>
<div class="input-group">
<select name="status" class="form-select" style="border-radius: 12px 0 0 12px;">
<label class="form-label small fw-bold text-muted"><?= __('update_status') ?></label>
<div class="input-group shadow-sm" style="border-radius: 12px; overflow: hidden;">
<select name="status" class="form-select border-0 bg-light">
<option value="received" <?= $order['status'] == 'received' ? 'selected' : '' ?>><?= __('received') ?></option>
<option value="processing" <?= $order['status'] == 'processing' ? 'selected' : '' ?>><?= __('processing') ?></option>
<option value="ready" <?= $order['status'] == 'ready' ? 'selected' : '' ?>><?= __('ready') ?></option>
<option value="delivered" <?= $order['status'] == 'delivered' ? 'selected' : '' ?>><?= __('delivered') ?></option>
<option value="cancelled" <?= $order['status'] == 'cancelled' ? 'selected' : '' ?>><?= __('cancelled') ?></option>
</select>
<button type="submit" class="btn btn-primary" style="border-radius: 0 12px 12px 0;"><?= __('update') ?></button>
<button type="submit" class="btn btn-primary px-3 fw-bold"><?= __('update') ?></button>
</div>
</form>
<hr>
<hr class="my-4 opacity-10">
<?php
$stmt = db()->prepare("SELECT SUM(amount) as total_paid FROM payments WHERE order_id = ?");
$stmt->execute([$order_id]);
$total_paid = $stmt->fetch()['total_paid'] ?? 0;
$remaining = $order['total_price'] - $total_paid;
?>
<div class="alert alert-<?= $remaining <= 0 ? 'success' : 'warning' ?> p-2 px-3 small rounded-4">
<?= __('remaining_amount') ?>: <strong><?= number_format(max(0, $remaining), 2) ?> SAR</strong>
<div class="d-flex justify-content-between align-items-center mb-3">
<span class="text-muted fw-bold small"><?= __('remaining_amount') ?></span>
<span class="fs-5 fw-bold <?= $remaining <= 0 ? 'text-success' : 'text-danger' ?>">
<?= number_format(max(0, $remaining), 2) ?> <small>SAR</small>
</span>
</div>
<?php if ($remaining > 0): ?>
<form method="POST">
<input type="hidden" name="action" value="add_payment">
<div class="mb-3">
<label class="form-label small text-muted"><?= __('amount') ?></label>
<input type="number" step="0.01" name="amount" class="form-control" value="<?= $remaining ?>" required style="border-radius: 12px;">
<label class="form-label small fw-bold text-muted"><?= __('amount') ?></label>
<input type="number" step="0.01" name="amount" class="form-control bg-light border-0" value="<?= $remaining ?>" required style="border-radius: 12px;">
</div>
<div class="mb-3">
<label class="form-label small text-muted"><?= __('payment_method') ?></label>
<select name="payment_method" class="form-select" style="border-radius: 12px;">
<label class="form-label small fw-bold text-muted"><?= __('payment_method') ?></label>
<select name="payment_method" class="form-select bg-light border-0" style="border-radius: 12px;">
<option value="cash"><?= __('cash') ?></option>
<option value="card"><?= __('card') ?></option>
<option value="transfer"><?= __('transfer') ?></option>
</select>
</div>
<button type="submit" class="btn btn-success w-100 py-2" style="border-radius: 12px;"><?= __('add_payment') ?></button>
<button type="submit" class="btn btn-success w-100 py-3 fw-bold shadow-sm" style="border-radius: 15px;"><?= __('add_payment') ?></button>
</form>
<?php endif; ?>
<button class="btn btn-outline-dark w-100 mt-3 py-2" style="border-radius: 12px;" onclick="window.print()">
<i class="bi bi-printer me-1"></i> <?= __('print_invoice') ?>
<button class="btn btn-outline-dark w-100 mt-4 py-3 fw-bold shadow-sm" style="border-radius: 15px;" onclick="window.print()">
<i class="bi bi-printer me-2"></i> <?= __('print_invoice') ?>
</button>
</div>
</div>
@ -234,4 +235,4 @@ function getStatusColor($status) {
][$status] ?? 'info';
}
require_once __DIR__ . '/includes/footer.php';
?>
?>

75
pos.php
View File

@ -16,12 +16,10 @@ $stmt->execute();
$items_raw = $stmt->fetchAll();
// Get all services and prices for this branch
$stmt = db()->prepare("SELECT p.item_id, p.variant_id, p.service_id, p.price,
s.name_en as service_en, s.name_ar as service_ar,
v.name_en as variant_en, v.name_ar as variant_ar
$stmt = db()->prepare("SELECT p.item_id, p.service_id, p.price,
s.name_en as service_en, s.name_ar as service_ar
FROM prices p
JOIN services s ON p.service_id = s.id
LEFT JOIN item_variants v ON p.variant_id = v.id
WHERE p.branch_id = ?");
$stmt->execute([$branch_id]);
$all_prices = $stmt->fetchAll();
@ -35,37 +33,19 @@ foreach ($items_raw as $i) {
'category_id' => $i['category_id'],
'image_url' => $i['image_url'],
'vat_percent' => (float)$i['vat_percent'],
'variants' => [],
'default_services' => []
'services' => []
];
}
foreach ($all_prices as $p) {
if (!isset($items[$p['item_id']])) continue;
if ($p['variant_id']) {
if (!isset($items[$p['item_id']]['variants'][$p['variant_id']])) {
$items[$p['item_id']]['variants'][$p['variant_id']] = [
'id' => $p['variant_id'],
'name_en' => $p['variant_en'],
'name_ar' => $p['variant_ar'],
'services' => []
];
}
$items[$p['item_id']]['variants'][$p['variant_id']]['services'][] = [
'id' => $p['service_id'],
'name_en' => $p['service_en'],
'name_ar' => $p['service_ar'],
'price' => (float)$p['price']
];
} else {
$items[$p['item_id']]['default_services'][] = [
'id' => $p['service_id'],
'name_en' => $p['service_en'],
'name_ar' => $p['service_ar'],
'price' => (float)$p['price']
];
}
$items[$p['item_id']]['services'][] = [
'id' => $p['service_id'],
'name_en' => $p['service_en'],
'name_ar' => $p['service_ar'],
'price' => (float)$p['price']
];
}
// Get all customers for this branch
@ -99,7 +79,7 @@ $customers = $stmt->fetchAll();
<div class="row g-3" id="itemsList">
<?php foreach($items as $item): ?>
<?php if (empty($item['default_services']) && empty($item['variants'])) continue; ?>
<?php if (empty($item['services'])) continue; ?>
<div class="col-md-4 col-sm-6 item-card-wrapper"
data-cat="<?= $item['category_id'] ?>"
data-name-en="<?= strtolower($item['name_en']) ?>"
@ -119,7 +99,7 @@ $customers = $stmt->fetchAll();
</div>
<div class="card-body p-3 text-center">
<div class="fw-bold fs-6"><?= $lang === 'ar' ? $item['name_ar'] : $item['name_en'] ?></div>
<small class="text-muted d-block mt-1"><?= count($item['default_services']) + count($item['variants']) ?> <?= __('options') ?? 'Options' ?></small>
<small class="text-muted d-block mt-1"><?= count($item['services']) ?> <?= __('services') ?></small>
</div>
</div>
</div>
@ -187,7 +167,7 @@ $customers = $stmt->fetchAll();
<div class="modal-header border-0 pb-0 p-4">
<div>
<h5 class="modal-title fw-bold" id="selectionItemName"></h5>
<p class="text-muted small m-0"><?= __('select_service_option') ?? 'Select service type' ?></p>
<p class="text-muted small m-0"><?= __('select_service') ?? 'Select service type' ?></p>
</div>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
@ -245,43 +225,30 @@ function showOptions(itemId) {
const optionsList = document.getElementById('optionsList');
optionsList.innerHTML = '';
// 1. Add Default Services
item.default_services.forEach(service => {
addOptionButton(item, null, service);
});
// 2. Add Variant Services
Object.values(item.variants).forEach(variant => {
variant.services.forEach(service => {
addOptionButton(item, variant, service);
});
item.services.forEach(service => {
addOptionButton(item, service);
});
selectionModal.show();
}
function addOptionButton(item, variant, service) {
function addOptionButton(item, service) {
const optionsList = document.getElementById('optionsList');
const btn = document.createElement('button');
btn.className = 'list-group-item list-group-item-action d-flex justify-content-between align-items-center border-0 py-3 mb-2 rounded-4 bg-light shadow-sm-hover transition';
let variantText = variant ? (lang === 'ar' ? variant.name_ar : variant.name_en) : '';
let serviceText = lang === 'ar' ? service.name_ar : service.name_en;
btn.innerHTML = `
<div>
${variantText ? `<div class="badge bg-primary text-white mb-1 small rounded-pill px-2" style="font-size: 0.7rem;">${variantText}</div>` : ''}
<div class="fw-bold">${serviceText}</div>
</div>
<div class="fw-bold">${serviceText}</div>
<div class="text-primary fw-bold fs-5">${service.price.toFixed(2)} <small style="font-size: 0.8rem;">SAR</small></div>
`;
btn.onclick = () => addToCart(item, variant, service);
btn.onclick = () => addToCart(item, service);
optionsList.appendChild(btn);
}
function addToCart(item, variant, service) {
const variantId = variant ? variant.id : null;
const cartItemId = `${item.id}-${variantId}-${service.id}`;
function addToCart(item, service) {
const cartItemId = `${item.id}-${service.id}`;
const existing = cart.find(i => i.cartItemId === cartItemId);
const vatPercent = item.vat_percent || 0;
@ -293,10 +260,8 @@ function addToCart(item, variant, service) {
cart.push({
cartItemId,
itemId: item.id,
variantId: variantId,
serviceId: service.id,
itemName: lang === 'ar' ? item.name_ar : item.name_en,
variantName: variant ? (lang === 'ar' ? variant.name_ar : variant.name_en) : null,
serviceName: lang === 'ar' ? service.name_ar : service.name_en,
price: service.price,
vatPercent: vatPercent,
@ -325,7 +290,7 @@ function updateCart() {
row.className = 'cart-item-row d-flex justify-content-between align-items-center mb-3 p-3 bg-white border rounded-4 shadow-sm';
row.innerHTML = `
<div style="flex: 1;">
<div class="fw-bold small">${item.itemName}${item.variantName ? ' <span class="badge bg-soft-primary text-primary mx-1" style="font-size: 0.65rem;">' + item.variantName + '</span>' : ''}</div>
<div class="fw-bold small">${item.itemName}</div>
<div class="text-muted" style="font-size: 0.75rem;">${item.serviceName}</div>
</div>
<div class="d-flex align-items-center mx-3 bg-light rounded-pill px-2 py-1">