Autosave: 20260302-152644
This commit is contained in:
parent
275baf63cd
commit
2a38c2ffdb
@ -119,8 +119,8 @@ $recent_orders = $stmt->fetchAll();
|
||||
<td><?= $order['id'] ?></td>
|
||||
<td><?= $lang === 'ar' ? ($order['customer_name_ar'] ?: $order['customer_name_en']) : $order['customer_name_en'] ?></td>
|
||||
<td><?= format_amount($order['total_price']) ?></td>
|
||||
<td><span class="badge bg-<?= getStatusColor($order['status']) ?>"><?= __($order['status']) ?></span></td>
|
||||
<td><span class="badge bg-<?= getPaymentStatusColor($order['payment_status']) ?>"><?= __($order['payment_status']) ?></span></td>
|
||||
<td><span class="badge bg-<?= getStatusColor($order['status']) ?> rounded-pill px-3 py-1"><?= __($order['status']) ?></span></td>
|
||||
<td><span class="badge badge-soft-<?= getPaymentStatusColor($order['payment_status']) ?> rounded-pill px-3 py-1"><?= __($order['payment_status']) ?></span></td>
|
||||
<td>
|
||||
<a href="order_details.php?id=<?= $order['id'] ?>" class="btn btn-sm btn-light border-0" style="border-radius: 8px;">
|
||||
<i class="bi bi-eye"></i>
|
||||
@ -166,4 +166,5 @@ function getPaymentStatusColor($status) {
|
||||
'paid' => 'success',
|
||||
][$status] ?? 'info';
|
||||
}
|
||||
require_once __DIR__ . '/includes/footer.php';
|
||||
require_once __DIR__ . '/includes/footer.php';
|
||||
?>
|
||||
42
api/translate.php
Normal file
42
api/translate.php
Normal file
@ -0,0 +1,42 @@
|
||||
<?php
|
||||
header('Content-Type: application/json');
|
||||
require_once __DIR__ . '/../db/config.php';
|
||||
require_once __DIR__ . '/../ai/LocalAIApi.php';
|
||||
|
||||
session_start();
|
||||
if (!isset($_SESSION['user_id'])) {
|
||||
echo json_encode(['success' => false, 'error' => 'Unauthorized']);
|
||||
exit;
|
||||
}
|
||||
|
||||
$text = $_POST['text'] ?? '';
|
||||
$direction = $_POST['direction'] ?? 'en-ar'; // en-ar or ar-en
|
||||
|
||||
if (empty($text)) {
|
||||
echo json_encode(['success' => false, 'error' => 'Text is empty']);
|
||||
exit;
|
||||
}
|
||||
|
||||
$target_lang = $direction === 'en-ar' ? 'Arabic' : 'English';
|
||||
$source_lang = $direction === 'en-ar' ? 'English' : 'Arabic';
|
||||
|
||||
try {
|
||||
$prompt = "Translate the following text from $source_lang to $target_lang. Provide ONLY the translated text, no explanation or extra characters.\n\nText: $text";
|
||||
|
||||
$response = LocalAIApi::createResponse([
|
||||
'input' => [
|
||||
['role' => 'system', 'content' => 'You are a professional translator specializing in business and laundry service terminology.'],
|
||||
['role' => 'user', 'content' => $prompt],
|
||||
],
|
||||
]);
|
||||
|
||||
if (!empty($response['success'])) {
|
||||
$translatedText = LocalAIApi::extractText($response);
|
||||
echo json_encode(['success' => true, 'translation' => trim($translatedText)]);
|
||||
} else {
|
||||
echo json_encode(['success' => false, 'error' => $response['error'] ?? 'AI translation failed']);
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
echo json_encode(['success' => false, 'error' => $e->getMessage()]);
|
||||
}
|
||||
|
||||
@ -49,6 +49,32 @@ body {
|
||||
padding: 0.5em 1em;
|
||||
}
|
||||
|
||||
/* Soft Badges */
|
||||
.badge-soft-success {
|
||||
background-color: rgba(16, 185, 129, 0.15) !important;
|
||||
color: #10b981 !important;
|
||||
}
|
||||
.badge-soft-danger {
|
||||
background-color: rgba(239, 68, 68, 0.15) !important;
|
||||
color: #ef4444 !important;
|
||||
}
|
||||
.badge-soft-warning {
|
||||
background-color: rgba(245, 158, 11, 0.15) !important;
|
||||
color: #f59e0b !important;
|
||||
}
|
||||
.badge-soft-primary {
|
||||
background-color: rgba(59, 130, 246, 0.15) !important;
|
||||
color: #3b82f6 !important;
|
||||
}
|
||||
.badge-soft-info {
|
||||
background-color: rgba(6, 182, 212, 0.15) !important;
|
||||
color: #06b6d4 !important;
|
||||
}
|
||||
.badge-soft-secondary {
|
||||
background-color: rgba(107, 114, 128, 0.15) !important;
|
||||
color: #6b7280 !important;
|
||||
}
|
||||
|
||||
.table thead th {
|
||||
background-color: #f9fafb;
|
||||
text-transform: uppercase;
|
||||
@ -81,4 +107,4 @@ body {
|
||||
|
||||
.item-card:hover {
|
||||
transform: scale(1.02);
|
||||
}
|
||||
}
|
||||
280
defined_keys.txt
Normal file
280
defined_keys.txt
Normal file
@ -0,0 +1,280 @@
|
||||
en
|
||||
dashboard
|
||||
pos
|
||||
orders
|
||||
customers
|
||||
items
|
||||
services
|
||||
branches
|
||||
users
|
||||
settings
|
||||
logout
|
||||
login
|
||||
username
|
||||
password
|
||||
confirm_password
|
||||
change_password
|
||||
submit
|
||||
save
|
||||
save_changes
|
||||
cancel
|
||||
add_new
|
||||
edit
|
||||
delete
|
||||
actions
|
||||
search
|
||||
total
|
||||
status
|
||||
date
|
||||
phone
|
||||
name
|
||||
name_en
|
||||
name_ar
|
||||
price
|
||||
quantity
|
||||
subtotal
|
||||
vat
|
||||
vat_total
|
||||
payment_status
|
||||
received
|
||||
processing
|
||||
ready
|
||||
delivered
|
||||
cancelled
|
||||
unpaid
|
||||
partially_paid
|
||||
paid
|
||||
cash
|
||||
card
|
||||
transfer
|
||||
new_order
|
||||
order_details
|
||||
customer_name
|
||||
select_customer
|
||||
add_item
|
||||
edit_item
|
||||
delete_item
|
||||
select_item
|
||||
select_service
|
||||
checkout
|
||||
back_to_pos
|
||||
language
|
||||
arabic
|
||||
english
|
||||
branch
|
||||
all_branches
|
||||
category
|
||||
categories
|
||||
add_category
|
||||
edit_category
|
||||
delete_category
|
||||
categories_management
|
||||
add_new_category
|
||||
select_category
|
||||
all
|
||||
variant
|
||||
variants
|
||||
add_variant
|
||||
select_variant
|
||||
variant_name_en
|
||||
variant_name_ar
|
||||
default
|
||||
vat_percent
|
||||
image_url
|
||||
items_management
|
||||
variants_prices
|
||||
no_items_found
|
||||
pricing_management
|
||||
are_you_sure
|
||||
company_profile
|
||||
user_profile
|
||||
logo
|
||||
favicon
|
||||
email
|
||||
address_en
|
||||
address_ar
|
||||
vat_number
|
||||
profile_picture
|
||||
full_name_en
|
||||
full_name_ar
|
||||
update_profile
|
||||
success_update
|
||||
error_update
|
||||
print
|
||||
print_invoice
|
||||
thermal_receipt
|
||||
order
|
||||
customer
|
||||
qty
|
||||
close
|
||||
payments
|
||||
no_payments
|
||||
update_status
|
||||
update
|
||||
remaining_amount
|
||||
add_payment
|
||||
payment_method
|
||||
customer_details
|
||||
order_date
|
||||
method
|
||||
amount
|
||||
currency
|
||||
ctr_no
|
||||
vat_no
|
||||
add_new_user
|
||||
role
|
||||
add_user
|
||||
lab
|
||||
outlet
|
||||
view_items
|
||||
initial_letters
|
||||
from_date
|
||||
to_date
|
||||
order_no
|
||||
all_status
|
||||
all_payments
|
||||
search_placeholder
|
||||
previous
|
||||
next
|
||||
page
|
||||
of
|
||||
ar
|
||||
dashboard
|
||||
pos
|
||||
orders
|
||||
customers
|
||||
items
|
||||
services
|
||||
branches
|
||||
users
|
||||
settings
|
||||
logout
|
||||
login
|
||||
username
|
||||
password
|
||||
confirm_password
|
||||
change_password
|
||||
submit
|
||||
save
|
||||
save_changes
|
||||
cancel
|
||||
add_new
|
||||
edit
|
||||
delete
|
||||
actions
|
||||
search
|
||||
total
|
||||
status
|
||||
date
|
||||
phone
|
||||
name
|
||||
name_en
|
||||
name_ar
|
||||
price
|
||||
quantity
|
||||
subtotal
|
||||
vat
|
||||
vat_total
|
||||
payment_status
|
||||
received
|
||||
processing
|
||||
ready
|
||||
delivered
|
||||
cancelled
|
||||
unpaid
|
||||
partially_paid
|
||||
paid
|
||||
cash
|
||||
card
|
||||
transfer
|
||||
new_order
|
||||
order_details
|
||||
customer_name
|
||||
select_customer
|
||||
add_item
|
||||
edit_item
|
||||
delete_item
|
||||
select_item
|
||||
select_service
|
||||
checkout
|
||||
back_to_pos
|
||||
language
|
||||
arabic
|
||||
english
|
||||
branch
|
||||
all_branches
|
||||
category
|
||||
categories
|
||||
add_category
|
||||
edit_category
|
||||
delete_category
|
||||
categories_management
|
||||
add_new_category
|
||||
select_category
|
||||
all
|
||||
variant
|
||||
variants
|
||||
add_variant
|
||||
select_variant
|
||||
variant_name_en
|
||||
variant_name_ar
|
||||
default
|
||||
vat_percent
|
||||
image_url
|
||||
items_management
|
||||
variants_prices
|
||||
no_items_found
|
||||
pricing_management
|
||||
are_you_sure
|
||||
company_profile
|
||||
user_profile
|
||||
logo
|
||||
favicon
|
||||
email
|
||||
address_en
|
||||
address_ar
|
||||
vat_number
|
||||
profile_picture
|
||||
full_name_en
|
||||
full_name_ar
|
||||
update_profile
|
||||
success_update
|
||||
error_update
|
||||
print
|
||||
print_invoice
|
||||
thermal_receipt
|
||||
order
|
||||
customer
|
||||
qty
|
||||
close
|
||||
payments
|
||||
no_payments
|
||||
update_status
|
||||
update
|
||||
remaining_amount
|
||||
add_payment
|
||||
payment_method
|
||||
customer_details
|
||||
order_date
|
||||
method
|
||||
amount
|
||||
currency
|
||||
ctr_no
|
||||
vat_no
|
||||
add_new_user
|
||||
role
|
||||
add_user
|
||||
lab
|
||||
outlet
|
||||
view_items
|
||||
initial_letters
|
||||
from_date
|
||||
to_date
|
||||
order_no
|
||||
all_status
|
||||
all_payments
|
||||
search_placeholder
|
||||
previous
|
||||
next
|
||||
page
|
||||
of
|
||||
@ -143,6 +143,12 @@ if ($current_user_id) {
|
||||
</a>
|
||||
</li>
|
||||
<?php if ($current_role !== 'cashier'): ?>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link <?= basename($_SERVER['PHP_SELF']) == 'reports.php' ? 'active' : '' ?>" href="reports.php">
|
||||
<i class="bi bi-file-earmark-bar-graph"></i>
|
||||
<?= __('reports') ?>
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link <?= basename($_SERVER['PHP_SELF']) == 'items.php' ? 'active' : '' ?>" href="items.php">
|
||||
<i class="bi bi-tags"></i>
|
||||
@ -239,4 +245,4 @@ if ($current_user_id) {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
</header>
|
||||
|
||||
@ -147,7 +147,45 @@ $translations = [
|
||||
'previous' => 'Previous',
|
||||
'next' => 'Next',
|
||||
'page' => 'Page',
|
||||
'of' => 'of'
|
||||
'of' => 'of',
|
||||
'Access Denied' => 'Access Denied',
|
||||
'active_orders' => 'Active Orders',
|
||||
'add_branch' => 'Add Branch',
|
||||
'add_new_branch' => 'Add New Branch',
|
||||
'add_new_customer' => 'Add New Customer',
|
||||
'add_new_service' => 'Add New Service',
|
||||
'company' => 'Company',
|
||||
'customers_list' => 'Customers List',
|
||||
'edit_service' => 'Edit Service',
|
||||
'exactly_3_letters' => 'Exactly 3 letters',
|
||||
'image' => 'Image',
|
||||
'item' => 'Item',
|
||||
'manage_orders_across_outlets' => 'Manage orders across outlets',
|
||||
'new_customers' => 'New Customers',
|
||||
'no_orders_found' => 'No orders found',
|
||||
'order_number' => 'Order Number',
|
||||
'orders_list' => 'Orders List',
|
||||
'pricing_services' => 'Pricing & Services',
|
||||
'quick_actions' => 'Quick Actions',
|
||||
'ready_orders' => 'Ready Orders',
|
||||
'recent_orders' => 'Recent Orders',
|
||||
'reports' => 'Reports',
|
||||
'service' => 'Service',
|
||||
'service_pricing' => 'Service Pricing',
|
||||
'services_management' => 'Services Management',
|
||||
'today_revenue' => 'Today Revenue',
|
||||
'view' => 'View',
|
||||
'generate_report' => 'Generate Report',
|
||||
'total_revenue' => 'Total Revenue',
|
||||
'total_orders' => 'Total Orders',
|
||||
'average_order_value' => 'Average Order Value',
|
||||
'revenue_by_outlet' => 'Revenue by Outlet',
|
||||
'revenue_by_cashier' => 'Revenue by Cashier',
|
||||
'orders_by_status' => 'Orders by Status',
|
||||
'top_items' => 'Top Items',
|
||||
'top_services' => 'Top Services',
|
||||
'cashier' => 'Cashier',
|
||||
'revenue_by_payment_method' => 'Revenue by Payment Method'
|
||||
],
|
||||
'ar' => [
|
||||
'dashboard' => 'لوحة القيادة',
|
||||
@ -288,7 +326,45 @@ $translations = [
|
||||
'previous' => 'السابق',
|
||||
'next' => 'التالي',
|
||||
'page' => 'صفحة',
|
||||
'of' => 'من'
|
||||
'of' => 'من',
|
||||
'Access Denied' => 'تم رفض الوصول',
|
||||
'active_orders' => 'الطلبات النشطة',
|
||||
'add_branch' => 'إضافة فرع',
|
||||
'add_new_branch' => 'إضافة فرع جديد',
|
||||
'add_new_customer' => 'إضافة عميل جديد',
|
||||
'add_new_service' => 'إضافة خدمة جديدة',
|
||||
'company' => 'الشركة',
|
||||
'customers_list' => 'قائمة العملاء',
|
||||
'edit_service' => 'تعديل خدمة',
|
||||
'exactly_3_letters' => '3 أحرف بالضبط',
|
||||
'image' => 'صورة',
|
||||
'item' => 'صنف',
|
||||
'manage_orders_across_outlets' => 'إدارة الطلبات عبر المنافذ',
|
||||
'new_customers' => 'عملاء جدد',
|
||||
'no_orders_found' => 'لا يوجد طلبات',
|
||||
'order_number' => 'رقم الطلب',
|
||||
'orders_list' => 'قائمة الطلبات',
|
||||
'pricing_services' => 'الأسعار والخدمات',
|
||||
'quick_actions' => 'إجراءات سريعة',
|
||||
'ready_orders' => 'طلبات جاهزة',
|
||||
'recent_orders' => 'آخر الطلبات',
|
||||
'reports' => 'التقارير',
|
||||
'service' => 'خدمة',
|
||||
'service_pricing' => 'أسعار الخدمات',
|
||||
'services_management' => 'إدارة الخدمات',
|
||||
'today_revenue' => 'إيرادات اليوم',
|
||||
'view' => 'عرض',
|
||||
'generate_report' => 'إنشاء تقرير',
|
||||
'total_revenue' => 'إجمالي الإيرادات',
|
||||
'total_orders' => 'إجمالي الطلبات',
|
||||
'average_order_value' => 'متوسط قيمة الطلب',
|
||||
'revenue_by_outlet' => 'الإيرادات حسب المنفذ',
|
||||
'revenue_by_cashier' => 'الإيرادات حسب الكاشير',
|
||||
'orders_by_status' => 'الطلبات حسب الحالة',
|
||||
'top_items' => 'أفضل الأصناف',
|
||||
'top_services' => 'أفضل الخدمات',
|
||||
'cashier' => 'الكاشير',
|
||||
'revenue_by_payment_method' => 'الإيرادات حسب طريقة الدفع'
|
||||
]
|
||||
];
|
||||
|
||||
@ -317,4 +393,4 @@ function decimals() {
|
||||
|
||||
function format_amount($amount) {
|
||||
return number_format((float)$amount, decimals()) . ' ' . currency();
|
||||
}
|
||||
}
|
||||
31
items.php
31
items.php
@ -322,11 +322,11 @@ foreach ($prices_raw as $p) {
|
||||
<div class="row">
|
||||
<div class="col-md-6 mb-3">
|
||||
<label class="form-label fw-bold small"><?= __('name_en') ?></label>
|
||||
<input type="text" name="name_en" id="itemNameEn" class="form-control" required style="border-radius: 12px;">
|
||||
<div class="input-group"><input type="text" name="name_en" id="itemNameEn" class="form-control" required style="border-top-left-radius: 12px; border-bottom-left-radius: 12px;"><button type="button" class="btn btn-outline-secondary" style="border-top-right-radius: 12px; border-bottom-right-radius: 12px;" onclick="translateField('itemNameEn', 'itemNameAr', 'en-ar')"><i class="bi bi-translate"></i></button></div>
|
||||
</div>
|
||||
<div class="col-md-6 mb-3">
|
||||
<label class="form-label fw-bold small"><?= __('name_ar') ?></label>
|
||||
<input type="text" name="name_ar" id="itemNameAr" class="form-control" style="border-radius: 12px;">
|
||||
<div class="input-group"><input type="text" name="name_ar" id="itemNameAr" class="form-control" style="border-top-left-radius: 12px; border-bottom-left-radius: 12px;"><button type="button" class="btn btn-outline-secondary" style="border-top-right-radius: 12px; border-bottom-right-radius: 12px;" onclick="translateField('itemNameAr', 'itemNameEn', 'ar-en')"><i class="bi bi-translate"></i></button></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -375,11 +375,11 @@ foreach ($prices_raw as $p) {
|
||||
<input type="hidden" name="id" id="catId">
|
||||
<div class="mb-3">
|
||||
<label class="form-label small"><?= __('name_en') ?></label>
|
||||
<input type="text" name="cat_name_en" id="catNameEn" class="form-control" required style="border-radius: 12px;">
|
||||
<div class="input-group"><input type="text" name="cat_name_en" id="catNameEn" class="form-control" required style="border-top-left-radius: 12px; border-bottom-left-radius: 12px;"><button type="button" class="btn btn-outline-secondary" style="border-top-right-radius: 12px; border-bottom-right-radius: 12px;" onclick="translateField('catNameEn', 'catNameAr', 'en-ar')"><i class="bi bi-translate"></i></button></div>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label small"><?= __('name_ar') ?></label>
|
||||
<input type="text" name="cat_name_ar" id="catNameAr" class="form-control" style="border-radius: 12px;">
|
||||
<div class="input-group"><input type="text" name="cat_name_ar" id="catNameAr" class="form-control" style="border-top-left-radius: 12px; border-bottom-left-radius: 12px;"><button type="button" class="btn btn-outline-secondary" style="border-top-right-radius: 12px; border-bottom-right-radius: 12px;" onclick="translateField('catNameAr', 'catNameEn', 'ar-en')"><i class="bi bi-translate"></i></button></div>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-secondary w-100 py-2 fw-bold" style="border-radius: 12px;">
|
||||
<?= __('save') ?>
|
||||
@ -444,11 +444,11 @@ foreach ($prices_raw as $p) {
|
||||
<input type="hidden" name="id" id="svcId">
|
||||
<div class="mb-3">
|
||||
<label class="form-label small"><?= __('name_en') ?></label>
|
||||
<input type="text" name="svc_name_en" id="svcNameEn" class="form-control" required style="border-radius: 12px;">
|
||||
<div class="input-group"><input type="text" name="svc_name_en" id="svcNameEn" class="form-control" required style="border-top-left-radius: 12px; border-bottom-left-radius: 12px;"><button type="button" class="btn btn-outline-secondary" style="border-top-right-radius: 12px; border-bottom-right-radius: 12px;" onclick="translateField('svcNameEn', 'svcNameAr', 'en-ar')"><i class="bi bi-translate"></i></button></div>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label small"><?= __('name_ar') ?></label>
|
||||
<input type="text" name="svc_name_ar" id="svcNameAr" class="form-control" style="border-radius: 12px;">
|
||||
<div class="input-group"><input type="text" name="svc_name_ar" id="svcNameAr" class="form-control" style="border-top-left-radius: 12px; border-bottom-left-radius: 12px;"><button type="button" class="btn btn-outline-secondary" style="border-top-right-radius: 12px; border-bottom-right-radius: 12px;" onclick="translateField('svcNameAr', 'svcNameEn', 'ar-en')"><i class="bi bi-translate"></i></button></div>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary w-100 py-2 fw-bold" style="border-radius: 12px;">
|
||||
<?= __('save') ?>
|
||||
@ -564,6 +564,25 @@ foreach ($prices_raw as $p) {
|
||||
</style>
|
||||
|
||||
<script>
|
||||
async function translateField(sourceId, targetId, direction) {
|
||||
const sourceEl = document.getElementById(sourceId);
|
||||
const targetEl = document.getElementById(targetId);
|
||||
const text = sourceEl.value.trim();
|
||||
if (!text) return;
|
||||
const btn = event.currentTarget;
|
||||
const originalHtml = btn.innerHTML;
|
||||
btn.disabled = true;
|
||||
btn.innerHTML = "<span class=\"spinner-border spinner-border-sm\"></span>";
|
||||
try {
|
||||
const formData = new FormData();
|
||||
formData.append("text", text);
|
||||
formData.append("direction", direction);
|
||||
const resp = await fetch("api/translate.php", { method: "POST", body: formData });
|
||||
const data = await resp.json();
|
||||
if (data.success) targetEl.value = data.translation;
|
||||
} catch (e) { console.error(e); }
|
||||
finally { btn.disabled = false; btn.innerHTML = originalHtml; }
|
||||
}
|
||||
function openItemModal(item = null) {
|
||||
const modal = new bootstrap.Modal(document.getElementById('itemModal'));
|
||||
const form = document.getElementById('itemForm');
|
||||
|
||||
@ -72,7 +72,10 @@ $payments = $stmt->fetchAll();
|
||||
<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" style="border-radius: 12px;"><?= __($order['status']) ?></span>
|
||||
<div class="d-flex gap-2">
|
||||
<span class="badge bg-<?= getStatusColor($order['status']) ?> fs-6 px-3 py-2" style="border-radius: 12px;"><?= __($order['status']) ?></span>
|
||||
<span class="badge badge-soft-<?= getPaymentStatusColor($order['payment_status']) ?> fs-6 px-3 py-2" style="border-radius: 12px;"><?= __($order['payment_status']) ?></span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="table-responsive mb-4">
|
||||
@ -243,5 +246,12 @@ function getStatusColor($status) {
|
||||
'cancelled' => 'danger',
|
||||
][$status] ?? 'info';
|
||||
}
|
||||
function getPaymentStatusColor($status) {
|
||||
return [
|
||||
'unpaid' => 'danger',
|
||||
'partially_paid' => 'warning',
|
||||
'paid' => 'success',
|
||||
][$status] ?? 'info';
|
||||
}
|
||||
require_once __DIR__ . '/includes/footer.php';
|
||||
?>
|
||||
?>
|
||||
|
||||
@ -161,7 +161,7 @@ if ($current_role === 'super_admin') {
|
||||
</td>
|
||||
<td class="fw-bold text-primary"><?= format_amount($order['total_price']) ?></td>
|
||||
<td><span class="badge bg-<?= getStatusColor($order['status']) ?> rounded-pill px-3 py-2"><?= __($order['status']) ?></span></td>
|
||||
<td><span class="badge bg-<?= getPaymentStatusColor($order['payment_status']) ?> rounded-pill px-3 py-2"><?= __($order['payment_status']) ?></span></td>
|
||||
<td><span class="badge badge-soft-<?= getPaymentStatusColor($order['payment_status']) ?> rounded-pill px-3 py-2"><?= __($order['payment_status']) ?></span></td>
|
||||
<td class="small"><?= date('d/m/Y H:i', strtotime($order['created_at'])) ?></td>
|
||||
<td class="text-end">
|
||||
<div class="d-flex gap-1 justify-content-end">
|
||||
@ -345,4 +345,4 @@ function getPaymentStatusColor($status) {
|
||||
][$status] ?? 'info';
|
||||
}
|
||||
require_once __DIR__ . '/includes/footer.php';
|
||||
?>
|
||||
?>
|
||||
8
pos.php
8
pos.php
@ -315,7 +315,13 @@ $pageTitle = $edit_order ? ($lang == 'en' ? 'Edit Order #' . $edit_order['order_
|
||||
<span class="small fw-bold"><?= $lang == 'en' ? 'Card' : 'بطاقة' ?></span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="col-12">
|
||||
<div class="col-6">
|
||||
<button class="btn btn-outline-primary w-100 py-3 rounded-3 d-flex flex-column align-items-center" onclick="completeCheckout('transfer')">
|
||||
<i class="bi bi-arrow-left-right mb-1 fs-4"></i>
|
||||
<span class="small fw-bold"><?= $lang == 'en' ? 'Transfer' : 'تحويل' ?></span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<button class="btn btn-outline-secondary w-100 py-3 rounded-3 d-flex flex-column align-items-center" onclick="completeCheckout('pay_later')">
|
||||
<i class="bi bi-clock-history mb-1 fs-4"></i>
|
||||
<span class="small fw-bold"><?= $lang == 'en' ? 'Pay Later' : 'الدفع لاحقاً' ?></span>
|
||||
|
||||
171
receipt.php
171
receipt.php
@ -42,9 +42,17 @@ $stmt->execute([$order_id]);
|
||||
$total_paid = $stmt->fetch()['total_paid'] ?? 0;
|
||||
$remaining = $order['total_price'] - $total_paid;
|
||||
|
||||
// Bilingual Helper for Labels
|
||||
function b_label($key) {
|
||||
global $translations;
|
||||
$en = $translations['en'][$key] ?? $key;
|
||||
$ar = $translations['ar'][$key] ?? $key;
|
||||
return '<span class="label-en">' . $en . '</span> / <span class="label-ar">' . $ar . '</span>';
|
||||
}
|
||||
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="<?= $lang ?>" dir="<?= is_rtl() ? 'rtl' : 'ltr' ?>">
|
||||
<html lang="en" dir="ltr">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
@ -67,8 +75,8 @@ $remaining = $order['total_price'] - $total_paid;
|
||||
margin: 0 auto;
|
||||
}
|
||||
.text-center { text-align: center; }
|
||||
.text-end { text-align: <?= is_rtl() ? 'left' : 'right' ?>; }
|
||||
.text-start { text-align: <?= is_rtl() ? 'right' : 'left' ?>; }
|
||||
.text-end { text-align: right; }
|
||||
.text-start { text-align: left; }
|
||||
.fw-bold { font-weight: bold; }
|
||||
.mb-1 { margin-bottom: 2mm; }
|
||||
.mb-2 { margin-bottom: 4mm; }
|
||||
@ -89,9 +97,24 @@ $remaining = $order['total_price'] - $total_paid;
|
||||
.info-row {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 1mm;
|
||||
margin-bottom: 1.5mm;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.info-label {
|
||||
font-size: 10px;
|
||||
flex-shrink: 0;
|
||||
margin-right: 2mm;
|
||||
}
|
||||
|
||||
.info-value {
|
||||
text-align: right;
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
.label-en { font-size: 10px; }
|
||||
.label-ar { font-size: 11px; font-family: 'Cairo', sans-serif; }
|
||||
|
||||
table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
@ -102,12 +125,26 @@ $remaining = $order['total_price'] - $total_paid;
|
||||
text-align: inherit;
|
||||
border-bottom: 1px solid #000;
|
||||
padding: 1mm 0;
|
||||
font-size: 11px;
|
||||
font-size: 10px;
|
||||
}
|
||||
|
||||
td {
|
||||
padding: 1.5mm 0;
|
||||
padding: 2mm 0;
|
||||
vertical-align: top;
|
||||
border-bottom: 0.1mm solid #eee;
|
||||
}
|
||||
|
||||
.item-name-ar {
|
||||
font-family: 'Cairo', sans-serif;
|
||||
font-size: 11px;
|
||||
display: block;
|
||||
margin-top: 0.5mm;
|
||||
}
|
||||
|
||||
.item-service {
|
||||
font-size: 9px;
|
||||
color: #555;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.totals {
|
||||
@ -119,6 +156,7 @@ $remaining = $order['total_price'] - $total_paid;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 1mm;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.grand-total {
|
||||
@ -134,12 +172,17 @@ $remaining = $order['total_price'] - $total_paid;
|
||||
padding-top: 3mm;
|
||||
font-size: 10px;
|
||||
}
|
||||
|
||||
.arabic-text {
|
||||
font-family: 'Cairo', sans-serif;
|
||||
direction: rtl;
|
||||
}
|
||||
|
||||
@media print {
|
||||
body {
|
||||
width: 80mm;
|
||||
margin: 0;
|
||||
padding: 5mm;
|
||||
padding: 3mm;
|
||||
}
|
||||
.no-print {
|
||||
display: none;
|
||||
@ -149,66 +192,92 @@ $remaining = $order['total_price'] - $total_paid;
|
||||
</head>
|
||||
<body>
|
||||
<div class="no-print text-center mb-2">
|
||||
<button onclick="window.print()" style="padding: 10px 20px; cursor: pointer; border-radius: 8px; border: 1px solid #000; background: #eee;"><?= __('print') ?? 'Print' ?></button>
|
||||
<button onclick="window.close()" style="padding: 10px 20px; cursor: pointer; border-radius: 8px; border: 1px solid #000; background: #fff;"><?= __('close') ?? 'Close' ?></button>
|
||||
<button onclick="window.print()" style="padding: 10px 20px; cursor: pointer; border-radius: 8px; border: 1px solid #000; background: #eee;">Print / طباعة</button>
|
||||
<button onclick="window.close()" style="padding: 10px 20px; cursor: pointer; border-radius: 8px; border: 1px solid #000; background: #fff;">Close / إغلاق</button>
|
||||
</div>
|
||||
|
||||
<div class="text-center receipt-header">
|
||||
<?php if ($company['logo']): ?>
|
||||
<img src="<?= $company['logo'] ?>" alt="Logo" class="logo">
|
||||
<?php else: ?>
|
||||
<h2 class="fw-bold"><?= is_arabic() ? $company['name_ar'] : $company['name_en'] ?></h2>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="fw-bold fs-6"><?= is_arabic() ? $order['branch_name_ar'] : $order['branch_name_en'] ?></div>
|
||||
<div><?= is_arabic() ? $order['branch_address_ar'] : $order['branch_address_en'] ?></div>
|
||||
<div><?= __('phone') ?>: <?= $order['branch_phone'] ?></div>
|
||||
<h3 class="fw-bold"><?= $company['name_en'] ?></h3>
|
||||
<h3 class="fw-bold arabic-text"><?= $company['name_ar'] ?></h3>
|
||||
|
||||
<div class="mt-1">
|
||||
<div class="fw-bold"><?= $order['branch_name_en'] ?></div>
|
||||
<div class="fw-bold arabic-text"><?= $order['branch_name_ar'] ?></div>
|
||||
</div>
|
||||
|
||||
<div class="small mt-1">
|
||||
<div><?= $order['branch_address_en'] ?></div>
|
||||
<div class="arabic-text"><?= $order['branch_address_ar'] ?></div>
|
||||
</div>
|
||||
|
||||
<div class="mt-1">
|
||||
<span><?= $translations['en']['phone'] ?> / <?= $translations['ar']['phone'] ?>:</span>
|
||||
<span><?= $order['branch_phone'] ?></span>
|
||||
</div>
|
||||
|
||||
<?php if (!empty($company['ctr_no'])): ?>
|
||||
<div><?= __('ctr_no') ?>: <?= $company['ctr_no'] ?></div>
|
||||
<div>
|
||||
<span><?= $translations['en']['ctr_no'] ?> / <?= $translations['ar']['ctr_no'] ?>:</span>
|
||||
<span><?= $company['ctr_no'] ?></span>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<?php if (!empty($company['vat_no'])): ?>
|
||||
<div><?= __('vat_no') ?>: <?= $company['vat_no'] ?></div>
|
||||
<?php elseif (!empty($company['vat_number'])): ?>
|
||||
<div><?= __('vat_no') ?>: <?= $company['vat_number'] ?></div>
|
||||
|
||||
<?php if (!empty($company['vat_no']) || !empty($company['vat_number'])): ?>
|
||||
<div>
|
||||
<span><?= $translations['en']['vat_no'] ?> / <?= $translations['ar']['vat_no'] ?>:</span>
|
||||
<span><?= $company['vat_no'] ?: $company['vat_number'] ?></span>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<div class="mb-2">
|
||||
<div class="info-row">
|
||||
<span class="fw-bold"><?= __('order') ?> #</span>
|
||||
<span><?= $order['order_number'] ?></span>
|
||||
<div class="info-label"><?= b_label('order') ?> #</div>
|
||||
<div class="info-value fw-bold"><?= $order['order_number'] ?></div>
|
||||
</div>
|
||||
<div class="info-row">
|
||||
<span class="fw-bold"><?= __('date') ?>:</span>
|
||||
<span><?= date('d/m/Y H:i', strtotime($order['created_at'])) ?></span>
|
||||
<div class="info-label"><?= b_label('date') ?></div>
|
||||
<div class="info-value"><?= date('d/m/Y H:i', strtotime($order['created_at'])) ?></div>
|
||||
</div>
|
||||
<div class="info-row">
|
||||
<span class="fw-bold"><?= __('customer') ?>:</span>
|
||||
<span><?= is_arabic() ? ($order['customer_name_ar'] ?: $order['customer_name_en']) : $order['customer_name_en'] ?></span>
|
||||
<div class="info-label"><?= b_label('customer') ?></div>
|
||||
<div class="info-value">
|
||||
<div><?= $order['customer_name_en'] ?: 'Walk-in' ?></div>
|
||||
<?php if ($order['customer_name_ar']): ?>
|
||||
<div class="arabic-text"><?= $order['customer_name_ar'] ?></div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
<?php if ($order['customer_phone']): ?>
|
||||
<div class="info-row">
|
||||
<span class="fw-bold"><?= __('phone') ?>:</span>
|
||||
<span><?= $order['customer_phone'] ?></span>
|
||||
<div class="info-label"><?= b_label('phone') ?></div>
|
||||
<div class="info-value"><?= $order['customer_phone'] ?></div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th><?= __('item') ?></th>
|
||||
<th class="text-center"><?= __('qty') ?? 'Qty' ?></th>
|
||||
<th class="text-end"><?= __('total') ?></th>
|
||||
<th style="width: 55%;"><?= b_label('item') ?></th>
|
||||
<th class="text-center" style="width: 15%;"><?= b_label('qty') ?></th>
|
||||
<th class="text-end" style="width: 30%;"><?= b_label('total') ?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach($order_items as $item): ?>
|
||||
<tr>
|
||||
<td>
|
||||
<div class="fw-bold"><?= is_arabic() ? ($item['item_ar'] ?: $item['item_en']) : $item['item_en'] ?></div>
|
||||
<div style="font-size: 10px; color: #444;"><?= is_arabic() ? ($item['service_ar'] ?: $item['service_en']) : $item['service_en'] ?></div>
|
||||
<div class="fw-bold" style="font-size: 11px;"><?= $item['item_en'] ?></div>
|
||||
<div class="item-name-ar"><?= $item['item_ar'] ?></div>
|
||||
<div class="item-service"><?= $item['service_en'] ?> / <span class="arabic-text"><?= $item['service_ar'] ?></span></div>
|
||||
</td>
|
||||
<td class="text-center"><?= $item['quantity'] ?></td>
|
||||
<td class="text-end"><?= format_amount($item['subtotal'] + ($item['vat_amount'] * $item['quantity'])) ?></td>
|
||||
<td class="text-end fw-bold"><?= number_format($item['subtotal'] + ($item['vat_amount'] * $item['quantity']), decimals()) ?></td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
@ -216,37 +285,43 @@ $remaining = $order['total_price'] - $total_paid;
|
||||
|
||||
<div class="totals">
|
||||
<div class="total-row">
|
||||
<span><?= __('subtotal') ?></span>
|
||||
<span><?= format_amount($order['total_price'] - $order['vat_total']) ?></span>
|
||||
<div class="info-label"><?= b_label('subtotal') ?></div>
|
||||
<div class="info-value"><?= format_amount($order['total_price'] - $order['vat_total']) ?></div>
|
||||
</div>
|
||||
<div class="total-row">
|
||||
<span><?= __('vat') ?></span>
|
||||
<span><?= format_amount($order['vat_total']) ?></span>
|
||||
<div class="info-label"><?= b_label('vat') ?></div>
|
||||
<div class="info-value"><?= format_amount($order['vat_total']) ?></div>
|
||||
</div>
|
||||
<div class="total-row fw-bold" style="font-size: 14px; border-top: 1px solid #000; margin-top: 1mm; padding-top: 1mm;">
|
||||
<span><?= __('total') ?></span>
|
||||
<span><?= format_amount($order['total_price']) ?></span>
|
||||
<div class="total-row fw-bold grand-total">
|
||||
<div class="info-label"><?= b_label('total') ?></div>
|
||||
<div class="info-value" style="font-size: 16px;"><?= format_amount($order['total_price']) ?></div>
|
||||
</div>
|
||||
|
||||
<div class="total-row mt-2">
|
||||
<span><?= __('paid') ?></span>
|
||||
<span><?= format_amount($total_paid) ?></span>
|
||||
<div class="info-label"><?= b_label('paid') ?></div>
|
||||
<div class="info-value"><?= format_amount($total_paid) ?></div>
|
||||
</div>
|
||||
<?php if ($remaining > 0): ?>
|
||||
<div class="total-row">
|
||||
<span><?= __('remaining_amount') ?></span>
|
||||
<span><?= format_amount(max(0, $remaining)) ?></span>
|
||||
<div class="info-label"><?= b_label('remaining_amount') ?></div>
|
||||
<div class="info-value fw-bold text-danger"><?= format_amount($remaining) ?></div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<div class="text-center footer">
|
||||
<div class="mb-1 fw-bold"><?= is_arabic() ? 'شكراً لزيارتكم!' : 'Thank you for your visit!' ?></div>
|
||||
<div><?= is_arabic() ? 'يرجى الاحتفاظ بالإيصال' : 'Please keep your receipt' ?></div>
|
||||
<div class="fw-bold mb-1">Thank you for your visit!</div>
|
||||
<div class="fw-bold arabic-text mb-1">شكراً لزيارتكم!</div>
|
||||
<div class="mt-1">Please keep your receipt</div>
|
||||
<div class="arabic-text">يرجى الاحتفاظ بالإيصال</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
window.onload = function() {
|
||||
// Uncomment for automatic print dialog
|
||||
// window.print();
|
||||
// Check if we are in the print iframe
|
||||
if (window.location.search.includes('id=')) {
|
||||
// Auto print is handled by the parent in pos.php
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
|
||||
347
reports.php
Normal file
347
reports.php
Normal file
@ -0,0 +1,347 @@
|
||||
<?php
|
||||
$title = 'reports';
|
||||
require_once __DIR__ . '/includes/header.php';
|
||||
|
||||
if ($current_role === 'cashier') {
|
||||
echo '<div class="alert alert-danger">' . __('Access Denied') . '</div>';
|
||||
require_once __DIR__ . '/includes/footer.php';
|
||||
exit;
|
||||
}
|
||||
|
||||
$from_date = $_GET['from_date'] ?? date('Y-m-01');
|
||||
$to_date = $_GET['to_date'] ?? date('Y-m-t');
|
||||
$branch_filter = $_GET['branch_id'] ?? 'all';
|
||||
$user_filter = $_GET['user_id'] ?? 'all';
|
||||
|
||||
// Base queries
|
||||
$where = "WHERE DATE(o.created_at) BETWEEN ? AND ?";
|
||||
$params = [$from_date, $to_date];
|
||||
|
||||
if ($branch_filter !== 'all') {
|
||||
$where .= " AND o.branch_id = ?";
|
||||
$params[] = $branch_filter;
|
||||
}
|
||||
|
||||
if ($user_filter !== 'all') {
|
||||
$where .= " AND o.user_id = ?";
|
||||
$params[] = $user_filter;
|
||||
}
|
||||
|
||||
// Summary Stats
|
||||
$stmt = db()->prepare("SELECT
|
||||
SUM(total_price) as total_revenue,
|
||||
COUNT(*) as total_orders,
|
||||
AVG(total_price) as avg_order_value
|
||||
FROM orders o $where");
|
||||
$stmt->execute($params);
|
||||
$summary = $stmt->fetch();
|
||||
|
||||
// Revenue by Branch
|
||||
$stmt = db()->prepare("SELECT
|
||||
b.name_en, b.name_ar, SUM(o.total_price) as revenue
|
||||
FROM orders o
|
||||
JOIN branches b ON o.branch_id = b.id
|
||||
$where
|
||||
GROUP BY o.branch_id");
|
||||
$stmt->execute($params);
|
||||
$revenue_by_branch = $stmt->fetchAll();
|
||||
|
||||
// Revenue by Cashier
|
||||
$stmt = db()->prepare("SELECT
|
||||
u.full_name_en, u.full_name_ar, SUM(o.total_price) as revenue
|
||||
FROM orders o
|
||||
JOIN users u ON o.user_id = u.id
|
||||
$where
|
||||
GROUP BY o.user_id");
|
||||
$stmt->execute($params);
|
||||
$revenue_by_user = $stmt->fetchAll();
|
||||
|
||||
// Orders by Status
|
||||
$stmt = db()->prepare("SELECT
|
||||
status, COUNT(*) as count
|
||||
FROM orders o
|
||||
$where
|
||||
GROUP BY status");
|
||||
$stmt->execute($params);
|
||||
$orders_by_status = $stmt->fetchAll();
|
||||
|
||||
// Revenue by Payment Method
|
||||
$stmt = db()->prepare("SELECT
|
||||
p.payment_method, SUM(p.amount) as revenue
|
||||
FROM payments p
|
||||
JOIN orders o ON p.order_id = o.id
|
||||
$where
|
||||
GROUP BY p.payment_method");
|
||||
$stmt->execute($params);
|
||||
$revenue_by_method = $stmt->fetchAll();
|
||||
|
||||
// Top Items
|
||||
$stmt = db()->prepare("SELECT
|
||||
i.name_en, i.name_ar, SUM(oi.quantity) as total_qty, SUM(oi.subtotal) as total_revenue
|
||||
FROM order_items oi
|
||||
JOIN orders o ON oi.order_id = o.id
|
||||
JOIN items i ON oi.item_id = i.id
|
||||
$where
|
||||
GROUP BY oi.item_id
|
||||
ORDER BY total_qty DESC LIMIT 10");
|
||||
$stmt->execute($params);
|
||||
$top_items = $stmt->fetchAll();
|
||||
|
||||
// Top Services
|
||||
$stmt = db()->prepare("SELECT
|
||||
s.name_en, s.name_ar, SUM(oi.quantity) as total_qty, SUM(oi.subtotal) as total_revenue
|
||||
FROM order_items oi
|
||||
JOIN orders o ON oi.order_id = o.id
|
||||
JOIN services s ON oi.service_id = s.id
|
||||
$where
|
||||
GROUP BY oi.service_id
|
||||
ORDER BY total_qty DESC LIMIT 10");
|
||||
$stmt->execute($params);
|
||||
$top_services = $stmt->fetchAll();
|
||||
|
||||
// Fetch branches and users for filters
|
||||
$branches = db()->query("SELECT id, name_en, name_ar FROM branches")->fetchAll();
|
||||
$users = db()->query("SELECT id, full_name_en, full_name_ar FROM users")->fetchAll();
|
||||
|
||||
?>
|
||||
|
||||
<div class="card p-4 mb-4">
|
||||
<form method="GET" class="row g-3 align-items-end">
|
||||
<div class="col-md-2">
|
||||
<label class="form-label small fw-bold"><?= __('from_date') ?></label>
|
||||
<input type="date" name="from_date" class="form-control" value="<?= $from_date ?>">
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<label class="form-label small fw-bold"><?= __('to_date') ?></label>
|
||||
<input type="date" name="to_date" class="form-control" value="<?= $to_date ?>">
|
||||
</div>
|
||||
<?php if ($current_role === 'super_admin'): ?>
|
||||
<div class="col-md-3">
|
||||
<label class="form-label small fw-bold"><?= __('outlet') ?></label>
|
||||
<select name="branch_id" class="form-select">
|
||||
<option value="all"><?= __('all_branches') ?></option>
|
||||
<?php foreach($branches as $b): ?>
|
||||
<option value="<?= $b['id'] ?>" <?= $branch_filter == $b['id'] ? 'selected' : '' ?>>
|
||||
<?= is_arabic() ? $b['name_ar'] : $b['name_en'] ?>
|
||||
</option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<div class="col-md-3">
|
||||
<label class="form-label small fw-bold"><?= __('cashier') ?></label>
|
||||
<select name="user_id" class="form-select">
|
||||
<option value="all"><?= __('all') ?></option>
|
||||
<?php foreach($users as $u): ?>
|
||||
<option value="<?= $u['id'] ?>" <?= $user_filter == $u['id'] ? 'selected' : '' ?>>
|
||||
<?= is_arabic() ? $u['full_name_ar'] : $u['full_name_en'] ?>
|
||||
</option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<button type="submit" class="btn btn-primary w-100">
|
||||
<i class="bi bi-filter me-2"></i> <?= __('generate_report') ?>
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="row g-4 mb-4">
|
||||
<div class="col-md-4">
|
||||
<div class="card p-4 text-center border-start border-primary border-5">
|
||||
<div class="text-muted small mb-1"><?= __('total_revenue') ?></div>
|
||||
<div class="fs-3 fw-bold text-primary"><?= format_amount($summary['total_revenue'] ?? 0) ?></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="card p-4 text-center border-start border-success border-5">
|
||||
<div class="text-muted small mb-1"><?= __('total_orders') ?></div>
|
||||
<div class="fs-3 fw-bold text-success"><?= $summary['total_orders'] ?? 0 ?></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="card p-4 text-center border-start border-info border-5">
|
||||
<div class="text-muted small mb-1"><?= __('average_order_value') ?></div>
|
||||
<div class="fs-3 fw-bold text-info"><?= format_amount($summary['avg_order_value'] ?? 0) ?></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row g-4 mb-4">
|
||||
<div class="col-md-6">
|
||||
<div class="card p-4 h-100">
|
||||
<h6 class="fw-bold mb-4"><?= __('revenue_by_outlet') ?></h6>
|
||||
<canvas id="revenueByBranchChart"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="card p-4 h-100">
|
||||
<h6 class="fw-bold mb-4"><?= __('orders_by_status') ?></h6>
|
||||
<canvas id="ordersByStatusChart"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row g-4 mb-4">
|
||||
<div class="col-md-6">
|
||||
<div class="card p-4 h-100">
|
||||
<h6 class="fw-bold mb-4"><?= __('revenue_by_cashier') ?></h6>
|
||||
<canvas id="revenueByCashierChart"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="card p-4 h-100">
|
||||
<h6 class="fw-bold mb-4"><?= __('revenue_by_payment_method') ?? 'Revenue by Payment Method' ?></h6>
|
||||
<canvas id="revenueByMethodChart"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row g-4 mb-4">
|
||||
<div class="col-md-6">
|
||||
<div class="card p-4 h-100">
|
||||
<h6 class="fw-bold mb-4"><?= __('top_items') ?></h6>
|
||||
<div class="table-responsive">
|
||||
<table class="table table-sm">
|
||||
<thead>
|
||||
<tr>
|
||||
<th><?= __('item') ?></th>
|
||||
<th class="text-center"><?= __('qty') ?></th>
|
||||
<th class="text-end"><?= __('revenue') ?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach($top_items as $item): ?>
|
||||
<tr>
|
||||
<td><?= is_arabic() ? $item['name_ar'] : $item['name_en'] ?></td>
|
||||
<td class="text-center"><?= $item['total_qty'] ?></td>
|
||||
<td class="text-end"><?= format_amount($item['total_revenue']) ?></td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="card p-4 h-100">
|
||||
<h6 class="fw-bold mb-4"><?= __('top_services') ?></h6>
|
||||
<div class="table-responsive">
|
||||
<table class="table table-sm">
|
||||
<thead>
|
||||
<tr>
|
||||
<th><?= __('service') ?></th>
|
||||
<th class="text-center"><?= __('qty') ?></th>
|
||||
<th class="text-end"><?= __('revenue') ?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach($top_services as $service): ?>
|
||||
<tr>
|
||||
<td><?= is_arabic() ? $service['name_ar'] : $service['name_en'] ?></td>
|
||||
<td class="text-center"><?= $service['total_qty'] ?></td>
|
||||
<td class="text-end"><?= format_amount($service['total_revenue']) ?></td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
||||
<script>
|
||||
// Revenue by Branch Chart
|
||||
new Chart(document.getElementById('revenueByBranchChart'), {
|
||||
type: 'bar',
|
||||
data: {
|
||||
labels: <?= json_encode(array_map(function($b) use ($lang) {
|
||||
return $lang === 'ar' ? $b['name_ar'] : $b['name_en'];
|
||||
}, $revenue_by_branch)) ?>,
|
||||
datasets: [{
|
||||
label: '<?= __('revenue') ?>',
|
||||
data: <?= json_encode(array_column($revenue_by_branch, 'revenue')) ?>,
|
||||
backgroundColor: 'rgba(54, 162, 235, 0.5)',
|
||||
borderColor: 'rgba(54, 162, 235, 1)',
|
||||
borderWidth: 1
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
responsive: true,
|
||||
scales: {
|
||||
y: { beginAtZero: true }
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Orders by Status Chart
|
||||
new Chart(document.getElementById('ordersByStatusChart'), {
|
||||
type: 'doughnut',
|
||||
data: {
|
||||
labels: <?= json_encode(array_map(function($s) {
|
||||
return __($s['status']);
|
||||
}, $orders_by_status)) ?>,
|
||||
datasets: [{
|
||||
data: <?= json_encode(array_column($orders_by_status, 'count')) ?>,
|
||||
backgroundColor: [
|
||||
'#6c757d', '#0d6efd', '#198754', '#212529', '#dc3545'
|
||||
]
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
responsive: true,
|
||||
plugins: {
|
||||
legend: { position: 'bottom' }
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Revenue by Cashier Chart
|
||||
new Chart(document.getElementById('revenueByCashierChart'), {
|
||||
type: 'bar',
|
||||
data: {
|
||||
labels: <?= json_encode(array_map(function($u) use ($lang) {
|
||||
return $lang === 'ar' ? $u['full_name_ar'] : $u['full_name_en'];
|
||||
}, $revenue_by_user)) ?>,
|
||||
datasets: [{
|
||||
label: '<?= __('revenue') ?>',
|
||||
data: <?= json_encode(array_column($revenue_by_user, 'revenue')) ?>,
|
||||
backgroundColor: 'rgba(75, 192, 192, 0.5)',
|
||||
borderColor: 'rgba(75, 192, 192, 1)',
|
||||
borderWidth: 1
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
responsive: true,
|
||||
scales: {
|
||||
y: { beginAtZero: true }
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Revenue by Method Chart
|
||||
new Chart(document.getElementById('revenueByMethodChart'), {
|
||||
type: 'pie',
|
||||
data: {
|
||||
labels: <?= json_encode(array_map(function($m) {
|
||||
return __($m['payment_method']);
|
||||
}, $revenue_by_method)) ?>,
|
||||
datasets: [{
|
||||
data: <?= json_encode(array_column($revenue_by_method, 'revenue')) ?>,
|
||||
backgroundColor: [
|
||||
'#ffc107', '#0dcaf0', '#6610f2'
|
||||
]
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
responsive: true,
|
||||
plugins: {
|
||||
legend: { position: 'bottom' }
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<?php require_once __DIR__ . '/includes/footer.php'; ?>
|
||||
135
used_keys.txt
Normal file
135
used_keys.txt
Normal file
@ -0,0 +1,135 @@
|
||||
Access Denied
|
||||
actions
|
||||
active_orders
|
||||
add_branch
|
||||
add_item
|
||||
add_new
|
||||
add_new_branch
|
||||
add_new_category
|
||||
add_new_customer
|
||||
add_new_service
|
||||
add_new_user
|
||||
add_payment
|
||||
add_user
|
||||
address_ar
|
||||
address_en
|
||||
all_branches
|
||||
all_payments
|
||||
all_status
|
||||
amount
|
||||
are_you_sure
|
||||
branch
|
||||
branches
|
||||
cancel
|
||||
cancelled
|
||||
card
|
||||
cash
|
||||
categories
|
||||
categories_management
|
||||
category
|
||||
change_password
|
||||
close
|
||||
company
|
||||
company_profile
|
||||
confirm_password
|
||||
ctr_no
|
||||
currency
|
||||
customer
|
||||
customer_details
|
||||
customer_name
|
||||
customers
|
||||
customers_list
|
||||
dashboard
|
||||
date
|
||||
delete
|
||||
delivered
|
||||
edit
|
||||
edit_category
|
||||
edit_item
|
||||
edit_service
|
||||
email
|
||||
error_update
|
||||
exactly_3_letters
|
||||
favicon
|
||||
from_date
|
||||
full_name_ar
|
||||
full_name_en
|
||||
image
|
||||
initial_letters
|
||||
item
|
||||
items
|
||||
items_management
|
||||
lab
|
||||
language
|
||||
login
|
||||
logo
|
||||
logout
|
||||
manage_orders_across_outlets
|
||||
method
|
||||
name
|
||||
name_ar
|
||||
name_en
|
||||
new_customers
|
||||
new_order
|
||||
next
|
||||
no_orders_found
|
||||
no_payments
|
||||
order
|
||||
order_date
|
||||
order_number
|
||||
orders
|
||||
orders_list
|
||||
outlet
|
||||
paid
|
||||
partially_paid
|
||||
password
|
||||
payment_method
|
||||
payment_status
|
||||
payments
|
||||
phone
|
||||
pos
|
||||
previous
|
||||
price
|
||||
pricing_services
|
||||
print_invoice
|
||||
processing
|
||||
profile_picture
|
||||
quantity
|
||||
quick_actions
|
||||
ready
|
||||
ready_orders
|
||||
received
|
||||
recent_orders
|
||||
remaining_amount
|
||||
reports
|
||||
role
|
||||
save
|
||||
save_changes
|
||||
search
|
||||
search_placeholder
|
||||
select_category
|
||||
service
|
||||
service_pricing
|
||||
services
|
||||
services_management
|
||||
status
|
||||
subtotal
|
||||
success_update
|
||||
thermal_receipt
|
||||
to_date
|
||||
today_revenue
|
||||
total
|
||||
transfer
|
||||
unpaid
|
||||
update
|
||||
update_profile
|
||||
update_status
|
||||
user_profile
|
||||
username
|
||||
users
|
||||
vat
|
||||
vat_no
|
||||
vat_percent
|
||||
vat_total
|
||||
view
|
||||
view_items
|
||||
Loading…
x
Reference in New Issue
Block a user