adding loyalty

This commit is contained in:
Flatlogic Bot 2026-02-18 04:39:05 +00:00
parent 41c061c036
commit 8d434a18ee
2 changed files with 316 additions and 32 deletions

View File

@ -0,0 +1,31 @@
-- Modern Loyalty System Migration
ALTER TABLE customers
ADD COLUMN IF NOT EXISTS loyalty_tier ENUM('bronze', 'silver', 'gold') DEFAULT 'bronze',
ADD COLUMN IF NOT EXISTS total_spent DECIMAL(15, 3) DEFAULT 0.000;
CREATE TABLE IF NOT EXISTS loyalty_transactions (
id INT AUTO_INCREMENT PRIMARY KEY,
customer_id INT NOT NULL,
transaction_id INT NULL,
points_change DECIMAL(15, 3) NOT NULL,
transaction_type ENUM('earned', 'redeemed', 'adjustment') NOT NULL,
description TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (customer_id) REFERENCES customers(id) ON DELETE CASCADE
);
-- Update existing total_spent based on previous transactions if possible
UPDATE customers c
SET c.total_spent = (
SELECT COALESCE(SUM(total_with_vat), 0)
FROM invoices
WHERE customer_id = c.id AND type = 'sale'
);
-- Initial tier update based on existing spent amount
UPDATE customers
SET loyalty_tier = CASE
WHEN total_spent >= 1500 THEN 'gold'
WHEN total_spent >= 500 THEN 'silver'
ELSE 'bronze'
END;

317
index.php
View File

