904 lines
58 KiB
HTML
904 lines
58 KiB
HTML
{% extends 'base.html' %}
|
|
{% load i18n %}
|
|
{% load static %}
|
|
|
|
{% block content %}
|
|
<div class="container-fluid">
|
|
<div class="row mb-4 align-items-center">
|
|
<div class="col-md-6">
|
|
<h1 class="h3 mb-0 text-gray-800">{% trans "System Settings" %}</h1>
|
|
<p class="text-muted">{% trans "Manage your business profile, payments, and loyalty system." %}</p>
|
|
</div>
|
|
</div>
|
|
|
|
{% if messages %}
|
|
<div class="row">
|
|
<div class="col-12">
|
|
{% for message in messages %}
|
|
<div class="alert alert-{{ message.tags }} alert-dismissible fade show" role="alert">
|
|
{{ message }}
|
|
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
|
|
</div>
|
|
{% endfor %}
|
|
</div>
|
|
</div>
|
|
{% endif %}
|
|
|
|
<ul class="nav nav-pills mb-4" id="settingsTabs" role="tablist">
|
|
<li class="nav-item" role="presentation">
|
|
<button class="nav-link active fw-bold px-4" id="profile-tab" data-bs-toggle="pill" data-bs-target="#profile" type="button" role="tab">
|
|
<i class="bi bi-building me-2"></i>{% trans "Business Profile" %}
|
|
</button>
|
|
</li>
|
|
<li class="nav-item" role="presentation">
|
|
<button class="nav-link fw-bold px-4" id="payments-tab" data-bs-toggle="pill" data-bs-target="#payments" type="button" role="tab">
|
|
<i class="bi bi-credit-card me-2"></i>{% trans "Payment Methods" %}
|
|
</button>
|
|
</li>
|
|
<li class="nav-item" role="presentation">
|
|
<button class="nav-link fw-bold px-4" id="devices-tab" data-bs-toggle="pill" data-bs-target="#devices" type="button" role="tab">
|
|
<i class="bi bi-printer me-2"></i>{% trans "Devices" %}
|
|
</button>
|
|
</li>
|
|
<li class="nav-item" role="presentation">
|
|
<button class="nav-link fw-bold px-4" id="loyalty-tab" data-bs-toggle="pill" data-bs-target="#loyalty" type="button" role="tab">
|
|
<i class="bi bi-star me-2"></i>{% trans "Loyalty System" %}
|
|
</button>
|
|
</li>
|
|
<li class="nav-item" role="presentation">
|
|
<button class="nav-link fw-bold px-4" id="whatsapp-tab" data-bs-toggle="pill" data-bs-target="#whatsapp" type="button" role="tab">
|
|
<i class="bi bi-whatsapp me-2"></i>{% trans "WhatsApp Gateway" %}
|
|
</button>
|
|
</li>
|
|
</ul>
|
|
|
|
<div class="tab-content" id="settingsTabsContent">
|
|
<!-- Business Profile Tab -->
|
|
<div class="tab-pane fade show active" id="profile" role="tabpanel">
|
|
<div class="row">
|
|
<div class="col-lg-8">
|
|
<div class="card shadow-sm border-0 glassmorphism mb-4">
|
|
<div class="card-header bg-transparent border-0 py-3">
|
|
<h5 class="card-title mb-0 fw-bold">{% trans "Business Profile" %}</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<form method="post" enctype="multipart/form-data" action="{% url 'settings' %}">
|
|
{% csrf_token %}
|
|
<div class="row g-3">
|
|
<div class="col-md-12 text-center mb-3">
|
|
<label class="form-label d-block fw-semibold">{% trans "Business Logo" %}</label>
|
|
{% if settings.logo %}
|
|
<img src="{{ settings.logo.url }}" alt="Logo" class="img-thumbnail mb-2" style="max-height: 100px;">
|
|
{% else %}
|
|
<div class="bg-light border rounded d-inline-flex align-items-center justify-content-center mb-2" style="width: 100px; height: 100px;">
|
|
<i class="bi bi-image text-muted fs-1"></i>
|
|
</div>
|
|
{% endif %}
|
|
<input type="file" name="logo" class="form-control form-control-sm mx-auto" style="max-width: 300px;" accept="image/*">
|
|
</div>
|
|
|
|
<div class="col-md-12">
|
|
<label class="form-label fw-semibold">{% trans "Business Name" %}</label>
|
|
<input type="text" name="business_name" class="form-control" value="{{ settings.business_name }}" required>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<label class="form-label fw-semibold">{% trans "Email Address" %}</label>
|
|
<input type="email" name="email" class="form-control" value="{{ settings.email }}">
|
|
</div>
|
|
<div class="col-md-6">
|
|
<label class="form-label fw-semibold">{% trans "Phone Number" %}</label>
|
|
<input type="text" name="phone" class="form-control" value="{{ settings.phone }}">
|
|
</div>
|
|
<div class="col-md-6">
|
|
<label class="form-label fw-semibold">{% trans "VAT Number" %}</label>
|
|
<input type="text" name="vat_number" class="form-control" value="{{ settings.vat_number }}">
|
|
</div>
|
|
<div class="col-md-6">
|
|
<label class="form-label fw-semibold">{% trans "Registration Number" %}</label>
|
|
<input type="text" name="registration_number" class="form-control" value="{{ settings.registration_number }}">
|
|
</div>
|
|
<div class="col-12">
|
|
<label class="form-label fw-semibold">{% trans "Address" %}</label>
|
|
<textarea name="address" class="form-control" rows="3">{{ settings.address }}</textarea>
|
|
</div>
|
|
|
|
<hr class="my-4">
|
|
|
|
<h5 class="fw-bold mb-3">{% trans "Financial Preferences" %}</h5>
|
|
<div class="col-md-4">
|
|
<label class="form-label fw-semibold">{% trans "Currency Symbol" %}</label>
|
|
<input type="text" name="currency_symbol" class="form-control" value="{{ settings.currency_symbol }}" required>
|
|
<div class="form-text">{% trans "e.g., OMR, $, £, SAR" %}</div>
|
|
</div>
|
|
<div class="col-md-4">
|
|
<label class="form-label fw-semibold">{% trans "Default Tax Rate (%)" %}</label>
|
|
<input type="number" step="0.01" name="tax_rate" class="form-control" value="{{ settings.tax_rate }}" required>
|
|
</div>
|
|
<div class="col-md-4">
|
|
<label class="form-label fw-semibold">{% trans "Decimal Places" %}</label>
|
|
<input type="number" name="decimal_places" class="form-control" value="{{ settings.decimal_places }}" min="0" max="5" required>
|
|
<div class="form-text">{% trans "For price display" %}</div>
|
|
</div>
|
|
|
|
<hr class="my-4">
|
|
<h5 class="fw-bold mb-3">{% trans "Loyalty Configuration" %}</h5>
|
|
<div class="col-md-6">
|
|
<div class="form-check form-switch mb-3">
|
|
<input class="form-check-input" type="checkbox" name="loyalty_enabled" {% if settings.loyalty_enabled %}checked{% endif %}>
|
|
<label class="form-check-label fw-bold">{% trans "Enable Loyalty System" %}</label>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<label class="form-label fw-semibold">{% trans "Minimum Points to Redeem" %}</label>
|
|
<input type="number" name="min_points_to_redeem" class="form-control" value="{{ settings.min_points_to_redeem }}">
|
|
</div>
|
|
<div class="col-md-6">
|
|
<label class="form-label fw-semibold">{% trans "Points per Currency Unit Spent" %}</label>
|
|
<input type="number" step="0.01" name="points_per_currency" class="form-control" value="{{ settings.points_per_currency }}">
|
|
<div class="form-text">{% trans "e.g., 1.0 means 1 point for every 1 OMR spent." %}</div>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<label class="form-label fw-semibold">{% trans "Currency Value per Point (Redemption)" %}</label>
|
|
<input type="number" step="0.001" name="currency_per_point" class="form-control" value="{{ settings.currency_per_point }}">
|
|
<div class="form-text">{% trans "e.g., 0.010 means 100 points = 1 OMR." %}</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="mt-4 pt-3 border-top d-flex justify-content-end">
|
|
<button type="submit" class="btn btn-primary px-4 py-2">
|
|
<i class="bi bi-check-circle me-2"></i> {% trans "Save Changes" %}
|
|
</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="col-lg-4">
|
|
<div class="card shadow-sm border-0 glassmorphism mb-4">
|
|
<div class="card-header bg-transparent border-0 py-3">
|
|
<h5 class="card-title mb-0 fw-bold">{% trans "Help & Support" %}</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<p class="text-muted small">
|
|
{% trans "Need help configuring your smart admin? Check our documentation or contact support." %}
|
|
</p>
|
|
<a href="#" class="btn btn-outline-secondary w-100 btn-sm">
|
|
<i class="bi bi-question-circle me-1"></i> {% trans "Documentation" %}
|
|
</a>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="card shadow-sm border-0 glassmorphism bg-light">
|
|
<div class="card-body text-center py-4">
|
|
<i class="bi bi-info-circle fs-1 text-primary mb-3"></i>
|
|
<h6 class="fw-bold">{% trans "Smart Admin Version" %}</h6>
|
|
<p class="text-muted mb-0">v2.1.0-Meezan</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Payment Methods Tab -->
|
|
<div class="tab-pane fade" id="payments" role="tabpanel">
|
|
<div class="card shadow-sm border-0 glassmorphism">
|
|
<div class="card-header bg-transparent border-0 py-3 d-flex justify-content-between align-items-center">
|
|
<h5 class="card-title mb-0 fw-bold">{% trans "Payment Methods" %}</h5>
|
|
<button class="btn btn-primary btn-sm" data-bs-toggle="modal" data-bs-target="#addPaymentModal">
|
|
<i class="bi bi-plus-lg me-1"></i> {% trans "Add Method" %}
|
|
</button>
|
|
</div>
|
|
<div class="card-body p-0">
|
|
<div class="table-responsive">
|
|
<table class="table table-hover align-middle mb-0" id="paymentMethodsTable">
|
|
<thead class="bg-light">
|
|
<tr>
|
|
<th class="ps-4">{% trans "Name (EN)" %}</th>
|
|
<th>{% trans "Name (AR)" %}</th>
|
|
<th>{% trans "Status" %}</th>
|
|
<th class="text-end pe-4">{% trans "Actions" %}</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{% for pm in payment_methods %}
|
|
<tr id="pm-row-{{ pm.id }}">
|
|
<td class="ps-4 fw-semibold">{{ pm.name_en }}</td>
|
|
<td>{{ pm.name_ar }}</td>
|
|
<td>
|
|
{% if pm.is_active %}
|
|
<span class="badge bg-success-soft text-success">{% trans "Active" %}</span>
|
|
{% else %}
|
|
<span class="badge bg-danger-soft text-danger">{% trans "Inactive" %}</span>
|
|
{% endif %}
|
|
</td>
|
|
<td class="text-end pe-4">
|
|
<button class="btn btn-sm btn-light text-primary me-1" data-bs-toggle="modal" data-bs-target="#editPaymentModal{{ pm.id }}">
|
|
<i class="bi bi-pencil"></i>
|
|
</button>
|
|
<button class="btn btn-sm btn-light text-danger" data-bs-toggle="modal" data-bs-target="#deletePaymentModal{{ pm.id }}">
|
|
<i class="bi bi-trash"></i>
|
|
</button>
|
|
</td>
|
|
</tr>
|
|
|
|
<!-- Edit Modal -->
|
|
<div class="modal fade" id="editPaymentModal{{ pm.id }}" tabindex="-1">
|
|
<div class="modal-dialog">
|
|
<div class="modal-content border-0">
|
|
<form action="{% url 'edit_payment_method' pm.id %}" method="post">
|
|
{% csrf_token %}
|
|
<div class="modal-header">
|
|
<h5 class="modal-title fw-bold">{% trans "Edit Payment Method" %}</h5>
|
|
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
|
</div>
|
|
<div class="modal-body">
|
|
<div class="mb-3">
|
|
<label class="form-label fw-semibold">{% trans "Name (English)" %}</label>
|
|
<input type="text" name="name_en" class="form-control" value="{{ pm.name_en }}" required>
|
|
</div>
|
|
<div class="mb-3">
|
|
<label class="form-label fw-semibold">{% trans "Name (Arabic)" %}</label>
|
|
<input type="text" name="name_ar" class="form-control" value="{{ pm.name_ar }}" required>
|
|
</div>
|
|
<div class="form-check form-switch">
|
|
<input class="form-check-input" type="checkbox" name="is_active" {% if pm.is_active %}checked{% endif %}>
|
|
<label class="form-check-label">{% trans "Active" %}</label>
|
|
</div>
|
|
</div>
|
|
<div class="modal-footer bg-light border-0">
|
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">{% trans "Cancel" %}</button>
|
|
<button type="submit" class="btn btn-primary">{% trans "Save Changes" %}</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Delete Modal -->
|
|
<div class="modal fade" id="deletePaymentModal{{ pm.id }}" tabindex="-1">
|
|
<div class="modal-dialog">
|
|
<div class="modal-content border-0">
|
|
<div class="modal-header">
|
|
<h5 class="modal-title fw-bold">{% trans "Confirm Delete" %}</h5>
|
|
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
|
</div>
|
|
<div class="modal-body">
|
|
<p>{% trans "Are you sure you want to delete" %} <strong>{{ pm.name_en }}</strong>?</p>
|
|
<div class="alert alert-warning mb-0">
|
|
<i class="bi bi-exclamation-triangle me-2"></i>
|
|
{% trans "Deleting this will not affect historical records but it will no longer be available for new transactions." %}
|
|
</div>
|
|
</div>
|
|
<div class="modal-footer bg-light border-0">
|
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">{% trans "Cancel" %}</button>
|
|
<a href="{% url 'delete_payment_method' pm.id %}" class="btn btn-danger">{% trans "Delete" %}</a>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% empty %}
|
|
<tr>
|
|
<td colspan="4" class="text-center py-5" id="noPaymentMethods">
|
|
<div class="text-muted">
|
|
<i class="bi bi-credit-card fs-1 d-block mb-3"></i>
|
|
{% trans "No payment methods found." %}
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
{% endfor %}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Devices Tab -->
|
|
<div class="tab-pane fade" id="devices" role="tabpanel">
|
|
<div class="card shadow-sm border-0 glassmorphism mb-4">
|
|
<div class="card-header bg-transparent border-0 py-3 d-flex justify-content-between align-items-center">
|
|
<h5 class="card-title mb-0 fw-bold">{% trans "Hardware Devices" %}</h5>
|
|
<button class="btn btn-primary btn-sm" data-bs-toggle="modal" data-bs-target="#addDeviceModal">
|
|
<i class="bi bi-plus-lg me-1"></i> {% trans "Add Device" %}
|
|
</button>
|
|
</div>
|
|
<div class="card-body p-0">
|
|
<div class="table-responsive">
|
|
<table class="table table-hover align-middle mb-0">
|
|
<thead class="bg-light">
|
|
<tr>
|
|
<th class="ps-4">{% trans "Name" %}</th>
|
|
<th>{% trans "Type" %}</th>
|
|
<th>{% trans "Connection" %}</th>
|
|
<th>{% trans "Status" %}</th>
|
|
<th class="text-end pe-4">{% trans "Actions" %}</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{% for device in devices %}
|
|
<tr>
|
|
<td class="ps-4 fw-bold">{{ device.name }}</td>
|
|
<td>{{ device.get_device_type_display }}</td>
|
|
<td>
|
|
{{ device.get_connection_type_display }}
|
|
{% if device.ip_address %}
|
|
<small class="d-block text-muted">{{ device.ip_address }}{% if device.port %}:{{ device.port }}{% endif %}</small>
|
|
{% endif %}
|
|
</td>
|
|
<td>
|
|
{% if device.is_active %}
|
|
<span class="badge bg-success-soft text-success">{% trans "Active" %}</span>
|
|
{% else %}
|
|
<span class="badge bg-danger-soft text-danger">{% trans "Inactive" %}</span>
|
|
{% endif %}
|
|
</td>
|
|
<td class="text-end pe-4">
|
|
<button class="btn btn-sm btn-light text-primary" data-bs-toggle="modal" data-bs-target="#editDeviceModal{{ device.id }}">
|
|
<i class="bi bi-pencil"></i>
|
|
</button>
|
|
<button class="btn btn-sm btn-light text-danger" data-bs-toggle="modal" data-bs-target="#deleteDeviceModal{{ device.id }}">
|
|
<i class="bi bi-trash"></i>
|
|
</button>
|
|
</td>
|
|
</tr>
|
|
|
|
<!-- Edit Device Modal -->
|
|
<div class="modal fade" id="editDeviceModal{{ device.id }}" tabindex="-1">
|
|
<div class="modal-dialog">
|
|
<div class="modal-content border-0">
|
|
<form action="{% url 'edit_device' device.id %}" method="post">
|
|
{% csrf_token %}
|
|
<div class="modal-header">
|
|
<h5 class="modal-title fw-bold">{% trans "Edit Device" %}</h5>
|
|
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
|
</div>
|
|
<div class="modal-body">
|
|
<div class="mb-3">
|
|
<label class="form-label fw-semibold">{% trans "Device Name" %}</label>
|
|
<input type="text" name="name" class="form-control" value="{{ device.name }}" required>
|
|
</div>
|
|
<div class="row g-3">
|
|
<div class="col-md-6">
|
|
<label class="form-label fw-semibold">{% trans "Type" %}</label>
|
|
<select name="device_type" class="form-select">
|
|
<option value="printer" {% if device.device_type == 'printer' %}selected{% endif %}>{% trans "Printer" %}</option>
|
|
<option value="scanner" {% if device.device_type == 'scanner' %}selected{% endif %}>{% trans "Scanner" %}</option>
|
|
<option value="scale" {% if device.device_type == 'scale' %}selected{% endif %}>{% trans "Weight Scale" %}</option>
|
|
<option value="display" {% if device.device_type == 'display' %}selected{% endif %}>{% trans "Customer Display" %}</option>
|
|
<option value="other" {% if device.device_type == 'other' %}selected{% endif %}>{% trans "Other" %}</option>
|
|
</select>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<label class="form-label fw-semibold">{% trans "Connection" %}</label>
|
|
<select name="connection_type" class="form-select">
|
|
<option value="network" {% if device.connection_type == 'network' %}selected{% endif %}>{% trans "Network (IP)" %}</option>
|
|
<option value="usb" {% if device.connection_type == 'usb' %}selected{% endif %}>{% trans "USB" %}</option>
|
|
<option value="bluetooth" {% if device.connection_type == 'bluetooth' %}selected{% endif %}>{% trans "Bluetooth" %}</option>
|
|
</select>
|
|
</div>
|
|
<div class="col-md-8">
|
|
<label class="form-label fw-semibold">{% trans "IP Address" %}</label>
|
|
<input type="text" name="ip_address" class="form-control" value="{{ device.ip_address|default:'' }}">
|
|
</div>
|
|
<div class="col-md-4">
|
|
<label class="form-label fw-semibold">{% trans "Port" %}</label>
|
|
<input type="number" name="port" class="form-control" value="{{ device.port|default:'' }}">
|
|
</div>
|
|
</div>
|
|
<div class="form-check form-switch mt-3">
|
|
<input class="form-check-input" type="checkbox" name="is_active" {% if device.is_active %}checked{% endif %}>
|
|
<label class="form-check-label">{% trans "Active" %}</label>
|
|
</div>
|
|
</div>
|
|
<div class="modal-footer bg-light border-0">
|
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">{% trans "Cancel" %}</button>
|
|
<button type="submit" class="btn btn-primary">{% trans "Save Changes" %}</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Delete Device Modal -->
|
|
<div class="modal fade" id="deleteDeviceModal{{ device.id }}" tabindex="-1">
|
|
<div class="modal-dialog">
|
|
<div class="modal-content border-0">
|
|
<div class="modal-header">
|
|
<h5 class="modal-title fw-bold">{% trans "Confirm Delete" %}</h5>
|
|
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
|
</div>
|
|
<div class="modal-body">
|
|
<p>{% trans "Are you sure you want to delete" %} <strong>{{ device.name }}</strong>?</p>
|
|
</div>
|
|
<div class="modal-footer bg-light border-0">
|
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">{% trans "Cancel" %}</button>
|
|
<a href="{% url 'delete_device' device.id %}" class="btn btn-danger">{% trans "Delete" %}</a>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% empty %}
|
|
<tr>
|
|
<td colspan="5" class="text-center py-5">
|
|
<div class="text-muted">
|
|
<i class="bi bi-printer fs-1 d-block mb-3"></i>
|
|
{% trans "No devices configured." %}
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
{% endfor %}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Loyalty Tab -->
|
|
<div class="tab-pane fade" id="loyalty" role="tabpanel">
|
|
<div class="card shadow-sm border-0 glassmorphism mb-4">
|
|
<div class="card-header bg-transparent border-0 py-3 d-flex justify-content-between align-items-center">
|
|
<h5 class="card-title mb-0 fw-bold">{% trans "Loyalty Tiers" %}</h5>
|
|
<button class="btn btn-primary btn-sm" data-bs-toggle="modal" data-bs-target="#addTierModal">
|
|
<i class="bi bi-plus-lg me-1"></i> {% trans "Add Tier" %}
|
|
</button>
|
|
</div>
|
|
<div class="card-body p-0">
|
|
<div class="table-responsive">
|
|
<table class="table table-hover align-middle mb-0">
|
|
<thead class="bg-light">
|
|
<tr>
|
|
<th class="ps-4">{% trans "Tier Name" %}</th>
|
|
<th>{% trans "Min. Points" %}</th>
|
|
<th>{% trans "Multiplier" %}</th>
|
|
<th>{% trans "Discount" %}</th>
|
|
<th class="text-end pe-4">{% trans "Actions" %}</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{% for tier in loyalty_tiers %}
|
|
<tr>
|
|
<td class="ps-4">
|
|
<div class="d-flex align-items-center">
|
|
<div class="rounded-circle me-2" style="width: 15px; height: 15px; background-color: {{ tier.color_code }};"></div>
|
|
<span class="fw-bold">{{ tier.name_en }} / {{ tier.name_ar }}</span>
|
|
</div>
|
|
</td>
|
|
<td>{{ tier.min_points }}</td>
|
|
<td>{{ tier.point_multiplier }}x</td>
|
|
<td>{{ tier.discount_percentage }}%</td>
|
|
<td class="text-end pe-4">
|
|
<button class="btn btn-sm btn-light text-primary" data-bs-toggle="modal" data-bs-target="#editTierModal{{ tier.id }}">
|
|
<i class="bi bi-pencil"></i>
|
|
</button>
|
|
<button class="btn btn-sm btn-light text-danger" data-bs-toggle="modal" data-bs-target="#deleteTierModal{{ tier.id }}">
|
|
<i class="bi bi-trash"></i>
|
|
</button>
|
|
</td>
|
|
</tr>
|
|
|
|
<!-- Edit Tier Modal -->
|
|
<div class="modal fade" id="editTierModal{{ tier.id }}" tabindex="-1">
|
|
<div class="modal-dialog">
|
|
<div class="modal-content border-0">
|
|
<form action="{% url 'edit_loyalty_tier' tier.id %}" method="post">
|
|
{% csrf_token %}
|
|
<div class="modal-header">
|
|
<h5 class="modal-title fw-bold">{% trans "Edit Loyalty Tier" %}</h5>
|
|
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
|
</div>
|
|
<div class="modal-body">
|
|
<div class="row g-3">
|
|
<div class="col-md-6">
|
|
<label class="form-label fw-semibold">{% trans "Name (EN)" %}</label>
|
|
<input type="text" name="name_en" class="form-control" value="{{ tier.name_en }}" required>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<label class="form-label fw-semibold">{% trans "Name (AR)" %}</label>
|
|
<input type="text" name="name_ar" class="form-control" value="{{ tier.name_ar }}" required>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<label class="form-label fw-semibold">{% trans "Min. Points" %}</label>
|
|
<input type="number" name="min_points" class="form-control" value="{{ tier.min_points }}" required>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<label class="form-label fw-semibold">{% trans "Point Multiplier" %}</label>
|
|
<input type="number" step="0.01" name="point_multiplier" class="form-control" value="{{ tier.point_multiplier }}" required>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<label class="form-label fw-semibold">{% trans "Discount (%)" %}</label>
|
|
<input type="number" step="0.01" name="discount_percentage" class="form-control" value="{{ tier.discount_percentage }}" required>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<label class="form-label fw-semibold">{% trans "Color Code" %}</label>
|
|
<input type="color" name="color_code" class="form-control form-control-color w-100" value="{{ tier.color_code }}">
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="modal-footer bg-light border-0">
|
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">{% trans "Cancel" %}</button>
|
|
<button type="submit" class="btn btn-primary">{% trans "Save Changes" %}</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% empty %}
|
|
<tr>
|
|
<td colspan="5" class="text-center py-5">
|
|
<div class="text-muted">
|
|
<i class="bi bi-star fs-1 d-block mb-3"></i>
|
|
{% trans "No loyalty tiers defined." %}
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
{% endfor %}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- WhatsApp Tab -->
|
|
<div class="tab-pane fade" id="whatsapp" role="tabpanel">
|
|
<div class="row">
|
|
<div class="col-lg-8">
|
|
<div class="card shadow-sm border-0 glassmorphism mb-4">
|
|
<div class="card-header bg-transparent border-0 py-3">
|
|
<h5 class="card-title mb-0 fw-bold">{% trans "Wablas WhatsApp Integration" %}</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<form method="post" action="{% url 'settings' %}">
|
|
{% csrf_token %}
|
|
<div class="row g-3">
|
|
<div class="col-md-12">
|
|
<div class="form-check form-switch mb-3">
|
|
<input class="form-check-input" type="checkbox" name="wablas_enabled" {% if settings.wablas_enabled %}checked{% endif %}>
|
|
<label class="form-check-label fw-bold">{% trans "Enable WhatsApp Gateway" %}</label>
|
|
</div>
|
|
<p class="text-muted small">{% trans "When enabled, you can send automated messages, invoices, and alerts via WhatsApp using the Wablas gateway." %}</p>
|
|
</div>
|
|
|
|
<div class="col-md-12">
|
|
<label class="form-label fw-semibold">{% trans "Wablas Server URL" %}</label>
|
|
<input type="text" name="wablas_server_url" class="form-control" value="{{ settings.wablas_server_url }}" placeholder="e.g. https://console.wablas.com">
|
|
<div class="form-text">{% trans "The server URL provided by Wablas." %}</div>
|
|
</div>
|
|
|
|
<div class="col-md-12">
|
|
<label class="form-label fw-semibold">{% trans "Wablas API Token" %}</label>
|
|
<input type="text" name="wablas_token" class="form-control" value="{{ settings.wablas_token }}" placeholder="e.g. your_api_token_here">
|
|
<div class="form-text">{% trans "Get your token from your Wablas dashboard." %}</div>
|
|
</div>
|
|
|
|
<div class="col-md-12">
|
|
<label class="form-label fw-semibold">{% trans "Wablas Secret Key" %}</label>
|
|
<input type="text" name="wablas_secret_key" class="form-control" value="{{ settings.wablas_secret_key }}" placeholder="e.g. your_secret_key_here">
|
|
<div class="form-text">{% trans "Required for some Wablas API versions." %}</div>
|
|
</div>
|
|
|
|
<div class="col-12 mt-4">
|
|
<button type="submit" class="btn btn-success px-4 py-2">
|
|
<i class="bi bi-whatsapp me-2"></i> {% trans "Save WhatsApp Settings" %}
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="card shadow-sm border-0 glassmorphism bg-light border-start border-4 border-success">
|
|
<div class="card-body">
|
|
<h6 class="fw-bold text-success"><i class="bi bi-info-circle me-2"></i>{% trans "How to use" %}</h6>
|
|
<ul class="mb-0 small text-muted">
|
|
<li>{% trans "Register an account at Wablas.com" %}</li>
|
|
<li>{% trans "Scan your WhatsApp QR code in the Wablas dashboard." %}</li>
|
|
<li>{% trans "Copy the API Token and Server URL into the fields above." %}</li>
|
|
<li>{% trans "Test by sending a sample message to your own number." %}</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="col-lg-4">
|
|
<div class="card shadow-sm border-0 glassmorphism mb-4">
|
|
<div class="card-header bg-transparent border-0 py-3">
|
|
<h5 class="card-title mb-0 fw-bold">{% trans "Test Connection" %}</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<p class="text-muted small">{% trans "Verify your WhatsApp gateway is working correctly." %}</p>
|
|
<div class="mb-3">
|
|
<label class="form-label small fw-bold">{% trans "Test Phone Number" %}</label>
|
|
<input type="text" id="test_phone" class="form-control form-control-sm" placeholder="e.g. 96891234567">
|
|
</div>
|
|
<button type="button" id="btn_test_whatsapp" class="btn btn-outline-success w-100 btn-sm">
|
|
<i class="bi bi-send me-1"></i> {% trans "Send Test Message" %}
|
|
</button>
|
|
<div id="test_result" class="mt-3 d-none"></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Add Tier Modal -->
|
|
<div class="modal fade" id="addTierModal" tabindex="-1">
|
|
<div class="modal-dialog">
|
|
<div class="modal-content border-0 shadow">
|
|
<form action="{% url 'add_loyalty_tier' %}" method="post">
|
|
{% csrf_token %}
|
|
<div class="modal-header">
|
|
<h5 class="modal-title fw-bold">{% trans "Add Loyalty Tier" %}</h5>
|
|
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
|
</div>
|
|
<div class="modal-body">
|
|
<div class="row g-3">
|
|
<div class="col-md-6">
|
|
<label class="form-label fw-semibold">{% trans "Name (EN)" %}</label>
|
|
<input type="text" name="name_en" class="form-control" required placeholder="e.g. Gold">
|
|
</div>
|
|
<div class="col-md-6">
|
|
<label class="form-label fw-semibold">{% trans "Name (AR)" %}</label>
|
|
<input type="text" name="name_ar" class="form-control" required placeholder="e.g. ذهبي">
|
|
</div>
|
|
<div class="col-md-6">
|
|
<label class="form-label fw-semibold">{% trans "Min. Points" %}</label>
|
|
<input type="number" name="min_points" class="form-control" required value="0">
|
|
</div>
|
|
<div class="col-md-6">
|
|
<label class="form-label fw-semibold">{% trans "Point Multiplier" %}</label>
|
|
<input type="number" step="0.01" name="point_multiplier" class="form-control" required value="1.00">
|
|
</div>
|
|
<div class="col-md-6">
|
|
<label class="form-label fw-semibold">{% trans "Discount (%)" %}</label>
|
|
<input type="number" step="0.01" name="discount_percentage" class="form-control" required value="0">
|
|
</div>
|
|
<div class="col-md-6">
|
|
<label class="form-label fw-semibold">{% trans "Color Code" %}</label>
|
|
<input type="color" name="color_code" class="form-control form-control-color w-100" value="#6c757d">
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="modal-footer bg-light border-0">
|
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">{% trans "Close" %}</button>
|
|
<button type="submit" class="btn btn-primary">{% trans "Save Tier" %}</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Add Payment Method Modal -->
|
|
<div class="modal fade" id="addPaymentModal" tabindex="-1">
|
|
<div class="modal-dialog">
|
|
<div class="modal-content border-0 shadow">
|
|
<div class="modal-header">
|
|
<h5 class="modal-title fw-bold">{% trans "Add Payment Method" %}</h5>
|
|
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
|
</div>
|
|
<div class="modal-body">
|
|
<div class="mb-3">
|
|
<label class="form-label fw-semibold">{% trans "Name (English)" %}</label>
|
|
<input type="text" id="addPmNameEn" class="form-control" required placeholder="e.g. Bank Transfer">
|
|
</div>
|
|
<div class="mb-3">
|
|
<label class="form-label fw-semibold">{% trans "Name (Arabic)" %}</label>
|
|
<input type="text" id="addPmNameAr" class="form-control" required placeholder="e.g. تحويل بنكي">
|
|
</div>
|
|
<div class="form-check form-switch">
|
|
<input class="form-check-input" type="checkbox" id="addPmIsActive" checked>
|
|
<label class="form-check-label">{% trans "Active" %}</label>
|
|
</div>
|
|
</div>
|
|
<div class="modal-footer bg-light border-0">
|
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">{% trans "Close" %}</button>
|
|
<button type="button" class="btn btn-outline-primary" id="saveAndAddAnotherPm">{% trans "Save & Add Another" %}</button>
|
|
<button type="button" class="btn btn-primary" id="savePm">{% trans "Save" %}</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Add Device Modal -->
|
|
<div class="modal fade" id="addDeviceModal" tabindex="-1">
|
|
<div class="modal-dialog">
|
|
<div class="modal-content border-0 shadow">
|
|
<form action="{% url 'add_device' %}" method="post">
|
|
{% csrf_token %}
|
|
<div class="modal-header">
|
|
<h5 class="modal-title fw-bold">{% trans "Add New Device" %}</h5>
|
|
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
|
</div>
|
|
<div class="modal-body">
|
|
<div class="mb-3">
|
|
<label class="form-label fw-semibold">{% trans "Device Name" %}</label>
|
|
<input type="text" name="name" class="form-control" required placeholder="e.g. Kitchen Printer">
|
|
</div>
|
|
<div class="row g-3">
|
|
<div class="col-md-6">
|
|
<label class="form-label fw-semibold">{% trans "Type" %}</label>
|
|
<select name="device_type" class="form-select">
|
|
<option value="printer">{% trans "Printer" %}</option>
|
|
<option value="scanner">{% trans "Scanner" %}</option>
|
|
<option value="scale">{% trans "Weight Scale" %}</option>
|
|
<option value="display">{% trans "Customer Display" %}</option>
|
|
<option value="other">{% trans "Other" %}</option>
|
|
</select>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<label class="form-label fw-semibold">{% trans "Connection" %}</label>
|
|
<select name="connection_type" class="form-select">
|
|
<option value="network" selected>{% trans "Network (IP)" %}</option>
|
|
<option value="usb">{% trans "USB" %}</option>
|
|
<option value="bluetooth">{% trans "Bluetooth" %}</option>
|
|
</select>
|
|
</div>
|
|
<div class="col-md-8">
|
|
<label class="form-label fw-semibold">{% trans "IP Address" %}</label>
|
|
<input type="text" name="ip_address" class="form-control" placeholder="192.168.1.100">
|
|
</div>
|
|
<div class="col-md-4">
|
|
<label class="form-label fw-semibold">{% trans "Port" %}</label>
|
|
<input type="number" name="port" class="form-control" placeholder="9100">
|
|
</div>
|
|
</div>
|
|
<div class="form-check form-switch mt-3">
|
|
<input class="form-check-input" type="checkbox" name="is_active" checked>
|
|
<label class="form-check-label">{% trans "Active" %}</label>
|
|
</div>
|
|
</div>
|
|
<div class="modal-footer bg-light border-0">
|
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">{% trans "Close" %}</button>
|
|
<button type="submit" class="btn btn-primary">{% trans "Save Device" %}</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{% endblock %}
|
|
|
|
{% block scripts %}
|
|
<script>
|
|
// Persist active tab on reload
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
var hash = window.location.hash;
|
|
if (hash) {
|
|
var triggerEl = document.querySelector('button[data-bs-target="' + hash + '"]');
|
|
if (triggerEl) {
|
|
var tab = new bootstrap.Tab(triggerEl);
|
|
tab.show();
|
|
}
|
|
}
|
|
|
|
var tabEls = document.querySelectorAll('button[data-bs-toggle="pill"]');
|
|
tabEls.forEach(function(el) {
|
|
el.addEventListener('shown.bs.tab', function(event) {
|
|
window.location.hash = event.target.getAttribute('data-bs-target');
|
|
});
|
|
});
|
|
|
|
// AJAX for Payment Method
|
|
async function savePaymentMethod(stayOpen = false) {
|
|
const nameEn = document.getElementById('addPmNameEn').value;
|
|
const nameAr = document.getElementById('addPmNameAr').value;
|
|
const isActive = document.getElementById('addPmIsActive').checked;
|
|
|
|
if (!nameEn || !nameAr) {
|
|
alert('{% trans "Please fill all required fields" %}');
|
|
return;
|
|
}
|
|
|
|
try {
|
|
const response = await fetch('{% url "add_payment_method_ajax" %}', {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
'X-CSRFToken': '{{ csrf_token }}'
|
|
},
|
|
body: JSON.stringify({
|
|
name_en: nameEn,
|
|
name_ar: nameAr,
|
|
is_active: isActive
|
|
})
|
|
});
|
|
|
|
const data = await response.json();
|
|
if (data.success) {
|
|
const tableBody = document.querySelector('#paymentMethodsTable tbody');
|
|
const noItems = document.getElementById('noPaymentMethods');
|
|
if (noItems) noItems.parentElement.remove();
|
|
|
|
const newRow = document.createElement('tr');
|
|
newRow.id = 'pm-row-' + data.id;
|
|
newRow.innerHTML = `
|
|
<td class="ps-4 fw-semibold">${data.name_en}</td>
|
|
<td>${data.name_ar}</td>
|
|
<td>
|
|
<span class="badge ${isActive ? 'bg-success-soft text-success' : 'bg-danger-soft text-danger'}">
|
|
${isActive ? '{% trans "Active" %}' : '{% trans "Inactive" %}'}
|
|
</span>
|
|
</td>
|
|
<td class="text-end pe-4">
|
|
<small class="text-muted">{% trans "Reload to edit" %}</small>
|
|
</td>
|
|
`;
|
|
tableBody.appendChild(newRow);
|
|
|
|
alert('{% trans "Payment method added successfully!" %}');
|
|
|
|
if (stayOpen) {
|
|
document.getElementById('addPmNameEn').value = '';
|
|
document.getElementById('addPmNameAr').value = '';
|
|
} else {
|
|
bootstrap.Modal.getInstance(document.getElementById('addPaymentModal')).hide();
|
|
window.location.reload();
|
|
}
|
|
} else {
|
|
alert('Error: ' + data.error);
|
|
}
|
|
} catch (error) {
|
|
console.error('Error:', error);
|
|
alert('{% trans "An error occurred. Please try again." %}');
|
|
}
|
|
}
|
|
|
|
const savePmBtn = document.getElementById('savePm');
|
|
if (savePmBtn) savePmBtn.addEventListener('click', () => savePaymentMethod(false));
|
|
|
|
const saveAndAddAnotherPmBtn = document.getElementById('saveAndAddAnotherPm');
|
|
if (saveAndAddAnotherPmBtn) saveAndAddAnotherPmBtn.addEventListener('click', () => savePaymentMethod(true));
|
|
|
|
// WhatsApp Test
|
|
const btnTestWhatsapp = document.getElementById('btn_test_whatsapp');
|
|
if (btnTestWhatsapp) {
|
|
btnTestWhatsapp.addEventListener('click', async function() {
|
|
const phone = document.getElementById('test_phone').value;
|
|
const resultDiv = document.getElementById('test_result');
|
|
|
|
if (!phone) {
|
|
alert('{% trans "Please enter a test phone number" %}');
|
|
return;
|
|
}
|
|
|
|
btnTestWhatsapp.disabled = true;
|
|
btnTestWhatsapp.innerHTML = '<span class="spinner-border spinner-border-sm me-1"></span> {% trans "Sending..." %}';
|
|
resultDiv.classList.add('d-none');
|
|
|
|
try {
|
|
const response = await fetch('{% url "test_whatsapp_connection" %}', {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
'X-CSRFToken': '{{ csrf_token }}'
|
|
},
|
|
body: JSON.stringify({ phone: phone })
|
|
});
|
|
|
|
const data = await response.json();
|
|
resultDiv.classList.remove('d-none');
|
|
if (data.success) {
|
|
resultDiv.className = 'mt-3 alert alert-success small py-2';
|
|
resultDiv.innerHTML = '<i class="bi bi-check-circle me-1"></i>' + data.message;
|
|
} else {
|
|
resultDiv.className = 'mt-3 alert alert-danger small py-2';
|
|
resultDiv.innerHTML = '<i class="bi bi-exclamation-triangle me-1"></i>' + data.error;
|
|
}
|
|
} catch (error) {
|
|
console.error('Error:', error);
|
|
resultDiv.classList.remove('d-none');
|
|
resultDiv.className = 'mt-3 alert alert-danger small py-2';
|
|
resultDiv.innerHTML = '<i class="bi bi-exclamation-triangle me-1"></i> {% trans "An error occurred." %}';
|
|
} finally {
|
|
btnTestWhatsapp.disabled = false;
|
|
btnTestWhatsapp.innerHTML = '<i class="bi bi-send me-1"></i> {% trans "Send Test Message" %}';
|
|
}
|
|
});
|
|
}
|
|
});
|
|
</script>
|
|
{% endblock %} |