@ -39,6 +39,58 @@ function getPromotionalPrice($item) {
return $price;
}
function getLoyaltyMultiplier($tier) {
return match($tier) {
'silver' => 1.2,
'gold' => 1.5,
default => 1.0,
};
}
function updateCustomerLoyalty($customer_id, $spent_amount, $points_earned, $loyalty_redeemed_value, $invoice_id = null) {
$db = db();
// Fetch settings for dynamic rates
$settings_res = $db->query("SELECT * FROM settings WHERE `key` IN ('loyalty_enabled', 'loyalty_redeem_points_per_unit')")->fetchAll(PDO::FETCH_ASSOC);
$settings = [];
foreach ($settings_res as $s) $settings[$s['key']] = $s['value'];
if (($settings['loyalty_enabled'] ?? '0') !== '1') return; // System disabled
$redeem_rate = (float)($settings['loyalty_redeem_points_per_unit'] ?? 100);
$points_redeemed = (float)$loyalty_redeemed_value * $redeem_rate;
// Update points and total_spent
$stmt = $db->prepare("UPDATE customers SET loyalty_points = loyalty_points - ? + ?, total_spent = total_spent + ? WHERE id = ?");
$stmt->execute([(float)$points_redeemed, (float)$points_earned, (float)$spent_amount, $customer_id]);
// Fetch updated total_spent to check for tier upgrade
$stmt = $db->prepare("SELECT total_spent, loyalty_tier FROM customers WHERE id = ?");
$stmt->execute([$customer_id]);
$customer = $stmt->fetch();
$new_tier = 'bronze';
if ($customer['total_spent'] >= 1500) $new_tier = 'gold';
elseif ($customer['total_spent'] >= 500) $new_tier = 'silver';
if ($new_tier !== $customer['loyalty_tier']) {
$stmt = $db->prepare("UPDATE customers SET loyalty_tier = ? WHERE id = ?");
$stmt->execute([$new_tier, $customer_id]);
}
// Log Earned Points
if ($points_earned > 0) {
$stmt = $db->prepare("INSERT INTO loyalty_transactions (customer_id, transaction_id, points_change, transaction_type, description) VALUES (?, ?, ?, 'earned', ?)");
$stmt->execute([$customer_id, $invoice_id, $points_earned, "Earned from transaction #$invoice_id (Tier: " . strtoupper($customer['loyalty_tier']) . ")"]);
}
// Log Redeemed Points
if ($points_redeemed > 0) {
$stmt = $db->prepare("INSERT INTO loyalty_transactions (customer_id, transaction_id, points_change, transaction_type, description) VALUES (?, ?, ?, 'redeemed', ?)");
$stmt->execute([$customer_id, $invoice_id, -$points_redeemed, "Redeemed $points_redeemed pts (Value: " . number_format((float)$loyalty_redeemed_value, 3) . " OMR) in transaction #$invoice_id"]);
}
}
function numberToWords($num) {
$num = (int)$num;
if ($num === 0) return "Zero";
@ -275,6 +327,13 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$loyalty_redeemed = (float)($_POST['loyalty_redeemed'] ?? 0);
$items = json_decode($_POST['items'] ?? '[]', true);
// Fetch settings
$settings_res = $db->query("SELECT * FROM settings WHERE `key` IN ('loyalty_enabled', 'loyalty_points_per_unit')")->fetchAll(PDO::FETCH_ASSOC);
$app_settings = [];
foreach ($settings_res as $s) $app_settings[$s['key']] = $s['value'];
$loyalty_enabled = ($app_settings['loyalty_enabled'] ?? '0') === '1';
$points_per_unit = (float)($app_settings['loyalty_points_per_unit'] ?? 1);
if (empty($items)) {
throw new Exception("Cart is empty");
}
@ -282,8 +341,15 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$net_amount = (float)($total_amount - $discount_amount - $loyalty_redeemed);
if ($net_amount < 0) $net_amount = 0;
// Loyalty Calculation: 1 point per 1 OMR spent on net amount
$loyalty_earned = floor($net_amount);
// Loyalty Calculation: Based on Tier Multiplier
$loyalty_multiplier = 1.0;
if ($customer_id && $loyalty_enabled) {
$stmtTier = $db->prepare("SELECT loyalty_tier FROM customers WHERE id = ?");
$stmtTier->execute([$customer_id]);
$tier = $stmtTier->fetchColumn() ?: 'bronze';
$loyalty_multiplier = getLoyaltyMultiplier($tier);
}
$loyalty_earned = $loyalty_enabled ? floor($net_amount * $points_per_unit * $loyalty_multiplier) : 0;
// Check if credit is used for walk-in or exceeds limit
$credit_total = 0;
@ -371,8 +437,14 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
}
}
$stmt = $db->prepare("UPDATE customers SET loyalty_points = loyalty_points - ? + ?, balance = balance - ? WHERE id = ?");
$stmt->execute([(float)$loyalty_redeemed, (float)$loyalty_earned, (float)$credit_total, $customer_id]);
// New Modern Loyalty Logic
updateCustomerLoyalty($customer_id, (float)$net_amount, (float)$loyalty_earned, (float)$loyalty_redeemed, (int)$invoice_id);
// Update Balance separately if credit used
if ($credit_total > 0) {
$stmt = $db->prepare("UPDATE customers SET balance = balance - ? WHERE id = ?");
$stmt->execute([(float)$credit_total, $customer_id]);
}
}
// Add Payments
@ -2129,6 +2201,26 @@ switch ($page) {
$data['payroll'] = db()->query("SELECT p.*, e.name as emp_name FROM hr_payroll p JOIN hr_employees e ON p.employee_id = e.id WHERE p.payroll_month = $month AND p.payroll_year = $year ORDER BY p.id DESC")->fetchAll();
$data['employees'] = db()->query("SELECT id, name, salary FROM hr_employees WHERE status = 'active' ORDER BY name ASC")->fetchAll();
break;
case 'loyalty_history':
$where = ["1=1"];
$params = [];
if (!empty($_GET['customer_id'])) {
$where[] = "lt.customer_id = ?";
$params[] = (int)$_GET['customer_id'];
}
if (!empty($_GET['type'])) {
$where[] = "lt.transaction_type = ?";
$params[] = $_GET['type'];
}
$whereSql = implode(" AND ", $where);
$stmt = db()->prepare("SELECT lt.*, c.name as customer_name, c.loyalty_tier, c.loyalty_points
FROM loyalty_transactions lt
JOIN customers c ON lt.customer_id = c.id
WHERE $whereSql
ORDER BY lt.created_at DESC");
$stmt->execute($params);
$data['loyalty_transactions'] = $stmt->fetchAll();
break;
case 'devices':
$data['devices'] = db()->query("SELECT * FROM hr_biometric_devices ORDER BY id DESC")->fetchAll();
break;
@ -2312,6 +2404,9 @@ $projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? 'Accounting System';
<a href="index.php?page=low_stock_report" class="nav-link <?= isset($_GET['page']) && $_GET['page'] === 'low_stock_report' ? 'active' : '' ?>">
<i class="bi bi-graph-down-arrow"></i> <span data-en="Low Stock Report" data-ar="تقرير نواقص المخزون">Low Stock Report</span>
</a>
<a href="index.php?page=loyalty_history" class="nav-link <?= isset($_GET['page']) && $_GET['page'] === 'loyalty_history' ? 'active' : '' ?>">
<i class="bi bi-star"></i> <span data-en="Loyalty History" data-ar="سجل الولاء">Loyalty History</span>
</a>
</div>
<!-- Configuration Section -->
@ -2381,6 +2476,7 @@ $projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? 'Accounting System';
'hr_attendance' => ['en' => 'HR Attendance', 'ar' => 'حضور الموارد البشرية'],
'hr_payroll' => ['en' => 'HR Payroll', 'ar' => 'رواتب الموارد البشرية'],
'cashflow_report' => ['en' => 'Cashflow Statement', 'ar' => 'قائمة التدفقات النقدية'],
'loyalty_history' => ['en' => 'Loyalty History', 'ar' => 'سجل الولاء'],
];
$currTitle = $titles[$page] ?? $titles['dashboard'];
?>
@ -3200,6 +3296,90 @@ $projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? 'Accounting System';
</div>
</div>
<?php elseif ($page === 'loyalty_history'): ?>
<div class="card p-4">
<div class="d-flex justify-content-between align-items-center mb-4">
<h5 class="m-0" data-en="Loyalty Transaction History" data-ar="سجل عمليات الولاء">Loyalty Transaction History</h5>
<button class="btn btn-outline-primary btn-sm d-print-none" onclick="window.print()">
<i class="bi bi-printer"></i> <span data-en="Print" data-ar="طباعة">Print</span>
</button>
</div>
<div class="bg-light p-3 rounded mb-4 d-print-none">
<form method="GET" class="row g-3 align-items-end">
<input type="hidden" name="page" value="loyalty_history">
<div class="col-md-4">
<label class="form-label small fw-bold" data-en="Customer" data-ar="العميل">Customer</label>
<select name="customer_id" class="form-select select2">
<option value="">All Customers</option>
<?php foreach ($data['customers_list'] as $c): ?>
<option value="<?= $c['id'] ?>" <?= (($_GET['customer_id'] ?? '') == $c['id']) ? 'selected' : '' ?>><?= htmlspecialchars($c['name']) ?></option>
<?php endforeach; ?>
</select>
</div>
<div class="col-md-3">
<label class="form-label small fw-bold" data-en="Type" data-ar="النوع">Type</label>
<select name="type" class="form-select">
<option value="">All Types</option>
<option value="earned" <?= (($_GET['type'] ?? '') == 'earned') ? 'selected' : '' ?>>Earned</option>
<option value="redeemed" <?= (($_GET['type'] ?? '') == 'redeemed') ? 'selected' : '' ?>>Redeemed</option>
<option value="adjustment" <?= (($_GET['type'] ?? '') == 'adjustment') ? 'selected' : '' ?>>Adjustment</option>
</select>
</div>
<div class="col-md-2">
<button type="submit" class="btn btn-primary w-100">
<i class="bi bi-filter"></i> <span data-en="Filter" data-ar="تصفية">Filter</span>
</button>
</div>
</form>
</div>
<div class="table-responsive">
<table class="table table-hover align-middle">
<thead>
<tr>
<th data-en="Date" data-ar="التاريخ">Date</th>
<th data-en="Customer" data-ar="العميل">Customer</th>
<th data-en="Tier" data-ar="الفئة">Tier</th>
<th data-en="Type" data-ar="النوع">Type</th>
<th data-en="Points" data-ar="النقاط">Points</th>
<th data-en="Description" data-ar="الوصف">Description</th>
</tr>
</thead>
<tbody>
<?php if (empty($data['loyalty_transactions'])): ?>
<tr><td colspan="6" class="text-center py-4 text-muted">No transactions found.</td></tr>
<?php endif; ?>
<?php foreach ($data['loyalty_transactions'] as $lt): ?>
<tr>
<td><?= date('Y-m-d H:i', strtotime($lt['created_at'])) ?></td>
<td>
<div class="fw-bold"><?= htmlspecialchars($lt['customer_name']) ?></div>
<div class="smaller text-muted">Current Balance: <?= number_format($lt['loyalty_points'], 0) ?> pts</div>
</td>
<td>
<?php
$tier = $lt['loyalty_tier'];
$badge = ($tier === 'gold') ? 'bg-warning text-dark' : (($tier === 'silver') ? 'bg-info text-dark' : 'bg-secondary');
?>
<span class="badge text-uppercase <?= $badge ?>"><?= $tier ?></span>
</td>
<td>
<?php
$type = $lt['transaction_type'];
$typeBadge = ($type === 'earned') ? 'bg-success' : (($type === 'redeemed') ? 'bg-danger' : 'bg-info');
?>
<span class="badge <?= $typeBadge ?>"><?= ucfirst($type) ?></span>
</td>
<td class="fw-bold <?= (float)$lt['points_change'] > 0 ? 'text-success' : 'text-danger' ?>">
<?= (float)$lt['points_change'] > 0 ? '+' : '' ?><?= number_format($lt['points_change'], 0) ?>
</td>
<td class="small"><?= htmlspecialchars($lt['description']) ?></td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
</div>
<?php elseif ($page === 'pos'): ?>
<?php
$products_raw = db()->query("SELECT * FROM stock_items WHERE stock_quantity > 0 ORDER BY name_en ASC")->fetchAll(PDO::FETCH_ASSOC);
@ -3270,17 +3450,32 @@ $projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? 'Accounting System';
<select id="posCustomer" class="form-select form-select-sm" onchange="cart.onCustomerChange()">
<option value="">Walk-in Customer</option>
<?php foreach ($customers as $c): ?>
<option value="<?= $c['id'] ?>"><?= htmlspecialchars($c['name']) ?></option>
<option value="<?= $c['id'] ?>"
data-points="<?= $c['loyalty_points'] ?>"
data-tier="<?= $c['loyalty_tier'] ?>"
data-multiplier="<?= getLoyaltyMultiplier($c['loyalty_tier'] ?? 'bronze') ?>"
data-spent="<?= $c['total_spent'] ?>">
<?= htmlspecialchars($c['name']) ?>
</option>
<?php endforeach; ?>
</select>
<button class="btn btn-sm btn-primary" data-bs-toggle="modal" data-bs-target="#addCustomerModal"><i class="bi bi-plus"></i></button>
</div>
<div id="loyaltyDisplay" class="smaller text-success mt-1" style="display:none">
Points: <span id="customerPoints">0</span>
<div class="form-check form-switch d-inline-block ms-2">
<input class="form-check-input" type="checkbox" id="redeemLoyalty" onchange="cart.render()">
<label class="form-check-label" for="redeemLoyalty">Redeem</label>
<div id="loyaltyDisplay" class="mt-2 p-2 rounded bg-light border border-primary-subtle" style="display:none">
<div class="d-flex justify-content-between align-items-center mb-1">
<div>
<span id="tierBadge" class="badge text-uppercase">Bronze</span>
<span class="fw-bold ms-1 text-primary"><span id="customerPoints">0</span> pts</span>
</div>
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" id="redeemLoyalty" onchange="cart.render()">
<label class="form-check-label small fw-bold" for="redeemLoyalty">Redeem</label>
</div>
</div>
<div class="progress" style="height: 4px;">
<div id="tierProgress" class="progress-bar bg-primary" role="progressbar" style="width: 0%"></div>
</div>
<div id="nextTierInfo" class="smaller text-muted mt-1">Spend more to unlock Silver</div>
</div>
</div>
<div>
@ -3324,6 +3519,11 @@ $projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? 'Accounting System';
customerPoints: 0,
selectedPaymentMethod: 'cash',
payments: [],
loyaltySettings: {
enabled: <?= json_encode($data['settings']['loyalty_enabled'] ?? '0') ?>,
pointsPerUnit: parseFloat(<?= json_encode($data['settings']['loyalty_points_per_unit'] ?? '1') ?>),
redeemPointsPerUnit: parseFloat(<?= json_encode($data['settings']['loyalty_redeem_points_per_unit'] ?? '100') ?>)
},
allCreditCustomers: <?php
$custData = [];
foreach ($customers as $c) {
@ -3369,24 +3569,49 @@ $projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? 'Accounting System';
if (loyaltyDisplay) loyaltyDisplay.style.display = 'none';
this.render();
},
async onCustomerChange() {
const id = document.getElementById('posCustomer').value;
onCustomerChange() {
const select = document.getElementById('posCustomer');
const option = select.options[select.selectedIndex];
const display = document.getElementById('loyaltyDisplay');
if (!id) {
display.style.display = 'none';
if (!select.value || this.loyaltySettings.enabled !== '1') {
if (display) display.style.display = 'none';
this.customerPoints = 0;
document.getElementById('redeemLoyalty').checked = false;
this.customerTier = 'bronze';
this.customerMultiplier = 1.0;
const redeemSwitch = document.getElementById('redeemLoyalty');
if (redeemSwitch) redeemSwitch.checked = false;
this.render();
return;
}
try {
const resp = await fetch(`index.php?action=get_customer_loyalty&customer_id=${id}`);
const res = await resp.json();
this.customerPoints = res.points || 0;
document.getElementById('customerPoints').innerText = this.customerPoints.toFixed(3);
display.style.display = 'block';
this.render();
} catch (err) { console.error(err); }
this.customerPoints = parseFloat(option.dataset.points) || 0;
this.customerTier = option.dataset.tier || 'bronze';
this.customerMultiplier = parseFloat(option.dataset.multiplier) || 1.0;
const spent = parseFloat(option.dataset.spent) || 0;
document.getElementById('customerPoints').innerText = Math.floor(this.customerPoints);
const badge = document.getElementById('tierBadge');
badge.innerText = this.customerTier;
badge.className = 'badge text-uppercase ' + (this.customerTier === 'gold' ? 'bg-warning text-dark' : (this.customerTier === 'silver' ? 'bg-info text-dark' : 'bg-secondary'));
const progressBar = document.getElementById('tierProgress');
const nextTierInfo = document.getElementById('nextTierInfo');
let progress = 0;
if (this.customerTier === 'bronze') {
progress = (spent / 500) * 100;
nextTierInfo.innerText = `Spend ${(500 - spent).toFixed(3)} OMR more for Silver (1.2x points)`;
} else if (this.customerTier === 'silver') {
progress = ((spent - 500) / 1000) * 100;
nextTierInfo.innerText = `Spend ${(1500 - spent).toFixed(3)} OMR more for Gold (1.5x points)`;
} else {
progress = 100;
nextTierInfo.innerText = 'You are a Gold member! (1.5x points)';
}
progressBar.style.width = Math.min(100, progress) + '%';
display.style.display = 'block';
this.render();
},
async applyDiscount() {
const code = document.getElementById('discountCode').value.trim();
@ -3549,19 +3774,27 @@ $projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? 'Accounting System';
}
}
let loyaltyRedeemed = 0;
let loyaltyRedeemedValue = 0;
const redeemSwitch = document.getElementById('redeemLoyalty');
if (redeemSwitch && redeemSwitch.checked) {
loyaltyRedeemed = Math.min(subtotal - discountAmount, this.customerPoints);
const maxRedeemValue = subtotal - discountAmount;
const availableRedeemValue = this.customerPoints / 100;
loyaltyRedeemedValue = Math.min(maxRedeemValue, availableRedeemValue);
}
const total = subtotal - discountAmount - loyaltyRedeemed;
const total = subtotal - discountAmount - loyaltyRedeemedValue;
const pointsToEarn = Math.floor(total * (this.customerMultiplier || 1.0));
document.getElementById('posSubtotal').innerText = 'OMR ' + subtotal.toFixed(3);
let totalHtml = '';
if (discountAmount > 0) totalHtml += `<div class="smaller text-danger">- Disc: OMR ${discountAmount.toFixed(3)}</div>`;
if (loyaltyRedeemed > 0) totalHtml += `<div class="smaller text-success">- Loyalty: OMR ${loyaltyRedeemed.toFixed(3)}</div>`;
if (loyaltyRedeemedValue > 0) totalHtml += `<div class="smaller text-success">- Loyalty: OMR ${loyaltyRedeemedValue.toFixed(3)}</div>`;
if (document.getElementById('posCustomer').value) {
totalHtml += `<div class="smaller text-info">+ Earn: ${pointsToEarn} pts</div>`;
}
totalHtml += 'OMR ' + total.toFixed(3);
document.getElementById('posTotal').innerHTML = totalHtml;
@ -3580,8 +3813,8 @@ $projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? 'Accounting System';
discountAmount = this.discount.type === 'percentage' ? subtotal * (parseFloat(this.discount.value) / 100) : parseFloat(this.discount.value);
}
const redeemSwitch = document.getElementById('redeemLoyalty');
let loyaltyRedeemed = (redeemSwitch && redeemSwitch.checked) ? Math.min(subtotal - discountAmount, this.customerPoints) : 0;
const total = subtotal - discountAmount - loyaltyRedeemed;
let loyaltyRedeemedValue = (redeemSwitch && redeemSwitch.checked) ? Math.min(subtotal - discountAmount, this.customerPoints / 100) : 0;
const total = subtotal - discountAmount - loyaltyRedeemedValue;
this.payments = [];
this.renderPayments();
@ -3652,8 +3885,8 @@ $projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? 'Accounting System';
discountAmount = this.discount.type === 'percentage' ? subtotal * (parseFloat(this.discount.value) / 100) : parseFloat(this.discount.value);
}
const redeemSwitch = document.getElementById('redeemLoyalty');
let loyaltyRedeemed = (redeemSwitch && redeemSwitch.checked) ? Math.min(subtotal - discountAmount, this.customerPoints) : 0;
return subtotal - discountAmount - loyaltyRedeemed;
let loyaltyRedeemedValue = (redeemSwitch && redeemSwitch.checked) ? Math.min(subtotal - discountAmount, this.customerPoints / this.loyaltySettings.redeemPointsPerUnit) : 0;
return subtotal - discountAmount - loyaltyRedeemedValue;
},
getRemaining() {
const total = this.getGrandTotal();
@ -3754,7 +3987,7 @@ $projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? 'Accounting System';
discountAmount = this.discount.type === 'percentage' ? subtotal * (parseFloat(this.discount.value) / 100) : parseFloat(this.discount.value);
}
const redeemSwitch = document.getElementById('redeemLoyalty');
let loyaltyRedeemed = (redeemSwitch && redeemSwitch.checked) ? Math.min(subtotal - discountAmount, this.customerPoints) : 0;
let loyaltyRedeemed = (redeemSwitch && redeemSwitch.checked) ? Math.min(subtotal - discountAmount, this.customerPoints / this.loyaltySettings.redeemPointsPerUnit) : 0;
const formData = new FormData();
formData.append('action', 'save_pos_transaction');
@ -5897,6 +6130,26 @@ $projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? 'Accounting System';
</div>
<?php endif; ?>
</div>
<div class="col-md-12 mt-4">
<h5 class="mb-3" data-en="Loyalty Configuration" data-ar="إعدادات الولاء">Loyalty Configuration</h5>
<div class="row g-3">
<div class="col-md-4">
<label class="form-label" data-en="Loyalty System" data-ar="نظام الولاء">Loyalty System</label>
<select name="settings[loyalty_enabled]" class="form-select">
<option value="0" <?= ($data['settings']['loyalty_enabled'] ?? '0') === '0' ? 'selected' : '' ?> data-en="Disabled" data-ar="معطل">Disabled</option>
<option value="1" <?= ($data['settings']['loyalty_enabled'] ?? '0') === '1' ? 'selected' : '' ?> data-en="Enabled" data-ar="مفعل">Enabled</option>
</select>
</div>
<div class="col-md-4">
<label class="form-label" data-en="Points per 1 OMR" data-ar="النقاط لكل 1 ريال">Points per 1 OMR</label>
<input type="number" step="0.01" name="settings[loyalty_points_per_unit]" class="form-control" value="<?= htmlspecialchars($data['settings']['loyalty_points_per_unit'] ?? '1') ?>">
</div>
<div class="col-md-4">
<label class="form-label" data-en="Points for 1 OMR Discount" data-ar="النقاط لخصم 1 ريال">Points for 1 OMR Discount</label>
<input type="number" step="0.01" name="settings[loyalty_redeem_points_per_unit]" class="form-control" value="<?= htmlspecialchars($data['settings']['loyalty_redeem_points_per_unit'] ?? '100') ?>">
</div>
</div>
</div>
<div class="col-md-12 mt-4">
<button type="submit" name="update_settings" class="btn btn-primary">
<i class="bi bi-save"></i> <span data-en="Save Changes" data-ar="حفظ التغييرات">Save Changes</span>