38471-vm/index.php
2026-02-18 13:50:40 +00:00

9895 lines
585 KiB
PHP

<?php
declare(strict_types=1);
// Sessions setup
if (!is_dir(__DIR__ . '/sessions')) {
mkdir(__DIR__ . '/sessions', 0777, true);
}
session_save_path(__DIR__ . '/sessions');
// Enhanced session security and iframe compatibility
if ((isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on') || (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https')) {
session_set_cookie_params([
'lifetime' => 0,
'path' => '/',
'secure' => true,
'httponly' => true,
'samesite' => 'None',
]);
}
session_start();
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
file_put_contents('post_debug.log', date('Y-m-d H:i:s') . " - POST: " . json_encode($_POST) . "\n", FILE_APPEND);
}
require_once 'db/config.php';
require_once 'lib/LicenseService.php';
// Licensing Middleware
$is_activated = LicenseService::isActivated();
$page = $_GET['page'] ?? 'dashboard';
if (!$is_activated && $page !== 'activate') {
header("Location: index.php?page=activate");
exit;
}
// Activation Page UI (accessible without login)
if ($page === 'activate') {
$error = '';
$success = '';
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['activate'])) {
$res = LicenseService::activate($_POST['license_key'] ?? '');
if ($res['success']) {
$success = "System activated successfully! Redirecting...";
header("refresh:2;url=index.php");
} else {
$error = $res['error'];
}
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Product Activation</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
<style>
body { background: #f4f7f6; height: 100vh; display: flex; align-items: center; justify-content: center; font-family: 'Inter', sans-serif; }
.activation-card { background: white; padding: 2rem; border-radius: 1rem; box-shadow: 0 10px 25px rgba(0,0,0,0.05); width: 100%; max-width: 450px; }
.fingerprint { background: #eee; padding: 0.5rem; border-radius: 0.5rem; font-family: monospace; font-size: 0.8rem; word-break: break-all; }
</style>
</head>
<body>
<div class="activation-card">
<h3 class="fw-bold mb-3">Activate Product</h3>
<p class="text-muted small mb-4">Please enter your serial key to continue using the application.</p>
<?php if ($error): ?>
<div class="alert alert-danger small"><?= $error ?></div>
<?php endif; ?>
<?php if ($success): ?>
<div class="alert alert-success small"><?= $success ?></div>
<?php endif; ?>
<form method="POST">
<div class="mb-3">
<label class="form-label small fw-bold">Serial Key</label>
<input type="text" name="license_key" class="form-control" placeholder="FLAT-XXXX-XXXX-XXXX" required>
<div class="form-text mt-1" style="font-size: 0.7rem;">Example: FLAT-8822-1192-3301</div>
</div>
<div class="mb-3">
<label class="form-label small fw-bold text-muted">Server Fingerprint</label>
<div class="fingerprint text-muted"><?= LicenseService::getFingerprint() ?></div>
</div>
<button type="submit" name="activate" class="btn btn-primary w-100 py-2">Activate Now</button>
</form>
<div class="mt-4 text-center">
<p class="text-muted small">Need a key? <a href="#">Contact Support</a></p>
</div>
</div>
</body>
</html>
<?php
exit;
}
require_once 'db/BackupService.php';
require_once 'includes/accounting_helper.php';
// Helper to check permissions
function can(string $permission): bool {
if (!isset($_SESSION['user_id'])) return false;
if (($_SESSION['user_role_name'] ?? '') === 'Administrator' || ($_SESSION['user_permissions'] ?? '') === 'all') return true;
$perms = json_decode($_SESSION['user_permissions'] ?? '[]', true);
return is_array($perms) && in_array($permission, $perms);
}
// Missing helper functions
function getLoyaltyMultiplier($tier) {
switch (strtolower((string)$tier)) {
case 'gold': return 2.0;
case 'silver': return 1.5;
default: return 1.0;
}
}
function numberToWords($num) {
$num = (int)$num;
if ($num == 0) return "zero";
$ones = ["", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "nineteen"];
$tens = ["", "", "twenty", "thirty", "forty", "fifty", "sixty", "seventy", "eighty", "ninety"];
if ($num < 20) return $ones[$num];
if ($num < 100) return $tens[(int)($num / 10)] . ($num % 10 ? "-" . $ones[$num % 10] : "");
if ($num < 1000) return $ones[(int)($num / 100)] . " hundred" . ($num % 100 ? " and " . numberToWords($num % 100) : "");
if ($num < 1000000) return numberToWords((int)($num / 1000)) . " thousand" . ($num % 1000 ? " " . numberToWords($num % 1000) : "");
return (string)$num;
}
// Login Logic
$login_error = '';
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['login'])) {
$user = $_POST['username'] ?? '';
$pass = $_POST['password'] ?? '';
$stmt = db()->prepare("SELECT u.*, g.permissions, g.name as role_name FROM users u LEFT JOIN role_groups g ON u.group_id = g.id WHERE u.username = ? AND u.status = 'active'");
$stmt->execute([$user]);
$u = $stmt->fetch();
if ($u && password_verify($pass, $u['password'])) {
$_SESSION['user_id'] = $u['id'];
$_SESSION['username'] = $u['username'];
$_SESSION['user_role_name'] = $u['role_name'];
$_SESSION['user_permissions'] = $u['permissions'];
$_SESSION['profile_pic'] = $u['profile_pic'];
$_SESSION['theme'] = $u['theme'] ?? 'default';
header("Location: index.php");
exit;
} else {
$login_error = "Invalid username or password";
// Debugging
$reason = (!$u) ? "User not found or inactive" : "Password mismatch";
file_put_contents('login_debug.log', date('Y-m-d H:i:s') . " - Failed login for '$user'. Reason: $reason\n", FILE_APPEND);
}
}
// Logout
if (isset($_GET['action']) && $_GET['action'] === 'logout') {
session_destroy();
header("Location: index.php");
exit;
}
// --- POS AJAX Handlers ---
if (isset($_GET['action']) || isset($_POST['action'])) {
$action = $_GET['action'] ?? $_POST['action'] ?? '';
if ($action === 'validate_discount') {
header('Content-Type: application/json');
$code = $_GET['code'] ?? '';
$stmt = db()->prepare("SELECT * FROM discount_codes WHERE code = ? AND status = 'active' AND (expiry_date IS NULL OR expiry_date >= CURDATE())");
$stmt->execute([$code]);
$discount = $stmt->fetch(PDO::FETCH_ASSOC);
if ($discount) {
echo json_encode(['success' => true, 'discount' => $discount]);
} else {
echo json_encode(['success' => false, 'error' => 'Invalid or expired discount code']);
}
exit;
}
if ($action === 'get_held_carts') {
header('Content-Type: application/json');
$stmt = db()->query("SELECT h.*, c.name as customer_name FROM pos_held_carts h LEFT JOIN customers c ON h.customer_id = c.id ORDER BY h.created_at DESC");
echo json_encode($stmt->fetchAll(PDO::FETCH_ASSOC));
exit;
}
if ($action === 'hold_pos_cart') {
header('Content-Type: application/json');
$name = $_POST['cart_name'] ?? 'Untitled Cart';
$items = $_POST['items'] ?? '[]';
$customer_id = !empty($_POST['customer_id']) ? (int)$_POST['customer_id'] : null;
$stmt = db()->prepare("INSERT INTO pos_held_carts (cart_name, items_json, customer_id) VALUES (?, ?, ?)");
$stmt->execute([$name, $items, $customer_id]);
echo json_encode(['success' => true]);
exit;
}
if ($action === 'delete_held_cart') {
header('Content-Type: application/json');
$id = (int)$_POST['id'];
$stmt = db()->prepare("DELETE FROM pos_held_carts WHERE id = ?");
$stmt->execute([$id]);
echo json_encode(['success' => true]);
exit;
}
if ($action === 'save_pos_transaction') {
header('Content-Type: application/json');
$db = db();
try {
$db->beginTransaction();
$customer_id = !empty($_POST['customer_id']) ? (int)$_POST['customer_id'] : null;
$payments = json_decode($_POST['payments'] ?? '[]', true);
$items = json_decode($_POST['items'] ?? '[]', true);
$total_amount = (float)($_POST['total_amount'] ?? 0);
$discount_code_id = !empty($_POST['discount_code_id']) ? (int)$_POST['discount_code_id'] : null;
$discount_amount = (float)($_POST['discount_amount'] ?? 0);
$loyalty_redeemed = (float)($_POST['loyalty_redeemed'] ?? 0);
$net_amount = $total_amount - $discount_amount - $loyalty_redeemed;
$transaction_no = 'POS-' . time() . rand(10, 99);
$session_id = $_SESSION['register_session_id'] ?? null;
// Insert Transaction
$stmt = $db->prepare("INSERT INTO pos_transactions (transaction_no, customer_id, total_amount, discount_code_id, discount_amount, loyalty_points_redeemed, net_amount, register_session_id, created_by, status) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, 'completed')");
$stmt->execute([$transaction_no, $customer_id, $total_amount, $discount_code_id, $discount_amount, $loyalty_redeemed, $net_amount, $session_id, $_SESSION['user_id']]);
$transaction_id = (int)$db->lastInsertId();
// Insert Items & Update Stock
$stmtItem = $db->prepare("INSERT INTO pos_items (transaction_id, product_id, quantity, unit_price, subtotal) VALUES (?, ?, ?, ?, ?)");
$stmtStock = $db->prepare("UPDATE stock_items SET stock_quantity = stock_quantity - ? WHERE id = ?");
foreach ($items as $item) {
$sub = (float)$item['price'] * (float)$item['qty'];
$stmtItem->execute([$transaction_id, $item['id'], $item['qty'], $item['price'], $sub]);
$stmtStock->execute([$item['qty'], $item['id']]);
}
// Insert Payments
$stmtPay = $db->prepare("INSERT INTO pos_payments (transaction_id, payment_method, amount) VALUES (?, ?, ?)");
foreach ($payments as $p) {
$stmtPay->execute([$transaction_id, $p['method'], $p['amount']]);
}
// Update Loyalty Points if customer exists
if ($customer_id) {
// Earn points
$points_earned = floor($net_amount);
$stmtPoints = $db->prepare("UPDATE customers SET loyalty_points = loyalty_points - ? + ? WHERE id = ?");
$stmtPoints->execute([$loyalty_redeemed * 100, $points_earned, $customer_id]);
// Record transactions
if ($points_earned > 0) {
$db->prepare("INSERT INTO loyalty_transactions (customer_id, transaction_id, points_change, transaction_type, description) VALUES (?, ?, ?, 'earned', ?)")
->execute([$customer_id, $transaction_id, $points_earned, "Earned from POS order #$transaction_no"]);
}
if ($loyalty_redeemed > 0) {
$db->prepare("INSERT INTO loyalty_transactions (customer_id, transaction_id, points_change, transaction_type, description) VALUES (?, ?, ?, 'redeemed', ?)")
->execute([$customer_id, $transaction_id, -$loyalty_redeemed * 100, "Redeemed for POS order #$transaction_no"]);
}
// Update transaction with points earned
$db->prepare("UPDATE pos_transactions SET loyalty_points_earned = ? WHERE id = ?")->execute([$points_earned, $transaction_id]);
}
$db->commit();
echo json_encode(['success' => true, 'invoice_id' => $transaction_id, 'transaction_no' => $transaction_no]);
} catch (Exception $e) {
$db->rollBack();
echo json_encode(['success' => false, 'error' => $e->getMessage()]);
}
exit;
}
if ($action === 'save_theme') {
header('Content-Type: application/json');
if (!isset($_SESSION['user_id'])) {
echo json_encode(['success' => false, 'error' => 'Not authenticated']);
exit;
}
$theme = $_POST['theme'] ?? 'default';
$allowed = ['default', 'dark', 'ocean', 'forest', 'sunset'];
if (!in_array($theme, $allowed)) $theme = 'default';
$stmt = db()->prepare("UPDATE users SET theme = ? WHERE id = ?");
$stmt->execute([$theme, $_SESSION['user_id']]);
$_SESSION['theme'] = $theme;
echo json_encode(['success' => true]);
exit;
}
}
// Redirect to login if not authenticated
if (!isset($_SESSION['user_id'])) {
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Login - Admin Panel</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.0/font/bootstrap-icons.css" rel="stylesheet">
<style>
body { background: #f8f9fa; height: 100vh; display: flex; align-items: center; justify-content: center; font-family: 'Inter', sans-serif; }
.login-card { border: none; border-radius: 20px; box-shadow: 0 10px 30px rgba(0,0,0,0.05); width: 100%; max-width: 400px; padding: 40px; background: #fff; }
.btn-primary { border-radius: 12px; padding: 12px; font-weight: 600; background: linear-gradient(135deg, #6e8efb, #a777e3); border: none; }
.form-control { border-radius: 12px; padding: 12px; border: 1px solid #eee; }
.form-control:focus { box-shadow: 0 0 0 4px rgba(110, 142, 251, 0.1); border-color: #6e8efb; }
</style>
</head>
<body>
<div class="login-card text-center">
<div class="mb-4">
<div class="d-inline-flex align-items-center justify-content-center bg-primary bg-opacity-10 rounded-circle mb-3" style="width: 60px; height: 60px;">
<i class="bi bi-shield-lock text-primary fs-3"></i>
</div>
<h4 class="fw-bold">Welcome Back</h4>
<p class="text-muted small">Please enter your details to sign in</p>
</div>
<?php if ($login_error): ?>
<div class="alert alert-danger small py-2 mb-4"><?= $login_error ?></div>
<?php endif; ?>
<form method="POST">
<div class="mb-3 text-start">
<label class="form-label small fw-semibold">Username</label>
<input type="text" name="username" class="form-control" placeholder="admin" required autofocus>
</div>
<div class="mb-4 text-start">
<label class="form-label small fw-semibold">Password</label>
<input type="password" name="password" class="form-control" placeholder="••••••••" required>
</div>
<button type="submit" name="login" class="btn btn-primary w-100 mb-3">Sign In</button>
<div class="text-muted small">Default user: admin / admin</div>
</form>
</div>
</body>
</html>
<?php
exit;
}
// Handle POST Requests
$message = '';
// Fetch theme if not in session but user is logged in
if (isset($_SESSION['user_id']) && !isset($_SESSION['theme'])) {
$stmt = db()->prepare("SELECT theme FROM users WHERE id = ?");
$stmt->execute([$_SESSION['user_id']]);
$_SESSION['theme'] = $stmt->fetchColumn() ?: 'default';
}
function numberToWordsOMR($number) {
$number = number_format((float)$number, 3, '.', '');
list($rials, $baisas) = explode('.', $number);
$rialsWords = numberToWords((int)$rials);
$baisasWords = numberToWords((int)$baisas);
$result = $rialsWords . " Omani Rials";
if ((int)$baisas > 0) {
$result .= " and " . $baisasWords . " Baisas";
}
return $result . " Only";
}
function getPromotionalPrice($item) {
$price = (float)$item['sale_price'];
if (isset($item['is_promotion']) && $item['is_promotion']) {
$today = date('Y-m-d');
$start = !empty($item['promotion_start']) ? $item['promotion_start'] : null;
$end = !empty($item['promotion_end']) ? $item['promotion_end'] : null;
$active = true;
if ($start && $today < $start) $active = false;
if ($end && $today > $end) $active = false;
if ($active) {
$price = $price * (1 - (float)$item['promotion_percent'] / 100);
}
}
return $price;
}
// --- HR Handlers ---
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
error_log("POST Request detected. Action: " . (print_r($_POST, true)));
}
if (isset($_POST['add_hr_department'])) {
$name = $_POST['name'] ?? '';
if ($name) {
$stmt = db()->prepare("INSERT INTO hr_departments (name) VALUES (?)");
$stmt->execute([$name]);
$message = "Department added successfully!";
}
}
if (isset($_POST['edit_hr_department'])) {
$id = (int)$_POST['id'];
$name = $_POST['name'] ?? '';
if ($id && $name) {
$stmt = db()->prepare("UPDATE hr_departments SET name = ? WHERE id = ?");
$stmt->execute([$name, $id]);
$message = "Department updated successfully!";
}
}
if (isset($_POST['delete_hr_department'])) {
$id = (int)$_POST['id'];
if ($id) {
$stmt = db()->prepare("DELETE FROM hr_departments WHERE id = ?");
$stmt->execute([$id]);
$message = "Department deleted successfully!";
}
}
if (isset($_POST['add_hr_employee'])) {
$dept_id = (int)$_POST['department_id'] ?: null;
$biometric_id = $_POST['biometric_id'] ?: null;
$name = $_POST['name'] ?? '';
$email = $_POST['email'] ?? '';
$phone = $_POST['phone'] ?? '';
$pos = $_POST['position'] ?? '';
$salary = (float)($_POST['salary'] ?? 0);
$j_date = $_POST['joining_date'] ?: null;
if ($name) {
$stmt = db()->prepare("INSERT INTO hr_employees (department_id, biometric_id, name, email, phone, position, salary, joining_date) VALUES (?, ?, ?, ?, ?, ?, ?, ?)");
$stmt->execute([$dept_id, $biometric_id, $name, $email, $phone, $pos, $salary, $j_date]);
$message = "Employee added successfully!";
}
}
if (isset($_POST['edit_hr_employee'])) {
$id = (int)$_POST['id'];
$dept_id = (int)$_POST['department_id'] ?: null;
$biometric_id = $_POST['biometric_id'] ?: null;
$name = $_POST['name'] ?? '';
$email = $_POST['email'] ?? '';
$phone = $_POST['phone'] ?? '';
$pos = $_POST['position'] ?? '';
$salary = (float)($_POST['salary'] ?? 0);
$j_date = $_POST['joining_date'] ?: null;
$status = $_POST['status'] ?? 'active';
if ($id && $name) {
$stmt = db()->prepare("UPDATE hr_employees SET department_id = ?, biometric_id = ?, name = ?, email = ?, phone = ?, position = ?, salary = ?, joining_date = ?, status = ? WHERE id = ?");
$stmt->execute([$dept_id, $biometric_id, $name, $email, $phone, $pos, $salary, $j_date, $status, $id]);
$message = "Employee updated successfully!";
}
}
if (isset($_POST['delete_hr_employee'])) {
$id = (int)$_POST['id'];
if ($id) {
$stmt = db()->prepare("DELETE FROM hr_employees WHERE id = ?");
$stmt->execute([$id]);
$message = "Employee deleted successfully!";
}
}
if (isset($_POST['mark_attendance'])) {
$emp_id = (int)$_POST['employee_id'];
$date = $_POST['attendance_date'] ?: date('Y-m-d');
$status = $_POST['status'] ?? 'present';
$in = $_POST['clock_in'] ?: null;
$out = $_POST['clock_out'] ?: null;
if ($emp_id) {
$stmt = db()->prepare("INSERT INTO hr_attendance (employee_id, attendance_date, status, clock_in, clock_out) VALUES (?, ?, ?, ?, ?) ON DUPLICATE KEY UPDATE status = ?, clock_in = ?, clock_out = ?");
$stmt->execute([$emp_id, $date, $status, $in, $out, $status, $in, $out]);
$message = "Attendance marked successfully!";
}
}
if (isset($_POST['generate_payroll'])) {
$emp_id = (int)$_POST['employee_id'];
$month = (int)$_POST['month'];
$year = (int)$_POST['year'];
$bonus = (float)($_POST['bonus'] ?? 0);
$deductions = (float)($_POST['deductions'] ?? 0);
$emp = db()->prepare("SELECT salary FROM hr_employees WHERE id = ?");
$emp->execute([$emp_id]);
$salary = (float)$emp->fetchColumn();
$net = $salary + $bonus - $deductions;
try {
$stmt = db()->prepare("INSERT INTO hr_payroll (employee_id, payroll_month, payroll_year, basic_salary, bonus, deductions, net_salary, status) VALUES (?, ?, ?, ?, ?, ?, ?, 'pending')");
$stmt->execute([$emp_id, $month, $year, $salary, $bonus, $deductions, $net]);
$message = "Payroll generated successfully!";
} catch (PDOException $e) {
if ($e->getCode() == 23000) { // Integrity constraint violation
$message = "Error: Payroll already exists for this employee in the selected period.";
} else {
$message = "Error: " . $e->getMessage();
}
}
}
if (isset($_POST['pay_payroll'])) {
$id = (int)$_POST['id'];
if ($id) {
// Get payroll details for accounting
$stmt = db()->prepare("SELECT p.*, e.name FROM hr_payroll p JOIN hr_employees e ON p.employee_id = e.id WHERE p.id = ?");
$stmt->execute([$id]);
$payroll = $stmt->fetch();
if ($payroll && $payroll['status'] !== 'paid') {
$stmt = db()->prepare("UPDATE hr_payroll SET status = 'paid', payment_date = CURDATE() WHERE id = ?");
$stmt->execute([$id]);
// Accounting Integration
recordPayrollJournal($id, (float)$payroll['net_salary'], date('Y-m-d'), $payroll['name']);
$message = "Payroll marked as paid and recorded in accounting!";
} else {
$message = "Payroll already paid or not found.";
}
}
}
if (isset($_POST['delete_payroll'])) {
$id = (int)$_POST['id'];
if ($id) {
$stmt = db()->prepare("DELETE FROM hr_payroll WHERE id = ?");
$stmt->execute([$id]);
$message = "Payroll record deleted successfully!";
}
}
// --- Biometric Devices Handlers ---
if (isset($_POST['add_biometric_device'])) {
$name = $_POST['device_name'] ?? '';
$ip = $_POST['ip_address'] ?? '';
$port = (int)($_POST['port'] ?? 4370);
$io = $_POST['io_address'] ?? '';
$serial = $_POST['serial_number'] ?? '';
if ($name && $ip) {
$stmt = db()->prepare("INSERT INTO hr_biometric_devices (device_name, ip_address, port, io_address, serial_number) VALUES (?, ?, ?, ?, ?)");
$stmt->execute([$name, $ip, $port, $io, $serial]);
$message = "Device added successfully!";
}
}
if (isset($_POST['edit_biometric_device'])) {
$id = (int)$_POST['id'];
$name = $_POST['device_name'] ?? '';
$ip = $_POST['ip_address'] ?? '';
$port = (int)($_POST['port'] ?? 4370);
$io = $_POST['io_address'] ?? '';
$serial = $_POST['serial_number'] ?? '';
if ($id && $name && $ip) {
$stmt = db()->prepare("UPDATE hr_biometric_devices SET device_name = ?, ip_address = ?, port = ?, io_address = ?, serial_number = ? WHERE id = ?");
$stmt->execute([$name, $ip, $port, $io, $serial, $id]);
$message = "Device updated successfully!";
}
}
if (isset($_POST['delete_biometric_device'])) {
$id = (int)$_POST['id'];
if ($id) {
$stmt = db()->prepare("DELETE FROM hr_biometric_devices WHERE id = ?");
$stmt->execute([$id]);
$message = "Device deleted successfully!";
}
}
if (isset($_POST['pull_biometric_data'])) {
$devices = db()->query("SELECT * FROM hr_biometric_devices WHERE status = 'active'")->fetchAll();
if (empty($devices)) {
$message = "No active biometric devices found to pull data from.";
} else {
// Simulation of pulling data from multiple devices
$employees = db()->query("SELECT id, biometric_id FROM hr_employees WHERE biometric_id IS NOT NULL")->fetchAll();
$pulled_count = 0;
$device_count = 0;
$date = date('Y-m-d');
foreach ($devices as $device) {
$device_pulled = 0;
foreach ($employees as $emp) {
// Randomly simulate logs for each employee for this device
if (rand(0, 1)) {
$check_in = $date . ' ' . str_pad((string)rand(7, 9), 2, '0', STR_PAD_LEFT) . ':' . str_pad((string)rand(0, 59), 2, '0', STR_PAD_LEFT) . ':00';
$check_out = $date . ' ' . str_pad((string)rand(16, 18), 2, '0', STR_PAD_LEFT) . ':' . str_pad((string)rand(0, 59), 2, '0', STR_PAD_LEFT) . ':00';
// Log check-in
$stmt = db()->prepare("INSERT INTO hr_biometric_logs (biometric_id, device_id, employee_id, timestamp, type) VALUES (?, ?, ?, ?, 'check_in')");
$stmt->execute([$emp['biometric_id'], $device['id'], $emp['id'], $check_in]);
// Log check-out
$stmt = db()->prepare("INSERT INTO hr_biometric_logs (biometric_id, device_id, employee_id, timestamp, type) VALUES (?, ?, ?, ?, 'check_out')");
$stmt->execute([$emp['biometric_id'], $device['id'], $emp['id'], $check_out]);
$device_pulled += 2;
$pulled_count += 2;
$in_time = date('H:i:s', strtotime($check_in));
$out_time = date('H:i:s', strtotime($check_out));
// Update attendance record (earliest in, latest out)
$stmt = db()->prepare("INSERT INTO hr_attendance (employee_id, attendance_date, status, clock_in, clock_out)
VALUES (?, ?, 'present', ?, ?)
ON DUPLICATE KEY UPDATE status = 'present',
clock_in = IF(clock_in IS NULL OR ? < clock_in, ?, clock_in),
clock_out = IF(clock_out IS NULL OR ? > clock_out, ?, clock_out)");
$stmt->execute([$emp['id'], $date, $in_time, $out_time, $in_time, $in_time, $out_time, $out_time]);
}
}
db()->prepare("UPDATE hr_biometric_devices SET last_sync = CURRENT_TIMESTAMP WHERE id = ?")->execute([$device['id']]);
$device_count++;
}
$message = "Successfully synced $device_count devices and pulled $pulled_count records.";
}
}
if (isset($_POST['test_device_connection'])) {
$id = (int)$_POST['id'];
$device = db()->prepare("SELECT * FROM hr_biometric_devices WHERE id = ?");
$device->execute([$id]);
$d = $device->fetch();
if ($d) {
// Simulated connection check
$message = "Connection to device '{$d['device_name']}' ({$d['ip_address']}) was successful! (Simulated)";
}
}
// --- User & Role Groups Handlers ---
if (isset($_POST['add_role_group'])) {
$name = $_POST['name'] ?? '';
$permissions = isset($_POST['permissions']) ? json_encode($_POST['permissions']) : '[]';
if ($name) {
try {
$stmt = db()->prepare("INSERT INTO role_groups (name, permissions) VALUES (?, ?)");
$stmt->execute([$name, $permissions]);
$message = "Role Group added successfully!";
} catch (PDOException $e) {
$message = "Error adding role group: " . $e->getMessage();
}
}
}
if (isset($_POST['add_user'])) {
$username = $_POST['username'] ?? '';
$password = $_POST['password'] ?? '';
$email = $_POST['email'] ?? '';
$phone = $_POST['phone'] ?? '';
$group_id = (int)($_POST['group_id'] ?? 0) ?: null;
if ($username && $password) {
$hashed_password = password_hash($password, PASSWORD_DEFAULT);
$stmt = db()->prepare("INSERT INTO users (username, password, email, phone, group_id) VALUES (?, ?, ?, ?, ?)");
try {
$stmt->execute([$username, $hashed_password, $email, $phone, $group_id]);
$message = "User added successfully!";
} catch (PDOException $e) {
if ($e->getCode() == '23000') {
$message = "Error: Username already exists.";
} else {
$message = "Error adding user: " . $e->getMessage();
}
}
}
}
if (isset($_POST['edit_role_group'])) {
$id = (int)$_POST['id'];
$name = $_POST['name'] ?? '';
$permissions = isset($_POST['permissions']) ? json_encode($_POST['permissions']) : '[]';
if ($id && $name) {
$stmt = db()->prepare("UPDATE role_groups SET name = ?, permissions = ? WHERE id = ?");
$stmt->execute([$name, $permissions, $id]);
$message = "Role Group updated successfully!";
}
}
if (isset($_POST['delete_role_group'])) {
$id = (int)$_POST['id'];
if ($id) {
$stmt = db()->prepare("DELETE FROM role_groups WHERE id = ?");
$stmt->execute([$id]);
$message = "Role Group deleted successfully!";
}
}
if (isset($_POST['edit_user'])) {
$id = (int)$_POST['id'];
$username = $_POST['username'] ?? '';
$email = $_POST['email'] ?? '';
$phone = $_POST['phone'] ?? '';
$group_id = (int)($_POST['group_id'] ?? 0) ?: null;
$status = $_POST['status'] ?? 'active';
if ($id && $username) {
$stmt = db()->prepare("UPDATE users SET username = ?, email = ?, phone = ?, group_id = ?, status = ? WHERE id = ?");
$stmt->execute([$username, $email, $phone, $group_id, $status, $id]);
if (!empty($_POST['password'])) {
$hashed_password = password_hash($_POST['password'], PASSWORD_DEFAULT);
$stmt = db()->prepare("UPDATE users SET password = ? WHERE id = ?");
$stmt->execute([$hashed_password, $id]);
}
$message = "User updated successfully!";
}
}
if (isset($_POST['delete_user'])) {
$id = (int)$_POST['id'];
if ($id) {
$stmt = db()->prepare("DELETE FROM users WHERE id = ?");
$stmt->execute([$id]);
$message = "User deleted successfully!";
}
}
// --- POS Devices Handlers ---
if (isset($_POST['add_pos_device'])) {
$name = $_POST['device_name'] ?? '';
$type = $_POST['device_type'] ?? 'scale';
$conn = $_POST['connection_type'] ?? 'usb';
$ip = $_POST['ip_address'] ?? '';
$port = $_POST['port'] ? (int)$_POST['port'] : null;
$baud = $_POST['baud_rate'] ? (int)$_POST['baud_rate'] : null;
if ($name) {
$stmt = db()->prepare("INSERT INTO pos_devices (device_name, device_type, connection_type, ip_address, port, baud_rate) VALUES (?, ?, ?, ?, ?, ?)");
$stmt->execute([$name, $type, $conn, $ip, $port, $baud]);
$message = "Device added successfully!";
}
}
if (isset($_POST['edit_pos_device'])) {
$id = (int)$_POST['id'];
$name = $_POST['device_name'] ?? '';
$type = $_POST['device_type'] ?? 'scale';
$conn = $_POST['connection_type'] ?? 'usb';
$ip = $_POST['ip_address'] ?? '';
$port = $_POST['port'] ? (int)$_POST['port'] : null;
$baud = $_POST['baud_rate'] ? (int)$_POST['baud_rate'] : null;
$status = $_POST['status'] ?? 'active';
if ($id && $name) {
$stmt = db()->prepare("UPDATE pos_devices SET device_name = ?, device_type = ?, connection_type = ?, ip_address = ?, port = ?, baud_rate = ?, status = ? WHERE id = ?");
$stmt->execute([$name, $type, $conn, $ip, $port, $baud, $status, $id]);
$message = "Device updated successfully!";
}
}
if (isset($_POST['delete_pos_device'])) {
$id = (int)$_POST['id'];
if ($id) {
$stmt = db()->prepare("DELETE FROM pos_devices WHERE id = ?");
$stmt->execute([$id]);
$message = "Device deleted successfully!";
}
}
if (isset($_POST['update_profile'])) {
$id = $_SESSION['user_id'];
$username = $_POST['username'] ?? '';
$email = $_POST['email'] ?? '';
$phone = $_POST['phone'] ?? '';
if ($id && $username) {
$stmt = db()->prepare("UPDATE users SET username = ?, email = ?, phone = ? WHERE id = ?");
$stmt->execute([$username, $email, $phone, $id]);
$_SESSION['username'] = $username;
if (!empty($_POST['password'])) {
$hashed_password = password_hash($_POST['password'], PASSWORD_DEFAULT);
$stmt = db()->prepare("UPDATE users SET password = ? WHERE id = ?");
$stmt->execute([$hashed_password, $id]);
}
if (isset($_FILES['profile_pic']) && $_FILES['profile_pic']['error'] === 0) {
$ext = pathinfo($_FILES['profile_pic']['name'], PATHINFO_EXTENSION);
$filename = 'uploads/profile_' . $id . '_' . time() . '.' . $ext;
if (!is_dir('uploads')) mkdir('uploads', 0777, true);
if (move_uploaded_file($_FILES['profile_pic']['tmp_name'], $filename)) {
$stmt = db()->prepare("UPDATE users SET profile_pic = ? WHERE id = ?");
$stmt->execute([$filename, $id]);
$_SESSION['profile_pic'] = $filename;
}
}
$message = "Profile updated successfully!";
}
}
if (isset($_POST['update_settings'])) {
if (can('settings_view')) {
$db = db();
if (isset($_POST['settings']) && is_array($_POST['settings'])) {
foreach ($_POST['settings'] as $key => $value) {
$stmt = $db->prepare("INSERT INTO settings (`key`, `value`) VALUES (?, ?) ON DUPLICATE KEY UPDATE `value` = ?");
$stmt->execute([$key, $value, $value]);
}
}
// Handle file uploads
$files = ['company_logo', 'favicon', 'manager_signature'];
foreach ($files as $file_key) {
if (isset($_FILES[$file_key]) && $_FILES[$file_key]['error'] === 0) {
$ext = pathinfo($_FILES[$file_key]['name'], PATHINFO_EXTENSION);
$filename = 'uploads/' . $file_key . '_' . time() . '.' . $ext;
if (!is_dir('uploads')) mkdir('uploads', 0777, true);
if (move_uploaded_file($_FILES[$file_key]['tmp_name'], $filename)) {
$stmt = $db->prepare("INSERT INTO settings (`key`, `value`) VALUES (?, ?) ON DUPLICATE KEY UPDATE `value` = ?");
$stmt->execute([$file_key, $filename, $filename]);
}
}
}
$message = "Settings updated successfully!";
// Reload settings for current request
$settings_raw = db()->query("SELECT * FROM settings")->fetchAll();
foreach ($settings_raw as $s) {
$data['settings'][$s['key']] = $s['value'];
}
}
}
// --- Backup Handlers ---
if (isset($_POST['create_backup'])) {
if (can('users_view')) { // Admin check
$res = BackupService::createBackup();
$message = $res['success'] ? "Backup created: " . $res['file'] : "Error: " . $res['error'];
}
}
if (isset($_POST['restore_backup'])) {
if (can('users_view')) {
$filename = $_POST['filename'] ?? '';
$res = BackupService::restoreBackup($filename);
$message = $res['success'] ? "Database restored successfully from $filename!" : "Error: " . $res['error'];
}
}
if (isset($_POST['delete_backup'])) {
if (can('users_view')) {
$filename = basename($_POST['filename'] ?? '');
if (unlink(__DIR__ . '/backups/' . $filename)) {
$message = "Backup deleted successfully.";
} else {
$message = "Error deleting backup.";
}
}
}
if (isset($_POST['save_backup_settings'])) {
if (can('users_view')) {
$limit = (int)($_POST['backup_limit'] ?? 5);
$auto = $_POST['backup_auto_enabled'] ?? '0';
$time = $_POST['backup_time'] ?? '00:00';
$db = db();
$stmt = $db->prepare("INSERT INTO settings (`key`, `value`) VALUES ('backup_limit', ?), ('backup_auto_enabled', ?), ('backup_time', ?) ON DUPLICATE KEY UPDATE `value` = VALUES(`value`)");
$stmt->execute([$limit, $auto, $time]);
$message = "Backup settings saved successfully!";
}
}
// --- Cash Register & Session Handlers ---
if (isset($_POST['add_cash_register'])) {
$name = $_POST['name'] ?? '';
if ($name) {
$stmt = db()->prepare("INSERT INTO cash_registers (name) VALUES (?)");
$stmt->execute([$name]);
$message = "Cash Register added successfully!";
}
}
if (isset($_POST['edit_cash_register'])) {
$id = (int)$_POST['id'];
$name = $_POST['name'] ?? '';
$status = $_POST['status'] ?? 'active';
if ($id && $name) {
$stmt = db()->prepare("UPDATE cash_registers SET name = ?, status = ? WHERE id = ?");
$stmt->execute([$name, $status, $id]);
$message = "Cash Register updated successfully!";
}
}
if (isset($_POST['delete_cash_register'])) {
$id = (int)$_POST['id'];
if ($id) {
$stmt = db()->prepare("DELETE FROM cash_registers WHERE id = ?");
$stmt->execute([$id]);
$message = "Cash Register deleted successfully!";
}
}
if (isset($_POST['open_register'])) {
$register_id = (int)$_POST['register_id'];
$user_id = $_SESSION['user_id'];
$opening_balance = (float)$_POST['opening_balance'];
// Check if user already has an open session
$check = db()->prepare("SELECT id FROM register_sessions WHERE user_id = ? AND status = 'open'");
$check->execute([$user_id]);
if ($check->fetch()) {
$message = "Error: You already have an open register session.";
} else {
$stmt = db()->prepare("INSERT INTO register_sessions (register_id, user_id, opening_balance, status) VALUES (?, ?, ?, 'open')");
$stmt->execute([$register_id, $user_id, $opening_balance]);
$_SESSION['register_session_id'] = db()->lastInsertId();
$message = "Register opened successfully!";
}
}
if (isset($_POST['close_register'])) {
$session_id = (int)$_POST['session_id'];
$cash_in_hand = (float)$_POST['cash_in_hand'];
$notes = $_POST['notes'] ?? '';
// Calculate expected closing balance
// Opening + Sum of POS Transactions (Cash) - Any cash outflows (if any)
$session = db()->prepare("SELECT opening_balance FROM register_sessions WHERE id = ?");
$session->execute([$session_id]);
$opening = (float)$session->fetchColumn();
$sales = db()->prepare("SELECT SUM(p.amount) FROM pos_payments p JOIN pos_transactions t ON p.transaction_id = t.id WHERE t.register_session_id = ? AND t.status = 'completed' AND p.payment_method = 'cash'");
$sales->execute([$session_id]);
$cash_sales = (float)$sales->fetchColumn();
$expected = $opening + $cash_sales;
$stmt = db()->prepare("UPDATE register_sessions SET closing_balance = ?, cash_in_hand = ?, closed_at = CURRENT_TIMESTAMP, status = 'closed', notes = ? WHERE id = ?");
$stmt->execute([$expected, $cash_in_hand, $notes, $session_id]);
unset($_SESSION['register_session_id']);
$message = "Register closed successfully!";
}
// Routing & Data Fetching
$page = $_GET['page'] ?? 'dashboard';
// Permission map for pages
$page_permissions = [
'dashboard' => 'dashboard_view',
'pos' => 'pos_view',
'sales' => 'sales_view',
'sales_returns' => 'sales_view',
'purchases' => 'purchases_view',
'purchase_returns' => 'purchases_view',
'quotations' => 'quotations_view',
'accounting' => 'accounting_view',
'expense_categories' => 'accounting_view',
'expenses' => 'accounting_view',
'items' => 'items_view',
'categories' => 'items_view',
'units' => 'items_view',
'customers' => 'customers_view',
'suppliers' => 'suppliers_view',
'customer_statement' => 'customers_view',
'supplier_statement' => 'suppliers_view',
'cashflow_report' => 'accounting_view',
'expiry_report' => 'items_view',
'low_stock_report' => 'items_view',
'loyalty_history' => 'customers_view',
'payment_methods' => 'settings_view',
'settings' => 'settings_view',
'devices' => 'settings_view',
'hr_departments' => 'hr_view',
'hr_employees' => 'hr_view',
'hr_attendance' => 'hr_view',
'hr_payroll' => 'hr_view',
'role_groups' => 'users_view',
'users' => 'users_view',
'scale_devices' => 'users_view',
'backups' => 'users_view',
'logs' => 'users_view',
'cash_registers' => 'users_view',
'register_sessions' => 'pos_view',
];
if (isset($page_permissions[$page]) && !can($page_permissions[$page])) {
$page = 'dashboard';
$message = "Access Denied: You don't have permission to view that module.";
}
$data = [
'payment_methods' => [],
'role_groups' => [],
'users' => [],
'expiry_items' => [],
'low_stock_items' => [],
'items' => [],
'cash_transactions' => [],
'monthly_sales' => [],
'yearly_sales' => [],
'opening_balance' => 0,
'stats' => [
'expired_items' => 0,
'near_expiry_items' => 0,
'low_stock_items_count' => 0,
'total_sales' => 0,
'total_received' => 0,
'total_receivable' => 0,
'total_purchases' => 0,
],
'settings' => [],
];
if ($page === 'export') {
$type = $_GET['type'] ?? 'sales';
$filename = $type . "_export_" . date('Y-m-d') . ".csv";
header('Content-Type: text/csv; charset=utf-8');
header('Content-Disposition: attachment; filename=' . $filename);
$output = fopen('php://output', 'w');
// Add UTF-8 BOM for Excel
fprintf($output, chr(0xEF).chr(0xBB).chr(0xBF));
if ($type === 'sales' || $type === 'purchases') {
$invType = ($type === 'sales') ? 'sale' : 'purchase';
$where = ["v.type = ?"];
$params = [$invType];
if (!empty($_GET['search'])) { $where[] = "(v.id LIKE ? OR c.name LIKE ?)"; $params[] = "%{$_GET['search']}%"; $params[] = "%{$_GET['search']}%"; }
if (!empty($_GET['customer_id'])) { $where[] = "v.customer_id = ?"; $params[] = $_GET['customer_id']; }
if (!empty($_GET['start_date'])) { $where[] = "v.invoice_date >= ?"; $params[] = $_GET['start_date']; }
if (!empty($_GET['end_date'])) { $where[] = "v.invoice_date <= ?"; $params[] = $_GET['end_date']; }
$whereSql = implode(" AND ", $where);
$stmt = db()->prepare("SELECT v.id, c.name as customer_name, v.invoice_date, v.payment_type, v.status, v.total_with_vat, v.paid_amount, (v.total_with_vat - v.paid_amount) as balance
FROM invoices v LEFT JOIN customers c ON v.customer_id = c.id
WHERE $whereSql ORDER BY v.id DESC");
$stmt->execute($params);
fputcsv($output, ['Invoice ID', 'Customer/Supplier', 'Date', 'Payment', 'Status', 'Total', 'Paid', 'Balance']);
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) fputcsv($output, $row);
} elseif ($type === 'customers' || $type === 'suppliers') {
$custType = ($type === 'suppliers') ? 'supplier' : 'customer';
$where = ["type = ?"];
$params = [$custType];
if (!empty($_GET['search'])) { $where[] = "(name LIKE ? OR email LIKE ? OR phone LIKE ? OR tax_id LIKE ?)"; $params[] = "%{$_GET['search']}%"; $params[] = "%{$_GET['search']}%"; $params[] = "%{$_GET['search']}%"; $params[] = "%{$_GET['search']}%"; }
if (!empty($_GET['start_date'])) { $where[] = "DATE(created_at) >= ?"; $params[] = $_GET['start_date']; }
if (!empty($_GET['end_date'])) { $where[] = "DATE(created_at) <= ?"; $params[] = $_GET['end_date']; }
$whereSql = implode(" AND ", $where);
$stmt = db()->prepare("SELECT id, name, email, phone, tax_id, balance, created_at FROM customers WHERE $whereSql ORDER BY id DESC");
$stmt->execute($params);
fputcsv($output, ['ID', 'Name', 'Email', 'Phone', 'Tax ID', 'Balance', 'Created At']);
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) fputcsv($output, $row);
} elseif ($type === 'items') {
$where = ["1=1"];
$params = [];
if (!empty($_GET['search'])) { $where[] = "(i.name_en LIKE ? OR i.name_ar LIKE ? OR i.sku LIKE ?)"; $params[] = "%{$_GET['search']}%"; $params[] = "%{$_GET['search']}%"; $params[] = "%{$_GET['search']}%"; }
$whereSql = implode(" AND ", $where);
$stmt = db()->prepare("SELECT i.sku, i.name_en, i.name_ar, c.name_en as category, i.purchase_price, i.sale_price, i.stock_quantity, i.vat_rate
FROM stock_items i LEFT JOIN stock_categories c ON i.category_id = c.id
WHERE $whereSql ORDER BY i.id DESC");
$stmt->execute($params);
fputcsv($output, ['SKU', 'Name (EN)', 'Name (AR)', 'Category', 'Purchase Price', 'Sale Price', 'Quantity', 'VAT %']);
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) fputcsv($output, $row);
}
fclose($output);
exit;
}
// Global data for modals
$data['categories'] = db()->query("SELECT * FROM stock_categories ORDER BY name_en ASC")->fetchAll();
$data['units'] = db()->query("SELECT * FROM stock_units ORDER BY name_en ASC")->fetchAll();
$data['suppliers'] = db()->query("SELECT * FROM customers WHERE type = 'supplier' ORDER BY name ASC")->fetchAll();
$data['accounts'] = db()->query("SELECT * FROM acc_accounts ORDER BY code ASC")->fetchAll();
$data['customers_list'] = db()->query("SELECT * FROM customers WHERE type = 'customer' ORDER BY name ASC")->fetchAll();
$customers = $data['customers_list']; // For backward compatibility in some modals
$settings_raw = db()->query("SELECT * FROM settings")->fetchAll();
$data['settings'] = [];
foreach ($settings_raw as $s) {
$data['settings'][$s['key']] = $s['value'];
}
switch ($page) {
case 'suppliers':
case 'customers':
$type = ($page === 'suppliers') ? 'supplier' : 'customer';
$where = ["type = ?"];
$params = [$type];
if (!empty($_GET['search'])) {
$where[] = "(name LIKE ? OR email LIKE ? OR phone LIKE ? OR tax_id LIKE ?)";
$params[] = "%{$_GET['search']}%";
$params[] = "%{$_GET['search']}%";
$params[] = "%{$_GET['search']}%";
$params[] = "%{$_GET['search']}%";
}
if (!empty($_GET['start_date'])) {
$where[] = "DATE(created_at) >= ?";
$params[] = $_GET['start_date'];
}
if (!empty($_GET['end_date'])) {
$where[] = "DATE(created_at) <= ?";
$params[] = $_GET['end_date'];
}
$whereSql = implode(" AND ", $where);
$stmt = db()->prepare("SELECT * FROM customers WHERE $whereSql ORDER BY id DESC");
$stmt->execute($params);
$data['customers'] = $stmt->fetchAll();
break;
case 'categories':
// Already fetched globally
break;
case 'units':
// Already fetched globally
break;
case 'items':
$where = ["1=1"];
$params = [];
if (!empty($_GET['search'])) {
$where[] = "(i.name_en LIKE ? OR i.name_ar LIKE ? OR i.sku LIKE ?)";
$params[] = "%{$_GET['search']}%";
$params[] = "%{$_GET['search']}%";
$params[] = "%{$_GET['search']}%";
}
$whereSql = implode(" AND ", $where);
$stmt = db()->prepare("SELECT i.*, c.name_en as cat_en, c.name_ar as cat_ar, u.short_name_en as unit_en, u.short_name_ar as unit_ar, s.name as supplier_name
FROM stock_items i
LEFT JOIN stock_categories c ON i.category_id = c.id
LEFT JOIN stock_units u ON i.unit_id = u.id
LEFT JOIN customers s ON i.supplier_id = s.id
WHERE $whereSql
ORDER BY i.id DESC");
$stmt->execute($params);
$data['items'] = $stmt->fetchAll();
break;
case 'quotations':
$where = ["1=1"];
$params = [];
if (!empty($_GET['search'])) {
$where[] = "(q.id LIKE ? OR c.name LIKE ?)";
$params[] = "%{$_GET['search']}%";
$params[] = "%{$_GET['search']}%";
}
if (!empty($_GET['customer_id'])) {
$where[] = "q.customer_id = ?";
$params[] = $_GET['customer_id'];
}
if (!empty($_GET['start_date'])) {
$where[] = "q.quotation_date >= ?";
$params[] = $_GET['start_date'];
}
if (!empty($_GET['end_date'])) {
$where[] = "q.quotation_date <= ?";
$params[] = $_GET['end_date'];
}
$whereSql = implode(" AND ", $where);
$stmt = db()->prepare("SELECT q.*, c.name as customer_name
FROM quotations q
LEFT JOIN customers c ON q.customer_id = c.id
WHERE $whereSql
ORDER BY q.id DESC");
$stmt->execute($params);
$data['quotations'] = $stmt->fetchAll();
$items_list_raw = db()->query("SELECT id, name_en, name_ar, sale_price, purchase_price, stock_quantity, vat_rate, is_promotion, promotion_start, promotion_end, promotion_percent FROM stock_items ORDER BY name_en ASC")->fetchAll(PDO::FETCH_ASSOC);
foreach ($items_list_raw as &$item) {
$item['sale_price'] = getPromotionalPrice($item);
}
$data['items_list'] = $items_list_raw;
$data['customers_list'] = db()->query("SELECT id, name FROM customers WHERE type = 'customer' ORDER BY name ASC")->fetchAll();
break;
case 'payment_methods':
$data['payment_methods'] = db()->query("SELECT * FROM payment_methods ORDER BY id DESC")->fetchAll();
break;
case 'settings':
// Already fetched globally
break;
case 'my_profile':
$stmt = db()->prepare("SELECT * FROM users WHERE id = ?");
$stmt->execute([$_SESSION['user_id']]);
$data['user'] = $stmt->fetch();
break;
case 'sales':
case 'purchases':
$type = ($page === 'sales') ? 'sale' : 'purchase';
$where = ["v.type = ?"];
$params = [$type];
if (!empty($_GET['search'])) {
$where[] = "(v.id LIKE ? OR c.name LIKE ?)";
$params[] = "%{$_GET['search']}%";
$params[] = "%{$_GET['search']}%";
}
if (!empty($_GET['customer_id'])) {
$where[] = "v.customer_id = ?";
$params[] = $_GET['customer_id'];
}
if (!empty($_GET['start_date'])) {
$where[] = "v.invoice_date >= ?";
$params[] = $_GET['start_date'];
}
if (!empty($_GET['end_date'])) {
$where[] = "v.invoice_date <= ?";
$params[] = $_GET['end_date'];
}
$whereSql = implode(" AND ", $where);
$stmt = db()->prepare("SELECT v.*, c.name as customer_name, c.tax_id as customer_tax_id, c.phone as customer_phone
FROM invoices v
LEFT JOIN customers c ON v.customer_id = c.id
WHERE $whereSql
ORDER BY v.id DESC");
$stmt->execute($params);
$data['invoices'] = $stmt->fetchAll();
foreach ($data['invoices'] as &$inv) {
$inv['total_in_words'] = numberToWordsOMR($inv['total_with_vat']);
}
unset($inv);
$items_list_raw = db()->query("SELECT id, name_en, name_ar, sale_price, purchase_price, stock_quantity, vat_rate, is_promotion, promotion_start, promotion_end, promotion_percent FROM stock_items ORDER BY name_en ASC")->fetchAll(PDO::FETCH_ASSOC);
foreach ($items_list_raw as &$item) {
$item['sale_price'] = getPromotionalPrice($item);
}
$data['items_list'] = $items_list_raw;
$data['customers_list'] = db()->query("SELECT id, name FROM customers WHERE type = '" . ($type === 'sale' ? 'customer' : 'supplier') . "' ORDER BY name ASC")->fetchAll();
break;
case 'sales_returns':
$where = ["1=1"];
$params = [];
if (!empty($_GET['search'])) {
$where[] = "(sr.id LIKE ? OR c.name LIKE ? OR sr.invoice_id LIKE ?)";
$params[] = "%{$_GET['search']}%";
$params[] = "%{$_GET['search']}%";
$params[] = "%{$_GET['search']}%";
}
$whereSql = implode(" AND ", $where);
$stmt = db()->prepare("SELECT sr.*, c.name as customer_name, i.total_with_vat as invoice_total
FROM sales_returns sr
LEFT JOIN customers c ON sr.customer_id = c.id
LEFT JOIN invoices i ON sr.invoice_id = i.id
WHERE $whereSql
ORDER BY sr.id DESC");
$stmt->execute($params);
$data['returns'] = $stmt->fetchAll();
$data['sales_invoices'] = db()->query("SELECT id, invoice_date, total_with_vat FROM invoices WHERE type = 'sale' ORDER BY id DESC")->fetchAll();
break;
case 'purchase_returns':
$where = ["1=1"];
$params = [];
if (!empty($_GET['search'])) {
$where[] = "(pr.id LIKE ? OR c.name LIKE ? OR pr.invoice_id LIKE ?)";
$params[] = "%{$_GET['search']}%";
$params[] = "%{$_GET['search']}%";
$params[] = "%{$_GET['search']}%";
}
$whereSql = implode(" AND ", $where);
$stmt = db()->prepare("SELECT pr.*, c.name as supplier_name, i.total_with_vat as invoice_total
FROM purchase_returns pr
LEFT JOIN customers c ON pr.supplier_id = c.id
LEFT JOIN invoices i ON pr.invoice_id = i.id
WHERE $whereSql
ORDER BY pr.id DESC");
$stmt->execute($params);
$data['returns'] = $stmt->fetchAll();
$data['purchase_invoices'] = db()->query("SELECT id, invoice_date, total_with_vat FROM invoices WHERE type = 'purchase' ORDER BY id DESC")->fetchAll();
break;
case 'customer_statement':
case 'supplier_statement':
$type = ($page === 'customer_statement') ? 'customer' : 'supplier';
$invType = ($type === 'customer') ? 'sale' : 'purchase';
$data['entities'] = db()->query("SELECT id, name, balance FROM customers WHERE type = '$type' ORDER BY name ASC")->fetchAll();
$entity_id = (int)($_GET['entity_id'] ?? 0);
if ($entity_id) {
$data['selected_entity'] = db()->query("SELECT * FROM customers WHERE id = $entity_id")->fetch();
$start_date = $_GET['start_date'] ?? date('Y-m-01');
$end_date = $_GET['end_date'] ?? date('Y-m-d');
// Fetch Opening Balance (Balance before start_date)
// This is complex as we don't have a ledger table.
// We can calculate it: Initial Balance + Invoices(before start_date) - Payments(before start_date)
// But for now, let's just show all transactions if no date filter, or just transactions in range.
$stmt = db()->prepare("SELECT 'invoice' as trans_type, id, invoice_date as trans_date, total_with_vat as amount, status, id as ref_no
FROM invoices
WHERE customer_id = ? AND type = ? AND invoice_date BETWEEN ? AND ?");
$stmt->execute([$entity_id, $invType, $start_date, $end_date]);
$invoices = $stmt->fetchAll(PDO::FETCH_ASSOC);
$stmt = db()->prepare("SELECT 'payment' as trans_type, p.id, p.payment_date as trans_date, p.amount, p.payment_method, p.invoice_id as ref_no
FROM payments p
JOIN invoices i ON p.invoice_id = i.id
WHERE i.customer_id = ? AND i.type = ? AND p.payment_date BETWEEN ? AND ?");
$stmt->execute([$entity_id, $invType, $start_date, $end_date]);
$payments = $stmt->fetchAll(PDO::FETCH_ASSOC);
$transactions = array_merge($invoices, $payments);
usort($transactions, function($a, $b) {
return strtotime($a['trans_date']) <=> strtotime($b['trans_date']);
});
$data['transactions'] = $transactions;
}
break;
case 'expense_categories':
$data['expense_categories'] = db()->query("SELECT * FROM expense_categories ORDER BY name_en ASC")->fetchAll();
break;
case 'expenses':
$where = ["1=1"];
$params = [];
if (!empty($_GET['category_id'])) {
$where[] = "e.category_id = ?";
$params[] = $_GET['category_id'];
}
if (!empty($_GET['start_date'])) {
$where[] = "e.expense_date >= ?";
$params[] = $_GET['start_date'];
}
if (!empty($_GET['end_date'])) {
$where[] = "e.expense_date <= ?";
$params[] = $_GET['end_date'];
}
$whereSql = implode(" AND ", $where);
$stmt = db()->prepare("SELECT e.*, c.name_en as cat_en, c.name_ar as cat_ar
FROM expenses e
LEFT JOIN expense_categories c ON e.category_id = c.id
WHERE $whereSql
ORDER BY e.expense_date DESC, e.id DESC");
$stmt->execute($params);
$data['expenses'] = $stmt->fetchAll();
break;
case 'role_groups':
$data['role_groups'] = db()->query("SELECT * FROM role_groups ORDER BY name ASC")->fetchAll();
break;
case 'users':
$data['users'] = db()->query("SELECT u.*, g.name as group_name FROM users u LEFT JOIN role_groups g ON u.group_id = g.id ORDER BY u.username ASC")->fetchAll();
$data['role_groups'] = db()->query("SELECT id, name FROM role_groups ORDER BY name ASC")->fetchAll();
break;
case 'backups':
$data['backups'] = BackupService::getBackups();
$stmt = db()->prepare("SELECT * FROM settings WHERE `key` IN ('backup_limit', 'backup_auto_enabled', 'backup_time')");
$stmt->execute();
$data['backup_settings'] = $stmt->fetchAll(PDO::FETCH_KEY_PAIR);
break;
case 'accounting':
$data['journal_entries'] = db()->query("SELECT je.*,
(SELECT SUM(debit) FROM acc_ledger WHERE journal_entry_id = je.id) as total_debit
FROM acc_journal_entries je
ORDER BY je.entry_date DESC, je.id DESC LIMIT 100")->fetchAll();
$data['accounts'] = db()->query("SELECT * FROM acc_accounts ORDER BY code ASC")->fetchAll();
if (isset($_GET['action']) && $_GET['action'] === 'get_entry_details') {
header('Content-Type: application/json');
$id = (int)$_GET['id'];
$stmt = db()->prepare("SELECT l.*, a.name_en, a.code FROM acc_ledger l JOIN acc_accounts a ON l.account_id = a.id WHERE l.journal_entry_id = ?");
$stmt->execute([$id]);
echo json_encode($stmt->fetchAll());
exit;
}
if (isset($_GET['view']) && $_GET['view'] === 'trial_balance') {
$data['trial_balance'] = db()->query("SELECT a.code, a.name_en, SUM(l.debit) as total_debit, SUM(l.credit) as total_credit
FROM acc_accounts a
LEFT JOIN acc_ledger l ON a.id = l.account_id
GROUP BY a.id
HAVING total_debit > 0 OR total_credit > 0
ORDER BY a.code ASC")->fetchAll();
}
if (isset($_GET['view']) && $_GET['view'] === 'profit_loss') {
$data['revenue_accounts'] = db()->query("SELECT code, name_en, name_ar FROM acc_accounts WHERE type = 'revenue' AND parent_id IS NOT NULL ORDER BY code ASC")->fetchAll();
$data['expense_accounts'] = db()->query("SELECT code, name_en, name_ar FROM acc_accounts WHERE type = 'expense' AND parent_id IS NOT NULL ORDER BY code ASC")->fetchAll();
}
if (isset($_GET['view']) && $_GET['view'] === 'balance_sheet') {
$data['asset_accounts'] = db()->query("SELECT code, name_en, name_ar FROM acc_accounts WHERE type = 'asset' AND parent_id IS NOT NULL ORDER BY code ASC")->fetchAll();
$data['liability_accounts'] = db()->query("SELECT code, name_en, name_ar FROM acc_accounts WHERE type = 'liability' AND parent_id IS NOT NULL ORDER BY code ASC")->fetchAll();
$data['equity_accounts'] = db()->query("SELECT code, name_en, name_ar FROM acc_accounts WHERE type = 'equity' AND parent_id IS NOT NULL ORDER BY code ASC")->fetchAll();
}
if (isset($_GET['view']) && $_GET['view'] === 'vat_report') {
$start = $_GET['start_date'] ?? date('Y-m-01');
$end = $_GET['end_date'] ?? date('Y-m-d');
$data['vat_report'] = getVatReport($start, $end);
$data['start_date'] = $start;
$data['end_date'] = $end;
}
if (isset($_GET['view']) && $_GET['view'] === 'coa') {
$data['coa'] = db()->query("SELECT a.*, p.name_en as parent_name
FROM acc_accounts a
LEFT JOIN acc_accounts p ON a.parent_id = p.id
ORDER BY a.code ASC")->fetchAll();
}
break;
case 'expense_report':
$start_date = $_GET['start_date'] ?? date('Y-m-01');
$end_date = $_GET['end_date'] ?? date('Y-m-d');
$stmt = db()->prepare("SELECT c.name_en, c.name_ar, SUM(e.amount) as total
FROM expenses e
JOIN expense_categories c ON e.category_id = c.id
WHERE e.expense_date BETWEEN ? AND ?
GROUP BY c.id
ORDER BY total DESC");
$stmt->execute([$start_date, $end_date]);
$data['report_by_category'] = $stmt->fetchAll();
$stmt = db()->prepare("SELECT SUM(amount) FROM expenses WHERE expense_date BETWEEN ? AND ?");
$stmt->execute([$start_date, $end_date]);
$data['total_expenses'] = $stmt->fetchColumn() ?: 0;
break;
case 'expiry_report':
$where = ["expiry_date IS NOT NULL"];
$params = [];
$filter = $_GET['filter'] ?? 'all';
if ($filter === 'expired') {
$where[] = "expiry_date <= CURDATE()";
} elseif ($filter === 'near_expiry') {
$where[] = "expiry_date > CURDATE() AND expiry_date <= DATE_ADD(CURDATE(), INTERVAL 30 DAY)";
}
$whereSql = implode(" AND ", $where);
$stmt = db()->prepare("SELECT i.*, c.name_en as cat_en, c.name_ar as cat_ar
FROM stock_items i
LEFT JOIN stock_categories c ON i.category_id = c.id
WHERE $whereSql
ORDER BY i.expiry_date ASC");
$stmt->execute($params);
$data['expiry_items'] = $stmt->fetchAll();
break;
case 'low_stock_report':
$stmt = db()->prepare("SELECT i.*, c.name_en as cat_en, c.name_ar as cat_ar, s.name as supplier_name
FROM stock_items i
LEFT JOIN stock_categories c ON i.category_id = c.id
LEFT JOIN customers s ON i.supplier_id = s.id AND s.type = 'supplier'
WHERE i.stock_quantity <= i.min_stock_level
ORDER BY (i.min_stock_level - i.stock_quantity) DESC");
$stmt->execute();
$data['low_stock_items'] = $stmt->fetchAll();
break;
case 'cashflow_report':
$start_date = $_GET['start_date'] ?? date('Y-m-01');
$end_date = $_GET['end_date'] ?? date('Y-m-d');
// Fetch Cash & Bank Account IDs
$cash_accounts = db()->query("SELECT id FROM acc_accounts WHERE code IN (1100, 1200)")->fetchAll(PDO::FETCH_COLUMN);
$cash_ids_str = implode(',', $cash_accounts);
if (!empty($cash_ids_str)) {
// Opening Balance
$stmt = db()->prepare("SELECT SUM(debit - credit) FROM acc_ledger l JOIN acc_journal_entries je ON l.journal_entry_id = je.id WHERE l.account_id IN ($cash_ids_str) AND je.entry_date < ?");
$stmt->execute([$start_date]);
$data['opening_balance'] = $stmt->fetchColumn() ?: 0;
// Transactions in range
$stmt = db()->prepare("SELECT
je.entry_date,
je.description,
l.debit as inflow,
l.credit as outflow,
a.name_en as other_account,
a.type as other_type
FROM acc_ledger l
JOIN acc_journal_entries je ON l.journal_entry_id = je.id
LEFT JOIN acc_ledger l2 ON l2.journal_entry_id = je.id AND l2.id != l.id
LEFT JOIN acc_accounts a ON l2.account_id = a.id
WHERE l.account_id IN ($cash_ids_str)
AND je.entry_date BETWEEN ? AND ?
ORDER BY je.entry_date ASC, je.id ASC");
$stmt->execute([$start_date, $end_date]);
$data['cash_transactions'] = $stmt->fetchAll(PDO::FETCH_ASSOC);
} else {
$data['opening_balance'] = 0;
$data['cash_transactions'] = [];
}
break;
case 'hr_departments':
$data['departments'] = db()->query("SELECT * FROM hr_departments ORDER BY id DESC")->fetchAll();
break;
case 'hr_employees':
$data['employees'] = db()->query("SELECT e.*, d.name as dept_name FROM hr_employees e LEFT JOIN hr_departments d ON e.department_id = d.id ORDER BY e.id DESC")->fetchAll();
$data['departments'] = db()->query("SELECT * FROM hr_departments ORDER BY name ASC")->fetchAll();
break;
case 'hr_attendance':
$date = $_GET['date'] ?? date('Y-m-d');
$data['attendance_date'] = $date;
$data['employees'] = db()->query("SELECT e.id, e.name, d.name as dept_name, a.status, a.clock_in, a.clock_out
FROM hr_employees e
LEFT JOIN hr_departments d ON e.department_id = d.id
LEFT JOIN hr_attendance a ON e.id = a.employee_id AND a.attendance_date = '$date'
WHERE e.status = 'active' ORDER BY e.name ASC")->fetchAll();
break;
case 'hr_payroll':
$month = (int)($_GET['month'] ?? date('m'));
$year = (int)($_GET['year'] ?? date('Y'));
$data['month'] = $month;
$data['year'] = $year;
$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;
case 'scale_devices':
$data['scale_devices'] = db()->query("SELECT * FROM pos_devices ORDER BY id DESC")->fetchAll();
break;
case 'cash_registers':
$data['cash_registers'] = db()->query("SELECT * FROM cash_registers ORDER BY id DESC")->fetchAll();
break;
case 'register_sessions':
$where = ["1=1"];
$params = [];
if (!can('users_view')) {
$where[] = "s.user_id = ?";
$params[] = $_SESSION['user_id'];
}
$whereSql = implode(" AND ", $where);
$stmt = db()->prepare("SELECT s.*, r.name as register_name, u.username
FROM register_sessions s
JOIN cash_registers r ON s.register_id = r.id
JOIN users u ON s.user_id = u.id
WHERE $whereSql
ORDER BY s.id DESC");
$stmt->execute($params);
$data['sessions'] = $stmt->fetchAll();
$data['cash_registers'] = db()->query("SELECT * FROM cash_registers WHERE status = 'active'")->fetchAll();
break;
default:
$data['customers'] = db()->query("SELECT * FROM customers WHERE type = 'customer' ORDER BY id DESC LIMIT 5")->fetchAll();
// Dashboard stats
$data['stats'] = [
'total_customers' => db()->query("SELECT COUNT(*) FROM customers WHERE type = 'customer'")->fetchColumn(),
'total_items' => db()->query("SELECT COUNT(*) FROM stock_items")->fetchColumn(),
'total_sales' => db()->query("SELECT SUM(total_with_vat) FROM invoices WHERE type = 'sale'")->fetchColumn() ?: 0,
'total_received' => db()->query("SELECT SUM(amount) FROM payments p JOIN invoices i ON p.invoice_id = i.id WHERE i.type = 'sale'")->fetchColumn() ?: 0,
'total_purchases' => db()->query("SELECT SUM(total_with_vat) FROM invoices WHERE type = 'purchase'")->fetchColumn() ?: 0,
'total_paid' => db()->query("SELECT SUM(amount) FROM payments p JOIN invoices i ON p.invoice_id = i.id WHERE i.type = 'purchase'")->fetchColumn() ?: 0,
'expired_items' => db()->query("SELECT COUNT(*) FROM stock_items WHERE expiry_date IS NOT NULL AND expiry_date <= CURDATE()")->fetchColumn(),
'near_expiry_items' => db()->query("SELECT COUNT(*) FROM stock_items WHERE expiry_date IS NOT NULL AND expiry_date > CURDATE() AND expiry_date <= DATE_ADD(CURDATE(), INTERVAL 30 DAY)")->fetchColumn(),
'low_stock_items_count' => db()->query("SELECT COUNT(*) FROM stock_items WHERE stock_quantity <= min_stock_level")->fetchColumn(),
];
$data['stats']['total_receivable'] = $data['stats']['total_sales'] - $data['stats']['total_received'];
$data['stats']['total_payable'] = $data['stats']['total_purchases'] - $data['stats']['total_paid'];
// Sales Chart Data
$data['monthly_sales'] = db()->query("SELECT DATE_FORMAT(invoice_date, '%M %Y') as label, SUM(total_with_vat) as total FROM invoices WHERE type = 'sale' GROUP BY DATE_FORMAT(invoice_date, '%Y-%m') ORDER BY invoice_date ASC LIMIT 12")->fetchAll(PDO::FETCH_ASSOC);
$data['yearly_sales'] = db()->query("SELECT YEAR(invoice_date) as label, SUM(total_with_vat) as total FROM invoices WHERE type = 'sale' GROUP BY label ORDER BY label ASC LIMIT 5")->fetchAll(PDO::FETCH_ASSOC);
break;
}
$projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? 'Accounting System';
?>
<!doctype html>
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title data-en="Accounting System" data-ar="نظام المحاسبة">Accounting System</title>
<meta name="description" content="<?= htmlspecialchars($projectDescription) ?>" />
<?php if (!empty($data['settings']['favicon'])): ?>
<link rel="icon" href="<?= htmlspecialchars($data['settings']['favicon']) ?>?v=<?= time() ?>">
<?php endif; ?>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.0/font/bootstrap-icons.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<link href="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/css/select2.min.css" rel="stylesheet" />
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/js/select2.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
<script src="https://cdn.jsdelivr.net/npm/jsbarcode@3.11.5/dist/JsBarcode.all.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script src="assets/js/main.js?v=<?php echo time(); ?>"></script>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700&display=swap" rel="stylesheet">
<link rel="stylesheet" href="assets/css/custom.css?v=<?php echo time(); ?>">
<style>
@media print {
.sidebar, .topbar, .d-print-none, .no-print { display: none !important; }
.main-content { margin: 0 !important; padding: 0 !important; }
}
</style>
</head>
<body class="theme-<?= htmlspecialchars($_SESSION['theme'] ?? 'default') ?>">
<div class="sidebar">
<div class="sidebar-header" data-en="Accounting" data-ar="المحاسبة">Accounting</div>
<nav class="mt-4">
<!-- General Section -->
<?php if (can('dashboard_view')): ?>
<a href="index.php?page=dashboard" class="nav-link <?= !isset($_GET['page']) || $_GET['page'] === 'dashboard' ? 'active' : '' ?>">
<i class="fas fa-chart-pie"></i> <span data-en="Dashboard" data-ar="لوحة القيادة">Dashboard</span>
</a>
<?php endif; ?>
<!-- Inventory Section -->
<?php if (can('items_view')): ?>
<div class="nav-section-title px-4 mt-3 mb-1 text-uppercase text-muted <?= !in_array($page, ['items', 'categories', 'units']) ? 'collapsed' : '' ?>" data-bs-toggle="collapse" data-bs-target="#stock-collapse">
<span><i class="fas fa-boxes-stacked group-icon"></i><span data-en="Inventory" data-ar="المخزون">Inventory</span></span>
<i class="fas fa-chevron-down chevron"></i>
</div>
<div class="collapse <?= in_array($page, ['items', 'categories', 'units']) ? 'show' : '' ?>" id="stock-collapse">
<a href="index.php?page=items" class="nav-link <?= isset($_GET['page']) && $_GET['page'] === 'items' ? 'active' : '' ?>">
<i class="fas fa-box"></i> <span data-en="Products" data-ar="المنتجات">Products</span>
</a>
<a href="index.php?page=categories" class="nav-link <?= isset($_GET['page']) && $_GET['page'] === 'categories' ? 'active' : '' ?>">
<i class="fas fa-tags"></i> <span data-en="Categories" data-ar="الفئات">Categories</span>
</a>
<a href="index.php?page=units" class="nav-link <?= isset($_GET['page']) && $_GET['page'] === 'units' ? 'active' : '' ?>">
<i class="fas fa-ruler-combined"></i> <span data-en="Units" data-ar="الوحدات">Units</span>
</a>
</div>
<?php endif; ?>
<!-- People Section -->
<?php if (can('customers_view') || can('suppliers_view')): ?>
<div class="nav-section-title px-4 mt-3 mb-1 text-uppercase text-muted <?= !in_array($page, ['customers', 'suppliers']) ? 'collapsed' : '' ?>" data-bs-toggle="collapse" data-bs-target="#crm-collapse">
<span><i class="fas fa-user-group group-icon"></i><span data-en="People" data-ar="الأشخاص">People</span></span>
<i class="fas fa-chevron-down chevron"></i>
</div>
<div class="collapse <?= in_array($page, ['customers', 'suppliers']) ? 'show' : '' ?>" id="crm-collapse">
<?php if (can('customers_view')): ?>
<a href="index.php?page=customers" class="nav-link <?= isset($_GET['page']) && $_GET['page'] === 'customers' ? 'active' : '' ?>">
<i class="fas fa-users"></i> <span data-en="Customers" data-ar="العملاء">Customers</span>
</a>
<?php endif; ?>
<?php if (can('suppliers_view')): ?>
<a href="index.php?page=suppliers" class="nav-link <?= isset($_GET['page']) && $_GET['page'] === 'suppliers' ? 'active' : '' ?>">
<i class="fas fa-truck-field"></i> <span data-en="Suppliers" data-ar="الموردين">Suppliers</span>
</a>
<?php endif; ?>
</div>
<?php endif; ?>
<!-- Operations Section -->
<?php if (can('pos_view') || can('sales_view') || can('purchases_view') || can('quotations_view')): ?>
<div class="nav-section-title px-4 mt-3 mb-1 text-uppercase text-muted <?= !in_array($page, ['sales', 'purchases', 'pos', 'quotations']) ? 'collapsed' : '' ?>" data-bs-toggle="collapse" data-bs-target="#ops-collapse">
<span><i class="fas fa-gears group-icon"></i><span data-en="Operations" data-ar="العمليات">Operations</span></span>
<i class="fas fa-chevron-down chevron"></i>
</div>
<div class="collapse <?= in_array($page, ['sales', 'purchases', 'pos', 'quotations']) ? 'show' : '' ?>" id="ops-collapse">
<?php if (can('pos_view')): ?>
<a href="index.php?page=pos" class="nav-link <?= isset($_GET['page']) && $_GET['page'] === 'pos' ? 'active' : '' ?>">
<i class="fas fa-cash-register"></i> <span data-en="Point of Sale" data-ar="نقطة البيع">Point of Sale</span>
</a>
<?php endif; ?>
<?php if (can('sales_view')): ?>
<a href="index.php?page=sales" class="nav-link <?= isset($_GET['page']) && $_GET['page'] === 'sales' ? 'active' : '' ?>">
<i class="fas fa-file-invoice-dollar"></i> <span data-en="Sales Tax Invoices" data-ar="فواتير المبيعات الضريبية">Sales Tax Invoices</span>
</a>
<a href="index.php?page=sales_returns" class="nav-link <?= isset($_GET['page']) && $_GET['page'] === 'sales_returns' ? 'active' : '' ?>">
<i class="fas fa-reply"></i> <span data-en="Sales Returns" data-ar="مرتجع المبيعات">Sales Returns</span>
</a>
<?php endif; ?>
<?php if (can('purchases_view')): ?>
<a href="index.php?page=purchases" class="nav-link <?= isset($_GET['page']) && $_GET['page'] === 'purchases' ? 'active' : '' ?>">
<i class="fas fa-cart-shopping"></i> <span data-en="Purchase Tax Invoices" data-ar="فواتير المشتريات الضريبية">Purchase Tax Invoices</span>
</a>
<a href="index.php?page=purchase_returns" class="nav-link <?= isset($_GET['page']) && $_GET['page'] === 'purchase_returns' ? 'active' : '' ?>">
<i class="fas fa-share"></i> <span data-en="Purchase Returns" data-ar="مرتجع المشتريات">Purchase Returns</span>
</a>
<?php endif; ?>
<?php if (can('quotations_view')): ?>
<a href="index.php?page=quotations" class="nav-link <?= isset($_GET['page']) && $_GET['page'] === 'quotations' ? 'active' : '' ?>">
<i class="fas fa-file-lines"></i> <span data-en="Quotations" data-ar="العروض">Quotations</span>
</a>
<?php endif; ?>
</div>
<?php endif; ?>
<!-- Expenses Section -->
<?php if (can('accounting_view')): ?>
<div class="nav-section-title px-4 mt-3 mb-1 text-uppercase text-muted <?= !in_array($page, ['expense_categories', 'expenses']) ? 'collapsed' : '' ?>" data-bs-toggle="collapse" data-bs-target="#expenses-collapse">
<span><i class="fas fa-wallet group-icon"></i><span data-en="Expenses" data-ar="المصروفات">Expenses</span></span>
<i class="fas fa-chevron-down chevron"></i>
</div>
<div class="collapse <?= in_array($page, ['expense_categories', 'expenses']) ? 'show' : '' ?>" id="expenses-collapse">
<a href="index.php?page=expense_categories" class="nav-link <?= isset($_GET['page']) && $_GET['page'] === 'expense_categories' ? 'active' : '' ?>">
<i class="fas fa-layer-group"></i> <span data-en="Categories" data-ar="الفئات">Categories</span>
</a>
<a href="index.php?page=expenses" class="nav-link <?= isset($_GET['page']) && $_GET['page'] === 'expenses' ? 'active' : '' ?>">
<i class="fas fa-file-invoice"></i> <span data-en="All Expenses" data-ar="كل المصروفات">All Expenses</span>
</a>
</div>
<?php endif; ?>
<!-- Accounting Section -->
<?php if (can('accounting_view')): ?>
<div class="nav-section-title px-4 mt-3 mb-1 text-uppercase text-muted <?= !in_array($page, ['accounting', 'expense_report']) ? 'collapsed' : '' ?>" data-bs-toggle="collapse" data-bs-target="#accounting-collapse">
<span><i class="fas fa-calculator group-icon"></i><span data-en="Accounting" data-ar="المحاسبة">Accounting</span></span>
<i class="fas fa-chevron-down chevron"></i>
</div>
<div class="collapse <?= in_array($page, ['accounting', 'expense_report']) ? 'show' : '' ?>" id="accounting-collapse">
<a href="index.php?page=accounting" class="nav-link <?= isset($_GET['page']) && $_GET['page'] === 'accounting' ? 'active' : '' ?>">
<i class="fas fa-book-open"></i> <span data-en="Journal & Ledger" data-ar="اليومية والأستاذ">Journal & Ledger</span>
</a>
<a href="index.php?page=accounting&view=trial_balance" class="nav-link <?= isset($_GET['view']) && $_GET['view'] === 'trial_balance' ? 'active' : '' ?>">
<i class="fas fa-scale-balanced"></i> <span data-en="Trial Balance" data-ar="ميزان المراجعة">Trial Balance</span>
</a>
<a href="index.php?page=accounting&view=profit_loss" class="nav-link <?= isset($_GET['view']) && $_GET['view'] === 'profit_loss' ? 'active' : '' ?>">
<i class="fas fa-chart-column"></i> <span data-en="Profit & Loss" data-ar="الأرباح والخسائر">Profit & Loss</span>
</a>
<a href="index.php?page=accounting&view=balance_sheet" class="nav-link <?= isset($_GET['view']) && $_GET['view'] === 'balance_sheet' ? 'active' : '' ?>">
<i class="fas fa-file-contract"></i> <span data-en="Balance Sheet" data-ar="الميزانية العمومية">Balance Sheet</span>
</a>
<a href="index.php?page=accounting&view=vat_report" class="nav-link <?= isset($_GET['view']) && $_GET['view'] === 'vat_report' ? 'active' : '' ?>">
<i class="fas fa-receipt"></i> <span data-en="VAT Report" data-ar="تقرير الضريبة">VAT Report</span>
</a>
</div>
<?php endif; ?>
<!-- HR Section -->
<?php if (can('hr_view')): ?>
<div class="nav-section-title px-4 mt-3 mb-1 text-uppercase text-muted <?= !in_array($page, ['hr_employees', 'hr_departments', 'hr_attendance', 'hr_payroll']) ? 'collapsed' : '' ?>" data-bs-toggle="collapse" data-bs-target="#hr-collapse">
<span><i class="fas fa-user-tie group-icon"></i><span data-en="HR" data-ar="الموارد البشرية">HR</span></span>
<i class="fas fa-chevron-down chevron"></i>
</div>
<div class="collapse <?= in_array($page, ['hr_employees', 'hr_departments', 'hr_attendance', 'hr_payroll']) ? 'show' : '' ?>" id="hr-collapse">
<a href="index.php?page=hr_departments" class="nav-link <?= $page === 'hr_departments' ? 'active' : '' ?>">
<i class="fas fa-building-user"></i> <span data-en="Departments" data-ar="الأقسام">Departments</span>
</a>
<a href="index.php?page=hr_employees" class="nav-link <?= $page === 'hr_employees' ? 'active' : '' ?>">
<i class="fas fa-user-badge"></i> <span data-en="Employees" data-ar="الموظفون">Employees</span>
</a>
<a href="index.php?page=hr_attendance" class="nav-link <?= $page === 'hr_attendance' ? 'active' : '' ?>">
<i class="fas fa-user-check"></i> <span data-en="Attendance" data-ar="الحضور">Attendance</span>
</a>
<a href="index.php?page=hr_payroll" class="nav-link <?= $page === 'hr_payroll' ? 'active' : '' ?>">
<i class="fas fa-sack-dollar"></i> <span data-en="Payroll" data-ar="الرواتب">Payroll</span>
</a>
</div>
<?php endif; ?>
<!-- Reports Section -->
<?php if (can('sales_view') || can('purchases_view') || can('items_view') || can('customers_view') || can('suppliers_view')): ?>
<div class="nav-section-title px-4 mt-3 mb-1 text-uppercase text-muted <?= !in_array($page, ['customer_statement', 'supplier_statement', 'cashflow_report', 'expiry_report', 'low_stock_report']) ? 'collapsed' : '' ?>" data-bs-toggle="collapse" data-bs-target="#reports-collapse">
<span><i class="fas fa-chart-line group-icon"></i><span data-en="Reports" data-ar="التقارير">Reports</span></span>
<i class="fas fa-chevron-down chevron"></i>
</div>
<div class="collapse <?= in_array($page, ['customer_statement', 'supplier_statement', 'cashflow_report', 'expiry_report', 'low_stock_report', 'loyalty_history']) ? 'show' : '' ?>" id="reports-collapse">
<?php if (can('customers_view')): ?>
<a href="index.php?page=customer_statement" class="nav-link <?= isset($_GET['page']) && $_GET['page'] === 'customer_statement' ? 'active' : '' ?>">
<i class="fas fa-file-invoice"></i> <span data-en="Customer Statement" data-ar="كشف حساب عميل">Customer Statement</span>
</a>
<?php endif; ?>
<?php if (can('suppliers_view')): ?>
<a href="index.php?page=supplier_statement" class="nav-link <?= isset($_GET['page']) && $_GET['page'] === 'supplier_statement' ? 'active' : '' ?>">
<i class="fas fa-file-lines"></i> <span data-en="Supplier Statement" data-ar="كشف حساب مورد">Supplier Statement</span>
</a>
<?php endif; ?>
<?php if (can('accounting_view')): ?>
<a href="index.php?page=cashflow_report" class="nav-link <?= isset($_GET['page']) && $_GET['page'] === 'cashflow_report' ? 'active' : '' ?>">
<i class="fas fa-money-bill-transfer"></i> <span data-en="Cashflow Statement" data-ar="قائمة التدفقات النقدية">Cashflow Statement</span>
</a>
<?php endif; ?>
<?php if (can('items_view')): ?>
<a href="index.php?page=expiry_report" class="nav-link <?= isset($_GET['page']) && $_GET['page'] === 'expiry_report' ? 'active' : '' ?>">
<i class="fas fa-calendar-xmark"></i> <span data-en="Expiry Report" data-ar="تقرير الانتهاء">Expiry Report</span>
</a>
<a href="index.php?page=low_stock_report" class="nav-link <?= isset($_GET['page']) && $_GET['page'] === 'low_stock_report' ? 'active' : '' ?>">
<i class="fas fa-arrow-trend-down"></i> <span data-en="Low Stock Report" data-ar="تقرير نواقص المخزون">Low Stock Report</span>
</a>
<?php endif; ?>
<?php if (can('customers_view')): ?>
<a href="index.php?page=loyalty_history" class="nav-link <?= isset($_GET['page']) && $_GET['page'] === 'loyalty_history' ? 'active' : '' ?>">
<i class="fas fa-award"></i> <span data-en="Loyalty History" data-ar="سجل الولاء">Loyalty History</span>
</a>
<?php endif; ?>
</div>
<?php endif; ?>
<!-- Configurations Section -->
<?php if (can('settings_view')): ?>
<div class="nav-section-title px-4 mt-3 mb-1 text-uppercase text-muted <?= !in_array($page, ['payment_methods', 'settings', 'devices']) ? 'collapsed' : '' ?>" data-bs-toggle="collapse" data-bs-target="#config-collapse">
<span><i class="fas fa-sliders group-icon"></i><span data-en="Configurations" data-ar="الإعدادات">Configurations</span></span>
<i class="fas fa-chevron-down chevron"></i>
</div>
<div class="collapse <?= in_array($page, ['payment_methods', 'settings', 'devices']) ? 'show' : '' ?>" id="config-collapse">
<a href="index.php?page=payment_methods" class="nav-link <?= isset($_GET['page']) && $_GET['page'] === 'payment_methods' ? 'active' : '' ?>">
<i class="fas fa-credit-card"></i> <span data-en="Payment Methods" data-ar="طرق الدفع">Payment Methods</span>
</a>
<a href="index.php?page=devices" class="nav-link <?= isset($_GET['page']) && $_GET['page'] === 'devices' ? 'active' : '' ?>">
<i class="fas fa-id-card"></i> <span data-en="Biometric Devices" data-ar="أجهزة البصمة">Biometric Devices</span>
</a>
<a href="index.php?page=settings" class="nav-link <?= isset($_GET['page']) && $_GET['page'] === 'settings' ? 'active' : '' ?>">
<i class="fas fa-building-gear"></i> <span data-en="Company Profile" data-ar="ملف الشركة">Company Profile</span>
</a>
</div>
<?php endif; ?>
<!-- Administrations Section -->
<?php if (can('users_view')): ?>
<div class="nav-section-title px-4 mt-3 mb-1 text-uppercase text-muted <?= !in_array($page, ['role_groups', 'users']) ? 'collapsed' : '' ?>" data-bs-toggle="collapse" data-bs-target="#admin-collapse">
<span><i class="fas fa-user-gear group-icon"></i><span data-en="Administrations" data-ar="الإدارة">Administrations</span></span>
<i class="fas fa-chevron-down chevron"></i>
</div>
<div class="collapse <?= in_array($page, ['role_groups', 'users']) ? 'show' : '' ?>" id="admin-collapse">
<a href="index.php?page=role_groups" class="nav-link <?= $page === 'role_groups' ? 'active' : '' ?>">
<i class="fas fa-user-shield"></i> <span data-en="Role Groups" data-ar="مجموعات الأدوار">Role Groups</span>
</a>
<a href="index.php?page=users" class="nav-link <?= $page === 'users' ? 'active' : '' ?>">
<i class="fas fa-users-gear"></i> <span data-en="Users" data-ar="المستخدمين">Users</span>
</a>
<a href="index.php?page=cash_registers" class="nav-link <?= $page === 'cash_registers' ? 'active' : '' ?>">
<i class="fas fa-cash-register"></i> <span data-en="Cash Registers" data-ar="خزائن الكاشير">Cash Registers</span>
</a>
<a href="index.php?page=register_sessions" class="nav-link <?= $page === 'register_sessions' ? 'active' : '' ?>">
<i class="fas fa-clock-rotate-left"></i> <span data-en="Register Sessions" data-ar="جلسات الكاشير">Register Sessions</span>
</a>
<a href="index.php?page=scale_devices" class="nav-link <?= $page === 'scale_devices' ? 'active' : '' ?>">
<i class="fas fa-microchip"></i> <span data-en="Devices" data-ar="الأجهزة">Devices</span>
</a>
<a href="index.php?page=backups" class="nav-link <?= $page === 'backups' ? 'active' : '' ?>">
<i class="fas fa-database"></i> <span data-en="Backups" data-ar="نسخ احتياطي">Backups</span>
</a>
</div>
<?php endif; ?>
<!-- Version & Logs -->
<div class="mt-5 px-4 pb-4 border-top pt-4 sidebar-footer">
<div class="d-flex align-items-center justify-content-between text-muted small mb-2">
<span><i class="bi bi-info-circle me-1"></i> v1.2.5</span>
<span class="badge bg-success-subtle text-success border border-success-subtle rounded-pill">Stable</span>
</div>
<a href="?page=logs" class="text-decoration-none text-muted small d-block">
<i class="bi bi-journal-text me-1"></i> <span data-en="System Logs" data-ar="سجلات النظام">System Logs</span>
</a>
</div>
</nav>
</div>
<div class="main-content">
<header class="topbar">
<div class="d-flex align-items-center">
<button id="sidebarToggle" class="btn btn-link text-dark p-0 me-3 d-lg-none">
<i class="bi bi-list fs-3"></i>
</button>
<h4 class="m-0">
<?php
$titles = [
'dashboard' => ['en' => 'Dashboard', 'ar' => 'لوحة القيادة'],
'my_profile' => ['en' => 'My Profile', 'ar' => 'ملفي الشخصي'],
'pos' => ['en' => 'Point of Sale', 'ar' => 'نقطة البيع'],
'quotations' => ['en' => 'Quotations', 'ar' => 'العروض'],
'customers' => ['en' => 'Customers', 'ar' => 'العملاء'],
'suppliers' => ['en' => 'Suppliers', 'ar' => 'الموردون'],
'categories' => ['en' => 'Stock Categories', 'ar' => 'فئات المخزون'],
'units' => ['en' => 'Stock Units', 'ar' => 'وحدات المخزون'],
'items' => ['en' => 'Stock Items', 'ar' => 'أصناف المخزون'],
'payment_methods' => ['en' => 'Payment Methods', 'ar' => 'طرق الدفع'],
'sales' => ['en' => 'Sales Tax Invoices', 'ar' => 'فواتير المبيعات الضريبية'],
'purchases' => ['en' => 'Purchase Tax Invoices', 'ar' => 'فواتير المشتريات الضريبية'],
'sales_returns' => ['en' => 'Sales Returns', 'ar' => 'مرتجع المبيعات'],
'customer_statement' => ['en' => 'Customer Statement', 'ar' => 'كشف حساب عميل'],
'supplier_statement' => ['en' => 'Supplier Statement', 'ar' => 'كشف حساب مورد'],
'expiry_report' => ['en' => 'Expiry Report', 'ar' => 'تقرير انتهاء الصلاحية'],
'low_stock_report' => ['en' => 'Low Stock Report', 'ar' => 'تقرير نواقص المخزون'],
'settings' => ['en' => 'Company Profile', 'ar' => 'ملف الشركة'],
'devices' => ['en' => 'Biometric Devices', 'ar' => 'أجهزة البصمة'],
'hr_departments' => ['en' => 'HR Departments', 'ar' => 'أقسام الموارد البشرية'],
'hr_employees' => ['en' => 'HR Employees', 'ar' => 'موظفي الموارد البشرية'],
'hr_attendance' => ['en' => 'HR Attendance', 'ar' => 'حضور الموارد البشرية'],
'hr_payroll' => ['en' => 'HR Payroll', 'ar' => 'رواتب الموارد البشرية'],
'cashflow_report' => ['en' => 'Cashflow Statement', 'ar' => 'قائمة التدفقات النقدية'],
'loyalty_history' => ['en' => 'Loyalty History', 'ar' => 'سجل الولاء'],
'users' => ['en' => 'User Management', 'ar' => 'إدارة المستخدمين'],
'backups' => ['en' => 'Database Backups', 'ar' => 'نسخ قاعدة البيانات'],
'role_groups' => ['en' => 'Role Groups', 'ar' => 'مجموعات الأدوار'],
'scale_devices' => ['en' => 'POS Devices', 'ar' => 'أجهزة نقاط البيع'],
'cash_registers' => ['en' => 'Cash Registers', 'ar' => 'خزائن الكاشير'],
'register_sessions' => ['en' => 'Register Sessions', 'ar' => 'جلسات الكاشير'],
];
$currTitle = $titles[$page] ?? $titles['dashboard'];
?>
<span data-en="<?= $currTitle['en'] ?>" data-ar="<?= $currTitle['ar'] ?>"><?= $currTitle['en'] ?></span>
</h4>
</div>
<div class="d-flex align-items-center">
<div class="dropdown me-3">
<button class="btn btn-outline-secondary btn-sm dropdown-toggle" type="button" data-bs-toggle="dropdown">
<i class="bi bi-palette"></i> <span data-en="Theme" data-ar="المظهر">Theme</span>
</button>
<ul class="dropdown-menu shadow-sm border-0">
<li><a class="dropdown-item d-flex align-items-center theme-select" href="#" data-theme="default"><span class="rounded-circle me-2" style="width:12px; height:12px; background:#0f172a;"></span> Default</a></li>
<li><a class="dropdown-item d-flex align-items-center theme-select" href="#" data-theme="dark"><span class="rounded-circle me-2" style="width:12px; height:12px; background:#1e293b;"></span> Midnight</a></li>
<li><a class="dropdown-item d-flex align-items-center theme-select" href="#" data-theme="ocean"><span class="rounded-circle me-2" style="width:12px; height:12px; background:#083344;"></span> Ocean</a></li>
<li><a class="dropdown-item d-flex align-items-center theme-select" href="#" data-theme="forest"><span class="rounded-circle me-2" style="width:12px; height:12px; background:#064e3b;"></span> Forest</a></li>
<li><a class="dropdown-item d-flex align-items-center theme-select" href="#" data-theme="sunset"><span class="rounded-circle me-2" style="width:12px; height:12px; background:#451a03;"></span> Sunset</a></li>
</ul>
</div>
<button id="langToggle" class="btn btn-outline-secondary btn-sm me-3">
<i class="bi bi-translate"></i> <span data-en="العربية" data-ar="English">العربية</span>
</button>
<div class="me-3 d-none d-md-block text-end">
<div class="fw-bold small">
<a href="index.php?page=my_profile" class="text-dark text-decoration-none">
<?= htmlspecialchars((string)($_SESSION['username'] ?? 'User')) ?>
</a>
</div>
<div class="text-muted" style="font-size: 0.7rem;"><?= htmlspecialchars((string)($_SESSION['user_role_name'] ?? '')) ?></div>
</div>
<div class="dropdown">
<a href="index.php?page=my_profile" class="btn btn-light rounded-circle p-0 overflow-hidden shadow-sm d-inline-block position-relative" style="width: 40px; height: 40px;" title="Edit Profile">
<?php if (!empty($_SESSION['profile_pic'])): ?>
<img src="<?= htmlspecialchars($_SESSION['profile_pic']) ?>?v=<?= time() ?>" alt="Profile" style="width: 100%; height: 100%; object-fit: cover;">
<?php else: ?>
<i class="bi bi-person fs-5" style="line-height: 40px;"></i>
<?php endif; ?>
<span class="position-absolute bottom-0 end-0 bg-primary rounded-circle text-white d-flex align-items-center justify-content-center" style="width: 15px; height: 15px; font-size: 0.6rem;">
<i class="bi bi-pencil-fill"></i>
</span>
</a>
<button class="btn btn-link text-dark p-0 ms-1" type="button" data-bs-toggle="dropdown">
<i class="bi bi-chevron-down small"></i>
</button>
<ul class="dropdown-menu dropdown-menu-end border-0 shadow-sm rounded-3 mt-2">
<li><a class="dropdown-item py-2" href="index.php?page=my_profile"><i class="bi bi-person-badge me-2"></i> My Profile</a></li>
<li><a class="dropdown-item py-2" href="index.php?page=settings"><i class="bi bi-gear me-2"></i> Company Settings</a></li>
<li><hr class="dropdown-divider"></li>
<li><a class="dropdown-item py-2 text-danger" href="index.php?action=logout"><i class="bi bi-box-arrow-right me-2"></i> Logout</a></li>
</ul>
</div>
</div>
</header>
<script>
const companySettings = <?= json_encode($data['settings']) ?>;
</script>
<?php if ($message): ?>
<script>
document.addEventListener('DOMContentLoaded', function() {
let msg = <?= json_encode($message) ?>;
let type = 'success';
let title = 'Success';
if (msg.toLowerCase().includes('error') || msg.toLowerCase().includes('failed')) {
type = 'error';
title = 'Error';
}
Swal.fire({
icon: type,
title: title,
text: msg,
timer: 3000,
timerProgressBar: true,
showConfirmButton: false
});
});
</script>
<?php endif; ?>
<?php if ($page === 'dashboard'): ?>
<?php if ($data['stats']['expired_items'] > 0 || $data['stats']['near_expiry_items'] > 0 || $data['stats']['low_stock_items_count'] > 0): ?>
<div class="row mb-4">
<div class="col-12">
<div class="alert alert-warning border-0 shadow-sm d-flex align-items-center mb-0">
<i class="bi bi-exclamation-triangle-fill h4 mb-0 me-3 text-warning"></i>
<div class="flex-grow-1">
<span data-en="Inventory Alert:" data-ar="تنبيه المخزون:"><strong>Inventory Alert:</strong></span>
<?php if ($data['stats']['expired_items'] > 0): ?>
<span data-en="<?= $data['stats']['expired_items'] ?> items have expired." data-ar="هنالك <?= $data['stats']['expired_items'] ?> صنف منتهي الصلاحية."><?= $data['stats']['expired_items'] ?> items have expired.</span>
<?php endif; ?>
<?php if ($data['stats']['near_expiry_items'] > 0): ?>
<span data-en="<?= $data['stats']['near_expiry_items'] ?> items are expiring soon (within 30 days)." data-ar="هنالك <?= $data['stats']['near_expiry_items'] ?> صنف ستنتهي صلاحيتها قريباً (خلال 30 يوم)."><?= $data['stats']['near_expiry_items'] ?> items are expiring soon (within 30 days).</span>
<?php endif; ?>
<?php if ($data['stats']['low_stock_items_count'] > 0): ?>
<span data-en="<?= $data['stats']['low_stock_items_count'] ?> items are below minimum level." data-ar="هنالك <?= $data['stats']['low_stock_items_count'] ?> صنف تحت الحد الأدنى للمخزون."><?= $data['stats']['low_stock_items_count'] ?> items are below minimum level.</span>
<?php endif; ?>
</div>
<div class="d-flex gap-2">
<a href="index.php?page=expiry_report" class="btn btn-warning btn-sm" data-en="Expiry Report" data-ar="تقرير الانتهاء">Expiry Report</a>
<a href="index.php?page=low_stock_report" class="btn btn-danger btn-sm" data-en="Low Stock Report" data-ar="تقرير النواقص">Low Stock Report</a>
</div>
</div>
</div>
</div>
<?php endif; ?>
<div class="row g-4 mb-4">
<div class="col-md-3">
<div class="card p-3 border-start border-primary border-4 h-100">
<div class="d-flex align-items-center">
<div class="flex-grow-1">
<div class="text-muted small" data-en="Total Sales" data-ar="إجمالي المبيعات">Total Sales</div>
<div class="h4 m-0">OMR <?= number_format((float)($data['stats']['total_sales'] ?? 0), 3) ?></div>
</div>
<div class="ms-3">
<i class="bi bi-cart h2 text-primary op-50"></i>
</div>
</div>
</div>
</div>
<div class="col-md-3">
<div class="card p-3 border-start border-warning border-4 h-100">
<div class="d-flex align-items-center">
<div class="flex-grow-1">
<div class="text-muted small" data-en="Total Received" data-ar="إجمالي المبالغ المحصلة">Total Received</div>
<div class="h4 m-0">OMR <?= number_format((float)($data['stats']['total_received'] ?? 0), 3) ?></div>
</div>
<div class="ms-3">
<i class="bi bi-cash-stack h2 text-warning op-50"></i>
</div>
</div>
</div>
</div>
<div class="col-md-3">
<div class="card p-3 border-start border-danger border-4 h-100">
<div class="d-flex align-items-center">
<div class="flex-grow-1">
<div class="text-muted small" data-en="Customer Due" data-ar="مستحقات العملاء">Customer Due</div>
<div class="h4 m-0">OMR <?= number_format((float)($data['stats']['total_receivable'] ?? 0), 3) ?></div>
</div>
<div class="ms-3">
<i class="bi bi-person-exclamation h2 text-danger op-50"></i>
</div>
</div>
</div>
</div>
<div class="col-md-3">
<div class="card p-3 border-start border-dark border-4 h-100 bg-light">
<div class="d-flex align-items-center">
<div class="flex-grow-1">
<div class="text-muted small" data-en="Total Purchases" data-ar="إجمالي المشتريات">Total Purchases</div>
<div class="h4 m-0">OMR <?= number_format((float)($data['stats']['total_purchases'] ?? 0), 3) ?></div>
</div>
<div class="ms-3">
<i class="bi bi-bag h2 text-dark op-50"></i>
</div>
</div>
</div>
</div>
</div>
<div class="row g-4 mb-4">
<div class="col-md-3">
<div class="card p-3 border-start border-info border-4 h-100 bg-light">
<div class="d-flex align-items-center">
<div class="flex-grow-1">
<div class="text-muted small" data-en="Total Paid" data-ar="إجمالي المدفوع">Total Paid</div>
<div class="h4 m-0">OMR <?= number_format((float)($data['stats']['total_paid'] ?? 0), 3) ?></div>
</div>
<div class="ms-3">
<i class="bi bi-wallet2 h2 text-info op-50"></i>
</div>
</div>
</div>
</div>
<div class="col-md-3">
<div class="card p-3 border-start border-secondary border-4 h-100 bg-light">
<div class="d-flex align-items-center">
<div class="flex-grow-1">
<div class="text-muted small" data-en="Supplier Due" data-ar="مستحقات الموردين">Supplier Due</div>
<div class="h4 m-0">OMR <?= number_format((float)($data['stats']['total_payable'] ?? 0), 3) ?></div>
</div>
<div class="ms-3">
<i class="bi bi-truck h2 text-secondary op-50"></i>
</div>
</div>
</div>
</div>
<div class="col-md-3">
<div class="card p-3 border-start border-success border-4 h-100">
<div class="d-flex align-items-center">
<div class="flex-grow-1">
<div class="text-muted small" data-en="Total Customers" data-ar="إجمالي العملاء">Total Customers</div>
<div class="h4 m-0"><?= (int)($data['stats']['total_customers'] ?? 0) ?></div>
</div>
<div class="ms-3">
<i class="bi bi-people h2 text-success op-50"></i>
</div>
</div>
</div>
</div>
<div class="col-md-3">
<div class="card p-3 border-start border-info border-4 h-100">
<div class="d-flex align-items-center">
<div class="flex-grow-1">
<div class="text-muted small" data-en="Total Items" data-ar="إجمالي الأصناف">Total Items</div>
<div class="h4 m-0"><?= (int)($data['stats']['total_items'] ?? 0) ?></div>
</div>
<div class="ms-3">
<i class="bi bi-box-seam h2 text-info op-50"></i>
</div>
</div>
</div>
</div>
</div>
<div class="row g-4 mb-4">
<div class="col-12">
<div class="card p-4">
<div class="d-flex justify-content-between align-items-center mb-4">
<h5 class="m-0" data-en="Sales Performance" data-ar="أداء المبيعات">Sales Performance</h5>
<div class="btn-group btn-group-sm">
<button type="button" class="btn btn-outline-primary active" id="btnMonthly" data-en="Monthly" data-ar="شهري">Monthly</button>
<button type="button" class="btn btn-outline-primary" id="btnYearly" data-en="Yearly" data-ar="سنوي">Yearly</button>
</div>
</div>
<div style="height: 300px;">
<canvas id="salesChart"></canvas>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-md-8">
<div class="card p-4">
<div class="d-flex justify-content-between align-items-center mb-4">
<h5 class="m-0" data-en="Recent Customers" data-ar="العملاء الحاليين">Recent Customers</h5>
<a href="index.php?page=customers" class="btn btn-outline-primary btn-sm">
<span data-en="View All" data-ar="عرض الكل">View All</span>
</a>
</div>
<div class="table-responsive">
<table class="table table-hover table-bordered align-middle">
<thead>
<tr>
<th data-en="Name" data-ar="الاسم">Name</th>
<th data-en="Phone" data-ar="الهاتف">Phone</th>
<th data-en="Balance" data-ar="الرصيد" class="text-end">Balance</th>
</tr>
</thead>
<tbody>
<?php foreach ($data['customers'] as $c): ?>
<tr>
<td><?= htmlspecialchars($c['name']) ?></td>
<td><?= htmlspecialchars($c['phone']) ?></td>
<td class="text-end">OMR <?= number_format((float)$c['balance'], 3) ?></td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
</div>
</div>
<div class="col-md-4">
<div class="card p-4">
<h5 class="mb-4" data-en="Quick Links" data-ar="روابط سريعة">Quick Links</h5>
<div class="list-group list-group-flush">
<button class="list-group-item list-group-item-action border-0 px-0" data-bs-toggle="modal" data-bs-target="#addCustomerModal">
<i class="bi bi-person-plus text-primary"></i> <span data-en="Add Customer" data-ar="إضافة عميل">Add Customer</span>
</button>
<button class="list-group-item list-group-item-action border-0 px-0" data-bs-toggle="modal" data-bs-target="#addItemModal">
<i class="bi bi-box-seam text-success"></i> <span data-en="Add Item" data-ar="إضافة صنف">Add Item</span>
</button>
<button class="list-group-item list-group-item-action border-0 px-0" data-bs-toggle="modal" data-bs-target="#importItemsModal">
<i class="bi bi-file-earmark-excel text-success"></i> <span data-en="Import Items" data-ar="استيراد أصناف">Import Items</span>
</button>
<a href="index.php?page=sales" class="list-group-item list-group-item-action border-0 px-0">
<i class="bi bi-cart text-primary"></i> <span data-en="Sales Tax Invoices" data-ar="فواتير المبيعات الضريبية">Sales Tax Invoices</span>
</a>
<a href="index.php?page=purchases" class="list-group-item list-group-item-action border-0 px-0">
<i class="bi bi-bag text-warning"></i> <span data-en="Purchase Tax Invoices" data-ar="فواتير المشتريات الضريبية">Purchase Tax Invoices</span>
</a>
</div>
</div>
</div>
</div>
<?php elseif ($page === 'customers' || $page === 'suppliers'): ?>
<div class="card p-4">
<div class="d-flex justify-content-between align-items-center mb-4">
<h5 class="m-0" data-en="<?= $currTitle['en'] ?> Management" data-ar="إدارة <?= $currTitle['ar'] ?>"><?= $currTitle['en'] ?> Management</h5>
<div>
<?php if (can('customers_add') || can('suppliers_add')): ?>
<button class="btn btn-outline-success me-2" data-bs-toggle="modal" data-bs-target="<?= $page === 'suppliers' ? '#importSuppliersModal' : '#importCustomersModal' ?>">
<i class="bi bi-file-earmark-excel"></i> <span data-en="Import Excel" data-ar="استيراد من اكسل">Import Excel</span>
</button>
<button class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#addCustomerModal">
<i class="bi bi-plus-lg"></i> <span data-en="Add <?= $currTitle['en'] ?>" data-ar="إضافة <?= $currTitle['ar'] ?>">Add <?= $currTitle['en'] ?></span>
</button>
<?php endif; ?>
</div>
</div>
<!-- Search & Filter Bar -->
<div class="bg-light p-3 rounded mb-4">
<form method="GET" class="row g-2 align-items-end">
<input type="hidden" name="page" value="<?= $page ?>">
<div class="col-md-4">
<label class="form-label small" data-en="Search" data-ar="بحث">Search</label>
<input type="text" name="search" class="form-control" value="<?= htmlspecialchars($_GET['search'] ?? '') ?>" placeholder="Name, email, or phone..." data-en="Name, email, or phone..." data-ar="الاسم، البريد، أو الهاتف...">
</div>
<div class="col-md-2">
<label class="form-label small" data-en="From Date" data-ar="من تاريخ">From Date</label>
<input type="date" name="start_date" class="form-control" value="<?= htmlspecialchars($_GET['start_date'] ?? '') ?>">
</div>
<div class="col-md-2">
<label class="form-label small" data-en="To Date" data-ar="إلى تاريخ">To Date</label>
<input type="date" name="end_date" class="form-control" value="<?= htmlspecialchars($_GET['end_date'] ?? '') ?>">
</div>
<div class="col-md-4 d-flex gap-1">
<button type="submit" class="btn btn-primary flex-grow-1">
<i class="bi bi-filter"></i> <span data-en="Filter" data-ar="تصفية">Filter</span>
</button>
<a href="index.php?page=export&type=<?= $page ?>&<?= http_build_query($_GET) ?>" class="btn btn-outline-success">
<i class="bi bi-download"></i> <span data-en="Export" data-ar="تصدير">Export</span>
</a>
<?php if (!empty($_GET['search']) || !empty($_GET['start_date']) || !empty($_GET['end_date'])): ?>
<a href="index.php?page=<?= $page ?>" class="btn btn-outline-secondary">
<i class="bi bi-x-lg"></i>
</a>
<?php endif; ?>
</div>
</form>
</div>
<div class="table-responsive">
<table class="table table-hover align-middle">
<thead>
<tr>
<th data-en="Name" data-ar="الاسم">Name</th>
<th data-en="Tax ID" data-ar="الرقم الضريبي">Tax ID</th>
<th data-en="Email" data-ar="البريد">Email</th>
<th data-en="Phone" data-ar="الهاتف">Phone</th>
<th data-en="Balance" data-ar="الرصيد" class="text-end">Balance</th>
<th data-en="Actions" data-ar="الإجراءات" class="text-end">Actions</th>
</tr>
</thead>
<tbody>
<?php foreach ($data['customers'] as $c): ?>
<tr>
<td><?= htmlspecialchars($c['name']) ?></td>
<td><?= htmlspecialchars($c['tax_id'] ?? '---') ?></td>
<td><?= htmlspecialchars($c['email']) ?></td>
<td><?= htmlspecialchars($c['phone']) ?></td>
<td class="text-end">OMR <?= number_format((float)$c['balance'], 3) ?></td>
<td class="text-end">
<div class="btn-group btn-group-sm">
<?php if (can('customers_edit') || can('suppliers_edit')): ?>
<button class="btn btn-outline-primary" title="Edit" data-bs-toggle="modal" data-bs-target="#editCustomerModal<?= $c['id'] ?>"><i class="bi bi-pencil"></i></button>
<?php endif; ?>
<?php if (can('customers_delete') || can('suppliers_delete')): ?>
<form method="POST" class="d-inline" onsubmit="return confirm('Are you sure?')">
<input type="hidden" name="id" value="<?= $c['id'] ?>">
<button type="submit" name="delete_customer" class="btn btn-outline-danger" title="Delete"><i class="bi bi-trash"></i></button>
</form>
<?php endif; ?>
</div>
<!-- Edit Customer Modal -->
<div class="modal fade" id="editCustomerModal<?= $c['id'] ?>" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content border-0 shadow text-start">
<div class="modal-header">
<h5 class="modal-title">
<span data-en="Edit <?= $currTitle['en'] ?>" data-ar="تعديل <?= $currTitle['ar'] ?>">Edit <?= $currTitle['en'] ?></span>
</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<form method="POST">
<input type="hidden" name="id" value="<?= $c['id'] ?>">
<div class="modal-body">
<div class="mb-3">
<label class="form-label" data-en="Name" data-ar="الاسم">Name</label>
<input type="text" name="name" class="form-control" value="<?= htmlspecialchars($c['name']) ?>" required>
</div>
<div class="mb-3">
<label class="form-label" data-en="Email" data-ar="البريد الإلكتروني">Email</label>
<input type="email" name="email" class="form-control" value="<?= htmlspecialchars($c['email'] ?? '') ?>">
</div>
<div class="mb-3">
<label class="form-label" data-en="Phone" data-ar="الهاتف">Phone</label>
<input type="text" name="phone" class="form-control" value="<?= htmlspecialchars($c['phone'] ?? '') ?>">
</div>
<div class="mb-3">
<label class="form-label" data-en="Tax ID / VAT No" data-ar="الرقم الضريبي">Tax ID / VAT No</label>
<input type="text" name="tax_id" class="form-control" value="<?= htmlspecialchars($c['tax_id'] ?? '') ?>">
</div>
<div class="mb-3">
<label class="form-label" data-en="Balance" data-ar="الرصيد">Balance</label>
<input type="number" step="0.001" name="balance" class="form-control" value="<?= (float)$c['balance'] ?>">
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-light" data-bs-dismiss="modal" data-en="Cancel" data-ar="إلغاء">Cancel</button>
<button type="submit" name="edit_customer" class="btn btn-primary" data-en="Update" data-ar="تحديث">Update</button>
</div>
</form>
</div>
</div>
</div>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
</div>
<?php elseif ($page === 'categories'): ?>
<div class="card p-4">
<div class="d-flex justify-content-between align-items-center mb-4">
<h5 class="m-0" data-en="Stock Categories" data-ar="فئات المخزون">Stock Categories</h5>
<div>
<button class="btn btn-outline-success me-2" data-bs-toggle="modal" data-bs-target="#importCategoriesModal">
<i class="bi bi-file-earmark-excel"></i> <span data-en="Import Excel" data-ar="استيراد من اكسل">Import Excel</span>
</button>
<button class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#addCategoryModal">
<i class="bi bi-plus-lg"></i> <span data-en="Add Category" data-ar="إضافة فئة">Add Category</span>
</button>
</div>
</div>
<div class="table-responsive">
<table class="table table-hover align-middle">
<thead>
<tr>
<th data-en="ID" data-ar="المعرف">ID</th>
<th data-en="Name (EN)" data-ar="الاسم (إنجليزي)">Name (EN)</th>
<th data-en="Name (AR)" data-ar="الاسم (عربي)">Name (AR)</th>
</tr>
</thead>
<tbody>
<?php foreach ($data['categories'] as $cat): ?>
<tr>
<td><?= $cat['id'] ?></td>
<td><?= htmlspecialchars($cat['name_en']) ?></td>
<td><?= htmlspecialchars($cat['name_ar']) ?></td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
</div>
<?php elseif ($page === 'units'): ?>
<div class="card p-4">
<div class="d-flex justify-content-between align-items-center mb-4">
<h5 class="m-0" data-en="Stock Units" data-ar="وحدات المخزون">Stock Units</h5>
<div>
<button class="btn btn-outline-success me-2" data-bs-toggle="modal" data-bs-target="#importUnitsModal">
<i class="bi bi-file-earmark-excel"></i> <span data-en="Import Excel" data-ar="استيراد من اكسل">Import Excel</span>
</button>
<button class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#addUnitModal">
<i class="bi bi-plus-lg"></i> <span data-en="Add Unit" data-ar="إضافة وحدة">Add Unit</span>
</button>
</div>
</div>
<div class="table-responsive">
<table class="table table-hover align-middle">
<thead>
<tr>
<th data-en="Name (EN)" data-ar="الاسم (إنجليزي)">Name (EN)</th>
<th data-en="Short (EN)" data-ar="الاختصار (إنجليزي)">Short (EN)</th>
<th data-en="Name (AR)" data-ar="الاسم (عربي)">Name (AR)</th>
<th data-en="Short (AR)" data-ar="الاختصار (عربي)">Short (AR)</th>
</tr>
</thead>
<tbody>
<?php foreach ($data['units'] as $u): ?>
<tr>
<td><?= htmlspecialchars($u['name_en']) ?></td>
<td><?= htmlspecialchars($u['short_name_en']) ?></td>
<td><?= htmlspecialchars($u['name_ar']) ?></td>
<td><?= htmlspecialchars($u['short_name_ar']) ?></td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
</div>
<?php elseif ($page === 'items'): ?>
<div class="card p-4">
<div class="d-flex justify-content-between align-items-center mb-4">
<h5 class="m-0" data-en="Stock Items" data-ar="أصناف المخزون">Stock Items</h5>
<div class="d-flex align-items-center">
<button class="btn btn-dark me-2" id="bulkBarcodeBtn" style="display:none;" onclick="openAveryModal()">
<i class="bi bi-printer"></i> <span data-en="Avery Labels" data-ar="ملصقات إيفري">Avery Labels</span>
</button>
<a href="promo-catalog.php" class="btn btn-outline-danger me-2">
<i class="bi bi-file-pdf"></i> <span data-en="Promo Catalog" data-ar="كتالوج العروض">Promo Catalog</span>
</a>
<button class="btn btn-outline-success me-2" data-bs-toggle="modal" data-bs-target="#importItemsModal">
<i class="bi bi-file-earmark-excel"></i> <span data-en="Import Excel" data-ar="استيراد من اكسل">Import Excel</span>
</button>
<button class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#addItemModal">
<i class="bi bi-plus-lg"></i> <span data-en="Add Item" data-ar="إضافة صنف">Add Item</span>
</button>
</div>
</div>
<!-- Search Bar -->
<div class="bg-light p-3 rounded mb-4">
<form method="GET" class="row g-2 align-items-end">
<input type="hidden" name="page" value="items">
<div class="col-md-7">
<label class="form-label small" data-en="Search" data-ar="بحث">Search</label>
<input type="text" name="search" class="form-control" value="<?= htmlspecialchars($_GET['search'] ?? '') ?>" placeholder="Name or SKU..." data-en="Name or SKU..." data-ar="الاسم أو الباركود...">
</div>
<div class="col-md-5 d-flex gap-1">
<button type="submit" class="btn btn-primary flex-grow-1">
<i class="bi bi-search"></i> <span data-en="Search" data-ar="بحث">Search</span>
</button>
<a href="index.php?page=export&type=items&<?= http_build_query($_GET) ?>" class="btn btn-outline-success">
<i class="bi bi-download"></i> <span data-en="Export" data-ar="تصدير">Export</span>
</a>
<?php if (!empty($_GET['search'])): ?>
<a href="index.php?page=items" class="btn btn-outline-secondary">
<i class="bi bi-x-lg"></i>
</a>
<?php endif; ?>
</div>
</form>
</div>
<div class="table-responsive">
<table class="table table-hover align-middle">
<thead>
<tr>
<th style="width: 40px;"><input type="checkbox" id="selectAllItems" class="form-check-input"></th>
<th data-en="Image" data-ar="الصورة">Image</th>
<th data-en="SKU" data-ar="الباركود">SKU</th>
<th data-en="Name" data-ar="الاسم">Name</th>
<th data-en="Category" data-ar="الفئة">Category</th>
<th data-en="Supplier" data-ar="المورد">Supplier</th>
<th data-en="Stock Level" data-ar="المخزون">Stock Level</th>
<th data-en="Expiry" data-ar="تاريخ الانتهاء">Expiry</th>
<th data-en="VAT" data-ar="الضريبة">VAT</th>
<th data-en="Actions" data-ar="الإجراءات">Actions</th>
</tr>
</thead>
<tbody>
<?php foreach ($data['items'] as $item): ?>
<tr>
<td><input type="checkbox" class="form-check-input item-checkbox" data-id="<?= $item['id'] ?>" data-sku="<?= htmlspecialchars($item['sku']) ?>" data-name="<?= htmlspecialchars($item['name_en']) ?>" data-price="<?= number_format((float)$item['sale_price'], 3) ?>"></td>
<td>
<?php if ($item['image_path']): ?>
<img src="<?= htmlspecialchars($item['image_path']) ?>" alt="item" style="width: 40px; height: 40px; object-fit: cover;" class="rounded">
<?php else: ?>
<div class="bg-light rounded d-flex align-items-center justify-content-center" style="width: 40px; height: 40px;">
<i class="bi bi-image text-muted"></i>
</div>
<?php endif; ?>
</td>
<td><?= htmlspecialchars($item['sku']) ?></td>
<td>
<div class="fw-bold">
<?= htmlspecialchars($item['name_en']) ?>
<?php if (isset($item['is_promotion']) && $item['is_promotion']): ?>
<span class="badge bg-success ms-1" style="font-size: 0.65rem;" data-en="Promo" data-ar="عرض">Promo</span>
<?php endif; ?>
</div>
<div class="small text-muted"><?= htmlspecialchars($item['name_ar']) ?></div>
</td>
<td><span data-en="<?= htmlspecialchars($item['cat_en']) ?>" data-ar="<?= htmlspecialchars($item['cat_ar']) ?>"><?= htmlspecialchars($item['cat_en']) ?></span></td>
<td><?= htmlspecialchars($item['supplier_name'] ?? '---') ?></td>
<td>
<div class="text-end">
<strong><?= number_format((float)$item['stock_quantity'], 3) ?></strong>
<div class="small text-muted">Min: <?= number_format((float)$item['min_stock_level'], 3) ?></div>
<?php if ($item['stock_quantity'] <= $item['min_stock_level']): ?>
<span class="badge bg-danger" data-en="Low Stock" data-ar="مخزون منخفض">Low Stock</span>
<?php endif; ?>
</div>
</td>
<td><?= !empty($item['expiry_date']) ? htmlspecialchars((string)$item['expiry_date']) : '---' ?></td>
<td><?= number_format((float)$item['vat_rate'], 3) ?>%</td>
<td>
<div class="btn-group btn-group-sm">
<button class="btn btn-outline-info" title="View" data-bs-toggle="modal" data-bs-target="#viewItemModal<?= $item['id'] ?>"><i class="bi bi-eye"></i></button>
<button class="btn btn-outline-primary" title="Edit" data-bs-toggle="modal" data-bs-target="#editItemModal<?= $item['id'] ?>"><i class="bi bi-pencil"></i></button>
<button class="btn btn-outline-dark" title="Barcode" onclick="printItemBarcode('<?= htmlspecialchars($item['sku']) ?>', '<?= htmlspecialchars($item['name_en']) ?>', '<?= number_format((float)$item['sale_price'], 3) ?>')"><i class="bi bi-upc"></i></button>
<form method="POST" class="d-inline" onsubmit="return confirm('Are you sure?')">
<input type="hidden" name="id" value="<?= $item['id'] ?>">
<button type="submit" name="delete_item" class="btn btn-outline-danger" title="Delete"><i class="bi bi-trash"></i></button>
</form>
</div>
<!-- View Item Modal -->
<div class="modal fade" id="viewItemModal<?= $item['id'] ?>" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content border-0 shadow">
<div class="modal-header">
<h5 class="modal-title"><?= htmlspecialchars($item['name_en']) ?></h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body">
<div class="text-center mb-3">
<?php if ($item['image_path']): ?>
<img src="<?= htmlspecialchars($item['image_path']) ?>" class="img-fluid rounded shadow-sm" style="max-height: 200px;">
<?php else: ?>
<div class="bg-light rounded d-flex align-items-center justify-content-center mx-auto" style="width: 150px; height: 150px;">
<i class="bi bi-image text-muted" style="font-size: 3rem;"></i>
</div>
<?php endif; ?>
</div>
<table class="table table-sm">
<tr><th class="text-muted">SKU</th><td><?= htmlspecialchars($item['sku']) ?></td></tr>
<tr><th class="text-muted">Category</th><td><?= htmlspecialchars($item['cat_en'] ?? '---') ?></td></tr>
<tr><th class="text-muted">Supplier</th><td><?= htmlspecialchars($item['supplier_name'] ?? '---') ?></td></tr>
<tr><th class="text-muted">Sale Price</th><td>OMR <?= number_format((float)$item['sale_price'], 3) ?></td></tr>
<tr><th class="text-muted">Stock Level</th><td><?= number_format((float)$item['stock_quantity'], 3) ?></td></tr>
<tr><th class="text-muted">VAT Rate</th><td><?= number_format((float)$item['vat_rate'], 3) ?>%</td></tr>
</table>
</div>
<div class="modal-footer">
<button class="btn btn-outline-dark" onclick="printItemBarcode('<?= htmlspecialchars($item['sku']) ?>', '<?= htmlspecialchars($item['name_en']) ?>', '<?= number_format((float)$item['sale_price'], 3) ?>')"><i class="bi bi-printer"></i> Print Barcode</button>
<button type="button" class="btn btn-light" data-bs-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
<!-- Edit Item Modal -->
<div class="modal fade" id="editItemModal<?= $item['id'] ?>" tabindex="-1">
<div class="modal-dialog modal-lg">
<div class="modal-content border-0 shadow">
<div class="modal-header">
<h5 class="modal-title" data-en="Edit Item" data-ar="تعديل صنف">Edit Item</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<form method="POST" enctype="multipart/form-data">
<input type="hidden" name="id" value="<?= $item['id'] ?>">
<div class="modal-body">
<div class="row g-3">
<div class="col-md-6">
<label class="form-label">Name (EN)</label>
<input type="text" name="name_en" class="form-control" value="<?= htmlspecialchars($item['name_en']) ?>" required>
</div>
<div class="col-md-6">
<label class="form-label">Name (AR)</label>
<input type="text" name="name_ar" class="form-control" value="<?= htmlspecialchars($item['name_ar']) ?>" required>
</div>
<div class="col-md-4">
<label class="form-label">Category</label>
<select name="category_id" class="form-select">
<option value="">---</option>
<?php foreach ($data['categories'] ?? [] as $c): ?>
<option value="<?= $c['id'] ?>" <?= $c['id'] == $item['category_id'] ? 'selected' : '' ?>><?= htmlspecialchars($c['name_en']) ?></option>
<?php endforeach; ?>
</select>
</div>
<div class="col-md-4">
<label class="form-label">Unit</label>
<select name="unit_id" class="form-select">
<option value="">---</option>
<?php foreach ($data['units'] ?? [] as $u): ?>
<option value="<?= $u['id'] ?>" <?= $u['id'] == $item['unit_id'] ? 'selected' : '' ?>><?= htmlspecialchars($u['short_name_en']) ?></option>
<?php endforeach; ?>
</select>
</div>
<div class="col-md-4">
<label class="form-label">Supplier</label>
<select name="supplier_id" class="form-select">
<option value="">---</option>
<?php foreach ($data['suppliers'] ?? [] as $s): ?>
<option value="<?= $s['id'] ?>" <?= $s['id'] == $item['supplier_id'] ? 'selected' : '' ?>><?= htmlspecialchars($s['name']) ?></option>
<?php endforeach; ?>
</select>
</div>
<div class="col-md-3">
<label class="form-label">Sale Price</label>
<input type="number" step="0.001" name="sale_price" class="form-control" value="<?= (float)$item['sale_price'] ?>">
</div>
<div class="col-md-3">
<label class="form-label">Purchase Price</label>
<input type="number" step="0.001" name="purchase_price" class="form-control" value="<?= (float)$item['purchase_price'] ?>">
</div>
<div class="col-md-3">
<label class="form-label">Stock Qty</label>
<input type="number" step="0.001" name="stock_quantity" class="form-control" value="<?= (float)$item['stock_quantity'] ?>">
</div>
<div class="col-md-3">
<label class="form-label">Min Level</label>
<input type="number" step="0.001" name="min_stock_level" class="form-control" value="<?= (float)$item['min_stock_level'] ?>">
</div>
<div class="col-md-6">
<label class="form-label">SKU</label>
<input type="text" name="sku" class="form-control" value="<?= htmlspecialchars($item['sku']) ?>">
</div>
<div class="col-md-6">
<label class="form-label">VAT Rate (%)</label>
<input type="number" step="0.001" name="vat_rate" class="form-control" value="<?= (float)$item['vat_rate'] ?>">
</div>
<div class="col-md-12">
<label class="form-label">Item Picture</label>
<input type="file" name="image" class="form-control" accept="image/*">
</div>
<div class="col-12">
<hr>
<h6 data-en="Promotion Details" data-ar="تفاصيل العرض">Promotion Details</h6>
</div>
<div class="col-md-4">
<div class="form-check form-switch mt-4">
<input class="form-check-input isPromotionToggleEdit" type="checkbox" name="is_promotion" value="1" <?= $item['is_promotion'] ? 'checked' : '' ?> id="isPromotionToggleEdit<?= $item['id'] ?>" data-id="<?= $item['id'] ?>">
<label class="form-check-label" for="isPromotionToggleEdit<?= $item['id'] ?>" data-en="On Promotion?" data-ar="في العرض؟">On Promotion?</label>
</div>
</div>
<div class="col-md-8">
<div class="row g-3 promotionFieldsContainerEdit" id="promotionFieldsContainerEdit<?= $item['id'] ?>" style="display: <?= $item['is_promotion'] ? 'flex' : 'none' ?>;">
<div class="col-md-4">
<label class="form-label">Start Date</label>
<input type="date" name="promotion_start" class="form-control" value="<?= $item['promotion_start'] ?>">
</div>
<div class="col-md-4">
<label class="form-label">End Date</label>
<input type="date" name="promotion_end" class="form-control" value="<?= $item['promotion_end'] ?>">
</div>
<div class="col-md-4">
<label class="form-label">Percent (%)</label>
<input type="number" step="0.01" name="promotion_percent" class="form-control" value="<?= (float)$item['promotion_percent'] ?>">
</div>
</div>
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-light" data-bs-dismiss="modal">Cancel</button>
<button type="submit" name="edit_item" class="btn btn-primary">Update Item</button>
</div>
</form>
</div>
</div>
</div>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
</div>
<?php elseif ($page === 'expiry_report'): ?>
<div class="card p-4">
<div class="d-flex justify-content-between align-items-center mb-4">
<h5 class="m-0" data-en="Expiry Report" data-ar="تقرير انتهاء الصلاحية">Expiry Report</h5>
<div class="d-flex gap-2">
<a href="index.php?page=expiry_report&filter=all" class="btn btn-sm <?= !isset($_GET['filter']) || $_GET['filter'] === 'all' ? 'btn-primary' : 'btn-outline-primary' ?>" data-en="All" data-ar="الكل">All</a>
<a href="index.php?page=expiry_report&filter=expired" class="btn btn-sm <?= isset($_GET['filter']) && $_GET['filter'] === 'expired' ? 'btn-danger' : 'btn-outline-danger' ?>" data-en="Expired" data-ar="منتهي">Expired</a>
<a href="index.php?page=expiry_report&filter=near_expiry" class="btn btn-sm <?= isset($_GET['filter']) && $_GET['filter'] === 'near_expiry' ? 'btn-warning' : 'btn-outline-warning' ?>" data-en="Near Expiry" data-ar="قريب الانتهاء">Near Expiry</a>
</div>
</div>
<div class="table-responsive">
<table class="table table-hover align-middle">
<thead>
<tr>
<th data-en="SKU" data-ar="الباركود">SKU</th>
<th data-en="Item Name" data-ar="اسم الصنف">Item Name</th>
<th data-en="Category" data-ar="الفئة">Category</th>
<th data-en="Stock Level" data-ar="المخزون">Stock Level</th>
<th data-en="Expiry Date" data-ar="تاريخ الانتهاء">Expiry Date</th>
<th data-en="Status" data-ar="الحالة">Status</th>
</tr>
</thead>
<tbody>
<?php if (empty($data['expiry_items'])): ?>
<tr>
<td colspan="6" class="text-center text-muted p-4" data-en="No items found." data-ar="لا توجد أصناف.">No items found.</td>
</tr>
<?php endif; ?>
<?php foreach ($data['expiry_items'] as $item): ?>
<?php
$expiry_date = $item['expiry_date'] ?? '';
$expiry_ts = $expiry_date !== '' ? strtotime($expiry_date) : null;
$is_expired = $expiry_ts ? $expiry_ts <= strtotime(date('Y-m-d')) : false;
$is_near = $expiry_ts ? (!$is_expired && $expiry_ts <= strtotime(date('Y-m-d', strtotime('+30 days')))) : false;
?>
<tr class="<?= $is_expired ? 'table-danger' : ($is_near ? 'table-warning' : '') ?>">
<td><?= htmlspecialchars($item['sku']) ?></td>
<td>
<div class="fw-bold"><?= htmlspecialchars($item['name_en']) ?></div>
<div class="small text-muted"><?= htmlspecialchars($item['name_ar']) ?></div>
</td>
<td><?= htmlspecialchars($item['cat_en'] ?? '---') ?></td>
<td><?= number_format((float)$item['stock_quantity'], 3) ?></td>
<td><?= $expiry_date !== '' ? htmlspecialchars((string)$expiry_date) : '---' ?></td>
<td>
<?php if ($is_expired): ?>
<span class="badge bg-danger" data-en="Expired" data-ar="منتهي">Expired</span>
<?php elseif ($is_near): ?>
<span class="badge bg-warning text-dark" data-en="Near Expiry" data-ar="قريب الانتهاء">Near Expiry</span>
<?php else: ?>
<span class="badge bg-success" data-en="Good" data-ar="صالح">Good</span>
<?php endif; ?>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
</div>
<?php elseif ($page === 'low_stock_report'): ?>
<div class="card p-4">
<div class="d-flex justify-content-between align-items-center mb-4">
<h5 class="m-0" data-en="Low Stock Report" data-ar="تقرير نواقص المخزون">Low Stock Report</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="table-responsive">
<table class="table table-hover align-middle">
<thead>
<tr>
<th data-en="SKU" data-ar="الباركود">SKU</th>
<th data-en="Item Name" data-ar="اسم الصنف">Item Name</th>
<th data-en="Category" data-ar="الفئة">Category</th>
<th data-en="Supplier" data-ar="المورد">Supplier</th>
<th data-en="Min Level" data-ar="أدنى مستوى">Min Level</th>
<th data-en="Current Stock" data-ar="المخزون الحالي">Current Stock</th>
<th data-en="Shortage" data-ar="النقص">Shortage</th>
</tr>
</thead>
<tbody>
<?php if (empty($data['low_stock_items'])): ?>
<tr>
<td colspan="7" class="text-center text-muted p-4" data-en="All items are above minimum levels." data-ar="جميع الأصناف فوق الحد الأدنى.">All items are above minimum levels.</td>
</tr>
<?php endif; ?>
<?php foreach ($data['low_stock_items'] as $item): ?>
<?php $shortage = (float)$item['min_stock_level'] - (float)$item['stock_quantity']; ?>
<tr class="<?= (float)$item['stock_quantity'] <= 0 ? 'table-danger' : 'table-warning' ?>">
<td><?= htmlspecialchars($item['sku']) ?></td>
<td>
<div class="fw-bold"><?= htmlspecialchars($item['name_en']) ?></div>
<div class="small text-muted"><?= htmlspecialchars($item['name_ar']) ?></div>
</td>
<td><?= htmlspecialchars($item['cat_en'] ?? '---') ?></td>
<td><?= htmlspecialchars($item['supplier_name'] ?? '---') ?></td>
<td><?= number_format((float)$item['min_stock_level'], 2) ?></td>
<td>
<span class="badge <?= (float)$item['stock_quantity'] <= 0 ? 'bg-danger' : 'bg-warning text-dark' ?>">
<?= number_format((float)$item['stock_quantity'], 3) ?>
</span>
</td>
<td class="fw-bold text-danger"><?= number_format($shortage, 3) ?></td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</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
$allow_zero_stock_sell = ($data['settings']['allow_zero_stock_sell'] ?? '1') === '1';
$sql = "SELECT * FROM stock_items ORDER BY name_en ASC";
$products_raw = db()->query($sql)->fetchAll(PDO::FETCH_ASSOC);
$products = [];
foreach ($products_raw as $p) {
$p['original_price'] = (float)$p['sale_price'];
$p['sale_price'] = getPromotionalPrice($p);
$products[] = $p;
}
$customers = db()->query("SELECT * FROM customers WHERE type = 'customer' ORDER BY name ASC")->fetchAll(PDO::FETCH_ASSOC);
?>
<div class="pos-container">
<div class="pos-products">
<div class="bg-white p-3 rounded mb-3 shadow-sm d-flex gap-2">
<div class="input-group flex-grow-1">
<span class="input-group-text bg-transparent border-end-0"><i class="bi bi-search"></i></span>
<input type="text" id="productSearch" class="form-control border-start-0" placeholder="Search products by name or SKU..." data-en="Search products..." data-ar="بحث عن منتجات...">
</div>
<div class="input-group flex-grow-1">
<span class="input-group-text bg-light border-end-0"><i class="bi bi-upc-scan"></i></span>
<input type="text" id="barcodeInput" class="form-control border-start-0" placeholder="Scan barcode..." data-en="Scan barcode..." data-ar="امسح الباركود..." autofocus>
</div>
<button class="btn btn-warning d-flex align-items-center gap-2" onclick="cart.openHeldCartsModal()">
<i class="bi bi-pause-btn-fill"></i>
<span class="d-none d-xl-inline" data-en="Held List" data-ar="قائمة الانتظار">Held List</span>
</button>
</div>
<div class="product-grid" id="productGrid">
<?php foreach ($products as $p): ?>
<div class="product-card" data-id="<?= $p['id'] ?>" data-name-en="<?= htmlspecialchars($p['name_en']) ?>" data-name-ar="<?= htmlspecialchars($p['name_ar']) ?>" data-price="<?= $p['sale_price'] ?>" data-sku="<?= htmlspecialchars($p['sku']) ?>" data-stock-quantity="<?= (float)$p['stock_quantity'] ?>">
<?php if ($p['image_path']): ?>
<img src="<?= htmlspecialchars($p['image_path']) ?>" alt="<?= htmlspecialchars($p['name_en']) ?>">
<?php else: ?>
<div class="bg-light d-flex align-items-center justify-content-center rounded mb-2" style="height: 120px;">
<i class="bi bi-box-seam text-muted" style="font-size: 3rem;"></i>
</div>
<?php endif; ?>
<div class="fw-bold mb-1 product-name" data-en="<?= htmlspecialchars($p['name_en']) ?>" data-ar="<?= htmlspecialchars($p['name_ar']) ?>"><?= htmlspecialchars($p['name_en']) ?></div>
<div class="small text-muted mb-2"><?= htmlspecialchars($p['sku']) ?></div>
<div class="d-flex justify-content-between align-items-center mt-auto">
<div class="d-flex flex-column">
<?php if ($p['sale_price'] < $p['original_price']): ?>
<span class="text-muted smaller text-decoration-line-through">OMR <?= number_format($p['original_price'], 3) ?></span>
<?php endif; ?>
<span class="price text-primary fw-bold">OMR <?= number_format((float)$p['sale_price'], 3) ?></span>
</div>
<span class="badge bg-light text-dark small"><?= (float)$p['stock_quantity'] ?> left</span>
</div>
</div>
<?php endforeach; ?>
</div>
</div>
<div class="pos-cart">
<div class="p-3 border-bottom d-flex justify-content-between align-items-center">
<h6 class="m-0 fw-bold"><i class="bi bi-cart3 me-2"></i>Cart</h6>
<div class="d-flex gap-2">
<button class="btn btn-sm btn-outline-warning" onclick="cart.openHeldCartsModal()" title="Held List"><i class="bi bi-list-task"></i></button>
<button class="btn btn-sm btn-outline-secondary" onclick="cart.hold()" title="Hold Cart"><i class="bi bi-pause-circle"></i></button>
<button class="btn btn-sm btn-outline-danger" onclick="cart.clear()" title="Clear Cart"><i class="bi bi-trash"></i></button>
</div>
</div>
<div class="p-3 bg-light border-bottom">
<div class="mb-2">
<label class="small fw-bold mb-1">Customer</label>
<div class="d-flex gap-2">
<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'] ?>"
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="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>
<label class="small fw-bold mb-1">Discount Code</label>
<div class="input-group input-group-sm">
<input type="text" id="discountCode" class="form-control" placeholder="Code">
<button class="btn btn-outline-primary" type="button" onclick="cart.applyDiscount()">Apply</button>
</div>
<div id="appliedDiscountInfo" class="smaller text-primary mt-1" style="display:none"></div>
</div>
</div>
<div class="cart-items" id="cartItems">
<!-- Cart items will be injected here -->
<div class="text-center text-muted mt-5">
<i class="bi bi-cart-x" style="font-size: 3rem;"></i>
<p>Cart is empty</p>
</div>
</div>
<div class="cart-total">
<div class="d-flex justify-content-between mb-1">
<span>Subtotal</span>
<span id="posSubtotal">OMR 0.000</span>
</div>
<div class="d-flex justify-content-between mb-3 fw-bold fs-5">
<span>Total</span>
<span id="posTotal" class="text-primary">OMR 0.000</span>
</div>
<button class="btn btn-primary w-100 py-2 fw-bold" id="checkoutBtn" onclick="cart.checkout()">
PLACE ORDER
</button>
</div>
</div>
</div>
<script>
const cart = {
items: [],
discount: null,
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) {
$custData[] = [
'value' => (string)$c['id'],
'text' => $c['name'] . ' (' . ($c['phone'] ?? '') . ')'
];
}
echo json_encode($custData);
?>,
add(product) {
if (!this.items) this.items = [];
const allowZeroStock = (typeof companySettings !== 'undefined' && String(companySettings.allow_zero_stock_sell) === '1');
const currentStock = parseFloat(product.stock_quantity) || 0;
const existing = this.items.find(item => item.id === product.id);
if (existing) {
if (!allowZeroStock && (existing.qty + 1) > currentStock) {
Swal.fire('Error', 'Insufficient stock!', 'error');
return;
}
existing.qty++;
} else {
if (!allowZeroStock && currentStock <= 0) {
Swal.fire('Error', 'Insufficient stock!', 'error');
return;
}
this.items.push({...product, qty: 1});
}
this.render();
// Add visual feedback
const lang = document.documentElement.lang || 'en';
const displayName = lang === 'ar' ? (product.nameAr || product.nameEn) : (product.nameEn || product.nameAr);
Swal.fire({
toast: true,
position: 'top-end',
icon: 'success',
title: (lang === 'ar' ? 'تم إضافة: ' : 'Added: ') + displayName,
showConfirmButton: false,
timer: 800
});
},
remove(id) {
this.items = this.items.filter(item => item.id !== id);
this.render();
},
updateQty(id, delta) {
if (!this.items) return;
const item = this.items.find(i => i.id === id);
if (item) {
const allowZeroStock = (typeof companySettings !== 'undefined' && String(companySettings.allow_zero_stock_sell) === '1');
const currentStock = parseFloat(item.stock_quantity) || 0;
if (delta > 0 && !allowZeroStock && (item.qty + delta) > currentStock) {
Swal.fire('Error', 'Insufficient stock!', 'error');
return;
}
item.qty += delta;
if (item.qty <= 0) this.remove(id);
else this.render();
}
},
clear() {
this.items = [];
this.discount = null;
this.customerPoints = 0;
const discInput = document.getElementById('discountCode');
if (discInput) discInput.value = '';
const discInfo = document.getElementById('appliedDiscountInfo');
if (discInfo) discInfo.style.display = 'none';
const redeemSwitch = document.getElementById('redeemLoyalty');
if (redeemSwitch) redeemSwitch.checked = false;
const loyaltyDisplay = document.getElementById('loyaltyDisplay');
if (loyaltyDisplay) loyaltyDisplay.style.display = 'none';
this.render();
},
onCustomerChange() {
const select = document.getElementById('posCustomer');
const option = select.options[select.selectedIndex];
const display = document.getElementById('loyaltyDisplay');
if (!select.value || this.loyaltySettings.enabled !== '1') {
if (display) display.style.display = 'none';
this.customerPoints = 0;
this.customerTier = 'bronze';
this.customerMultiplier = 1.0;
const redeemSwitch = document.getElementById('redeemLoyalty');
if (redeemSwitch) redeemSwitch.checked = false;
this.render();
return;
}
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();
if (!code) return;
try {
const resp = await fetch(`index.php?action=validate_discount&code=${code}`);
const res = await resp.json();
if (res.success) {
this.discount = res.discount;
const info = document.getElementById('appliedDiscountInfo');
info.innerText = `Applied: ${this.discount.code} (${this.discount.type === 'percentage' ? this.discount.value + '%' : 'OMR ' + parseFloat(this.discount.value).toFixed(3)})`;
info.style.display = 'block';
this.render();
} else {
Swal.fire('Error', res.error, 'error');
}
} catch (err) { console.error(err); }
},
async hold() {
if (this.items.length === 0) return;
const { value: name } = await Swal.fire({
title: 'Hold Cart',
input: 'text',
inputLabel: 'Enter a name for this cart',
inputValue: 'Cart ' + new Date().toLocaleTimeString(),
showCancelButton: true
});
if (name) {
const formData = new FormData();
formData.append('action', 'hold_pos_cart');
formData.append('cart_name', name);
formData.append('items', JSON.stringify(this.items));
formData.append('customer_id', document.getElementById('posCustomer').value);
const resp = await fetch('index.php', { method: 'POST', body: formData });
const res = await resp.json();
if (res.success) {
this.clear();
Swal.fire('Held', 'Cart has been parked', 'success');
}
}
},
async openHeldCartsModal() {
try {
const resp = await fetch('index.php?action=get_held_carts');
const text = await resp.text();
let carts;
try {
carts = JSON.parse(text);
} catch (e) {
console.error('Failed to parse held carts:', text);
throw new Error('Invalid server response');
}
const lang = document.documentElement.lang || 'en';
let html = '<div class="list-group list-group-flush shadow-sm rounded">';
if (carts.length === 0) {
html += `
<div class="text-center p-5 text-muted">
<i class="bi bi-folder2-open mb-3 d-block" style="font-size: 3rem;"></i>
<p data-en="No held carts found" data-ar="لا توجد طلبات معلقة">${lang === 'ar' ? 'لا توجد طلبات معلقة' : 'No held carts found'}</p>
</div>`;
}
carts.forEach(c => {
html += `
<div class="list-group-item d-flex justify-content-between align-items-center p-3 hover-bg-light border-start-0 border-end-0">
<div class="text-start">
<div class="fw-bold text-primary">${c.cart_name}</div>
<div class="small text-muted">
<i class="bi bi-person me-1"></i>${c.customer_name || (lang === 'ar' ? 'عميل عابر' : 'Walk-in')}
<span class="mx-2 text-silver">|</span>
<i class="bi bi-clock me-1"></i>${new Date(c.created_at).toLocaleString()}
</div>
</div>
<div class="btn-group">
<button class="btn btn-sm btn-primary" onclick="cart.resume(${c.id})">
<i class="bi bi-arrow-repeat me-1"></i><span data-en="Resume" data-ar="استرجاع">${lang === 'ar' ? 'استرجاع' : 'Resume'}</span>
</button>
<button class="btn btn-sm btn-outline-danger" onclick="cart.deleteHeld(${c.id})">
<i class="bi bi-trash"></i>
</button>
</div>
</div>
`;
});
html += '</div>';
Swal.fire({
title: lang === 'ar' ? 'الطلبات المعلقة' : 'Held Carts',
html: html,
showConfirmButton: false,
width: '700px',
customClass: {
container: 'held-carts-swal'
}
});
} catch (err) {
console.error(err);
Swal.fire('Error', 'Failed to load held carts: ' + err.message, 'error');
}
},
async resume(id) {
try {
const resp = await fetch('index.php?action=get_held_carts');
const carts = await resp.json();
const c = carts.find(x => x.id == id);
if (c) {
this.items = JSON.parse(c.items_json);
document.getElementById('posCustomer').value = c.customer_id || '';
await this.onCustomerChange();
await this.deleteHeld(id, true);
Swal.close();
}
} catch (err) {
console.error(err);
Swal.fire('Error', 'Failed to resume cart', 'error');
}
},
async deleteHeld(id, silent = false) {
const formData = new FormData();
formData.append('action', 'delete_held_cart');
formData.append('id', id);
await fetch('index.php', { method: 'POST', body: formData });
if (!silent) this.openHeldCartsModal();
},
render() {
try {
const container = document.getElementById('cartItems');
if (!container) return;
const lang = document.documentElement.lang || 'en';
const items = Array.isArray(this.items) ? this.items : [];
if (items.length === 0) {
container.innerHTML = `<div class="text-center text-muted mt-5"><i class="bi bi-cart-x" style="font-size: 3rem;"></i><p data-en="Cart is empty" data-ar="السلة فارغة">${lang === 'ar' ? 'السلة فارغة' : 'Cart is empty'}</p></div>`;
const subtotalEl = document.getElementById('posSubtotal');
const totalEl = document.getElementById('posTotal');
const checkoutBtn = document.getElementById('checkoutBtn');
if (subtotalEl) subtotalEl.innerText = 'OMR 0.000';
if (totalEl) totalEl.innerText = 'OMR 0.000';
if (checkoutBtn) checkoutBtn.disabled = true;
return;
}
let subtotal = 0;
container.innerHTML = items.map(item => {
const price = parseFloat(item.price) || 0;
const qty = parseFloat(item.qty) || 0;
subtotal += price * qty;
const displayName = (lang === 'ar' ? (item.nameAr || item.nameEn) : (item.nameEn || item.nameAr)) || 'Unknown Item';
return `
<div class="cart-item">
<div class="flex-grow-1">
<div class="fw-bold small">${displayName}</div>
<div class="text-muted smaller">OMR ${price.toFixed(3)}</div>
</div>
<div class="qty-controls mx-3">
<button class="qty-btn" onclick="cart.updateQty(${item.id}, -1)">-</button>
<span class="small fw-bold">${qty}</span>
<button class="qty-btn" onclick="cart.updateQty(${item.id}, 1)">+</button>
</div>
<div class="fw-bold small">OMR ${(price * qty).toFixed(3)}</div>
</div>
`;
}).join('');
let discountAmount = 0;
if (this.discount) {
if (this.discount.type === 'percentage') {
discountAmount = subtotal * (parseFloat(this.discount.value) / 100);
} else {
discountAmount = parseFloat(this.discount.value);
}
}
let loyaltyRedeemedValue = 0;
const redeemSwitch = document.getElementById('redeemLoyalty');
if (redeemSwitch && redeemSwitch.checked) {
const maxRedeemValue = subtotal - discountAmount;
const redeemRate = (this.loyaltySettings && this.loyaltySettings.redeemPointsPerUnit) ? this.loyaltySettings.redeemPointsPerUnit : 100;
const availableRedeemValue = (parseFloat(this.customerPoints) || 0) / redeemRate;
loyaltyRedeemedValue = Math.min(Math.max(0, maxRedeemValue), availableRedeemValue);
}
const total = Math.max(0, subtotal - discountAmount - loyaltyRedeemedValue);
const multiplier = parseFloat(this.customerMultiplier) || 1.0;
const pointsToEarn = Math.floor(total * multiplier);
const subtotalDisplay = document.getElementById('posSubtotal');
if (subtotalDisplay) subtotalDisplay.innerText = 'OMR ' + subtotal.toFixed(3);
let totalHtml = '';
if (discountAmount > 0) totalHtml += `<div class="smaller text-danger">- Disc: OMR ${discountAmount.toFixed(3)}</div>`;
if (loyaltyRedeemedValue > 0) totalHtml += `<div class="smaller text-success">- Loyalty: OMR ${loyaltyRedeemedValue.toFixed(3)}</div>`;
const customerId = document.getElementById('posCustomer') ? document.getElementById('posCustomer').value : '';
if (customerId) {
totalHtml += `<div class="smaller text-info">+ Earn: ${pointsToEarn} pts</div>`;
}
totalHtml += 'OMR ' + total.toFixed(3);
const totalDisplay = document.getElementById('posTotal');
if (totalDisplay) {
totalDisplay.innerHTML = totalHtml;
}
const checkoutBtn = document.getElementById('checkoutBtn');
if (checkoutBtn) checkoutBtn.disabled = false;
} catch (e) {
console.error('Cart render error:', e);
}
},
async checkout() {
if (this.items.length === 0) return;
const customerSelect = document.getElementById('posCustomer');
const customerName = customerSelect.options[customerSelect.selectedIndex].text;
document.getElementById('paymentCustomerName').innerText = customerName;
const subtotal = this.items.reduce((sum, item) => sum + (item.price * item.qty), 0);
let discountAmount = 0;
if (this.discount) {
discountAmount = this.discount.type === 'percentage' ? subtotal * (parseFloat(this.discount.value) / 100) : parseFloat(this.discount.value);
}
const redeemSwitch = document.getElementById('redeemLoyalty');
let loyaltyRedeemedValue = (redeemSwitch && redeemSwitch.checked) ? Math.min(subtotal - discountAmount, this.customerPoints / 100) : 0;
const total = subtotal - discountAmount - loyaltyRedeemedValue;
this.payments = [];
this.renderPayments();
document.getElementById('paymentAmountDue').innerText = 'OMR ' + total.toFixed(3);
document.getElementById('partialAmount').value = total.toFixed(3);
// Sync credit customer selection if credit is default or already selected
const creditSection = document.getElementById('creditCustomerSection');
if (this.selectedPaymentMethod === 'credit') {
creditSection.style.display = 'block';
const creditSelect = $('#paymentCreditCustomer');
creditSelect.val(customerSelect.value).trigger('change');
} else {
creditSection.style.display = 'none';
}
this.updateRemaining();
const modal = new bootstrap.Modal(document.getElementById('posPaymentModal'));
modal.show();
},
selectMethod(method, btn) {
this.selectedPaymentMethod = method;
document.querySelectorAll('.payment-method-btn').forEach(b => b.classList.remove('active'));
btn.classList.add('active');
const creditSection = document.getElementById('creditCustomerSection');
if (method === 'credit') {
creditSection.style.display = 'block';
// Sync with main customer select
const creditSelect = $('#paymentCreditCustomer');
creditSelect.val(document.getElementById('posCustomer').value).trigger('change');
} else {
creditSection.style.display = 'none';
}
this.updateRemaining();
},
fillPartial(amount) {
const input = document.getElementById('partialAmount');
input.value = parseFloat(amount).toFixed(3);
this.updateRemaining();
},
addPaymentLine() {
const amount = parseFloat(document.getElementById('partialAmount').value) || 0;
if (amount <= 0) return;
this.payments.push({
method: this.selectedPaymentMethod,
amount: amount
});
this.renderPayments();
this.updateRemaining();
// Auto-fill remaining for next line if any
const remaining = this.getRemaining();
document.getElementById('partialAmount').value = remaining > 0 ? remaining.toFixed(3) : '0.000';
},
removePaymentLine(index) {
this.payments.splice(index, 1);
this.renderPayments();
this.updateRemaining();
},
getGrandTotal() {
const subtotal = this.items.reduce((sum, item) => sum + (item.price * item.qty), 0);
let discountAmount = 0;
if (this.discount) {
discountAmount = this.discount.type === 'percentage' ? subtotal * (parseFloat(this.discount.value) / 100) : parseFloat(this.discount.value);
}
const redeemSwitch = document.getElementById('redeemLoyalty');
let loyaltyRedeemedValue = (redeemSwitch && redeemSwitch.checked) ? Math.min(subtotal - discountAmount, this.customerPoints / this.loyaltySettings.redeemPointsPerUnit) : 0;
return subtotal - discountAmount - loyaltyRedeemedValue;
},
getRemaining() {
const total = this.getGrandTotal();
const paid = this.payments.reduce((sum, p) => sum + p.amount, 0);
return total - paid;
},
renderPayments() {
const container = document.getElementById('paymentList');
container.innerHTML = this.payments.map((p, i) => `
<div class="payment-line">
<div>
<span class="method">${p.method}</span>
<span class="ms-2 badge bg-secondary small">OMR ${p.amount.toFixed(3)}</span>
</div>
<button class="btn btn-sm btn-outline-danger border-0" onclick="cart.removePaymentLine(${i})">
<i class="bi bi-trash"></i>
</button>
</div>
`).join('');
},
updateRemaining() {
const remaining = this.getRemaining();
const currentInput = parseFloat(document.getElementById('partialAmount').value) || 0;
const display = document.getElementById('paymentRemaining');
display.innerText = 'OMR ' + Math.max(0, remaining).toFixed(3);
// Calculate potential change if the user types an amount > remaining
const totalPaid = this.payments.reduce((sum, p) => sum + p.amount, 0);
const grandTotal = this.getGrandTotal();
const actualChange = Math.max(0, totalPaid - grandTotal);
const potentialChange = Math.max(0, currentInput - remaining);
const displayChange = Math.max(actualChange, potentialChange);
const changeDisplay = document.getElementById('changeDue');
if (changeDisplay) {
changeDisplay.innerText = 'OMR ' + displayChange.toFixed(3);
const cashSection = document.getElementById('cashPaymentSection');
if (displayChange > 0 || this.selectedPaymentMethod === 'cash' || this.payments.some(p => p.method === 'cash')) {
cashSection.style.display = 'block';
} else {
cashSection.style.display = 'none';
}
}
if (remaining <= 0.0001 || currentInput >= remaining - 0.0001) {
display.classList.remove('text-danger');
display.classList.add('text-success');
document.getElementById('confirmPaymentBtn').disabled = false;
} else {
display.classList.remove('text-success');
display.classList.add('text-danger');
document.getElementById('confirmPaymentBtn').disabled = true;
}
},
async completeOrder() {
if (this.items.length === 0) {
Swal.fire('Error', 'Cart is empty', 'error');
return;
}
// If there's an amount in the input and payments are not enough, add it
const remainingBefore = this.getRemaining();
const currentInput = parseFloat(document.getElementById('partialAmount').value) || 0;
if (remainingBefore > 0.0001 && currentInput >= remainingBefore - 0.0001) {
this.payments.push({
method: this.selectedPaymentMethod,
amount: currentInput
});
} else if (this.payments.length === 0) {
const total = this.getGrandTotal();
this.payments.push({
method: this.selectedPaymentMethod,
amount: total
});
}
const remaining = this.getRemaining();
if (remaining > 0.001) {
Swal.fire('Error', 'Payment is incomplete', 'error');
return;
}
const customerId = document.getElementById('posCustomer').value;
if (this.payments.some(p => p.method === 'credit') && !customerId) {
Swal.fire('Error', 'Credit payment is only allowed for registered customers', 'error');
return;
}
const btn = document.getElementById('confirmPaymentBtn');
const originalText = btn.innerText;
btn.disabled = true;
btn.innerText = 'PROCESSING...';
const subtotal = this.items.reduce((sum, item) => sum + (parseFloat(item.price) * item.qty), 0);
let discountAmount = 0;
if (this.discount) {
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 / this.loyaltySettings.redeemPointsPerUnit) : 0;
const formData = new FormData();
formData.append('action', 'save_pos_transaction');
formData.append('customer_id', customerId);
formData.append('payments', JSON.stringify(this.payments));
formData.append('total_amount', subtotal);
formData.append('discount_code_id', this.discount ? this.discount.id : '');
formData.append('discount_amount', discountAmount);
formData.append('loyalty_redeemed', loyaltyRedeemed);
formData.append('items', JSON.stringify(this.items.map(i => ({id: i.id, qty: i.qty, price: i.price}))));
try {
const resp = await fetch('index.php', { method: 'POST', body: formData });
const text = await resp.text();
let result;
try {
result = JSON.parse(text);
} catch (e) {
console.error('Invalid JSON response:', text);
throw new Error('Server returned an invalid response');
}
if (result.success) {
const payModal = bootstrap.Modal.getInstance(document.getElementById('posPaymentModal'));
if (payModal) payModal.hide();
this.showReceipt(result.invoice_id, discountAmount, loyaltyRedeemed, result.transaction_no);
} else {
Swal.fire('Error', result.error, 'error');
btn.disabled = false;
btn.innerText = originalText;
}
} catch (err) {
console.error(err);
Swal.fire('Error', err.message || 'Something went wrong', 'error');
btn.disabled = false;
btn.innerText = originalText;
}
},
showReceipt(invId, discountAmount, loyaltyRedeemed, transactionNo) {
const container = document.getElementById('posReceiptContent');
const customerName = document.getElementById('posCustomer').options[document.getElementById('posCustomer').selectedIndex].text;
const paymentsHtml = this.payments.map(p => `
<div class="d-flex justify-content-between small">
<span class="text-uppercase">${p.method}</span>
<span>OMR ${p.amount.toFixed(3)}</span>
</div>
`).join('');
const date = new Date().toLocaleString();
let itemsHtml = this.items.map(item => `
<tr>
<td>${item.nameEn}<br><small>${item.qty} x ${parseFloat(item.price).toFixed(3)}</small></td>
<td style="text-align: right; vertical-align: bottom;">${(item.price * item.qty).toFixed(3)}</td>
</tr>
`).join('');
const subtotal = this.items.reduce((sum, item) => sum + (item.price * item.qty), 0);
const total = subtotal - discountAmount - loyaltyRedeemed;
const companyName = "<?= htmlspecialchars($data['settings']['company_name'] ?? 'Accounting System') ?>";
const companyPhone = "<?= htmlspecialchars($data['settings']['company_phone'] ?? '') ?>";
const companyVat = "<?= htmlspecialchars($data['settings']['vat_number'] ?? '') ?>";
container.innerHTML = `
<div class="thermal-receipt">
<div class="center">
<h5 class="mb-0 fw-bold">${companyName}</h5>
${companyPhone ? `<div>Tel: ${companyPhone}</div>` : ''}
${companyVat ? `<div>VAT: ${companyVat}</div>` : ''}
<div class="separator"></div>
<h6 class="fw-bold">TAX INVOICE</h6>
<div>Inv: ${transactionNo || 'POS-'+invId}</div>
<div>Date: ${date}</div>
<div class="separator"></div>
</div>
<div>
<strong>Customer:</strong> ${customerName}
</div>
<div class="mt-1">
<strong>Payments:</strong>
${paymentsHtml}
</div>
<div class="separator"></div>
<table>
<thead>
<tr>
<th>ITEM</th>
<th style="text-align: right;">TOTAL</th>
</tr>
</thead>
<tbody>
${itemsHtml}
</tbody>
</table>
<div class="separator"></div>
<div class="d-flex justify-content-between">
<span>Subtotal</span>
<span>OMR ${subtotal.toFixed(3)}</span>
</div>
${discountAmount > 0 ? `<div class="d-flex justify-content-between text-danger"><span>Discount</span><span>- OMR ${parseFloat(discountAmount).toFixed(3)}</span></div>` : ''}
${loyaltyRedeemed > 0 ? `<div class="d-flex justify-content-between text-success"><span>Loyalty</span><span>- OMR ${parseFloat(loyaltyRedeemed).toFixed(3)}</span></div>` : ''}
<div class="separator"></div>
<div class="d-flex justify-content-between total-row">
<span>TOTAL</span>
<span>OMR ${total.toFixed(3)}</span>
</div>
<div class="separator"></div>
<div class="center small">
Thank you for your business!<br>
Please keep the receipt.
</div>
</div>
`;
const modal = new bootstrap.Modal(document.getElementById('posReceiptModal'));
modal.show();
this.clear();
document.getElementById('posReceiptModal').addEventListener('hidden.bs.modal', function () {
location.reload();
}, { once: true });
},
async syncCustomer(val) {
document.getElementById('posCustomer').value = val;
const customerSelect = document.getElementById('posCustomer');
const customerName = customerSelect.options[customerSelect.selectedIndex].text;
document.getElementById('paymentCustomerName').innerText = customerName;
await this.onCustomerChange();
}
};
document.querySelectorAll('.product-card').forEach(card => {
card.addEventListener('click', () => {
const product = {
id: parseInt(card.dataset.id),
nameEn: card.dataset.nameEn,
nameAr: card.dataset.nameAr,
price: parseFloat(card.dataset.price),
stock_quantity: parseFloat(card.dataset.stockQuantity)
};
cart.add(product);
});
});
document.getElementById('productSearch').addEventListener('input', (e) => {
const q = e.target.value.toLowerCase();
document.querySelectorAll('.product-grid .product-card').forEach(card => {
const name = card.dataset.nameEn.toLowerCase() + ' ' + card.dataset.nameAr.toLowerCase();
const sku = card.dataset.sku.toLowerCase();
if (name.includes(q) || sku.includes(q)) {
card.style.display = 'flex';
} else {
card.style.display = 'none';
}
});
});
document.getElementById('barcodeInput').addEventListener('keypress', (e) => {
if (e.key === 'Enter') {
const barcode = e.target.value.trim();
if (!barcode) return;
const card = Array.from(document.querySelectorAll('.product-card')).find(c => c.dataset.sku === barcode);
if (card) {
const product = {
id: parseInt(card.dataset.id),
nameEn: card.dataset.nameEn,
nameAr: card.dataset.nameAr,
price: parseFloat(card.dataset.price),
sku: card.dataset.sku,
stock_quantity: parseFloat(card.dataset.stockQuantity)
};
cart.add(product);
e.target.value = '';
Swal.fire({
toast: true,
position: 'top-end',
icon: 'success',
title: 'Added: ' + product.nameEn,
showConfirmButton: false,
timer: 1000
});
} else {
Swal.fire({
toast: true,
position: 'top-end',
icon: 'error',
title: 'Product not found',
showConfirmButton: false,
timer: 1500
});
e.target.select();
}
}
});
// Keep barcode input focused
document.addEventListener('click', () => {
if (document.activeElement.tagName !== 'INPUT' && document.activeElement.tagName !== 'SELECT' && document.activeElement.tagName !== 'TEXTAREA') {
const bc = document.getElementById('barcodeInput');
if (bc) bc.focus();
}
});
$(document).ready(function() {
$('#posCustomer').select2({
width: '100%',
placeholder: 'Select Customer'
});
$('#paymentCreditCustomer').select2({
width: '100%',
placeholder: 'Select Customer',
dropdownParent: $('#posPaymentModal')
});
});
</script>
<?php elseif ($page === 'quotations'): ?>
<div class="card p-4">
<div class="d-flex justify-content-between align-items-center mb-4">
<h5 class="m-0" data-en="Quotations" data-ar="عروض الأسعار">Quotations</h5>
<button class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#addQuotationModal">
<i class="bi bi-plus-lg"></i> <span data-en="Create New Quotation" data-ar="إنشاء عرض سعر جديد">Create New Quotation</span>
</button>
</div>
<!-- Filters Section -->
<div class="bg-light p-3 rounded mb-4">
<form method="GET" class="row g-3">
<input type="hidden" name="page" value="quotations">
<div class="col-md-3">
<label class="form-label small fw-bold" data-en="Search" data-ar="بحث">Search</label>
<input type="text" name="search" class="form-control form-control-sm" value="<?= htmlspecialchars($_GET['search'] ?? '') ?>" placeholder="Quot # or Name...">
</div>
<div class="col-md-3">
<label class="form-label small fw-bold" data-en="Customer" data-ar="العميل">Customer</label>
<select name="customer_id" class="form-select form-select-sm">
<option value="" data-en="All" data-ar="الكل">All</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-2">
<label class="form-label small fw-bold" data-en="Start Date" data-ar="من تاريخ">Start Date</label>
<input type="date" name="start_date" class="form-control form-control-sm" value="<?= htmlspecialchars($_GET['start_date'] ?? '') ?>">
</div>
<div class="col-md-2">
<label class="form-label small fw-bold" data-en="End Date" data-ar="إلى تاريخ">End Date</label>
<input type="date" name="end_date" class="form-control form-control-sm" value="<?= htmlspecialchars($_GET['end_date'] ?? '') ?>">
</div>
<div class="col-md-2 d-flex align-items-end gap-1">
<button type="submit" class="btn btn-primary btn-sm flex-grow-1">
<i class="bi bi-filter"></i> <span data-en="Filter" data-ar="تصفية">Filter</span>
</button>
<a href="index.php?page=quotations" class="btn btn-outline-secondary btn-sm flex-grow-1">
<i class="bi bi-x-circle"></i> <span data-en="Clear" data-ar="مسح">Clear</span>
</a>
</div>
</form>
</div>
<div class="table-responsive">
<table class="table table-hover align-middle">
<thead>
<tr>
<th data-en="Quotation #" data-ar="رقم العرض">Quotation #</th>
<th data-en="Date" data-ar="التاريخ">Date</th>
<th data-en="Valid Until" data-ar="صالح حتى">Valid Until</th>
<th data-en="Customer" data-ar="العميل">Customer</th>
<th data-en="Status" data-ar="الحالة">Status</th>
<th data-en="Total" data-ar="الإجمالي" class="text-end">Total</th>
<th data-en="Actions" data-ar="الإجراءات" class="text-end">Actions</th>
</tr>
</thead>
<tbody>
<?php
foreach ($data['quotations'] as $q):
$items = db()->prepare("SELECT qi.*, i.name_en, i.name_ar, i.vat_rate
FROM quotation_items qi
JOIN stock_items i ON qi.item_id = i.id
WHERE qi.quotation_id = ?");
$items->execute([$q['id']]);
$q['items'] = $items->fetchAll(PDO::FETCH_ASSOC);
?>
<tr>
<td>QUO-<?= str_pad((string)$q['id'], 5, '0', STR_PAD_LEFT) ?></td>
<td><?= $q['quotation_date'] ?></td>
<td><?= $q['valid_until'] ?: '---' ?></td>
<td><?= htmlspecialchars($q['customer_name'] ?? '---') ?></td>
<td>
<?php
$statusClass = 'bg-secondary';
if ($q['status'] === 'converted') $statusClass = 'bg-success';
elseif ($q['status'] === 'pending') $statusClass = 'bg-warning text-dark';
elseif ($q['status'] === 'expired' || $q['status'] === 'cancelled') $statusClass = 'bg-danger';
?>
<span class="badge text-uppercase <?= $statusClass ?>"><?= htmlspecialchars($q['status']) ?></span>
</td>
<td class="text-end fw-bold">OMR <?= number_format((float)$q['total_with_vat'], 3) ?></td>
<td class="text-end">
<div class="btn-group btn-group-sm">
<button class="btn btn-outline-info view-quotation-btn" data-json="<?= htmlspecialchars(json_encode($q)) ?>" title="View"><i class="bi bi-eye"></i></button>
<button class="btn btn-outline-secondary" onclick="window.viewAndPrintQuotation(<?= htmlspecialchars(json_encode($q)) ?>)" title="Print"><i class="bi bi-printer"></i></button>
<button class="btn btn-outline-primary edit-quotation-btn" data-json="<?= htmlspecialchars(json_encode($q)) ?>" data-bs-toggle="modal" data-bs-target="#editQuotationModal" title="Edit"><i class="bi bi-pencil-square"></i></button>
<?php if ($q['status'] === 'pending'): ?>
<button class="btn btn-outline-success convert-quotation-btn" data-id="<?= $q['id'] ?>" title="Convert to Invoice"><i class="bi bi-receipt"></i></button>
<?php endif; ?>
<button class="btn btn-outline-danger" onclick="if(confirm('Delete this quotation?')) { const f = document.createElement('form'); f.method='POST'; f.innerHTML='<input type=hidden name=delete_quotation><input type=hidden name=id value=<?= $q['id'] ?>>'; document.body.appendChild(f); f.submit(); }" title="Delete"><i class="bi bi-trash"></i></button>
</div>
</td>
</tr>
<?php endforeach; ?>
<?php if (empty($data['quotations'])): ?>
<tr><td colspan="7" class="text-center py-4 text-muted" data-en="No quotations found" data-ar="لا توجد عروض أسعار">No quotations found</td></tr>
<?php endif; ?>
</tbody>
</table>
</div>
</div>
<?php elseif ($page === 'sales' || $page === 'purchases'): ?>
<div class="card p-4">
<div class="d-flex justify-content-between align-items-center mb-4">
<h5 class="m-0" data-en="<?= $currTitle['en'] ?>" data-ar="<?= $currTitle['ar'] ?>"><?= $currTitle['en'] ?></h5>
<?php if (can($page . '_add')): ?>
<button class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#addInvoiceModal">
<i class="bi bi-plus-lg"></i> <span data-en="Create New Tax Invoice" data-ar="إنشاء فاتورة ضريبية جديدة">Create New Tax Invoice</span>
</button>
<?php endif; ?>
</div>
<!-- Filters Section -->
<div class="bg-light p-3 rounded mb-4">
<form method="GET" class="row g-3">
<input type="hidden" name="page" value="<?= $page ?>">
<div class="col-md-3">
<label class="form-label small fw-bold" data-en="Search" data-ar="بحث">Search</label>
<input type="text" name="search" class="form-control form-control-sm" value="<?= htmlspecialchars($_GET['search'] ?? '') ?>" placeholder="Inv # or Name...">
</div>
<div class="col-md-3">
<label class="form-label small fw-bold" data-en="<?= $page === 'sales' ? 'Customer' : 'Supplier' ?>" data-ar="<?= $page === 'sales' ? 'العميل' : 'المورد' ?>"><?= $page === 'sales' ? 'Customer' : 'Supplier' ?></label>
<select name="customer_id" class="form-select form-select-sm">
<option value="" data-en="All" data-ar="الكل">All</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-2">
<label class="form-label small fw-bold" data-en="Start Date" data-ar="من تاريخ">Start Date</label>
<input type="date" name="start_date" class="form-control form-control-sm" value="<?= htmlspecialchars($_GET['start_date'] ?? '') ?>">
</div>
<div class="col-md-2">
<label class="form-label small fw-bold" data-en="End Date" data-ar="إلى تاريخ">End Date</label>
<input type="date" name="end_date" class="form-control form-control-sm" value="<?= htmlspecialchars($_GET['end_date'] ?? '') ?>">
</div>
<div class="col-md-2 d-flex align-items-end gap-1">
<button type="submit" class="btn btn-primary btn-sm flex-grow-1">
<i class="bi bi-filter"></i> <span data-en="Filter" data-ar="تصفية">Filter</span>
</button>
<a href="index.php?page=export&type=<?= $page ?>&<?= http_build_query($_GET) ?>" class="btn btn-success btn-sm">
<i class="bi bi-download"></i> <span data-en="Export" data-ar="تصدير">Export</span>
</a>
<a href="index.php?page=<?= $page ?>" class="btn btn-outline-secondary btn-sm flex-grow-1">
<i class="bi bi-x-circle"></i> <span data-en="Clear" data-ar="مسح">Clear</span>
</a>
</div>
</form>
</div>
<div class="table-responsive">
<table class="table table-hover align-middle">
<thead>
<tr>
<th data-en="Invoice #" data-ar="رقم الفاتورة">Invoice #</th>
<th data-en="Date" data-ar="التاريخ">Date</th>
<th data-en="<?= $page === 'sales' ? 'Customer' : 'Supplier' ?>" data-ar="<?= $page === 'sales' ? 'العميل' : 'المورد' ?>"><?= $page === 'sales' ? 'Customer' : 'Supplier' ?></th>
<th data-en="Status" data-ar="الحالة">Status</th>
<th data-en="Total" data-ar="الإجمالي" class="text-end">Total</th>
<th data-en="Paid" data-ar="المدفوع" class="text-end">Paid</th>
<th data-en="Balance" data-ar="المتبقي" class="text-end">Balance</th>
<th data-en="Actions" data-ar="الإجراءات" class="text-end">Actions</th>
</tr>
</thead>
<tbody>
<?php
foreach ($data['invoices'] as $inv):
$items = db()->prepare("SELECT ii.*, i.name_en, i.name_ar, i.vat_rate
FROM invoice_items ii
JOIN stock_items i ON ii.item_id = i.id
WHERE ii.invoice_id = ?");
$items->execute([$inv['id']]);
$inv['items'] = $items->fetchAll(PDO::FETCH_ASSOC);
?>
<tr>
<td>INV-<?= str_pad((string)$inv['id'], 5, '0', STR_PAD_LEFT) ?></td>
<td><?= $inv['invoice_date'] ?></td>
<td><?= htmlspecialchars($inv['customer_name'] ?? '---') ?></td>
<td>
<?php
$statusClass = 'bg-secondary';
if ($inv['status'] === 'paid') $statusClass = 'bg-success';
elseif ($inv['status'] === 'unpaid') $statusClass = 'bg-danger';
elseif ($inv['status'] === 'partially_paid') $statusClass = 'bg-warning text-dark';
?>
<span class="badge text-uppercase <?= $statusClass ?>"><?= htmlspecialchars(str_replace('_', ' ', $inv['status'])) ?></span>
</td>
<td class="text-end fw-bold">OMR <?= number_format((float)$inv['total_with_vat'], 3) ?></td>
<td class="text-end text-success">OMR <?= number_format((float)$inv['paid_amount'], 3) ?></td>
<td class="text-end text-danger fw-bold">OMR <?= number_format((float)($inv['total_with_vat'] - $inv['paid_amount']), 3) ?></td>
<td class="text-end">
<div class="btn-group btn-group-sm">
<button class="btn btn-outline-info view-invoice-btn" data-json="<?= htmlspecialchars(json_encode($inv)) ?>" title="View"><i class="bi bi-eye"></i></button>
<button class="btn btn-outline-warning return-invoice-btn" data-id="<?= $inv['id'] ?>" data-bs-toggle="modal" data-bs-target="<?= $page === 'sales' ? '#addSalesReturnModal' : '#addPurchaseReturnModal' ?>" title="Return"><i class="bi bi-arrow-return-left"></i></button>
<button class="btn btn-outline-primary edit-invoice-btn" data-json="<?= htmlspecialchars(json_encode($inv)) ?>" data-bs-toggle="modal" data-bs-target="#editInvoiceModal" title="Edit"><i class="bi bi-pencil"></i></button>
<?php if ($inv['status'] !== 'paid'): ?>
<button class="btn btn-outline-success pay-invoice-btn" data-id="<?= $inv['id'] ?>" data-total="<?= $inv['total_with_vat'] ?>" data-paid="<?= $inv['paid_amount'] ?>" data-bs-toggle="modal" data-bs-target="#payInvoiceModal" title="Payment"><i class="bi bi-cash-coin"></i></button>
<?php endif; ?>
<button class="btn btn-outline-secondary print-a4-btn" data-json="<?= htmlspecialchars(json_encode($inv)) ?>" title="Print A4 Invoice"><i class="bi bi-printer"></i></button>
<form method="POST" class="d-inline" onsubmit="return confirm('Are you sure you want to delete this invoice?')">
<input type="hidden" name="id" value="<?= $inv['id'] ?>">
<button type="submit" name="delete_invoice" class="btn btn-outline-danger" title="Delete"><i class="bi bi-trash"></i></button>
</form>
</div>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
</div>
<?php elseif ($page === 'customer_statement' || $page === 'supplier_statement'): ?>
<div class="card p-4">
<div class="d-flex justify-content-between align-items-center mb-4 d-print-none">
<h5 class="m-0" data-en="<?= $currTitle['en'] ?>" data-ar="<?= $currTitle['ar'] ?>"><?= $currTitle['en'] ?></h5>
<button class="btn btn-outline-secondary 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="<?= $page ?>">
<div class="col-md-4">
<label class="form-label small fw-bold" data-en="Select <?= $page === 'customer_statement' ? 'Customer' : 'Supplier' ?>" data-ar="اختر <?= $page === 'customer_statement' ? 'العميل' : 'المورد' ?>">Select <?= $page === 'customer_statement' ? 'Customer' : 'Supplier' ?></label>
<select name="entity_id" class="form-select select2" required>
<option value="">---</option>
<?php foreach ($data['entities'] as $e): ?>
<option value="<?= $e['id'] ?>" <?= (($_GET['entity_id'] ?? '') == $e['id']) ? 'selected' : '' ?>><?= htmlspecialchars($e['name']) ?></option>
<?php endforeach; ?>
</select>
</div>
<div class="col-md-3">
<label class="form-label small fw-bold" data-en="From Date" data-ar="من تاريخ">From Date</label>
<input type="date" name="start_date" class="form-control" value="<?= htmlspecialchars($_GET['start_date'] ?? date('Y-m-01')) ?>">
</div>
<div class="col-md-3">
<label class="form-label small fw-bold" data-en="To Date" data-ar="إلى تاريخ">To Date</label>
<input type="date" name="end_date" class="form-control" value="<?= htmlspecialchars($_GET['end_date'] ?? date('Y-m-d')) ?>">
</div>
<div class="col-md-2">
<button type="submit" class="btn btn-primary w-100">
<i class="bi bi-search"></i> <span data-en="View Report" data-ar="عرض التقرير">View Report</span>
</button>
</div>
</form>
</div>
<?php if (isset($data['transactions'])): ?>
<div id="statement-print">
<div class="row mb-4">
<div class="col-6">
<h3 class="mb-0"><?= htmlspecialchars($data['settings']['company_name'] ?? 'Accounting System') ?></h3>
<p class="text-muted small"><?= nl2br(htmlspecialchars($data['settings']['company_address'] ?? '')) ?></p>
</div>
<div class="col-6 text-end">
<h2 class="text-uppercase text-muted" data-en="Statement of Account" data-ar="كشف حساب">Statement of Account</h2>
<p class="mb-0"><strong><?= htmlspecialchars($data['selected_entity']['name']) ?></strong></p>
<p class="text-muted small"><?= htmlspecialchars($data['selected_entity']['email']) ?> | <?= htmlspecialchars($data['selected_entity']['phone']) ?><br>Period: <?= $_GET['start_date'] ?> to <?= $_GET['end_date'] ?></p>
</div>
</div>
<div class="table-responsive">
<table class="table table-bordered table-sm">
<thead class="bg-light">
<tr>
<th data-en="Date" data-ar="التاريخ">Date</th>
<th data-en="Reference" data-ar="المرجع">Reference</th>
<th data-en="Description" data-ar="الوصف">Description</th>
<th data-en="Debit" data-ar="مدين" class="text-end">Debit</th>
<th data-en="Credit" data-ar="دائن" class="text-end">Credit</th>
<th data-en="Balance" data-ar="الرصيد" class="text-end">Balance</th>
</tr>
</thead>
<tbody>
<?php
$running_balance = 0;
foreach ($data['transactions'] as $t):
$debit = 0; $credit = 0;
if ($t['trans_type'] === 'invoice') {
if ($page === 'customer_statement') $debit = (float)$t['amount']; else $credit = (float)$t['amount'];
} else {
if ($page === 'customer_statement') $credit = (float)$t['amount']; else $debit = (float)$t['amount'];
}
$running_balance += ($debit - $credit);
?>
<tr>
<td><?= $t['trans_date'] ?></td>
<td><?= $t['trans_type'] === 'invoice' ? 'INV-'.str_pad((string)$t['ref_no'], 5, '0', STR_PAD_LEFT) : 'RCP-'.str_pad((string)$t['id'], 5, '0', STR_PAD_LEFT) ?></td>
<td><?= $t['trans_type'] === 'invoice' ? 'Tax Invoice' : 'Payment - '.$t['payment_method'] ?></td>
<td class="text-end"><?= $debit > 0 ? number_format($debit, 3) : '' ?></td>
<td class="text-end"><?= $credit > 0 ? number_format($credit, 3) : '' ?></td>
<td class="text-end fw-bold"><?= number_format($running_balance, 3) ?></td>
</tr>
<?php endforeach; ?>
</tbody>
<tfoot class="bg-light fw-bold">
<tr>
<td colspan="5" class="text-end">Closing Balance</td>
<td class="text-end">OMR <?= number_format($running_balance, 3) ?></td>
</tr>
</tfoot>
</table>
</div>
</div>
<?php else: ?>
<div class="text-center py-5 text-muted"><p>Please select an entity and date range to generate the statement.</p></div>
<?php endif; ?>
</div>
<?php elseif ($page === 'cashflow_report'): ?>
<div class="card p-4">
<div class="d-flex justify-content-between align-items-center mb-4 d-print-none">
<h5 class="m-0" data-en="Cashflow Statement" data-ar="قائمة التدفقات النقدية">Cashflow Statement</h5>
<button class="btn btn-outline-secondary 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="<?= $page ?>">
<div class="col-md-5">
<label class="form-label small fw-bold" data-en="From Date" data-ar="من تاريخ">From Date</label>
<input type="date" name="start_date" class="form-control" value="<?= htmlspecialchars($_GET['start_date'] ?? date('Y-m-01')) ?>">
</div>
<div class="col-md-5">
<label class="form-label small fw-bold" data-en="To Date" data-ar="إلى تاريخ">To Date</label>
<input type="date" name="end_date" class="form-control" value="<?= htmlspecialchars($_GET['end_date'] ?? date('Y-m-d')) ?>">
</div>
<div class="col-md-2">
<button type="submit" class="btn btn-primary w-100">
<i class="bi bi-search"></i> <span data-en="Generate" data-ar="توليد">Generate</span>
</button>
</div>
</form>
</div>
<div id="cashflow-print">
<div class="row mb-4">
<div class="col-6">
<h3 class="mb-0"><?= htmlspecialchars($data['settings']['company_name'] ?? 'Accounting System') ?></h3>
<p class="text-muted small"><?= nl2br(htmlspecialchars($data['settings']['company_address'] ?? '')) ?></p>
</div>
<div class="col-6 text-end">
<h2 class="text-uppercase text-muted" data-en="Cashflow Statement" data-ar="قائمة التدفقات النقدية">Cashflow Statement</h2>
<p class="text-muted small">Period: <?= htmlspecialchars($_GET['start_date'] ?? date('Y-m-01')) ?> to <?= htmlspecialchars($_GET['end_date'] ?? date('Y-m-d')) ?></p>
</div>
</div>
<table class="table table-bordered">
<thead class="bg-light">
<tr>
<th data-en="Description" data-ar="الوصف">Description</th>
<th data-en="Amount (OMR)" data-ar="المبلغ (ريال عماني)" class="text-end">Amount (OMR)</th>
</tr>
</thead>
<tbody>
<tr class="fw-bold table-light">
<td data-en="Opening Cash Balance" data-ar="رصيد النقدية الافتتاحي">Opening Cash Balance</td>
<td class="text-end"><?= number_format($data['opening_balance'], 3) ?></td>
</tr>
<tr>
<td colspan="2" class="fw-bold bg-light" data-en="Operating Activities" data-ar="الأنشطة التشغيلية">Operating Activities</td>
</tr>
<?php
$op_inflow = 0; $op_outflow = 0;
$inv_inflow = 0; $inv_outflow = 0;
$fin_inflow = 0; $fin_outflow = 0;
foreach ($data['cash_transactions'] as $t) {
$amt = (float)$t['inflow'] - (float)$t['outflow'];
// Very simple categorization based on account type
if ($t['other_type'] === 'revenue' || $t['other_type'] === 'expense' || in_array($t['other_account'], ['Accounts Receivable', 'Accounts Payable', 'VAT Input', 'VAT Payable'])) {
if ($amt > 0) $op_inflow += $amt; else $op_outflow += abs($amt);
} elseif ($t['other_type'] === 'asset' && !in_array($t['other_account'], ['Accounts Receivable', 'Inventory'])) {
// Fixed assets etc
if ($amt > 0) $inv_inflow += $amt; else $inv_outflow += abs($amt);
} elseif ($t['other_type'] === 'equity' || $t['other_type'] === 'liability') {
if ($amt > 0) $fin_inflow += $amt; else $fin_outflow += abs($amt);
} else {
// Default to operating if unsure
if ($amt > 0) $op_inflow += $amt; else $op_outflow += abs($amt);
}
}
?>
<tr>
<td class="ps-4" data-en="Cash Received from Customers & Others" data-ar="المقبوضات النقدية من العملاء وغيرهم">Cash Received from Customers & Others</td>
<td class="text-end text-success"><?= number_format($op_inflow, 3) ?></td>
</tr>
<tr>
<td class="ps-4" data-en="Cash Paid to Suppliers & Expenses" data-ar="المدفوعات النقدية للموردين والمصروفات">Cash Paid to Suppliers & Expenses</td>
<td class="text-end text-danger">(<?= number_format($op_outflow, 3) ?>)</td>
</tr>
<tr class="fw-bold">
<td data-en="Net Cash from Operating Activities" data-ar="صافي النقد من الأنشطة التشغيلية">Net Cash from Operating Activities</td>
<td class="text-end border-top"><?= number_format($op_inflow - $op_outflow, 3) ?></td>
</tr>
<tr>
<td colspan="2" class="fw-bold bg-light" data-en="Investing Activities" data-ar="الأنشطة الاستثمارية">Investing Activities</td>
</tr>
<tr>
<td class="ps-4" data-en="Net Cash from Investing Activities" data-ar="صافي النقد من الأنشطة الاستثمارية">Net Cash from Investing Activities</td>
<td class="text-end"><?= number_format($inv_inflow - $inv_outflow, 3) ?></td>
</tr>
<tr>
<td colspan="2" class="fw-bold bg-light" data-en="Financing Activities" data-ar="الأنشطة التمويلية">Financing Activities</td>
</tr>
<tr>
<td class="ps-4" data-en="Net Cash from Financing Activities" data-ar="صافي النقد من الأنشطة التمويلية">Net Cash from Financing Activities</td>
<td class="text-end"><?= number_format($fin_inflow - $fin_outflow, 3) ?></td>
</tr>
<tr class="fw-bold table-primary">
<?php $net_change = ($op_inflow - $op_outflow) + ($inv_inflow - $inv_outflow) + ($fin_inflow - $fin_outflow); ?>
<td data-en="Net Change in Cash" data-ar="صافي التغير في النقدية">Net Change in Cash</td>
<td class="text-end"><?= number_format($net_change, 3) ?></td>
</tr>
<tr class="fw-bold table-success">
<td data-en="Closing Cash Balance" data-ar="رصيد النقدية الختامي">Closing Cash Balance</td>
<td class="text-end"><?= number_format($data['opening_balance'] + $net_change, 3) ?></td>
</tr>
</tbody>
</table>
<div class="mt-4 d-none d-print-block">
<div class="row">
<div class="col-6">
<p>___________________<br>Prepared By</p>
</div>
<div class="col-6 text-end">
<p>___________________<br>Approved By</p>
</div>
</div>
</div>
</div>
</div>
<div class="card p-4 d-print-none">
<div class="d-flex justify-content-between align-items-center mb-4">
<h5 class="m-0" data-en="Payment Methods" data-ar="طرق الدفع">Payment Methods</h5>
<button class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#addPaymentMethodModal">
<i class="bi bi-plus-lg"></i> <span data-en="Add Payment Method" data-ar="إضافة طريقة دفع">Add Payment Method</span>
</button>
</div>
<div class="table-responsive">
<table class="table table-hover align-middle">
<thead>
<tr>
<th data-en="ID" data-ar="المعرف">ID</th>
<th data-en="Name (EN)" data-ar="الاسم (EN)">Name (EN)</th>
<th data-en="Name (AR)" data-ar="الاسم (AR)">Name (AR)</th>
<th data-en="Actions" data-ar="الإجراءات" class="text-end">Actions</th>
</tr>
</thead>
<tbody>
<?php foreach ($data['payment_methods'] as $pm): ?>
<tr>
<td><?= $pm['id'] ?></td>
<td><?= htmlspecialchars($pm['name_en'] ?? '') ?></td>
<td><?= htmlspecialchars($pm['name_ar'] ?? '') ?></td>
<td class="text-end">
<div class="btn-group btn-group-sm">
<button class="btn btn-outline-primary" title="Edit" data-bs-toggle="modal" data-bs-target="#editPaymentMethodModal<?= $pm['id'] ?>"><i class="bi bi-pencil"></i></button>
<form method="POST" class="d-inline" onsubmit="return confirm('Are you sure?')">
<input type="hidden" name="id" value="<?= $pm['id'] ?>">
<button type="submit" name="delete_payment_method" class="btn btn-outline-danger" title="Delete"><i class="bi bi-trash"></i></button>
</form>
</div>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
</div>
<!-- Add Payment Method Modal -->
<div class="modal fade" id="addPaymentMethodModal" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content border-0 shadow">
<div class="modal-header">
<h5 class="modal-title" data-en="Add Payment Method" data-ar="إضافة طريقة دفع">Add Payment Method</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<form method="POST">
<div class="modal-body">
<div class="mb-3">
<label class="form-label" data-en="Name (EN)" data-ar="الاسم (EN)">Name (EN)</label>
<input type="text" name="name_en" class="form-control" required>
</div>
<div class="mb-3">
<label class="form-label" data-en="Name (AR)" data-ar="الاسم (AR)">Name (AR)</label>
<input type="text" name="name_ar" class="form-control" required>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-light" data-bs-dismiss="modal" data-en="Cancel" data-ar="إلغاء">Cancel</button>
<button type="submit" name="add_payment_method" class="btn btn-primary" data-en="Save" data-ar="حفظ">Save</button>
</div>
</form>
</div>
</div>
</div>
<?php elseif ($page === 'expense_categories'): ?>
<div class="card p-4">
<div class="d-flex justify-content-between align-items-center mb-4">
<h5 class="m-0" data-en="Expense Categories" data-ar="فئات المصروفات">Expense Categories</h5>
<button class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#addExpenseCategoryModal">
<i class="bi bi-plus-lg"></i> <span data-en="Add Category" data-ar="إضافة فئة">Add Category</span>
</button>
</div>
<div class="table-responsive">
<table class="table table-hover align-middle">
<thead>
<tr>
<th data-en="ID" data-ar="المعرف">ID</th>
<th data-en="Name (EN)" data-ar="الاسم (إنجليزي)">Name (EN)</th>
<th data-en="Name (AR)" data-ar="الاسم (عربي)">Name (AR)</th>
<th data-en="Actions" data-ar="الإجراءات" class="text-end">Actions</th>
</tr>
</thead>
<tbody>
<?php foreach ($data['expense_categories'] as $cat): ?>
<tr>
<td><?= $cat['id'] ?></td>
<td><?= htmlspecialchars($cat['name_en']) ?></td>
<td><?= htmlspecialchars($cat['name_ar']) ?></td>
<td class="text-end">
<div class="btn-group btn-group-sm">
<button class="btn btn-outline-primary" data-bs-toggle="modal" data-bs-target="#editExpCatModal<?= $cat['id'] ?>"><i class="bi bi-pencil"></i></button>
<form method="POST" class="d-inline" onsubmit="return confirm('Are you sure?')">
<input type="hidden" name="id" value="<?= $cat['id'] ?>">
<button type="submit" name="delete_expense_category" class="btn btn-outline-danger"><i class="bi bi-trash"></i></button>
</form>
</div>
<!-- Edit Modal -->
<div class="modal fade" id="editExpCatModal<?= $cat['id'] ?>" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content text-start">
<div class="modal-header">
<h5 class="modal-title">Edit Category</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<form method="POST">
<input type="hidden" name="id" value="<?= $cat['id'] ?>">
<div class="modal-body">
<div class="mb-3">
<label class="form-label">Name (EN)</label>
<input type="text" name="name_en" class="form-control" value="<?= htmlspecialchars($cat['name_en']) ?>" required>
</div>
<div class="mb-3">
<label class="form-label">Name (AR)</label>
<input type="text" name="name_ar" class="form-control" value="<?= htmlspecialchars($cat['name_ar']) ?>" required>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-light" data-bs-dismiss="modal">Cancel</button>
<button type="submit" name="edit_expense_category" class="btn btn-primary">Update</button>
</div>
</form>
</div>
</div>
</div>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
</div>
<!-- Add Modal -->
<div class="modal fade" id="addExpenseCategoryModal" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Add Category</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<form method="POST">
<div class="modal-body">
<div class="mb-3">
<label class="form-label">Name (EN)</label>
<input type="text" name="name_en" class="form-control" required>
</div>
<div class="mb-3">
<label class="form-label">Name (AR)</label>
<input type="text" name="name_ar" class="form-control" required>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-light" data-bs-dismiss="modal">Cancel</button>
<button type="submit" name="add_expense_category" class="btn btn-primary">Save</button>
</div>
</form>
</div>
</div>
</div>
<?php elseif ($page === 'accounting'): ?>
<div class="card p-4">
<div class="d-flex justify-content-between align-items-center mb-4 d-print-none">
<h5 class="m-0"><i class="fas fa-calculator me-2"></i> <span data-en="Accounting Module" data-ar="وحدة المحاسبة">Accounting Module</span></h5>
<div class="d-flex gap-2">
<form method="POST" onsubmit="return confirm('This will re-calculate all automatic journal entries from scratch. Continue?')">
<button type="submit" name="sync_accounting" class="btn btn-outline-warning">
<i class="bi bi-arrow-repeat"></i> <span data-en="Sync All" data-ar="مزامنة الكل">Sync All</span>
</button>
</form>
<button class="btn btn-success" data-bs-toggle="modal" data-bs-target="#addManualJournalModal">
<i class="bi bi-plus-lg"></i> <span data-en="Manual Entry" data-ar="قيد يدوي">Manual Entry</span>
</button>
<div class="btn-group">
<a href="index.php?page=accounting" class="btn <?= !isset($_GET['view']) ? 'btn-primary' : 'btn-outline-primary' ?>" data-en="Journal" data-ar="اليومية">Journal</a>
<a href="index.php?page=accounting&view=coa" class="btn <?= isset($_GET['view']) && $_GET['view'] === 'coa' ? 'btn-primary' : 'btn-outline-primary' ?>" data-en="Accounts" data-ar="الحسابات">Accounts</a>
<a href="index.php?page=accounting&view=trial_balance" class="btn <?= isset($_GET['view']) && $_GET['view'] === 'trial_balance' ? 'btn-primary' : 'btn-outline-primary' ?>" data-en="Trial Balance" data-ar="ميزان المراجعة">Trial Balance</a>
<a href="index.php?page=accounting&view=profit_loss" class="btn <?= isset($_GET['view']) && $_GET['view'] === 'profit_loss' ? 'btn-primary' : 'btn-outline-primary' ?>" data-en="P&L" data-ar="الأرباح">P&L</a>
<a href="index.php?page=accounting&view=balance_sheet" class="btn <?= isset($_GET['view']) && $_GET['view'] === 'balance_sheet' ? 'btn-primary' : 'btn-outline-primary' ?>" data-en="Balance Sheet" data-ar="الميزانية">Balance Sheet</a>
<a href="index.php?page=accounting&view=vat_report" class="btn <?= isset($_GET['view']) && $_GET['view'] === 'vat_report' ? 'btn-primary' : 'btn-outline-primary' ?>" data-en="VAT Report" data-ar="تقرير الضريبة">VAT Report</a>
</div>
<button class="btn btn-outline-secondary" onclick="window.print()">
<i class="bi bi-printer"></i> <span data-en="Print" data-ar="طباعة">Print</span>
</button>
</div>
</div>
<div class="d-none d-print-block mb-4">
<div class="row">
<div class="col-6">
<h3 class="mb-0"><?= htmlspecialchars($data['settings']['company_name'] ?? 'Accounting System') ?></h3>
<p class="text-muted small"><?= nl2br(htmlspecialchars($data['settings']['company_address'] ?? '')) ?></p>
</div>
<div class="col-6 text-end">
<h2 class="text-uppercase text-muted"><?= isset($_GET['view']) ? ucwords(str_replace('_', ' ', $_GET['view'])) : 'Journal' ?></h2>
</div>
</div>
</div>
<?php if (!isset($_GET['view'])): ?>
<div class="table-responsive">
<table class="table table-hover align-middle">
<thead>
<tr>
<th data-en="Date" data-ar="التاريخ">Date</th>
<th data-en="Description" data-ar="الوصف">Description</th>
<th data-en="Reference" data-ar="المرجع">Reference</th>
<th data-en="Amount" data-ar="المبلغ">Amount</th>
<th data-en="Action" data-ar="الإجراء">Action</th>
</tr>
</thead>
<tbody>
<?php foreach ($data['journal_entries'] as $entry): ?>
<tr>
<td><?= $entry['entry_date'] ?></td>
<td><?= htmlspecialchars($entry['description']) ?></td>
<td><span class="badge bg-secondary"><?= htmlspecialchars($entry['reference']) ?></span></td>
<td><?= number_format((float)$entry['total_debit'], 3) ?></td>
<td>
<button class="btn btn-sm btn-outline-info" onclick="viewJournalEntry(<?= $entry['id'] ?>)">
<i class="bi bi-eye"></i> <span data-en="View" data-ar="عرض">View</span>
</button>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
<?php elseif ($_GET['view'] === 'coa'): ?>
<div class="d-flex justify-content-end mb-3">
<button class="btn btn-primary btn-sm" data-bs-toggle="modal" data-bs-target="#addAccountModal">
<i class="bi bi-plus-lg"></i> <span data-en="Add Account" data-ar="إضافة حساب">Add Account</span>
</button>
</div>
<div class="table-responsive">
<table class="table table-hover">
<thead class="table-light">
<tr>
<th data-en="Code" data-ar="الكود">Code</th>
<th data-en="Name" data-ar="الاسم">Name</th>
<th data-en="Type" data-ar="النوع">Type</th>
<th data-en="Parent" data-ar="الحساب الأب">Parent</th>
<th data-en="Balance" data-ar="الرصيد" class="text-end">Balance</th>
</tr>
</thead>
<tbody>
<?php foreach ($data['coa'] as $acc): ?>
<tr>
<td class="fw-bold"><?= $acc['code'] ?></td>
<td>
<?= htmlspecialchars($acc['name_en']) ?><br>
<small class="text-muted"><?= htmlspecialchars($acc['name_ar']) ?></small>
</td>
<td><span class="badge bg-light text-dark border text-uppercase"><?= $acc['type'] ?></span></td>
<td><?= htmlspecialchars($acc['parent_name'] ?? '---') ?></td>
<td class="text-end fw-bold"><?= number_format(getAccountBalance($acc['code']), 3) ?></td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
<?php elseif ($_GET['view'] === 'vat_report'): ?>
<div class="row">
<div class="col-md-6 mx-auto">
<div class="bg-light p-3 rounded mb-4 d-print-none">
<form method="GET" class="row g-2">
<input type="hidden" name="page" value="accounting">
<input type="hidden" name="view" value="vat_report">
<div class="col">
<input type="date" name="start_date" class="form-control" value="<?= $data['start_date'] ?>">
</div>
<div class="col">
<input type="date" name="end_date" class="form-control" value="<?= $data['end_date'] ?>">
</div>
<div class="col-auto">
<button type="submit" class="btn btn-primary">Filter</button>
</div>
</form>
</div>
<div class="card shadow-sm border-0">
<div class="card-body">
<h4 class="text-center mb-4 d-print-none">VAT Summary Report</h4>
<table class="table">
<tr>
<th data-en="VAT Input (Purchases)" data-ar="ضريبة المدخلات (المشتريات)">VAT Input (Purchases)</th>
<td class="text-end text-success fw-bold"><?= number_format($data['vat_report']['input_vat'], 3) ?></td>
</tr>
<tr>
<th data-en="VAT Output (Sales)" data-ar="ضريبة المخرجات (المبيعات)">VAT Output (Sales)</th>
<td class="text-end text-danger fw-bold"><?= number_format($data['vat_report']['output_vat'], 3) ?></td>
</tr>
<tr class="table-dark h5">
<th data-en="Net VAT Payable / (Refundable)" data-ar="صافي الضريبة المستحقة / (المستردة)">Net VAT Payable / (Refundable)</th>
<td class="text-end"><?= number_format($data['vat_report']['net_vat'], 3) ?></td>
</tr>
</table>
<div class="alert alert-info small mt-3">
<i class="bi bi-info-circle me-1"></i>
This report calculates the difference between VAT collected on sales and VAT paid on purchases for the selected period.
</div>
</div>
</div>
</div>
</div>
<?php elseif ($_GET['view'] === 'trial_balance'): ?>
<div class="table-responsive">
<table class="table table-bordered">
<thead class="table-light">
<tr>
<th data-en="Code" data-ar="الكود">Code</th>
<th data-en="Account Name" data-ar="اسم الحساب">Account Name</th>
<th class="text-end" data-en="Debit" data-ar="مدين">Debit</th>
<th class="text-end" data-en="Credit" data-ar="دائن">Credit</th>
</tr>
</thead>
<tbody>
<?php
$total_d = 0; $total_c = 0;
foreach ($data['trial_balance'] as $row):
$total_d += (float)$row['total_debit'];
$total_c += (float)$row['total_credit'];
?>
<tr>
<td><?= $row['code'] ?></td>
<td><?= htmlspecialchars($row['name_en']) ?></td>
<td class="text-end"><?= number_format((float)$row['total_debit'], 3) ?></td>
<td class="text-end"><?= number_format((float)$row['total_credit'], 3) ?></td>
</tr>
<?php endforeach; ?>
</tbody>
<tfoot class="table-light fw-bold">
<tr>
<td colspan="2" class="text-end" data-en="Total" data-ar="الإجمالي">Total</td>
<td class="text-end"><?= number_format($total_d, 3) ?></td>
<td class="text-end"><?= number_format($total_c, 3) ?></td>
</tr>
</tfoot>
</table>
</div>
<?php elseif ($_GET['view'] === 'profit_loss'): ?>
<div class="row">
<div class="col-md-8 mx-auto">
<div class="card bg-light">
<div class="card-body">
<h4 class="text-center mb-4 d-print-none" data-en="Profit & Loss Statement" data-ar="قائمة الأرباح والخسائر">Profit & Loss Statement</h4>
<table class="table">
<tr class="table-primary"><th colspan="2" data-en="Revenue" data-ar="الإيرادات">Revenue</th></tr>
<?php
$total_rev = 0;
foreach ($data['revenue_accounts'] as $acc):
$bal = getAccountBalance($acc['code']);
if ($bal == 0) continue;
$total_rev += $bal;
?>
<tr>
<td><?= htmlspecialchars($acc['name_en']) ?></td>
<td class="text-end"><?= number_format($bal, 3) ?></td>
</tr>
<?php endforeach; ?>
<tr class="fw-bold">
<td data-en="Total Revenue" data-ar="إجمالي الإيرادات">Total Revenue</td>
<td class="text-end border-top"><?= number_format($total_rev, 3) ?></td>
</tr>
<tr class="table-warning"><th colspan="2" class="pt-4" data-en="Expenses" data-ar="المصروفات">Expenses</th></tr>
<?php
$total_exp = 0;
foreach ($data['expense_accounts'] as $acc):
$bal = getAccountBalance($acc['code']);
if ($bal == 0) continue;
$total_exp += $bal;
?>
<tr>
<td><?= htmlspecialchars($acc['name_en']) ?></td>
<td class="text-end"><?= number_format($bal, 3) ?></td>
</tr>
<?php endforeach; ?>
<tr class="fw-bold">
<td data-en="Total Expenses" data-ar="إجمالي المصروفات">Total Expenses</td>
<td class="text-end border-top"><?= number_format($total_exp, 3) ?></td>
</tr>
<tr class="table-success h4">
<td data-en="Net Profit / Loss" data-ar="صافي الربح / الخسارة">Net Profit / Loss</td>
<td class="text-end"><?= number_format($total_rev - $total_exp, 3) ?></td>
</tr>
</table>
</div>
</div>
</div>
</div>
<?php elseif ($_GET['view'] === 'balance_sheet'): ?>
<div class="row">
<div class="col-md-10 mx-auto">
<div class="card bg-light">
<div class="card-body">
<h4 class="text-center mb-4 d-print-none" data-en="Balance Sheet" data-ar="الميزانية العمومية">Balance Sheet</h4>
<div class="row">
<div class="col-md-6 border-end">
<h5 class="text-primary border-bottom pb-2" data-en="Assets" data-ar="الأصول">Assets</h5>
<table class="table table-sm">
<?php
$total_assets = 0;
foreach ($data['asset_accounts'] as $acc):
$bal = getAccountBalance($acc['code']);
if ($bal == 0) continue;
$total_assets += $bal;
?>
<tr>
<td><?= htmlspecialchars($acc['name_en']) ?></td>
<td class="text-end"><?= number_format($bal, 3) ?></td>
</tr>
<?php endforeach; ?>
<tr class="fw-bold h5">
<td data-en="Total Assets" data-ar="إجمالي الأصول">Total Assets</td>
<td class="text-end border-top"><?= number_format($total_assets, 3) ?></td>
</tr>
</table>
</div>
<div class="col-md-6">
<h5 class="text-danger border-bottom pb-2" data-en="Liabilities & Equity" data-ar="الالتزامات وحقوق الملكية">Liabilities & Equity</h5>
<table class="table table-sm">
<tr class="bg-light"><td colspan="2" class="small fw-bold text-muted">Liabilities</td></tr>
<?php
$total_liab = 0;
foreach ($data['liability_accounts'] as $acc):
$bal = getAccountBalance($acc['code']);
if ($bal == 0) continue;
$total_liab += $bal;
?>
<tr>
<td><?= htmlspecialchars($acc['name_en']) ?></td>
<td class="text-end"><?= number_format($bal, 3) ?></td>
</tr>
<?php endforeach; ?>
<tr class="bg-light"><td colspan="2" class="small fw-bold text-muted pt-3">Equity</td></tr>
<?php
$total_equity = 0;
foreach ($data['equity_accounts'] as $acc):
$bal = getAccountBalance($acc['code']);
if ($bal == 0) continue;
$total_equity += $bal;
?>
<tr>
<td><?= htmlspecialchars($acc['name_en']) ?></td>
<td class="text-end"><?= number_format($bal, 3) ?></td>
</tr>
<?php endforeach; ?>
<?php
// Current Year Earnings (Revenue - Expenses)
$rev = 0; foreach(db()->query("SELECT code FROM acc_accounts WHERE type='revenue' AND parent_id IS NOT NULL")->fetchAll() as $a) $rev += getAccountBalance($a['code']);
$exp = 0; foreach(db()->query("SELECT code FROM acc_accounts WHERE type='expense' AND parent_id IS NOT NULL")->fetchAll() as $a) $exp += getAccountBalance($a['code']);
$earnings = $rev - $exp;
$total_equity += $earnings;
?>
<tr>
<td data-en="Retained Earnings (Current)" data-ar="الأرباح المحتجزة (الحالية)">Retained Earnings (Current)</td>
<td class="text-end"><?= number_format($earnings, 3) ?></td>
</tr>
<tr class="fw-bold h5 pt-3">
<td data-en="Total Liab. & Equity" data-ar="إجمالي الالتزامات وحقوق الملكية">Total Liab. & Equity</td>
<td class="text-end border-top"><?= number_format($total_liab + $total_equity, 3) ?></td>
</tr>
</table>
</div>
</div>
</div>
</div>
</div>
</div>
<?php endif; ?>
</div>
<!-- Journal Entry Details Modal -->
<div class="modal fade" id="journalModal" tabindex="-1">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" data-en="Journal Entry Details" data-ar="تفاصيل قيد اليومية">Journal Entry Details</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body">
<table class="table table-bordered">
<thead>
<tr>
<th data-en="Account" data-ar="الحساب">Account</th>
<th class="text-end" data-en="Debit" data-ar="مدين">Debit</th>
<th class="text-end" data-en="Credit" data-ar="دائن">Credit</th>
</tr>
</thead>
<tbody id="journalDetailsBody"></tbody>
</table>
</div>
</div>
</div>
</div>
<script>
function viewJournalEntry(id) {
fetch('index.php?page=accounting&action=get_entry_details&id=' + id)
.then(r => r.json())
.then(data => {
let html = '';
data.forEach(row => {
html += `<tr>
<td>${row.code} - ${row.name_en}</td>
<td class="text-end">${parseFloat(row.debit).toFixed(3)}</td>
<td class="text-end">${parseFloat(row.credit).toFixed(3)}</td>
</tr>`;
});
document.getElementById('journalDetailsBody').innerHTML = html;
new bootstrap.Modal(document.getElementById('journalModal')).show();
});
}
</script>
<?php elseif ($page === 'expenses'): ?>
<div class="card p-4">
<div class="d-flex justify-content-between align-items-center mb-4">
<h5 class="m-0" data-en="Expenses List" data-ar="قائمة المصروفات">Expenses List</h5>
<button class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#addExpenseModal">
<i class="bi bi-plus-lg"></i> <span data-en="Add Expense" data-ar="إضافة مصروف">Add Expense</span>
</button>
</div>
<div class="bg-light p-3 rounded mb-4">
<form method="GET" class="row g-3">
<input type="hidden" name="page" value="expenses">
<div class="col-md-3">
<label class="form-label small">Category</label>
<select name="category_id" class="form-select">
<option value="">All</option>
<?php foreach ($data['expense_categories'] as $c): ?>
<option value="<?= $c['id'] ?>" <?= ($_GET['category_id'] ?? '') == $c['id'] ? 'selected' : '' ?>><?= htmlspecialchars($c['name_en']) ?></option>
<?php endforeach; ?>
</select>
</div>
<div class="col-md-3">
<label class="form-label small">Start Date</label>
<input type="date" name="start_date" class="form-control" value="<?= htmlspecialchars($_GET['start_date'] ?? '') ?>">
</div>
<div class="col-md-3">
<label class="form-label small">End Date</label>
<input type="date" name="end_date" class="form-control" value="<?= htmlspecialchars($_GET['end_date'] ?? '') ?>">
</div>
<div class="col-md-3 d-flex align-items-end">
<button type="submit" class="btn btn-primary w-100">Filter</button>
</div>
</form>
</div>
<div class="table-responsive">
<table class="table table-hover align-middle">
<thead>
<tr>
<th>Date</th>
<th>Reference</th>
<th>Category</th>
<th>Description</th>
<th class="text-end">Amount</th>
<th class="text-end">Actions</th>
</tr>
</thead>
<tbody>
<?php foreach ($data['expenses'] as $exp): ?>
<tr>
<td><?= $exp['expense_date'] ?></td>
<td><?= htmlspecialchars($exp['reference_no'] ?: '---') ?></td>
<td><?= htmlspecialchars($exp['cat_en'] ?? 'Unknown') ?></td>
<td><?= htmlspecialchars($exp['description']) ?></td>
<td class="text-end fw-bold">OMR <?= number_format((float)$exp['amount'], 3) ?></td>
<td class="text-end">
<div class="btn-group btn-group-sm">
<button class="btn btn-outline-primary" data-bs-toggle="modal" data-bs-target="#editExpenseModal<?= $exp['id'] ?>"><i class="bi bi-pencil"></i></button>
<form method="POST" class="d-inline" onsubmit="return confirm('Are you sure?')">
<input type="hidden" name="id" value="<?= $exp['id'] ?>">
<button type="submit" name="delete_expense" class="btn btn-outline-danger"><i class="bi bi-trash"></i></button>
</form>
</div>
<!-- Edit Modal -->
<div class="modal fade" id="editExpenseModal<?= $exp['id'] ?>" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content text-start">
<div class="modal-header">
<h5 class="modal-title">Edit Expense</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<form method="POST">
<input type="hidden" name="id" value="<?= $exp['id'] ?>">
<div class="modal-body">
<div class="mb-3">
<label class="form-label">Category</label>
<select name="category_id" class="form-select select2" required>
<?php foreach ($data['expense_categories'] as $c): ?>
<option value="<?= $c['id'] ?>" <?= $c['id'] == $exp['category_id'] ? 'selected' : '' ?>><?= htmlspecialchars($c['name_en']) ?></option>
<?php endforeach; ?>
</select>
</div>
<div class="mb-3">
<label class="form-label">Date</label>
<input type="date" name="expense_date" class="form-control" value="<?= $exp['expense_date'] ?>" required>
</div>
<div class="mb-3">
<label class="form-label">Amount</label>
<input type="number" step="0.001" name="amount" class="form-control" value="<?= (float)$exp['amount'] ?>" required>
</div>
<div class="mb-3">
<label class="form-label">Reference No</label>
<input type="text" name="reference_no" class="form-control" value="<?= htmlspecialchars($exp['reference_no']) ?>">
</div>
<div class="mb-3">
<label class="form-label">Description</label>
<textarea name="description" class="form-control"><?= htmlspecialchars($exp['description']) ?></textarea>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-light" data-bs-dismiss="modal">Cancel</button>
<button type="submit" name="edit_expense" class="btn btn-primary">Update</button>
</div>
</form>
</div>
</div>
</div>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
</div>
<!-- Add Expense Modal -->
<div class="modal fade" id="addExpenseModal" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Add Expense</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<form method="POST">
<div class="modal-body">
<div class="mb-3">
<label class="form-label">Category</label>
<select name="category_id" class="form-select" required>
<option value="">Select Category</option>
<?php foreach ($data['expense_categories'] as $c): ?>
<option value="<?= $c['id'] ?>"><?= htmlspecialchars($c['name_en']) ?></option>
<?php endforeach; ?>
</select>
</div>
<div class="mb-3">
<label class="form-label">Date</label>
<input type="date" name="expense_date" class="form-control" value="<?= date('Y-m-d') ?>" required>
</div>
<div class="mb-3">
<label class="form-label">Amount</label>
<input type="number" step="0.001" name="amount" class="form-control" required>
</div>
<div class="mb-3">
<label class="form-label">Reference No</label>
<input type="text" name="reference_no" class="form-control">
</div>
<div class="mb-3">
<label class="form-label">Description</label>
<textarea name="description" class="form-control"></textarea>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-light" data-bs-dismiss="modal">Cancel</button>
<button type="submit" name="add_expense" class="btn btn-primary">Save</button>
</div>
</form>
</div>
</div>
</div>
<?php elseif ($page === 'expense_report'): ?>
<div class="card p-4">
<div class="d-flex justify-content-between align-items-center mb-4">
<h5 class="m-0" data-en="Expense Report" data-ar="تقرير المصروفات">Expense Report</h5>
<button class="btn btn-outline-secondary d-print-none" onclick="window.print()">
<i class="bi bi-printer"></i> Print
</button>
</div>
<div class="bg-light p-3 rounded mb-4 d-print-none">
<form method="GET" class="row g-3">
<input type="hidden" name="page" value="expense_report">
<div class="col-md-4">
<label class="form-label small">From Date</label>
<input type="date" name="start_date" class="form-control" value="<?= htmlspecialchars($_GET['start_date'] ?? date('Y-m-01')) ?>">
</div>
<div class="col-md-4">
<label class="form-label small">To Date</label>
<input type="date" name="end_date" class="form-control" value="<?= htmlspecialchars($_GET['end_date'] ?? date('Y-m-d')) ?>">
</div>
<div class="col-md-4 d-flex align-items-end">
<button type="submit" class="btn btn-primary w-100">Generate Report</button>
</div>
</form>
</div>
<div class="row mb-4">
<div class="col-md-12">
<div class="card bg-light border-0">
<div class="card-body text-center">
<h6 class="text-muted text-uppercase mb-2">Total Expenses</h6>
<h2 class="text-danger mb-0">OMR <?= number_format((float)$data['total_expenses'], 3) ?></h2>
<small class="text-muted">Period: <?= htmlspecialchars($_GET['start_date'] ?? date('Y-m-01')) ?> to <?= htmlspecialchars($_GET['end_date'] ?? date('Y-m-d')) ?></small>
</div>
</div>
</div>
</div>
<div class="table-responsive">
<table class="table table-bordered">
<thead class="bg-light">
<tr>
<th>Category</th>
<th class="text-end">Total Amount</th>
<th class="text-end">% of Total</th>
</tr>
</thead>
<tbody>
<?php if (empty($data['report_by_category'])): ?>
<tr><td colspan="3" class="text-center text-muted">No expenses found for this period.</td></tr>
<?php else: ?>
<?php foreach ($data['report_by_category'] as $row):
$percent = $data['total_expenses'] > 0 ? ($row['total'] / $data['total_expenses'] * 100) : 0;
?>
<tr>
<td>
<div><?= htmlspecialchars($row['name_en']) ?></div>
<small class="text-muted"><?= htmlspecialchars($row['name_ar']) ?></small>
</td>
<td class="text-end fw-bold">OMR <?= number_format((float)$row['total'], 3) ?></td>
<td class="text-end"><?= number_format($percent, 1) ?>%</td>
</tr>
<?php endforeach; ?>
<?php endif; ?>
</tbody>
</table>
</div>
</div>
<?php elseif ($page === 'sales_returns'): ?>
<div class="card p-4">
<div class="d-flex justify-content-between align-items-center mb-4">
<h5 class="m-0" data-en="Sales Returns" data-ar="مرتجع المبيعات">Sales Returns</h5>
<button type="button" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#addSalesReturnModal" id="createSalesReturnBtn">
<i class="bi bi-plus-lg"></i> <span data-en="Create New Return" data-ar="إنشاء مرتجع جديد">Create New Return</span>
</button>
</div>
<div class="bg-light p-3 rounded mb-4">
<form method="GET" class="row g-3">
<input type="hidden" name="page" value="sales_returns">
<div class="col-md-9">
<input type="text" name="search" class="form-control form-control-sm" value="<?= htmlspecialchars($_GET['search'] ?? '') ?>" placeholder="Search by Return ID, Customer or Invoice ID...">
</div>
<div class="col-md-3">
<button type="submit" class="btn btn-primary btn-sm w-100">Filter</button>
</div>
</form>
</div>
<div class="table-responsive">
<table class="table table-hover align-middle">
<thead>
<tr>
<th data-en="Return #" data-ar="رقم المرتجع">Return #</th>
<th data-en="Date" data-ar="التاريخ">Date</th>
<th data-en="Invoice #" data-ar="رقم الفاتورة">Invoice #</th>
<th data-en="Customer" data-ar="العميل">Customer</th>
<th data-en="Total Amount" data-ar="إجمالي المرتجع" class="text-end">Total Amount</th>
<th data-en="Actions" data-ar="الإجراءات" class="text-end">Actions</th>
</tr>
</thead>
<tbody>
<?php foreach ($data['returns'] as $ret): ?>
<tr>
<td>RET-<?= str_pad((string)$ret['id'], 5, '0', STR_PAD_LEFT) ?></td>
<td><?= $ret['return_date'] ?></td>
<td>INV-<?= str_pad((string)$ret['invoice_id'], 5, '0', STR_PAD_LEFT) ?></td>
<td><?= htmlspecialchars($ret['customer_name'] ?? 'Walk-in') ?></td>
<td class="text-end fw-bold text-danger">OMR <?= number_format((float)$ret['total_amount'], 3) ?></td>
<td class="text-end">
<div class="btn-group btn-group-sm">
<button class="btn btn-outline-info view-return-btn" data-id="<?= $ret['id'] ?>"><i class="bi bi-eye"></i></button>
</div>
</td>
</tr>
<?php endforeach; ?>
<?php if (empty($data['returns'])): ?>
<tr><td colspan="6" class="text-center py-4 text-muted">No returns found</td></tr>
<?php endif; ?>
</tbody>
</table>
</div>
</div>
<?php elseif ($page === 'purchase_returns'): ?>
<div class="card p-4">
<div class="d-flex justify-content-between align-items-center mb-4">
<h5 class="m-0" data-en="Purchase Returns" data-ar="مرتجع المشتريات">Purchase Returns</h5>
<button type="button" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#addPurchaseReturnModal">
<i class="bi bi-plus-lg"></i> <span data-en="Create New Return" data-ar="إنشاء مرتجع جديد">Create New Return</span>
</button>
</div>
<div class="bg-light p-3 rounded mb-4">
<form method="GET" class="row g-3">
<input type="hidden" name="page" value="purchase_returns">
<div class="col-md-9">
<input type="text" name="search" class="form-control form-control-sm" value="<?= htmlspecialchars($_GET['search'] ?? '') ?>" placeholder="Search by Return ID, Supplier or Invoice ID...">
</div>
<div class="col-md-3">
<button type="submit" class="btn btn-primary btn-sm w-100">Filter</button>
</div>
</form>
</div>
<div class="table-responsive">
<table class="table table-hover align-middle">
<thead>
<tr>
<th data-en="Return #" data-ar="رقم المرتجع">Return #</th>
<th data-en="Date" data-ar="التاريخ">Date</th>
<th data-en="Invoice #" data-ar="رقم الفاتورة">Invoice #</th>
<th data-en="Supplier" data-ar="المورد">Supplier</th>
<th data-en="Total Amount" data-ar="إجمالي المرتجع" class="text-end">Total Amount</th>
<th data-en="Actions" data-ar="الإجراءات" class="text-end">Actions</th>
</tr>
</thead>
<tbody>
<?php foreach ($data['returns'] as $ret): ?>
<tr>
<td>PRET-<?= str_pad((string)$ret['id'], 5, '0', STR_PAD_LEFT) ?></td>
<td><?= $ret['return_date'] ?></td>
<td>INV-<?= str_pad((string)$ret['invoice_id'], 5, '0', STR_PAD_LEFT) ?></td>
<td><?= htmlspecialchars($ret['supplier_name'] ?? 'Unknown') ?></td>
<td class="text-end fw-bold text-danger">OMR <?= number_format((float)$ret['total_amount'], 3) ?></td>
<td class="text-end">
<div class="btn-group btn-group-sm">
<button class="btn btn-outline-info view-return-btn" data-id="<?= $ret['id'] ?>"><i class="bi bi-eye"></i></button>
</div>
</td>
</tr>
<?php endforeach; ?>
<?php if (empty($data['returns'])): ?>
<tr><td colspan="6" class="text-center py-4 text-muted">No returns found</td></tr>
<?php endif; ?>
</tbody>
</table>
</div>
</div>
<?php elseif ($page === 'hr_departments'): ?>
<div class="card p-4">
<div class="d-flex justify-content-between align-items-center mb-4">
<h5 class="m-0" data-en="HR Departments" data-ar="أقسام الموارد البشرية">HR Departments</h5>
<button class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#addHrDepartmentModal">
<i class="bi bi-plus-lg"></i> <span data-en="Add Department" data-ar="إضافة قسم">Add Department</span>
</button>
</div>
<div class="table-responsive">
<table class="table table-hover align-middle">
<thead>
<tr>
<th data-en="ID" data-ar="المعرف">ID</th>
<th data-en="Department Name" data-ar="اسم القسم">Department Name</th>
<th data-en="Actions" data-ar="الإجراءات" class="text-end">Actions</th>
</tr>
</thead>
<tbody>
<?php foreach ($data['departments'] as $d): ?>
<tr>
<td><?= $d['id'] ?></td>
<td><?= htmlspecialchars($d['name']) ?></td>
<td class="text-end">
<button class="btn btn-sm btn-outline-primary" data-bs-toggle="modal" data-bs-target="#editHrDepartmentModal<?= $d['id'] ?>"><i class="bi bi-pencil"></i></button>
<form method="POST" class="d-inline" onsubmit="return confirm('Are you sure?')">
<input type="hidden" name="id" value="<?= $d['id'] ?>">
<button type="submit" name="delete_hr_department" class="btn btn-sm btn-outline-danger"><i class="bi bi-trash"></i></button>
</form>
</td>
</tr>
<!-- Edit Dept Modal -->
<div class="modal fade" id="editHrDepartmentModal<?= $d['id'] ?>" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content border-0 shadow">
<div class="modal-header">
<h5 class="modal-title" data-en="Edit Department" data-ar="تعديل القسم">Edit Department</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<form method="POST">
<input type="hidden" name="id" value="<?= $d['id'] ?>">
<div class="modal-body">
<div class="mb-3">
<label class="form-label" data-en="Department Name" data-ar="اسم القسم">Department Name</label>
<input type="text" name="name" class="form-control" value="<?= htmlspecialchars($d['name']) ?>" required>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-light" data-bs-dismiss="modal" data-en="Cancel" data-ar="إلغاء">Cancel</button>
<button type="submit" name="edit_hr_department" class="btn btn-primary" data-en="Update" data-ar="تحديث">Update</button>
</div>
</form>
</div>
</div>
</div>
<?php endforeach; ?>
</tbody>
</table>
</div>
</div>
<?php elseif ($page === 'hr_employees'): ?>
<div class="card p-4">
<div class="d-flex justify-content-between align-items-center mb-4">
<h5 class="m-0" data-en="HR Employees" data-ar="موظفي الموارد البشرية">HR Employees</h5>
<button class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#addHrEmployeeModal">
<i class="bi bi-plus-lg"></i> <span data-en="Add Employee" data-ar="إضافة موظف">Add Employee</span>
</button>
</div>
<div class="table-responsive">
<table class="table table-hover align-middle">
<thead>
<tr>
<th data-en="Name" data-ar="الاسم">Name</th>
<th data-en="Biometric ID" data-ar="معرف البصمة">Biometric ID</th>
<th data-en="Department" data-ar="القسم">Department</th>
<th data-en="Position" data-ar="المنصب">Position</th>
<th data-en="Salary" data-ar="الراتب">Salary</th>
<th data-en="Status" data-ar="الحالة">Status</th>
<th data-en="Actions" data-ar="الإجراءات" class="text-end">Actions</th>
</tr>
</thead>
<tbody>
<?php foreach ($data['employees'] as $e): ?>
<tr>
<td>
<div class="fw-bold"><?= htmlspecialchars($e['name']) ?></div>
<div class="small text-muted"><?= htmlspecialchars($e['email']) ?></div>
</td>
<td><span class="badge bg-light text-dark border"><?= htmlspecialchars($e['biometric_id'] ?? '---') ?></span></td>
<td><?= htmlspecialchars($e['dept_name'] ?? '---') ?></td>
<td><?= htmlspecialchars($e['position']) ?></td>
<td>OMR <?= number_format($e['salary'], 3) ?></td>
<td>
<span class="badge <?= $e['status'] === 'active' ? 'bg-success' : 'bg-danger' ?> text-uppercase">
<?= $e['status'] ?>
</span>
</td>
<td class="text-end">
<button class="btn btn-sm btn-outline-primary" data-bs-toggle="modal" data-bs-target="#editHrEmployeeModal<?= $e['id'] ?>"><i class="bi bi-pencil"></i></button>
<form method="POST" class="d-inline" onsubmit="return confirm('Are you sure?')">
<input type="hidden" name="id" value="<?= $e['id'] ?>">
<button type="submit" name="delete_hr_employee" class="btn btn-sm btn-outline-danger"><i class="bi bi-trash"></i></button>
</form>
</td>
</tr>
<!-- Edit Employee Modal -->
<div class="modal fade" id="editHrEmployeeModal<?= $e['id'] ?>" tabindex="-1">
<div class="modal-dialog modal-lg">
<div class="modal-content border-0 shadow">
<div class="modal-header">
<h5 class="modal-title" data-en="Edit Employee" data-ar="تعديل الموظف">Edit Employee</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<form method="POST">
<input type="hidden" name="id" value="<?= $e['id'] ?>">
<div class="modal-body">
<div class="row g-3">
<div class="col-md-6">
<label class="form-label" data-en="Full Name" data-ar="الاسم الكامل">Full Name</label>
<input type="text" name="name" class="form-control" value="<?= htmlspecialchars($e['name']) ?>" required>
</div>
<div class="col-md-6">
<label class="form-label" data-en="Department" data-ar="القسم">Department</label>
<select name="department_id" class="form-select">
<option value="">--- Select ---</option>
<?php foreach ($data['departments'] as $d): ?>
<option value="<?= $d['id'] ?>" <?= $e['department_id'] == $d['id'] ? 'selected' : '' ?>><?= htmlspecialchars($d['name']) ?></option>
<?php endforeach; ?>
</select>
</div>
<div class="col-md-6">
<label class="form-label" data-en="Email" data-ar="البريد">Email</label>
<input type="email" name="email" class="form-control" value="<?= htmlspecialchars($e['email']) ?>">
</div>
<div class="col-md-6">
<label class="form-label" data-en="Phone" data-ar="الهاتف">Phone</label>
<input type="text" name="phone" class="form-control" value="<?= htmlspecialchars($e['phone']) ?>">
</div>
<div class="col-md-4">
<label class="form-label" data-en="Position" data-ar="المنصب">Position</label>
<input type="text" name="position" class="form-control" value="<?= htmlspecialchars($e['position']) ?>">
</div>
<div class="col-md-4">
<label class="form-label" data-en="Basic Salary" data-ar="الراتب الأساسي">Basic Salary</label>
<input type="number" step="0.001" name="salary" class="form-control" value="<?= $e['salary'] ?>">
</div>
<div class="col-md-4">
<label class="form-label" data-en="Biometric ID" data-ar="معرف البصمة">Biometric ID</label>
<input type="text" name="biometric_id" class="form-control" value="<?= htmlspecialchars($e['biometric_id'] ?? '') ?>">
</div>
<div class="col-md-4">
<label class="form-label" data-en="Joining Date" data-ar="تاريخ الانضمام">Joining Date</label>
<input type="date" name="joining_date" class="form-control" value="<?= $e['joining_date'] ?>">
</div>
<div class="col-md-4">
<label class="form-label" data-en="Status" data-ar="الحالة">Status</label>
<select name="status" class="form-select">
<option value="active" <?= $e['status'] === 'active' ? 'selected' : '' ?>>Active</option>
<option value="inactive" <?= $e['status'] === 'inactive' ? 'selected' : '' ?>>Inactive</option>
</select>
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-light" data-bs-dismiss="modal" data-en="Cancel" data-ar="إلغاء">Cancel</button>
<button type="submit" name="edit_hr_employee" class="btn btn-primary" data-en="Update" data-ar="تحديث">Update</button>
</div>
</form>
</div>
</div>
</div>
<?php endforeach; ?>
</tbody>
</table>
</div>
</div>
<?php elseif ($page === 'hr_attendance'): ?>
<div class="card p-4">
<div class="d-flex justify-content-between align-items-center mb-4">
<h5 class="m-0" data-en="HR Attendance" data-ar="حضور الموارد البشرية">HR Attendance</h5>
<div class="d-flex gap-2">
<form method="POST" class="d-inline">
<button type="submit" name="pull_biometric_data" class="btn btn-primary btn-sm">
<i class="bi bi-cloud-download"></i> <span data-en="Pull Data from Devices" data-ar="سحب البيانات من الأجهزة">Pull Data from Devices</span>
</button>
</form>
<button class="btn btn-outline-secondary btn-sm" data-bs-toggle="modal" data-bs-target="#biometricInfoModal">
<i class="bi bi-fingerprint"></i> <span data-en="Biometric Sync" data-ar="مزامنة البصمة">Biometric Sync</span>
</button>
<form method="GET" class="d-flex gap-2">
<input type="hidden" name="page" value="hr_attendance">
<input type="date" name="date" class="form-control form-control-sm" value="<?= $data['attendance_date'] ?>" onchange="this.form.submit()">
</form>
</div>
</div>
<div class="table-responsive">
<table class="table table-hover align-middle">
<thead>
<tr>
<th data-en="Employee" data-ar="الموظف">Employee</th>
<th data-en="Department" data-ar="القسم">Department</th>
<th data-en="Status" data-ar="الحالة">Status</th>
<th data-en="Clock In" data-ar="وقت الدخول">Clock In</th>
<th data-en="Clock Out" data-ar="وقت الخروج">Clock Out</th>
<th data-en="Action" data-ar="إجراء" class="text-end">Action</th>
</tr>
</thead>
<tbody>
<?php foreach ($data['employees'] as $e): ?>
<tr>
<td><?= htmlspecialchars($e['name']) ?></td>
<td><?= htmlspecialchars($e['dept_name'] ?? '---') ?></td>
<td>
<?php if ($e['status']): ?>
<span class="badge <?= $e['status'] === 'present' ? 'bg-success' : ($e['status'] === 'absent' ? 'bg-danger' : 'bg-warning') ?> text-uppercase">
<?= $e['status'] ?>
</span>
<?php else: ?>
<span class="badge bg-secondary text-uppercase">Not Marked</span>
<?php endif; ?>
</td>
<td><?= $e['clock_in'] ?? '---' ?></td>
<td><?= $e['clock_out'] ?? '---' ?></td>
<td class="text-end">
<button class="btn btn-sm btn-outline-primary" data-bs-toggle="modal" data-bs-target="#markAttendanceModal<?= $e['id'] ?>">
<i class="bi bi-calendar-check"></i> <span data-en="Mark" data-ar="تسجيل">Mark</span>
</button>
</td>
</tr>
<!-- Attendance Modal -->
<div class="modal fade" id="markAttendanceModal<?= $e['id'] ?>" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content border-0 shadow">
<div class="modal-header">
<h5 class="modal-title" data-en="Mark Attendance" data-ar="تسجيل الحضور">Mark Attendance - <?= htmlspecialchars($e['name']) ?></h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<form method="POST">
<input type="hidden" name="employee_id" value="<?= $e['id'] ?>">
<input type="hidden" name="attendance_date" value="<?= $data['attendance_date'] ?>">
<div class="modal-body">
<div class="mb-3">
<label class="form-label" data-en="Status" data-ar="الحالة">Status</label>
<select name="status" class="form-select">
<option value="present" <?= $e['status'] === 'present' ? 'selected' : '' ?>>Present</option>
<option value="absent" <?= $e['status'] === 'absent' ? 'selected' : '' ?>>Absent</option>
<option value="on_leave" <?= $e['status'] === 'on_leave' ? 'selected' : '' ?>>On Leave</option>
</select>
</div>
<div class="row g-3">
<div class="col-md-6">
<label class="form-label" data-en="Clock In" data-ar="وقت الدخول">Clock In</label>
<input type="time" name="clock_in" class="form-control" value="<?= $e['clock_in'] ?>">
</div>
<div class="col-md-6">
<label class="form-label" data-en="Clock Out" data-ar="وقت الخروج">Clock Out</label>
<input type="time" name="clock_out" class="form-control" value="<?= $e['clock_out'] ?>">
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-light" data-bs-dismiss="modal" data-en="Cancel" data-ar="إلغاء">Cancel</button>
<button type="submit" name="mark_attendance" class="btn btn-primary" data-en="Save" data-ar="حفظ">Save</button>
</div>
</form>
</div>
</div>
</div>
<?php endforeach; ?>
</tbody>
</table>
</div>
</div>
<!-- Biometric Info Modal -->
<div class="modal fade" id="biometricInfoModal" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content border-0 shadow">
<div class="modal-header">
<h5 class="modal-title" data-en="Biometric Integration Info" data-ar="معلومات تكامل البصمة">Biometric Integration Info</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body">
<p data-en="To sync attendance from your biometric device, use the following API endpoint:" data-ar="لمزامنة الحضور من جهاز البصمة الخاص بك، استخدم نقطة نهاية API التالية:">
To sync attendance from your biometric device, use the following API endpoint:
</p>
<div class="bg-light p-3 rounded mb-3 border">
<code><?= (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on' ? "https" : "http") . "://$_SERVER[HTTP_HOST]" ?>/api/biometric_sync.php</code>
</div>
<p data-en="Expected JSON format:" data-ar="تنسيق JSON المتوقع:">Expected JSON format:</p>
<pre class="bg-dark text-light p-3 rounded">
[
{
"biometric_id": "101",
"device_id": 1,
"timestamp": "2026-02-17 08:30:00",
"type": "in"
},
{
"biometric_id": "101",
"device_id": 1,
"timestamp": "2026-02-17 17:30:00",
"type": "out"
}
]
</pre>
<p class="small text-muted" data-en="Note: Ensure Employee Biometric IDs match those in the device logs." data-ar="ملاحظة: تأكد من مطابقة معرفات الموظفين الحيوية مع تلك الموجودة في سجلات الجهاز.">
Note: Ensure Employee Biometric IDs match those in the device logs.
</p>
</div>
</div>
</div>
</div>
<?php elseif ($page === 'hr_payroll'): ?>
<div class="card p-4">
<div class="d-flex justify-content-between align-items-center mb-4">
<h5 class="m-0" data-en="HR Payroll" data-ar="رواتب الموارد البشرية">HR Payroll</h5>
<div class="d-flex gap-2">
<form method="GET" class="d-flex gap-2">
<input type="hidden" name="page" value="hr_payroll">
<select name="month" class="form-select form-select-sm" onchange="this.form.submit()">
<?php for($m=1; $m<=12; $m++): ?>
<option value="<?= $m ?>" <?= $data['month'] == $m ? 'selected' : '' ?>><?= date('F', mktime(0, 0, 0, $m, 1)) ?></option>
<?php endfor; ?>
</select>
<select name="year" class="form-select form-select-sm" onchange="this.form.submit()">
<?php for($y=date('Y'); $y>=date('Y')-2; $y--): ?>
<option value="<?= $y ?>" <?= $data['year'] == $y ? 'selected' : '' ?>><?= $y ?></option>
<?php endfor; ?>
</select>
</form>
<button class="btn btn-primary btn-sm" data-bs-toggle="modal" data-bs-target="#generatePayrollModal">
<i class="bi bi-gear"></i> <span data-en="Generate" data-ar="توليد">Generate</span>
</button>
</div>
</div>
<div class="table-responsive">
<table class="table table-hover align-middle">
<thead>
<tr>
<th data-en="Employee" data-ar="الموظف">Employee</th>
<th data-en="Basic" data-ar="الأساسي">Basic</th>
<th data-en="Bonus" data-ar="مكافأة">Bonus</th>
<th data-en="Deductions" data-ar="استقطاعات">Deductions</th>
<th data-en="Net Salary" data-ar="صافي الراتب">Net Salary</th>
<th data-en="Status" data-ar="الحالة">Status</th>
<th data-en="Actions" data-ar="الإجراءات" class="text-end">Actions</th>
</tr>
</thead>
<tbody>
<?php foreach ($data['payroll'] as $p): ?>
<tr>
<td><?= htmlspecialchars($p['emp_name']) ?></td>
<td>OMR <?= number_format($p['basic_salary'], 3) ?></td>
<td class="text-success">+ OMR <?= number_format($p['bonus'], 3) ?></td>
<td class="text-danger">- OMR <?= number_format($p['deductions'], 3) ?></td>
<td class="fw-bold">OMR <?= number_format($p['net_salary'], 3) ?></td>
<td>
<span class="badge <?= $p['status'] === 'paid' ? 'bg-success' : 'bg-warning' ?> text-uppercase">
<?= $p['status'] ?>
</span>
</td>
<td class="text-end">
<?php if ($p['status'] === 'pending'): ?>
<form method="POST" class="d-inline">
<input type="hidden" name="id" value="<?= $p['id'] ?>">
<button type="submit" name="pay_payroll" class="btn btn-sm btn-success" title="Mark Paid"><i class="bi bi-check-circle"></i></button>
</form>
<?php endif; ?>
<form method="POST" class="d-inline" onsubmit="return confirm('Are you sure?')">
<input type="hidden" name="id" value="<?= $p['id'] ?>">
<button type="submit" name="delete_payroll" class="btn btn-sm btn-outline-danger"><i class="bi bi-trash"></i></button>
</form>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
</div>
<!-- Generate Payroll Modal -->
<div class="modal fade" id="generatePayrollModal" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content border-0 shadow">
<div class="modal-header">
<h5 class="modal-title" data-en="Generate Payroll" data-ar="توليد الرواتب">Generate Payroll</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<form method="POST">
<input type="hidden" name="month" value="<?= $data['month'] ?>">
<input type="hidden" name="year" value="<?= $data['year'] ?>">
<div class="modal-body">
<div class="mb-3">
<label class="form-label" data-en="Employee" data-ar="الموظف">Employee</label>
<select name="employee_id" class="form-select select2" required>
<option value="">--- Select ---</option>
<?php foreach ($data['employees'] as $e): ?>
<option value="<?= $e['id'] ?>"><?= htmlspecialchars($e['name']) ?> (Basic: <?= number_format($e['salary'], 3) ?>)</option>
<?php endforeach; ?>
</select>
</div>
<div class="row g-3">
<div class="col-md-6">
<label class="form-label" data-en="Bonus" data-ar="مكافأة">Bonus</label>
<input type="number" step="0.001" name="bonus" class="form-control" value="0.000">
</div>
<div class="col-md-6">
<label class="form-label" data-en="Deductions" data-ar="استقطاعات">Deductions</label>
<input type="number" step="0.001" name="deductions" class="form-control" value="0.000">
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-light" data-bs-dismiss="modal" data-en="Cancel" data-ar="إلغاء">Cancel</button>
<button type="submit" name="generate_payroll" class="btn btn-primary" data-en="Generate" data-ar="توليد">Generate</button>
</div>
</form>
</div>
</div>
</div>
<?php elseif ($page === 'devices'): ?>
<div class="card p-4">
<div class="d-flex justify-content-between align-items-center mb-4">
<h5 class="m-0" data-en="Biometric Devices" data-ar="أجهزة البصمة">Biometric Devices</h5>
<button class="btn btn-primary btn-sm" data-bs-toggle="modal" data-bs-target="#addDeviceModal">
<i class="bi bi-plus-circle"></i> <span data-en="Add Device" data-ar="إضافة جهاز">Add Device</span>
</button>
</div>
<div class="table-responsive">
<table class="table table-hover align-middle">
<thead>
<tr>
<th data-en="Device Name" data-ar="اسم الجهاز">Device Name</th>
<th data-en="IP / IO Address" data-ar="عنوان IP / IO">IP / IO Address</th>
<th data-en="Port" data-ar="المنفذ">Port</th>
<th data-en="Serial" data-ar="الرقم التسلسلي">Serial</th>
<th data-en="Last Sync" data-ar="آخر مزامنة">Last Sync</th>
<th data-en="Status" data-ar="الحالة">Status</th>
<th data-en="Actions" data-ar="الإجراءات" class="text-end">Actions</th>
</tr>
</thead>
<tbody>
<?php foreach ($data['devices'] as $d): ?>
<tr>
<td>
<strong><?= htmlspecialchars($d['device_name']) ?></strong>
</td>
<td>
<div><small class="text-muted">IP:</small> <?= htmlspecialchars($d['ip_address']) ?></div>
<?php if ($d['io_address']): ?>
<div><small class="text-muted">IO:</small> <?= htmlspecialchars($d['io_address']) ?></div>
<?php endif; ?>
</td>
<td><?= $d['port'] ?></td>
<td><?= htmlspecialchars($d['serial_number'] ?? '---') ?></td>
<td><?= $d['last_sync'] ?? 'Never' ?></td>
<td>
<span class="badge <?= $d['status'] === 'active' ? 'bg-success' : 'bg-danger' ?> text-uppercase">
<?= $d['status'] ?>
</span>
</td>
<td class="text-end">
<form method="POST" class="d-inline">
<input type="hidden" name="id" value="<?= $d['id'] ?>">
<button type="submit" name="test_device_connection" class="btn btn-sm btn-outline-info" title="Test Connection"><i class="bi bi-broadcast"></i></button>
</form>
<button class="btn btn-sm btn-outline-primary" data-bs-toggle="modal" data-bs-target="#editDeviceModal<?= $d['id'] ?>"><i class="bi bi-pencil"></i></button>
<form method="POST" class="d-inline" onsubmit="return confirm('Are you sure?')">
<input type="hidden" name="id" value="<?= $d['id'] ?>">
<button type="submit" name="delete_biometric_device" class="btn btn-sm btn-outline-danger"><i class="bi bi-trash"></i></button>
</form>
</td>
</tr>
<!-- Edit Device Modal -->
<div class="modal fade" id="editDeviceModal<?= $d['id'] ?>" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content border-0 shadow">
<div class="modal-header">
<h5 class="modal-title" data-en="Edit Device" data-ar="تعديل الجهاز">Edit Device</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<form method="POST">
<input type="hidden" name="id" value="<?= $d['id'] ?>">
<div class="modal-body">
<div class="mb-3">
<label class="form-label" data-en="Device Name" data-ar="اسم الجهاز">Device Name</label>
<input type="text" name="device_name" class="form-control" value="<?= htmlspecialchars($d['device_name']) ?>" required>
</div>
<div class="row g-3 mb-3">
<div class="col-md-8">
<label class="form-label" data-en="IP Address" data-ar="عنوان IP">IP Address</label>
<input type="text" name="ip_address" class="form-control" value="<?= htmlspecialchars($d['ip_address']) ?>" required>
</div>
<div class="col-md-4">
<label class="form-label" data-en="Port" data-ar="المنفذ">Port</label>
<input type="number" name="port" class="form-control" value="<?= $d['port'] ?>" required>
</div>
</div>
<div class="mb-3">
<label class="form-label" data-en="IO Address" data-ar="عنوان IO">IO Address</label>
<input type="text" name="io_address" class="form-control" value="<?= htmlspecialchars($d['io_address']) ?>">
</div>
<div class="mb-3">
<label class="form-label" data-en="Serial Number" data-ar="الرقم التسلسلي">Serial Number</label>
<input type="text" name="serial_number" class="form-control" value="<?= htmlspecialchars($d['serial_number']) ?>">
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-light" data-bs-dismiss="modal" data-en="Cancel" data-ar="إلغاء">Cancel</button>
<button type="submit" name="edit_biometric_device" class="btn btn-primary" data-en="Update" data-ar="تحديث">Update</button>
</div>
</form>
</div>
</div>
</div>
<?php endforeach; ?>
</tbody>
</table>
</div>
</div>
<!-- Add Device Modal -->
<div class="modal fade" id="addDeviceModal" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content border-0 shadow">
<div class="modal-header">
<h5 class="modal-title" data-en="Add Biometric Device" data-ar="إضافة جهاز بصمة">Add Biometric Device</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<form method="POST">
<div class="modal-body">
<div class="mb-3">
<label class="form-label" data-en="Device Name" data-ar="اسم الجهاز">Device Name</label>
<input type="text" name="device_name" class="form-control" required placeholder="e.g. Main Entrance">
</div>
<div class="row g-3 mb-3">
<div class="col-md-8">
<label class="form-label" data-en="IP Address" data-ar="عنوان IP">IP Address</label>
<input type="text" name="ip_address" class="form-control" required placeholder="192.168.1.201">
</div>
<div class="col-md-4">
<label class="form-label" data-en="Port" data-ar="المنفذ">Port</label>
<input type="number" name="port" class="form-control" value="4370" required>
</div>
</div>
<div class="mb-3">
<label class="form-label" data-en="IO Address" data-ar="عنوان IO">IO Address</label>
<input type="text" name="io_address" class="form-control" placeholder="Optional IO address">
</div>
<div class="mb-3">
<label class="form-label" data-en="Serial Number" data-ar="الرقم التسلسلي">Serial Number</label>
<input type="text" name="serial_number" class="form-control" placeholder="Device Serial Number">
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-light" data-bs-dismiss="modal" data-en="Cancel" data-ar="إلغاء">Cancel</button>
<button type="submit" name="add_biometric_device" class="btn btn-primary" data-en="Save" data-ar="حفظ">Save</button>
</div>
</form>
</div>
</div>
</div>
<?php elseif ($page === 'scale_devices'): ?>
<div class="card border-0 shadow-sm rounded-4 overflow-hidden">
<div class="card-header bg-white border-0 py-3 d-flex justify-content-between align-items-center">
<h5 class="mb-0 fw-bold" data-en="POS Devices" data-ar="أجهزة نقاط البيع">POS Devices</h5>
<button class="btn btn-primary rounded-3" data-bs-toggle="modal" data-bs-target="#addScaleDeviceModal">
<i class="fas fa-plus me-1"></i> <span data-en="Add Device" data-ar="إضافة جهاز">Add Device</span>
</button>
</div>
<div class="table-responsive">
<table class="table table-hover align-middle mb-0">
<thead class="bg-light">
<tr>
<th data-en="Device Name" data-ar="اسم الجهاز">Device Name</th>
<th data-en="Type" data-ar="النوع">Type</th>
<th data-en="Connection" data-ar="الاتصال">Connection</th>
<th data-en="Details" data-ar="التفاصيل">Details</th>
<th data-en="Status" data-ar="الحالة">Status</th>
<th class="text-end" data-en="Actions" data-ar="الإجراءات">Actions</th>
</tr>
</thead>
<tbody>
<?php foreach ($data['scale_devices'] as $d): ?>
<tr>
<td>
<div class="fw-bold"><?= htmlspecialchars($d['device_name']) ?></div>
</td>
<td>
<span class="badge bg-info-subtle text-info text-capitalize"><?= $d['device_type'] ?></span>
</td>
<td>
<span class="badge bg-secondary-subtle text-secondary text-uppercase"><?= $d['connection_type'] ?></span>
</td>
<td class="small text-muted">
<?php if ($d['connection_type'] === 'network'): ?>
<?= htmlspecialchars((string)$d['ip_address']) ?>:<?= $d['port'] ?>
<?php elseif ($d['connection_type'] === 'serial'): ?>
Baud: <?= $d['baud_rate'] ?>
<?php else: ?>
USB Interface
<?php endif; ?>
</td>
<td>
<span class="badge bg-<?= $d['status'] === 'active' ? 'success' : 'danger' ?>-subtle text-<?= $d['status'] === 'active' ? 'success' : 'danger' ?> text-capitalize"><?= $d['status'] ?></span>
</td>
<td class="text-end">
<button class="btn btn-sm btn-light rounded-pill px-3" data-bs-toggle="modal" data-bs-target="#editScaleDeviceModal<?= $d['id'] ?>">
<i class="fas fa-edit me-1"></i> <span data-en="Edit" data-ar="تعديل">Edit</span>
</button>
<form method="POST" class="d-inline" onsubmit="return confirm('Are you sure?')">
<input type="hidden" name="id" value="<?= $d['id'] ?>">
<button type="submit" name="delete_pos_device" class="btn btn-sm btn-outline-danger border-0 rounded-pill">
<i class="fas fa-trash"></i>
</button>
</form>
</td>
</tr>
<!-- Edit Device Modal -->
<div class="modal fade" id="editScaleDeviceModal<?= $d['id'] ?>" tabindex="-1">
<div class="modal-dialog border-0">
<div class="modal-content shadow border-0 rounded-4">
<div class="modal-header border-0">
<h5 class="modal-title fw-bold" data-en="Edit Device" data-ar="تعديل الجهاز">Edit Device</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<form method="POST">
<input type="hidden" name="id" value="<?= $d['id'] ?>">
<div class="modal-body">
<div class="mb-3">
<label class="form-label" data-en="Device Name" data-ar="اسم الجهاز">Device Name</label>
<input type="text" name="device_name" class="form-control" value="<?= htmlspecialchars($d['device_name']) ?>" required>
</div>
<div class="row g-3 mb-3">
<div class="col-md-6">
<label class="form-label" data-en="Device Type" data-ar="نوع الجهاز">Device Type</label>
<select name="device_type" class="form-select">
<option value="scale" <?= $d['device_type'] === 'scale' ? 'selected' : '' ?>>Weight Scale</option>
<option value="printer" <?= $d['device_type'] === 'printer' ? 'selected' : '' ?>>Receipt Printer</option>
<option value="display" <?= $d['device_type'] === 'display' ? 'selected' : '' ?>>Customer Display</option>
</select>
</div>
<div class="col-md-6">
<label class="form-label" data-en="Connection Type" data-ar="نوع الاتصال">Connection Type</label>
<select name="connection_type" class="form-select">
<option value="usb" <?= $d['connection_type'] === 'usb' ? 'selected' : '' ?>>USB</option>
<option value="network" <?= $d['connection_type'] === 'network' ? 'selected' : '' ?>>Network (TCP/IP)</option>
<option value="serial" <?= $d['connection_type'] === 'serial' ? 'selected' : '' ?>>Serial (RS232)</option>
</select>
</div>
</div>
<div class="row g-3 mb-3">
<div class="col-md-8">
<label class="form-label" data-en="IP Address" data-ar="عنوان IP">IP Address</label>
<input type="text" name="ip_address" class="form-control" value="<?= htmlspecialchars((string)$d['ip_address']) ?>">
</div>
<div class="col-md-4">
<label class="form-label" data-en="Port" data-ar="المنفذ">Port</label>
<input type="number" name="port" class="form-control" value="<?= $d['port'] ?>">
</div>
</div>
<div class="mb-3">
<label class="form-label" data-en="Baud Rate" data-ar="معدل الباود">Baud Rate</label>
<input type="number" name="baud_rate" class="form-control" value="<?= $d['baud_rate'] ?>">
</div>
<div class="mb-3">
<label class="form-label" data-en="Status" data-ar="الحالة">Status</label>
<select name="status" class="form-select">
<option value="active" <?= $d['status'] === 'active' ? 'selected' : '' ?>>Active</option>
<option value="inactive" <?= $d['status'] === 'inactive' ? 'selected' : '' ?>>Inactive</option>
</select>
</div>
</div>
<div class="modal-footer border-0">
<button type="button" class="btn btn-light" data-bs-dismiss="modal" data-en="Cancel" data-ar="إلغاء">Cancel</button>
<button type="submit" name="edit_pos_device" class="btn btn-primary" data-en="Update" data-ar="تحديث">Update</button>
</div>
</form>
</div>
</div>
</div>
<?php endforeach; ?>
</tbody>
</table>
</div>
</div>
<!-- Add Scale Device Modal -->
<div class="modal fade" id="addScaleDeviceModal" tabindex="-1">
<div class="modal-dialog border-0">
<div class="modal-content shadow border-0 rounded-4">
<div class="modal-header border-0">
<h5 class="modal-title fw-bold" data-en="Add POS Device" data-ar="إضافة جهاز">Add POS Device</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<form method="POST">
<div class="modal-body">
<div class="mb-3">
<label class="form-label" data-en="Device Name" data-ar="اسم الجهاز">Device Name</label>
<input type="text" name="device_name" class="form-control" required placeholder="e.g. Counter 1 Scale">
</div>
<div class="row g-3 mb-3">
<div class="col-md-6">
<label class="form-label" data-en="Device Type" data-ar="نوع الجهاز">Device Type</label>
<select name="device_type" class="form-select">
<option value="scale">Weight Scale</option>
<option value="printer">Receipt Printer</option>
<option value="display">Customer Display</option>
</select>
</div>
<div class="col-md-6">
<label class="form-label" data-en="Connection Type" data-ar="نوع الاتصال">Connection Type</label>
<select name="connection_type" class="form-select">
<option value="usb">USB</option>
<option value="network">Network (TCP/IP)</option>
<option value="serial">Serial (RS232)</option>
</select>
</div>
</div>
<div class="row g-3 mb-3">
<div class="col-md-8">
<label class="form-label" data-en="IP Address" data-ar="عنوان IP">IP Address</label>
<input type="text" name="ip_address" class="form-control" placeholder="192.168.1.50">
</div>
<div class="col-md-4">
<label class="form-label" data-en="Port" data-ar="المنفذ">Port</label>
<input type="number" name="port" class="form-control" placeholder="9100">
</div>
</div>
<div class="mb-3">
<label class="form-label" data-en="Baud Rate" data-ar="معدل الباود">Baud Rate</label>
<input type="number" name="baud_rate" class="form-control" placeholder="9600">
</div>
</div>
<div class="modal-footer border-0">
<button type="button" class="btn btn-light" data-bs-dismiss="modal" data-en="Cancel" data-ar="إلغاء">Cancel</button>
<button type="submit" name="add_pos_device" class="btn btn-primary" data-en="Save" data-ar="حفظ">Save</button>
</div>
</form>
</div>
</div>
</div>
<?php elseif ($page === 'my_profile'): ?>
<div class="row">
<div class="col-md-4">
<div class="card p-4 text-center border-0 shadow-sm rounded-4">
<h5 class="mb-4 fw-bold" data-en="Profile Picture" data-ar="صورة الملف الشخصي">Profile Picture</h5>
<div class="mb-3">
<?php if (!empty($data['user']['profile_pic'])): ?>
<img src="<?= htmlspecialchars($data['user']['profile_pic']) ?>?v=<?= time() ?>" alt="Profile" class="rounded-circle shadow-sm" style="width: 150px; height: 150px; object-fit: cover; border: 5px solid #fff;">
<?php else: ?>
<div class="rounded-circle bg-light d-inline-flex align-items-center justify-content-center shadow-sm" style="width: 150px; height: 150px; border: 5px solid #fff;">
<i class="bi bi-person text-muted" style="font-size: 5rem;"></i>
</div>
<?php endif; ?>
</div>
<div class="mt-3">
<h6 class="fw-bold mb-0"><?= htmlspecialchars($data['user']['username']) ?></h6>
<p class="text-muted small"><?= htmlspecialchars($_SESSION['user_role_name'] ?? 'User') ?></p>
</div>
</div>
</div>
<div class="col-md-8">
<div class="card p-4 border-0 shadow-sm rounded-4">
<h5 class="mb-4 fw-bold" data-en="Edit Profile" data-ar="تعديل الملف الشخصي">Edit Profile</h5>
<form method="POST" enctype="multipart/form-data">
<div class="row g-3">
<div class="col-md-6">
<label class="form-label fw-semibold" data-en="Username" data-ar="اسم المستخدم">Username</label>
<input type="text" name="username" class="form-control rounded-3" value="<?= htmlspecialchars($data['user']['username'] ?? '') ?>" required>
</div>
<div class="col-md-6">
<label class="form-label fw-semibold" data-en="Email" data-ar="البريد الإلكتروني">Email</label>
<input type="email" name="email" class="form-control rounded-3" value="<?= htmlspecialchars($data['user']['email'] ?? '') ?>">
</div>
<div class="col-md-6">
<label class="form-label fw-semibold" data-en="Phone" data-ar="الهاتف">Phone</label>
<input type="text" name="phone" class="form-control rounded-3" value="<?= htmlspecialchars($data['user']['phone'] ?? '') ?>">
</div>
<div class="col-md-6">
<label class="form-label fw-semibold" data-en="New Password" data-ar="كلمة مرور جديدة">New Password</label>
<input type="password" name="password" class="form-control rounded-3" placeholder="Leave blank to keep current">
</div>
<div class="col-md-6">
<label class="form-label fw-semibold" data-en="Change Profile Picture" data-ar="تغيير صورة الملف الشخصي">Change Profile Picture</label>
<input type="file" name="profile_pic" class="form-control rounded-3" accept="image/*">
</div>
<div class="col-md-12 mt-4">
<button type="submit" name="update_profile" class="btn btn-primary rounded-pill px-4">
<i class="bi bi-check-circle me-1"></i> <span data-en="Save Changes" data-ar="حفظ التغييرات">Save Changes</span>
</button>
</div>
</div>
</form>
</div>
</div>
</div>
<?php elseif ($page === 'settings'): ?>
<div class="card p-4">
<h5 class="mb-4" data-en="Company Profile" data-ar="ملف الشركة">Company Profile</h5>
<form method="POST" enctype="multipart/form-data">
<div class="row g-3">
<div class="col-md-6">
<label class="form-label" data-en="Company Name" data-ar="اسم الشركة">Company Name</label>
<input type="text" name="settings[company_name]" class="form-control" value="<?= htmlspecialchars($data['settings']['company_name'] ?? '') ?>">
</div>
<div class="col-md-6">
<label class="form-label" data-en="Phone" data-ar="الهاتف">Phone</label>
<input type="text" name="settings[company_phone]" class="form-control" value="<?= htmlspecialchars($data['settings']['company_phone'] ?? '') ?>">
</div>
<div class="col-md-6">
<label class="form-label" data-en="Email" data-ar="البريد الإلكتروني">Email</label>
<input type="email" name="settings[company_email]" class="form-control" value="<?= htmlspecialchars($data['settings']['company_email'] ?? '') ?>">
</div>
<div class="col-md-6">
<label class="form-label" data-en="VAT Number" data-ar="الرقم الضريبي">VAT Number</label>
<input type="text" name="settings[vat_number]" class="form-control" value="<?= htmlspecialchars($data['settings']['vat_number'] ?? '') ?>">
</div>
<div class="col-md-12">
<label class="form-label" data-en="Address" data-ar="العنوان">Address</label>
<textarea name="settings[company_address]" class="form-control" rows="3"><?= htmlspecialchars($data['settings']['company_address'] ?? '') ?></textarea>
</div>
<div class="col-md-4 mt-3">
<label class="form-label" data-en="Allow Selling Out of Stock" data-ar="السماح بالبيع عند نفاذ المخزون">Allow Selling Out of Stock</label>
<select name="settings[allow_zero_stock_sell]" class="form-select">
<option value="0" <?= ($data['settings']['allow_zero_stock_sell'] ?? '1') === '0' ? 'selected' : '' ?> data-en="Disabled" data-ar="معطل">Disabled</option>
<option value="1" <?= ($data['settings']['allow_zero_stock_sell'] ?? '1') === '1' ? 'selected' : '' ?> data-en="Enabled" data-ar="مفعل">Enabled</option>
</select>
</div>
<div class="col-md-4 mt-3">
<label class="form-label" data-en="Company Logo" data-ar="شعار الشركة">Company Logo</label>
<input type="file" name="company_logo" class="form-control" accept="image/*">
<?php if (!empty($data['settings']['company_logo'])): ?>
<div class="mt-2">
<img src="<?= htmlspecialchars($data['settings']['company_logo']) ?>?v=<?= time() ?>" alt="Logo" class="img-thumbnail" style="max-height: 80px;">
</div>
<?php endif; ?>
</div>
<div class="col-md-4">
<label class="form-label" data-en="Favicon" data-ar="أيقونة الموقع">Favicon</label>
<input type="file" name="favicon" class="form-control" accept="image/*">
<?php if (!empty($data['settings']['favicon'])): ?>
<div class="mt-2">
<img src="<?= htmlspecialchars($data['settings']['favicon']) ?>?v=<?= time() ?>" alt="Favicon" class="img-thumbnail" style="max-height: 32px;">
</div>
<?php endif; ?>
</div>
<div class="col-md-4">
<label class="form-label" data-en="Manager Signature" data-ar="توقيع المدير">Manager Signature</label>
<input type="file" name="manager_signature" class="form-control" accept="image/*">
<?php if (!empty($data['settings']['manager_signature'])): ?>
<div class="mt-2">
<img src="<?= htmlspecialchars($data['settings']['manager_signature']) ?>?v=<?= time() ?>" alt="Signature" class="img-thumbnail" style="max-height: 80px;">
</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>
</button>
</div>
</div>
</form>
</div>
<?php elseif ($page === 'role_groups'): ?>
<div class="card border-0 shadow-sm rounded-4 overflow-hidden">
<div class="card-header bg-white py-3 d-flex justify-content-between align-items-center border-0">
<div>
<h5 class="m-0 fw-bold text-primary" data-en="Role Groups" data-ar="مجموعات الأدوار">Role Groups</h5>
<p class="text-muted small mb-0" data-en="Manage access levels and permissions" data-ar="إدارة مستويات الوصول والصلاحيات">Manage access levels and permissions</p>
</div>
<button class="btn btn-primary rounded-pill px-4" data-bs-toggle="modal" data-bs-target="#addRoleGroupModal">
<i class="bi bi-shield-plus me-1"></i> <span data-en="Create New Group" data-ar="إنشاء مجموعة جديدة">Create New Group</span>
</button>
</div>
<div class="table-responsive">
<table class="table table-hover align-middle mb-0">
<thead class="bg-light">
<tr>
<th class="ps-4" data-en="Group Name" data-ar="اسم المجموعة">Group Name</th>
<th data-en="Created Date" data-ar="تاريخ الإنشاء">Created Date</th>
<th data-en="Status" data-ar="الحالة">Status</th>
<th data-en="Actions" data-ar="الإجراءات" class="text-end pe-4">Actions</th>
</tr>
</thead>
<tbody>
<?php foreach ($data['role_groups'] as $group): ?>
<tr>
<td class="ps-4">
<div class="d-flex align-items-center">
<div class="rounded-circle bg-primary bg-opacity-10 p-2 me-3 text-primary">
<i class="bi bi-shield-check"></i>
</div>
<span class="fw-semibold text-dark"><?= htmlspecialchars((string)$group['name']) ?></span>
</div>
</td>
<td><span class="text-muted small"><?= date('M d, Y', strtotime((string)$group['created_at'])) ?></span></td>
<td><span class="badge rounded-pill bg-success bg-opacity-10 text-success px-3">Active</span></td>
<td class="text-end pe-4">
<div class="dropdown">
<button class="btn btn-light btn-sm rounded-circle" type="button" data-bs-toggle="dropdown">
<i class="bi bi-three-dots-vertical"></i>
</button>
<ul class="dropdown-menu dropdown-menu-end shadow-sm border-0">
<?php if (can('users_edit')): ?>
<li><a class="dropdown-item" href="#" data-bs-toggle="modal" data-bs-target="#editRoleGroupModal<?= $group['id'] ?>"><i class="bi bi-pencil me-2 text-primary"></i> Edit Permissions</a></li>
<?php endif; ?>
<?php if (can('users_delete')): ?>
<li><hr class="dropdown-divider"></li>
<li>
<form method="POST" onsubmit="return confirm('Delete this role group? This cannot be undone.')">
<input type="hidden" name="id" value="<?= $group['id'] ?>">
<button type="submit" name="delete_role_group" class="dropdown-item text-danger"><i class="bi bi-trash me-2"></i> Delete Group</button>
</form>
</li>
<?php endif; ?>
</ul>
</div>
<!-- Edit Role Group Modal -->
<div class="modal fade" id="editRoleGroupModal<?= $group['id'] ?>" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content border-0 shadow text-start">
<div class="modal-header">
<h5 class="modal-title fw-bold" data-en="Edit Role Group" data-ar="تعديل مجموعة الأدوار">Edit Role Group</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<form method="POST">
<input type="hidden" name="id" value="<?= $group['id'] ?>">
<div class="modal-body">
<div class="mb-3">
<label class="form-label fw-semibold" data-en="Group Name" data-ar="اسم المجموعة">Group Name</label>
<input type="text" name="name" class="form-control" value="<?= htmlspecialchars($group['name']) ?>" required>
</div>
<div class="mb-3">
<label class="form-label fw-semibold" data-en="Permissions" data-ar="الصلاحيات">Permissions</label>
<div class="row overflow-auto" style="max-height: 300px;">
<?php
$perms = json_decode($group['permissions'] ?? '[]', true);
$modules = ['dashboard', 'pos', 'quotations', 'customers', 'suppliers', 'items', 'sales', 'purchases', 'accounting', 'hr', 'settings', 'users'];
$actions = ['view', 'add', 'edit', 'delete'];
foreach ($modules as $m): ?>
<div class="col-12 mt-2 border-bottom pb-1 mb-2">
<span class="badge bg-secondary text-uppercase"><?= ucfirst($m) ?></span>
</div>
<?php foreach ($actions as $a):
$p = $m . '_' . $a;
?>
<div class="col-3 mb-2">
<div class="form-check">
<input class="form-check-input" type="checkbox" name="permissions[]" value="<?= $p ?>" id="perm_<?= $group['id'] ?>_<?= $p ?>" <?= in_array($p, (array)$perms) ? 'checked' : '' ?>>
<label class="form-check-label small" for="perm_<?= $group['id'] ?>_<?= $p ?>"><?= ucfirst($a) ?></label>
</div>
</div>
<?php endforeach; ?>
<?php endforeach; ?>
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-light rounded-pill px-3" data-bs-dismiss="modal" data-en="Cancel" data-ar="إلغاء">Cancel</button>
<button type="submit" name="edit_role_group" class="btn btn-primary rounded-pill px-4" data-en="Update" data-ar="تحديث">Update</button>
</div>
</form>
</div>
</div>
</div>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
</div>
<?php elseif ($page === 'backups'): ?>
<div class="row g-4">
<div class="col-md-4">
<div class="card border-0 shadow-sm mb-4">
<div class="card-header bg-white py-3 border-0">
<h5 class="card-title mb-0" data-en="Backup Settings" data-ar="إعدادات النسخ الاحتياطي">Backup Settings</h5>
</div>
<div class="card-body">
<form method="POST">
<div class="mb-3">
<label class="form-label small fw-semibold" data-en="Keep Last N Backups" data-ar="الاحتفاظ بآخر N نسخ">Keep Last N Backups</label>
<input type="number" name="backup_limit" class="form-control" value="<?= htmlspecialchars($data['backup_settings']['backup_limit'] ?? '5') ?>" min="1" max="50">
</div>
<div class="mb-3">
<label class="form-label small fw-semibold" data-en="Auto Backup Time" data-ar="وقت النسخ التلقائي">Auto Backup Time</label>
<input type="time" name="backup_time" class="form-control" value="<?= htmlspecialchars($data['backup_settings']['backup_time'] ?? '00:00') ?>">
</div>
<div class="mb-4">
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" name="backup_auto_enabled" value="1" id="autoBackupSwitch" <?= ($data['backup_settings']['backup_auto_enabled'] ?? '0') === '1' ? 'checked' : '' ?>>
<label class="form-check-label small fw-semibold" for="autoBackupSwitch" data-en="Enable Automated Backups" data-ar="تفعيل النسخ الاحتياطي التلقائي">Enable Automated Backups</label>
</div>
<small class="text-muted" data-en="Requires a cron job running cron_backup.php every minute to respect the scheduled time." data-ar="يتطلب تعيين مهمة مجدولة (cron) لتشغيل cron_backup.php كل دقيقة للالتزام بالوقت المحدد.">Requires a cron job running cron_backup.php every minute to respect the scheduled time.</small>
</div>
<button type="submit" name="save_backup_settings" class="btn btn-primary w-100" data-en="Save Settings" data-ar="حفظ الإعدادات">Save Settings</button>
</form>
</div>
</div>
<div class="card border-0 shadow-sm">
<div class="card-body text-center py-4">
<div class="bg-primary bg-opacity-10 rounded-circle d-inline-flex align-items-center justify-content-center mb-3" style="width: 60px; height: 60px;">
<i class="bi bi-cloud-upload text-primary fs-3"></i>
</div>
<h5 data-en="Manual Backup" data-ar="نسخ يدوي">Manual Backup</h5>
<p class="text-muted small" data-en="Create a database backup immediately." data-ar="إنشاء نسخة احتياطية من قاعدة البيانات فوراً.">Create a database backup immediately.</p>
<form method="POST">
<button type="submit" name="create_backup" class="btn btn-outline-primary" data-en="Backup Now" data-ar="نسخ الآن">Backup Now</button>
</form>
</div>
</div>
</div>
<div class="col-md-8">
<div class="card border-0 shadow-sm">
<div class="card-header bg-white py-3 border-0 d-flex justify-content-between align-items-center">
<h5 class="card-title mb-0" data-en="Available Backups" data-ar="النسخ المتاحة">Available Backups</h5>
</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" data-en="Filename" data-ar="اسم الملف">Filename</th>
<th data-en="Size" data-ar="الحجم">Size</th>
<th data-en="Date" data-ar="التاريخ">Date</th>
<th class="text-end pe-4" data-en="Actions" data-ar="الإجراءات">Actions</th>
</tr>
</thead>
<tbody>
<?php if (empty($data['backups'])): ?>
<tr>
<td colspan="4" class="text-center py-4 text-muted" data-en="No backups found." data-ar="لا توجد نسخ احتياطية.">No backups found.</td>
</tr>
<?php else: ?>
<?php foreach ($data['backups'] as $b): ?>
<tr>
<td class="ps-4 fw-medium"><?= htmlspecialchars($b['name']) ?></td>
<td><?= htmlspecialchars($b['size']) ?></td>
<td><?= htmlspecialchars($b['date']) ?></td>
<td class="text-end pe-4">
<div class="btn-group">
<form method="POST" class="d-inline" onsubmit="return confirm('Restore this backup? Current data will be overwritten!');">
<input type="hidden" name="filename" value="<?= htmlspecialchars($b['name']) ?>">
<button type="submit" name="restore_backup" class="btn btn-sm btn-outline-success" title="Restore" data-en="Restore" data-ar="استعادة"><i class="bi bi-arrow-counterclockwise"></i></button>
</form>
<form method="POST" class="d-inline" onsubmit="return confirm('Permanently delete this backup?');">
<input type="hidden" name="filename" value="<?= htmlspecialchars($b['name']) ?>">
<button type="submit" name="delete_backup" class="btn btn-sm btn-outline-danger ms-1" title="Delete" data-en="Delete" data-ar="حذف"><i class="bi bi-trash"></i></button>
</form>
</div>
</td>
</tr>
<?php endforeach; ?>
<?php endif; ?>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
<?php elseif ($page === 'users'): ?>
<div class="card border-0 shadow-sm rounded-4 overflow-hidden">
<div class="card-header bg-white py-3 d-flex justify-content-between align-items-center border-0">
<div>
<h5 class="m-0 fw-bold text-primary" data-en="User Management" data-ar="إدارة المستخدمين">User Management</h5>
<p class="text-muted small mb-0" data-en="Maintain your team accounts and security" data-ar="صيانة حسابات فريقك وأمنها">Maintain your team accounts and security</p>
</div>
<?php if (can('users_add')): ?>
<button class="btn btn-primary rounded-pill px-4" data-bs-toggle="modal" data-bs-target="#addUserModal">
<i class="bi bi-person-plus me-1"></i> <span data-en="Invite User" data-ar="دعوة مستخدم">Invite User</span>
</button>
<?php endif; ?>
</div>
<div class="table-responsive">
<table class="table table-hover align-middle mb-0">
<thead class="bg-light">
<tr>
<th class="ps-4" data-en="User Info" data-ar="معلومات المستخدم">User Info</th>
<th data-en="Access Level" data-ar="مستوى الوصول">Access Level</th>
<th data-en="Contact" data-ar="الاتصال">Contact</th>
<th data-en="Status" data-ar="الحالة">Status</th>
<th data-en="Actions" data-ar="الإجراءات" class="text-end pe-4">Actions</th>
</tr>
</thead>
<tbody>
<?php foreach ($data['users'] as $u): ?>
<tr>
<td class="ps-4">
<div class="d-flex align-items-center">
<?php if (!empty($u['profile_pic'])): ?>
<img src="<?= htmlspecialchars((string)$u['profile_pic']) ?>?v=<?= time() ?>" alt="Avatar" class="rounded-circle me-3 shadow-sm" style="width: 35px; height: 35px; object-fit: cover;">
<?php else: ?>
<div class="avatar-sm bg-gradient-primary rounded-circle me-3 text-white d-flex align-items-center justify-content-center fw-bold" style="width: 35px; height: 35px; background: linear-gradient(135deg, #6e8efb, #a777e3);">
<?= strtoupper(substr((string)$u['username'], 0, 1)) ?>
</div>
<?php endif; ?>
<div>
<div class="fw-bold text-dark"><?= htmlspecialchars((string)$u['username']) ?></div>
<div class="text-muted small">ID: #<?= str_pad((string)$u['id'], 4, '0', STR_PAD_LEFT) ?></div>
</div>
</div>
</td>
<td>
<span class="badge rounded-pill bg-info bg-opacity-10 text-info px-3">
<?= htmlspecialchars((string)($u['group_name'] ?? 'No Role Assigned')) ?>
</span>
</td>
<td>
<div class="text-dark small mb-1"><i class="bi bi-envelope me-1"></i> <?= htmlspecialchars((string)($u['email'] ?? '')) ?></div>
<div class="text-muted small"><i class="bi bi-phone me-1"></i> <?= htmlspecialchars((string)($u['phone'] ?? '-')) ?></div>
</td>
<td>
<?php if ($u['status'] === 'active'): ?>
<span class="badge rounded-pill bg-success bg-opacity-10 text-success px-3">Active</span>
<?php else: ?>
<span class="badge rounded-pill bg-secondary bg-opacity-10 text-secondary px-3">Suspended</span>
<?php endif; ?>
</td>
<td class="text-end pe-4">
<div class="dropdown">
<button class="btn btn-light btn-sm rounded-circle" type="button" data-bs-toggle="dropdown">
<i class="bi bi-three-dots-vertical"></i>
</button>
<ul class="dropdown-menu dropdown-menu-end shadow-sm border-0">
<?php if (can('users_edit')): ?>
<li><a class="dropdown-item" href="#" data-bs-toggle="modal" data-bs-target="#editUserModal<?= $u['id'] ?>"><i class="bi bi-pencil me-2 text-primary"></i> Edit Profile</a></li>
<?php endif; ?>
<?php if (can('users_delete')): ?>
<li><hr class="dropdown-divider"></li>
<li>
<form method="POST" onsubmit="return confirm('Deactivate this user account?')">
<input type="hidden" name="id" value="<?= $u['id'] ?>">
<button type="submit" name="delete_user" class="dropdown-item text-danger"><i class="bi bi-trash me-2"></i> Remove Access</button>
</form>
</li>
<?php endif; ?>
</ul>
</div>
<!-- Edit User Modal -->
<div class="modal fade" id="editUserModal<?= $u['id'] ?>" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content border-0 shadow text-start">
<div class="modal-header">
<h5 class="modal-title fw-bold" data-en="Edit User Account" data-ar="تعديل حساب المستخدم">Edit User Account</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<form method="POST">
<input type="hidden" name="id" value="<?= $u['id'] ?>">
<div class="modal-body">
<div class="mb-3">
<label class="form-label fw-semibold" data-en="Username" data-ar="اسم المستخدم">Username</label>
<input type="text" name="username" class="form-control" value="<?= htmlspecialchars((string)$u['username']) ?>" required>
</div>
<div class="mb-3">
<label class="form-label fw-semibold" data-en="Email Address" data-ar="البريد الإلكتروني">Email Address</label>
<input type="email" name="email" class="form-control" value="<?= htmlspecialchars((string)($u['email'] ?? '')) ?>">
</div>
<div class="mb-3">
<label class="form-label fw-semibold" data-en="Phone Number" data-ar="رقم الهاتف">Phone Number</label>
<input type="text" name="phone" class="form-control" value="<?= htmlspecialchars((string)($u['phone'] ?? '')) ?>">
</div>
<div class="mb-3">
<label class="form-label fw-semibold" data-en="Assign Role Group" data-ar="تعيين مجموعة الأدوار">Assign Role Group</label>
<select name="group_id" class="form-select">
<option value="">--- No Group ---</option>
<?php foreach (($data['role_groups'] ?? []) as $g): ?>
<option value="<?= $g['id'] ?>" <?= ($u['group_id'] ?? null) == $g['id'] ? 'selected' : '' ?>><?= htmlspecialchars((string)$g['name']) ?></option>
<?php endforeach; ?>
</select>
</div>
<div class="mb-3">
<label class="form-label fw-semibold" data-en="Account Status" data-ar="حالة الحساب">Account Status</label>
<select name="status" class="form-select">
<option value="active" <?= $u['status'] === 'active' ? 'selected' : '' ?>>Active</option>
<option value="inactive" <?= $u['status'] === 'inactive' ? 'selected' : '' ?>>Inactive</option>
</select>
</div>
<div class="mb-3">
<label class="form-label fw-semibold" data-en="New Password" data-ar="كلمة مرور جديدة">New Password</label>
<input type="password" name="password" class="form-control" placeholder="Leave blank to keep current" autocomplete="new-password">
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-light rounded-pill px-3" data-bs-dismiss="modal" data-en="Cancel" data-ar="إلغاء">Cancel</button>
<button type="submit" name="edit_user" class="btn btn-primary rounded-pill px-4" data-en="Save Changes" data-ar="حفظ التغييرات">Save Changes</button>
</div>
</form>
</div>
</div>
</div>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
</div>
<?php elseif ($page === 'cash_registers'): ?>
<div class="card p-4 rounded-4 shadow-sm border-0">
<div class="d-flex justify-content-between align-items-center mb-4">
<div>
<h5 class="m-0 fw-bold text-primary" data-en="Cash Registers Management" data-ar="إدارة خزائن الكاشير">Cash Registers Management</h5>
<p class="text-muted small mb-0">Define your shop counters and registers.</p>
</div>
<button class="btn btn-primary rounded-pill px-4" data-bs-toggle="modal" data-bs-target="#addRegisterModal">
<i class="bi bi-plus-lg me-2"></i> <span data-en="Add Register" data-ar="إضافة خزينة">Add Register</span>
</button>
</div>
<div class="table-responsive">
<table class="table table-hover align-middle">
<thead>
<tr>
<th data-en="ID" data-ar="المعرف">ID</th>
<th data-en="Name" data-ar="الاسم">Name</th>
<th data-en="Status" data-ar="الحالة">Status</th>
<th data-en="Created At" data-ar="تاريخ الإنشاء">Created At</th>
<th class="text-end" data-en="Actions" data-ar="الإجراءات">Actions</th>
</tr>
</thead>
<tbody>
<?php foreach ($data['cash_registers'] as $r): ?>
<tr>
<td>#<?= $r['id'] ?></td>
<td class="fw-bold"><?= htmlspecialchars($r['name']) ?></td>
<td>
<span class="badge rounded-pill <?= $r['status'] === 'active' ? 'bg-success' : 'bg-danger' ?>">
<?= ucfirst($r['status']) ?>
</span>
</td>
<td><?= $r['created_at'] ?></td>
<td class="text-end">
<button class="btn btn-sm btn-light rounded-circle" data-bs-toggle="modal" data-bs-target="#editRegisterModal<?= $r['id'] ?>"><i class="bi bi-pencil text-primary"></i></button>
<form method="POST" class="d-inline" onsubmit="return confirm('Are you sure?')">
<input type="hidden" name="id" value="<?= $r['id'] ?>">
<button type="submit" name="delete_cash_register" class="btn btn-sm btn-light rounded-circle"><i class="bi bi-trash text-danger"></i></button>
</form>
<!-- Edit Modal -->
<div class="modal fade" id="editRegisterModal<?= $r['id'] ?>" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content border-0 shadow">
<div class="modal-header">
<h5 class="modal-title">Edit Register</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<form method="POST">
<div class="modal-body text-start">
<input type="hidden" name="id" value="<?= $r['id'] ?>">
<div class="mb-3">
<label class="form-label">Register Name</label>
<input type="text" name="name" class="form-control" value="<?= htmlspecialchars($r['name']) ?>" required>
</div>
<div class="mb-3">
<label class="form-label">Status</label>
<select name="status" class="form-select">
<option value="active" <?= $r['status'] === 'active' ? 'selected' : '' ?>>Active</option>
<option value="inactive" <?= $r['status'] === 'inactive' ? 'selected' : '' ?>>Inactive</option>
</select>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-light" data-bs-dismiss="modal">Cancel</button>
<button type="submit" name="edit_cash_register" class="btn btn-primary">Save Changes</button>
</div>
</form>
</div>
</div>
</div>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
</div>
<!-- Add Modal -->
<div class="modal fade" id="addRegisterModal" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content border-0 shadow">
<div class="modal-header">
<h5 class="modal-title">Add Cash Register</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<form method="POST">
<div class="modal-body">
<div class="mb-3">
<label class="form-label">Register Name</label>
<input type="text" name="name" class="form-control" placeholder="Counter 1" required>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-light" data-bs-dismiss="modal">Cancel</button>
<button type="submit" name="add_cash_register" class="btn btn-primary">Add Register</button>
</div>
</form>
</div>
</div>
</div>
<?php elseif ($page === 'register_sessions'): ?>
<div class="card p-4 rounded-4 shadow-sm border-0 mb-4">
<div class="d-flex justify-content-between align-items-center mb-4">
<div>
<h5 class="m-0 fw-bold text-primary" data-en="Register Sessions" data-ar="جلسات الكاشير">Register Sessions</h5>
<p class="text-muted small mb-0">Manage daily opening and closing of cash registers.</p>
</div>
<div>
<?php
$active_session = db()->prepare("SELECT s.*, r.name as register_name FROM register_sessions s JOIN cash_registers r ON s.register_id = r.id WHERE s.user_id = ? AND s.status = 'open'");
$active_session->execute([$_SESSION['user_id']]);
$session = $active_session->fetch();
?>
<?php if (!$session): ?>
<button class="btn btn-success rounded-pill px-4" data-bs-toggle="modal" data-bs-target="#openRegisterModal">
<i class="bi bi-unlock me-2"></i> <span data-en="Open Register" data-ar="فتح الخزينة">Open Register</span>
</button>
<?php else: ?>
<button class="btn btn-danger rounded-pill px-4" data-bs-toggle="modal" data-bs-target="#closeRegisterModal">
<i class="bi bi-lock me-2"></i> <span data-en="Close Register" data-ar="إغلاق الخزينة">Close Register</span>
</button>
<?php endif; ?>
</div>
</div>
<?php if ($session): ?>
<div class="alert alert-info border-0 shadow-sm d-flex justify-content-between align-items-center mb-4">
<div>
<i class="bi bi-info-circle-fill me-2"></i>
Current Open Register: <strong><?= htmlspecialchars($session['register_name']) ?></strong> |
Opened At: <strong><?= $session['opened_at'] ?></strong> |
Opening Balance: <strong>OMR <?= number_format((float)$session['opening_balance'], 3) ?></strong>
</div>
<div>
<a href="index.php?page=pos" class="btn btn-sm btn-primary rounded-pill px-3">Go to POS</a>
</div>
</div>
<?php endif; ?>
<div class="table-responsive">
<table class="table table-hover align-middle">
<thead>
<tr>
<th data-en="Register" data-ar="الخزينة">Register</th>
<th data-en="Cashier" data-ar="الكاشير">Cashier</th>
<th data-en="Opened At" data-ar="وقت الفتح">Opened At</th>
<th data-en="Closed At" data-ar="وقت الإغلاق">Closed At</th>
<th data-en="Opening Bal." data-ar="رصيد الافتتاح">Opening Bal.</th>
<th data-en="Expected Bal." data-ar="الرصيد المتوقع">Expected Bal.</th>
<th data-en="Cash in Hand" data-ar="النقد الفعلي">Cash in Hand</th>
<th data-en="Difference" data-ar="الفرق">Difference</th>
<th data-en="Status" data-ar="الحالة">Status</th>
<th class="text-end" data-en="Report" data-ar="تقرير">Report</th>
</tr>
</thead>
<tbody>
<?php foreach ($data['sessions'] as $s): ?>
<tr>
<td class="fw-bold"><?= htmlspecialchars($s['register_name']) ?></td>
<td><?= htmlspecialchars($s['username']) ?></td>
<td><?= $s['opened_at'] ?></td>
<td><?= $s['closed_at'] ?? '---' ?></td>
<td>OMR <?= number_format((float)$s['opening_balance'], 3) ?></td>
<td>OMR <?= number_format((float)($s['closing_balance'] ?? 0), 3) ?></td>
<td>OMR <?= number_format((float)($s['cash_in_hand'] ?? 0), 3) ?></td>
<td>
<?php if ($s['status'] === 'closed'):
$diff = $s['cash_in_hand'] - $s['closing_balance'];
$color = $diff == 0 ? 'text-success' : ($diff > 0 ? 'text-info' : 'text-danger');
?>
<span class="<?= $color ?> fw-bold">OMR <?= number_format($diff, 3) ?></span>
<?php else: ?>---<?php endif; ?>
</td>
<td>
<span class="badge rounded-pill <?= $s['status'] === 'open' ? 'bg-success' : 'bg-secondary' ?>">
<?= ucfirst($s['status']) ?>
</span>
</td>
<td class="text-end">
<button class="btn btn-sm btn-light rounded-circle" data-bs-toggle="modal" data-bs-target="#sessionReportModal<?= $s['id'] ?>"><i class="bi bi-file-earmark-text text-primary"></i></button>
<!-- Session Report Modal -->
<div class="modal fade" id="sessionReportModal<?= $s['id'] ?>" tabindex="-1">
<div class="modal-dialog modal-lg">
<div class="modal-content border-0 shadow">
<div class="modal-header">
<h5 class="modal-title">Session Cashflow Report (#<?= $s['id'] ?>)</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body text-start">
<div class="row g-3">
<div class="col-md-6">
<p class="mb-1 text-muted small">Register</p>
<h6><?= htmlspecialchars($s['register_name']) ?></h6>
</div>
<div class="col-md-6">
<p class="mb-1 text-muted small">Cashier</p>
<h6><?= htmlspecialchars($s['username']) ?></h6>
</div>
<div class="col-md-6">
<p class="mb-1 text-muted small">Opened At</p>
<h6><?= $s['opened_at'] ?></h6>
</div>
<div class="col-md-6">
<p class="mb-1 text-muted small">Closed At</p>
<h6><?= $s['closed_at'] ?? 'Still Open' ?></h6>
</div>
</div>
<hr>
<div class="d-flex justify-content-between mb-2">
<span>Opening Balance:</span>
<span>OMR <?= number_format((float)$s['opening_balance'], 3) ?></span>
</div>
<?php
// Breakdown of sales by payment method
$breakdown = db()->prepare("SELECT p.payment_method, SUM(p.amount) as total FROM pos_payments p JOIN pos_transactions t ON p.transaction_id = t.id WHERE t.register_session_id = ? AND t.status = 'completed' GROUP BY p.payment_method");
$breakdown->execute([$s['id']]);
$methods = $breakdown->fetchAll();
$total_sales = 0;
foreach ($methods as $m): $total_sales += $m['total']; ?>
<div class="d-flex justify-content-between mb-2">
<span class="text-uppercase">Sales (<?= htmlspecialchars($m['payment_method']) ?>):</span>
<span>OMR <?= number_format((float)$m['total'], 3) ?></span>
</div>
<?php endforeach; ?>
<div class="d-flex justify-content-between mb-2 fw-bold border-top pt-2">
<span>Total Sales:</span>
<span>OMR <?= number_format($total_sales, 3) ?></span>
</div>
<hr>
<div class="d-flex justify-content-between mb-2 h5 text-primary">
<span>Expected Cash in Hand:</span>
<span>OMR <?= number_format((float)($s['closing_balance'] ?? 0), 3) ?></span>
</div>
<div class="d-flex justify-content-between mb-2 h5 text-success">
<span>Actual Cash in Hand:</span>
<span>OMR <?= number_format((float)($s['cash_in_hand'] ?? 0), 3) ?></span>
</div>
<div class="d-flex justify-content-between mb-2 h5 <?= ($s['cash_in_hand'] - $s['closing_balance']) >= 0 ? 'text-info' : 'text-danger' ?>">
<span>Difference:</span>
<span>OMR <?= number_format((float)(($s['cash_in_hand'] ?? 0) - ($s['closing_balance'] ?? 0)), 3) ?></span>
</div>
<hr>
<h6 class="fw-bold mb-3">Detailed Transactions by Method</h6>
<?php
foreach ($methods as $m):
$details = db()->prepare("SELECT t.transaction_no, t.created_at, p.amount FROM pos_payments p JOIN pos_transactions t ON p.transaction_id = t.id WHERE t.register_session_id = ? AND t.status = 'completed' AND p.payment_method = ?");
$details->execute([$s['id'], $m['payment_method']]);
$trans = $details->fetchAll();
?>
<div class="mb-4">
<div class="bg-light p-2 mb-2 d-flex justify-content-between align-items-center rounded border-start border-4 <?= strtolower($m['payment_method']) === 'cash' ? 'border-success' : 'border-primary' ?>">
<span class="text-uppercase fw-bold small"><?= htmlspecialchars($m['payment_method']) ?></span>
<span class="badge bg-white text-dark border rounded-pill">OMR <?= number_format((float)$m['total'], 3) ?></span>
</div>
<table class="table table-sm table-hover small mb-0">
<thead>
<tr class="text-muted border-bottom">
<th>TX #</th>
<th>Time</th>
<th class="text-end">Amount</th>
</tr>
</thead>
<tbody>
<?php foreach ($trans as $tr): ?>
<tr>
<td><?= htmlspecialchars($tr['transaction_no']) ?></td>
<td><?= date('H:i', strtotime($tr['created_at'])) ?></td>
<td class="text-end">OMR <?= number_format((float)$tr['amount'], 3) ?></td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
<?php endforeach; ?>
<?php if ($s['notes']): ?>
<hr>
<p class="mb-1 text-muted small">Notes:</p>
<p class="mb-0 small bg-light p-2 rounded"><?= nl2br(htmlspecialchars($s['notes'])) ?></p>
<?php endif; ?>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" onclick="window.print()">Print Report</button>
<button type="button" class="btn btn-light" data-bs-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
</div>
<!-- Open Register Modal -->
<div class="modal fade" id="openRegisterModal" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content border-0 shadow">
<div class="modal-header">
<h5 class="modal-title">Open Register Session</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<form method="POST">
<div class="modal-body">
<div class="mb-3">
<label class="form-label">Select Register / Counter</label>
<select name="register_id" class="form-select" required>
<?php foreach ($data['cash_registers'] as $reg): ?>
<option value="<?= $reg['id'] ?>"><?= htmlspecialchars($reg['name']) ?></option>
<?php endforeach; ?>
</select>
</div>
<div class="mb-3">
<label class="form-label">Opening Cash Balance (OMR)</label>
<input type="number" step="0.001" name="opening_balance" class="form-control" value="0.000" required>
<div class="form-text">Enter the amount of cash already in the drawer.</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-light" data-bs-dismiss="modal">Cancel</button>
<button type="submit" name="open_register" class="btn btn-success">Open Register</button>
</div>
</form>
</div>
</div>
</div>
<!-- Close Register Modal -->
<?php if ($session): ?>
<div class="modal fade" id="closeRegisterModal" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content border-0 shadow">
<div class="modal-header">
<h5 class="modal-title">Close Register Session (#<?= $session['id'] ?>)</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<form method="POST">
<div class="modal-body">
<input type="hidden" name="session_id" value="<?= $session['id'] ?>">
<div class="alert alert-warning py-2 small border-0 shadow-sm">
<i class="bi bi-exclamation-triangle me-2"></i> Before closing, please count all cash in your register.
</div>
<?php
$curBreakdown = db()->prepare("SELECT p.payment_method, SUM(p.amount) as total FROM pos_payments p JOIN pos_transactions t ON p.transaction_id = t.id WHERE t.register_session_id = ? AND t.status = 'completed' GROUP BY p.payment_method");
$curBreakdown->execute([$session['id']]);
$curMethods = $curBreakdown->fetchAll();
$curCashSales = 0;
foreach($curMethods as $cm) if(strtolower($cm['payment_method']) === 'cash') $curCashSales = (float)$cm['total'];
?>
<div class="card bg-light border-0 mb-3 small">
<div class="card-body">
<h6 class="card-title fw-bold small text-uppercase mb-2">Session Summary</h6>
<div class="d-flex justify-content-between mb-1">
<span class="text-muted">Opening Cash:</span>
<span class="fw-bold">OMR <?= number_format((float)$session['opening_balance'], 3) ?></span>
</div>
<div class="d-flex justify-content-between mb-1">
<span class="text-muted">Cash Sales:</span>
<span class="fw-bold">OMR <?= number_format($curCashSales, 3) ?></span>
</div>
<hr class="my-2">
<div class="d-flex justify-content-between fw-bold text-primary mb-2">
<span>Expected Cash in Hand:</span>
<span>OMR <?= number_format((float)$session['opening_balance'] + $curCashSales, 3) ?></span>
</div>
<?php $hasOther = false; foreach($curMethods as $cm): if(strtolower($cm['payment_method']) !== 'cash'): $hasOther = true; ?>
<div class="d-flex justify-content-between mt-1 text-muted border-top pt-1">
<span><?= htmlspecialchars($cm['payment_method']) ?> Total:</span>
<span>OMR <?= number_format((float)$cm['total'], 3) ?></span>
</div>
<?php endif; endforeach; ?>
</div>
</div>
<div class="mb-3">
<label class="form-label">Total Cash in Hand (Actual Counted)</label>
<input type="number" step="0.001" name="cash_in_hand" class="form-control" required placeholder="0.000">
</div>
<div class="mb-3">
<label class="form-label">Closing Notes / Comments</label>
<textarea name="notes" class="form-control" rows="3" placeholder="Any discrepancies or remarks..."></textarea>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-light" data-bs-dismiss="modal">Cancel</button>
<button type="submit" name="close_register" class="btn btn-danger">Close Register & Submit</button>
</div>
</form>
</div>
</div>
</div>
<?php endif; ?>
<?php elseif ($page === 'logs'): ?>
<div class="card border-0 shadow-sm rounded-4 overflow-hidden">
<div class="card-header bg-white py-3 d-flex justify-content-between align-items-center border-0">
<div>
<h5 class="m-0 fw-bold text-primary" data-en="System Logs" data-ar="سجلات النظام">System Logs</h5>
<p class="text-muted small mb-0" data-en="Monitor system activity and errors" data-ar="مراقبة نشاط النظام والأخطاء">Monitor system activity and errors</p>
</div>
<div class="d-flex gap-2">
<button onclick="window.location.reload()" class="btn btn-outline-primary btn-sm rounded-pill">
<i class="bi bi-arrow-clockwise"></i> Refresh
</button>
</div>
</div>
<div class="card-body p-0">
<div class="bg-dark text-light p-4 font-monospace small" style="max-height: 600px; overflow-y: auto;">
<?php
$log_files = ['error_log', 'login_debug.log', 'post_debug.log'];
$found_logs = false;
foreach ($log_files as $file) {
$path = __DIR__ . '/' . $file;
if (file_exists($path) && is_readable($path)) {
$found_logs = true;
echo "<div class='mb-4'><h6 class='text-warning border-bottom border-secondary pb-2'>--- " . htmlspecialchars(basename($file)) . " ---</h6>";
$lines = shell_exec("tail -n 50 " . escapeshellarg($path));
echo "<pre class='mb-0 text-info'>" . htmlspecialchars((string)$lines) . "</pre></div>";
}
}
if (!$found_logs) {
echo "<div class='text-center py-5'><i class='bi bi-journal-x fs-1 opacity-25'></i><p class='mt-2 opacity-50'>No accessible log files found.</p></div>";
}
?>
</div>
</div>
</div>
<?php endif; ?>
</div>
<!-- Add HR Department Modal -->
<div class="modal fade" id="addHrDepartmentModal" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content border-0 shadow">
<div class="modal-header">
<h5 class="modal-title" data-en="Add HR Department" data-ar="إضافة قسم">Add HR Department</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<form method="POST">
<div class="modal-body">
<div class="mb-3">
<label class="form-label" data-en="Department Name" data-ar="اسم القسم">Department Name</label>
<input type="text" name="name" class="form-control" required>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-light" data-bs-dismiss="modal" data-en="Cancel" data-ar="إلغاء">Cancel</button>
<button type="submit" name="add_hr_department" class="btn btn-primary" data-en="Save" data-ar="حفظ">Save</button>
</div>
</form>
</div>
</div>
</div>
<!-- Add HR Employee Modal -->
<div class="modal fade" id="addHrEmployeeModal" tabindex="-1">
<div class="modal-dialog modal-lg">
<div class="modal-content border-0 shadow">
<div class="modal-header">
<h5 class="modal-title" data-en="Add HR Employee" data-ar="إضافة موظف">Add HR Employee</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<form method="POST">
<div class="modal-body">
<div class="row g-3">
<div class="col-md-6">
<label class="form-label" data-en="Full Name" data-ar="الاسم الكامل">Full Name</label>
<input type="text" name="name" class="form-control" required>
</div>
<div class="col-md-6">
<label class="form-label" data-en="Department" data-ar="القسم">Department</label>
<select name="department_id" class="form-select">
<option value="">--- Select ---</option>
<?php foreach ($data['departments'] ?? [] as $d): ?>
<option value="<?= $d['id'] ?>"><?= htmlspecialchars($d['name']) ?></option>
<?php endforeach; ?>
</select>
</div>
<div class="col-md-6">
<label class="form-label" data-en="Email" data-ar="البريد">Email</label>
<input type="email" name="email" class="form-control">
</div>
<div class="col-md-6">
<label class="form-label" data-en="Phone" data-ar="الهاتف">Phone</label>
<input type="text" name="phone" class="form-control">
</div>
<div class="col-md-4">
<label class="form-label" data-en="Position" data-ar="المنصب">Position</label>
<input type="text" name="position" class="form-control">
</div>
<div class="col-md-4">
<label class="form-label" data-en="Basic Salary" data-ar="الراتب الأساسي">Basic Salary</label>
<input type="number" step="0.001" name="salary" class="form-control" value="0.000">
</div>
<div class="col-md-4">
<label class="form-label" data-en="Biometric ID" data-ar="معرف البصمة">Biometric ID</label>
<input type="text" name="biometric_id" class="form-control">
</div>
<div class="col-md-4">
<label class="form-label" data-en="Joining Date" data-ar="تاريخ الانضمام">Joining Date</label>
<input type="date" name="joining_date" class="form-control" value="<?= date('Y-m-d') ?>">
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-light" data-bs-dismiss="modal" data-en="Cancel" data-ar="إلغاء">Cancel</button>
<button type="submit" name="add_hr_employee" class="btn btn-primary" data-en="Save" data-ar="حفظ">Save</button>
</div>
</form>
</div>
</div>
</div>
<!-- Add Role Group Modal -->
<div class="modal fade" id="addRoleGroupModal" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content border-0 shadow">
<div class="modal-header">
<h5 class="modal-title" data-en="Add Role Group" data-ar="إضافة مجموعة أدوار">Add Role Group</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<form method="POST">
<div class="modal-body">
<div class="mb-3">
<label class="form-label" data-en="Group Name" data-ar="اسم المجموعة">Group Name</label>
<input type="text" name="name" class="form-control" required>
</div>
<div class="mb-3">
<label class="form-label" data-en="Permissions" data-ar="الصلاحيات">Permissions</label>
<div class="row overflow-auto" style="max-height: 300px;">
<?php
$modules = ['dashboard', 'pos', 'quotations', 'customers', 'suppliers', 'items', 'sales', 'purchases', 'accounting', 'hr', 'settings', 'users'];
$actions = ['view', 'add', 'edit', 'delete'];
foreach ($modules as $m): ?>
<div class="col-12 mt-2 border-bottom pb-1 mb-2">
<span class="badge bg-secondary text-uppercase"><?= ucfirst($m) ?></span>
</div>
<?php foreach ($actions as $a):
$p = $m . '_' . $a;
?>
<div class="col-3 mb-2">
<div class="form-check">
<input class="form-check-input" type="checkbox" name="permissions[]" value="<?= $p ?>" id="add_perm_<?= $p ?>">
<label class="form-check-label small" for="add_perm_<?= $p ?>"><?= ucfirst($a) ?></label>
</div>
</div>
<?php endforeach; ?>
<?php endforeach; ?>
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-light" data-bs-dismiss="modal" data-en="Cancel" data-ar="إلغاء">Cancel</button>
<button type="submit" name="add_role_group" class="btn btn-primary" data-en="Save" data-ar="حفظ">Save</button>
</div>
</form>
</div>
</div>
</div>
<!-- Add User Modal -->
<div class="modal fade" id="addUserModal" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content border-0 shadow">
<div class="modal-header">
<h5 class="modal-title" data-en="Add New User" data-ar="إضافة مستخدم جديد">Add New User</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<form method="POST">
<div class="modal-body">
<div class="mb-3">
<label class="form-label" data-en="Username" data-ar="اسم المستخدم">Username</label>
<input type="text" name="username" class="form-control" required autocomplete="username">
</div>
<div class="mb-3">
<label class="form-label" data-en="Email" data-ar="البريد الإلكتروني">Email</label>
<input type="email" name="email" class="form-control" autocomplete="email">
</div>
<div class="mb-3">
<label class="form-label" data-en="Phone" data-ar="الهاتف">Phone</label>
<input type="text" name="phone" class="form-control" autocomplete="tel">
</div>
<div class="mb-3">
<label class="form-label" data-en="Password" data-ar="كلمة المرور">Password</label>
<input type="password" name="password" class="form-control" required autocomplete="new-password">
</div>
<div class="mb-3">
<label class="form-label" data-en="Role Group" data-ar="مجموعة الأدوار">Role Group</label>
<select name="group_id" class="form-select">
<option value="">--- Select Group ---</option>
<?php foreach (($data['role_groups'] ?? []) as $g): ?>
<option value="<?= $g['id'] ?>"><?= htmlspecialchars($g['name']) ?></option>
<?php endforeach; ?>
</select>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-light" data-bs-dismiss="modal" data-en="Cancel" data-ar="إلغاء">Cancel</button>
<button type="submit" name="add_user" class="btn btn-primary" data-en="Save" data-ar="حفظ">Save</button>
</div>
</form>
</div>
</div>
</div>
<!-- Add Customer Modal -->
<div class="modal fade" id="addCustomerModal" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content border-0 shadow">
<div class="modal-header">
<h5 class="modal-title">
<?php if ($page === 'suppliers'): ?>
<span data-en="Add New Supplier" data-ar="إضافة مورد جديد">Add New Supplier</span>
<?php else: ?>
<span data-en="Add New Customer" data-ar="إضافة عميل جديد">Add New Customer</span>
<?php endif; ?>
</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<form method="POST">
<input type="hidden" name="type" value="<?= $page === 'suppliers' ? 'supplier' : 'customer' ?>">
<div class="modal-body">
<div class="mb-3">
<label class="form-label" data-en="Name" data-ar="الاسم">Name</label>
<input type="text" name="name" class="form-control" required>
</div>
<div class="mb-3">
<label class="form-label" data-en="Email" data-ar="البريد الإلكتروني">Email</label>
<input type="email" name="email" class="form-control">
</div>
<div class="mb-3">
<label class="form-label" data-en="Phone" data-ar="الهاتف">Phone</label>
<input type="text" name="phone" class="form-control">
</div>
<div class="mb-3">
<label class="form-label" data-en="Tax ID / VAT No" data-ar="الرقم الضريبي">Tax ID / VAT No</label>
<input type="text" name="tax_id" class="form-control">
</div>
<div class="mb-3">
<label class="form-label" data-en="Initial Balance" data-ar="الرصيد الافتتاحي">Initial Balance</label>
<input type="number" step="0.001" name="balance" class="form-control" value="0.000">
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-light" data-bs-dismiss="modal" data-en="Cancel" data-ar="إلغاء">Cancel</button>
<button type="submit" name="add_customer" class="btn btn-primary" data-en="Save" data-ar="حفظ">Save</button>
</div>
</form>
</div>
</div>
</div>
<!-- Add Item Modal -->
<div class="modal fade" id="addItemModal" tabindex="-1">
<div class="modal-dialog modal-lg">
<div class="modal-content border-0 shadow">
<div class="modal-header">
<h5 class="modal-title" data-en="Add New Item" data-ar="إضافة صنف جديد">Add New Item</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<form method="POST" enctype="multipart/form-data">
<div class="modal-body">
<div class="row g-3">
<div class="col-md-6">
<label class="form-label" data-en="Name (EN)" data-ar="الاسم (إنجليزي)">Name (EN)</label>
<input type="text" name="name_en" class="form-control" required>
</div>
<div class="col-md-6">
<label class="form-label" data-en="Name (AR)" data-ar="الاسم (عربي)">Name (AR)</label>
<input type="text" name="name_ar" class="form-control" required>
</div>
<div class="col-md-4">
<label class="form-label" data-en="Category" data-ar="الفئة">Category</label>
<select name="category_id" class="form-select">
<option value="">---</option>
<?php foreach ($data['categories'] ?? [] as $c): ?>
<option value="<?= $c['id'] ?>"><?= htmlspecialchars($c['name_en']) ?> / <?= htmlspecialchars($c['name_ar']) ?></option>
<?php endforeach; ?>
</select>
</div>
<div class="col-md-4">
<label class="form-label" data-en="Unit" data-ar="الوحدة">Unit</label>
<select name="unit_id" class="form-select">
<option value="">---</option>
<?php foreach ($data['units'] ?? [] as $u): ?>
<option value="<?= $u['id'] ?>"><?= htmlspecialchars($u['short_name_en']) ?> / <?= htmlspecialchars($u['short_name_ar']) ?></option>
<?php endforeach; ?>
</select>
</div>
<div class="col-md-4">
<label class="form-label" data-en="Supplier" data-ar="المورد">Supplier</label>
<select name="supplier_id" class="form-select">
<option value="">---</option>
<?php foreach ($data['suppliers'] ?? [] as $s): ?>
<option value="<?= $s['id'] ?>"><?= htmlspecialchars($s['name']) ?></option>
<?php endforeach; ?>
</select>
</div>
<div class="col-md-6">
<label class="form-label" data-en="SKU / Barcode" data-ar="الباركود">SKU / Barcode</label>
<div class="input-group">
<input type="text" name="sku" id="skuInput" class="form-control">
<button class="btn btn-outline-secondary" type="button" id="suggestSkuBtn" data-en="Suggest" data-ar="اقتراح">Suggest</button>
</div>
</div>
<div class="col-md-3">
<label class="form-label" data-en="Sale Price" data-ar="سعر البيع">Sale Price</label>
<input type="number" step="0.001" name="sale_price" class="form-control" value="0.000">
</div>
<div class="col-md-3">
<label class="form-label" data-en="Purchase Price" data-ar="سعر الشراء">Purchase Price</label>
<input type="number" step="0.001" name="purchase_price" class="form-control" value="0.000">
</div>
<div class="col-md-4">
<label class="form-label" data-en="Initial Stock" data-ar="المخزون الحالي">Initial Stock</label>
<input type="number" step="0.001" name="stock_quantity" class="form-control" value="0.000">
</div>
<div class="col-md-4">
<label class="form-label" data-en="Min Stock Level" data-ar="الحد الأدنى للمخزون">Min Stock Level</label>
<input type="number" step="0.001" name="min_stock_level" class="form-control" value="0.000">
</div>
<div class="col-md-4">
<label class="form-label" data-en="Item Picture" data-ar="صورة الصنف">Item Picture</label>
<input type="file" name="image" class="form-control" accept="image/*">
</div>
<div class="col-md-4">
<label class="form-label" data-en="VAT Rate (%)" data-ar="ضريبة القيمة المضافة (%)">VAT Rate (%)</label>
<input type="number" step="0.001" name="vat_rate" class="form-control" value="15.00">
</div>
<div class="col-md-8">
<div class="form-check form-switch mt-4">
<input class="form-check-input" type="checkbox" id="hasExpiryToggle">
<label class="form-check-label" for="hasExpiryToggle" data-en="Has Expiry Date?" data-ar="هل له تاريخ انتهاء؟">Has Expiry Date?</label>
</div>
</div>
<div class="col-md-6" id="expiryDateContainer" style="display: none;">
<label class="form-label" data-en="Expiry Date" data-ar="تاريخ الانتهاء">Expiry Date</label>
<input type="date" name="expiry_date" class="form-control">
</div>
<div class="col-12 mt-3">
<hr>
<h6 data-en="Promotion Details" data-ar="تفاصيل العرض">Promotion Details</h6>
</div>
<div class="col-md-4">
<div class="form-check form-switch mt-4">
<input class="form-check-input" type="checkbox" name="is_promotion" id="isPromotionToggle">
<label class="form-check-label" for="isPromotionToggle" data-en="On Promotion?" data-ar="في العرض؟">On Promotion?</label>
</div>
</div>
<div class="col-md-8">
<div class="row g-3" id="promotionFieldsContainer" style="display: none;">
<div class="col-md-4">
<label class="form-label" data-en="Start Date" data-ar="تاريخ البدء">Start Date</label>
<input type="date" name="promotion_start" class="form-control">
</div>
<div class="col-md-4">
<label class="form-label" data-en="End Date" data-ar="تاريخ الانتهاء">End Date</label>
<input type="date" name="promotion_end" class="form-control">
</div>
<div class="col-md-4">
<label class="form-label" data-en="Percent (%)" data-ar="النسبة (%)">Percent (%)</label>
<input type="number" step="0.01" name="promotion_percent" class="form-control" value="0.00">
</div>
</div>
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-light" data-bs-dismiss="modal" data-en="Cancel" data-ar="إلغاء">Cancel</button>
<button type="submit" name="add_item" class="btn btn-primary" data-en="Save Item" data-ar="حفظ الصنف">Save Item</button>
</div>
</form>
</div>
</div>
</div>
<!-- Import Items Modal -->
<div class="modal fade" id="importItemsModal" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content border-0 shadow text-start">
<div class="modal-header">
<h5 class="modal-title" data-en="Import Items from Excel (CSV)" data-ar="استيراد الأصناف من اكسل (CSV)">Import Items from Excel (CSV)</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<form method="POST" enctype="multipart/form-data">
<div class="modal-body">
<div class="alert alert-info py-2">
<small data-en="Please upload a CSV file with the following columns: SKU, English Name, Arabic Name, Sale Price, Cost Price." data-ar="يرجى رفع ملف CSV بالأعمدة التالية: الباركود، الاسم الإنجليزي، الاسم العربي، سعر البيع، سعر التكلفة.">
Please upload a CSV file with the following columns: SKU, English Name, Arabic Name, Sale Price, Cost Price.
</small>
</div>
<div class="mb-3">
<label class="form-label" data-en="Choose CSV File" data-ar="اختر ملف CSV">Choose CSV File</label>
<input type="file" name="excel_file" class="form-control" accept=".csv" required>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-light" data-bs-dismiss="modal" data-en="Cancel" data-ar="إلغاء">Cancel</button>
<button type="submit" name="import_items" class="btn btn-success" data-en="Import Now" data-ar="استيراد الآن">Import Now</button>
</div>
</form>
</div>
</div>
</div>
<!-- Import Customers Modal -->
<div class="modal fade" id="importCustomersModal" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content border-0 shadow text-start">
<div class="modal-header">
<h5 class="modal-title" data-en="Import Customers from Excel (CSV)" data-ar="استيراد العملاء من اكسل (CSV)">Import Customers from Excel (CSV)</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<form method="POST" enctype="multipart/form-data">
<div class="modal-body">
<div class="alert alert-info py-2">
<small data-en="Please upload a CSV file with the following columns: Name, Email, Phone, Tax ID, Balance." data-ar="يرجى رفع ملف CSV بالأعمدة التالية: الاسم، البريد الإلكتروني، الهاتف، الرقم الضريبي، الرصيد.">
Please upload a CSV file with the following columns: Name, Email, Phone, Tax ID, Balance.
</small>
</div>
<div class="mb-3">
<label class="form-label" data-en="Choose CSV File" data-ar="اختر ملف CSV">Choose CSV File</label>
<input type="file" name="excel_file" class="form-control" accept=".csv" required>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-light" data-bs-dismiss="modal" data-en="Cancel" data-ar="إلغاء">Cancel</button>
<button type="submit" name="import_customers" class="btn btn-success" data-en="Import Now" data-ar="استيراد الآن">Import Now</button>
</div>
</form>
</div>
</div>
</div>
<!-- Import Suppliers Modal -->
<div class="modal fade" id="importSuppliersModal" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content border-0 shadow text-start">
<div class="modal-header">
<h5 class="modal-title" data-en="Import Suppliers from Excel (CSV)" data-ar="استيراد الموردين من اكسل (CSV)">Import Suppliers from Excel (CSV)</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<form method="POST" enctype="multipart/form-data">
<div class="modal-body">
<div class="alert alert-info py-2">
<small data-en="Please upload a CSV file with the following columns: Name, Email, Phone, Tax ID, Balance." data-ar="يرجى رفع ملف CSV بالأعمدة التالية: الاسم، البريد الإلكتروني، الهاتف، الرقم الضريبي، الرصيد.">
Please upload a CSV file with the following columns: Name, Email, Phone, Tax ID, Balance.
</small>
</div>
<div class="mb-3">
<label class="form-label" data-en="Choose CSV File" data-ar="اختر ملف CSV">Choose CSV File</label>
<input type="file" name="excel_file" class="form-control" accept=".csv" required>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-light" data-bs-dismiss="modal" data-en="Cancel" data-ar="إلغاء">Cancel</button>
<button type="submit" name="import_suppliers" class="btn btn-success" data-en="Import Now" data-ar="استيراد الآن">Import Now</button>
</div>
</form>
</div>
</div>
</div>
<!-- Import Categories Modal -->
<div class="modal fade" id="importCategoriesModal" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content border-0 shadow text-start">
<div class="modal-header">
<h5 class="modal-title" data-en="Import Categories from Excel (CSV)" data-ar="استيراد الفئات من اكسل (CSV)">Import Categories from Excel (CSV)</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<form method="POST" enctype="multipart/form-data">
<div class="modal-body">
<div class="alert alert-info py-2">
<small data-en="Please upload a CSV file with the following columns: Name (EN), Name (AR)." data-ar="يرجى رفع ملف CSV بالأعمدة التالية: الاسم (إنجليزي)، الاسم (عربي).">
Please upload a CSV file with the following columns: Name (EN), Name (AR).
</small>
</div>
<div class="mb-3">
<label class="form-label" data-en="Choose CSV File" data-ar="اختر ملف CSV">Choose CSV File</label>
<input type="file" name="excel_file" class="form-control" accept=".csv" required>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-light" data-bs-dismiss="modal" data-en="Cancel" data-ar="إلغاء">Cancel</button>
<button type="submit" name="import_categories" class="btn btn-success" data-en="Import Now" data-ar="استيراد الآن">Import Now</button>
</div>
</form>
</div>
</div>
</div>
<!-- Import Units Modal -->
<div class="modal fade" id="importUnitsModal" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content border-0 shadow text-start">
<div class="modal-header">
<h5 class="modal-title" data-en="Import Units from Excel (CSV)" data-ar="استيراد الوحدات من اكسل (CSV)">Import Units from Excel (CSV)</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<form method="POST" enctype="multipart/form-data">
<div class="modal-body">
<div class="alert alert-info py-2">
<small data-en="Please upload a CSV file with the following columns: Name (EN), Name (AR), Short (EN), Short (AR)." data-ar="يرجى رفع ملف CSV بالأعمدة التالية: الاسم (إنجليزي)، الاسم (عربي)، الاختصار (إنجليزي)، الاختصار (عربي).">
Please upload a CSV file with the following columns: Name (EN), Name (AR), Short (EN), Short (AR).
</small>
</div>
<div class="mb-3">
<label class="form-label" data-en="Choose CSV File" data-ar="اختر ملف CSV">Choose CSV File</label>
<input type="file" name="excel_file" class="form-control" accept=".csv" required>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-light" data-bs-dismiss="modal" data-en="Cancel" data-ar="إلغاء">Cancel</button>
<button type="submit" name="import_units" class="btn btn-success" data-en="Import Now" data-ar="استيراد الآن">Import Now</button>
</div>
</form>
</div>
</div>
</div>
<!-- Add Category Modal -->
<div class="modal fade" id="addCategoryModal" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content border-0 shadow">
<div class="modal-header">
<h5 class="modal-title" data-en="Add Category" data-ar="إضافة فئة">Add Category</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<form method="POST">
<div class="modal-body">
<div class="mb-3">
<label class="form-label" data-en="Name (EN)" data-ar="الاسم (إنجليزي)">Name (EN)</label>
<input type="text" name="name_en" class="form-control" required>
</div>
<div class="mb-3">
<label class="form-label" data-en="Name (AR)" data-ar="الاسم (عربي)">Name (AR)</label>
<input type="text" name="name_ar" class="form-control" required>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-light" data-bs-dismiss="modal" data-en="Cancel" data-ar="إلغاء">Cancel</button>
<button type="submit" name="add_category" class="btn btn-primary" data-en="Save" data-ar="حفظ">Save</button>
</div>
</form>
</div>
</div>
</div>
<!-- Add Unit Modal -->
<div class="modal fade" id="addUnitModal" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content border-0 shadow">
<div class="modal-header">
<h5 class="modal-title" data-en="Add Unit" data-ar="إضافة وحدة">Add Unit</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<form method="POST">
<div class="modal-body">
<div class="row g-3">
<div class="col-md-6">
<label class="form-label" data-en="Name (EN)" data-ar="الاسم (إنجليزي)">Name (EN)</label>
<input type="text" name="name_en" class="form-control" required>
</div>
<div class="col-md-6">
<label class="form-label" data-en="Short Name (EN)" data-ar="الاختصار (إنجليزي)">Short (EN)</label>
<input type="text" name="short_en" class="form-control" required placeholder="e.g. Kg">
</div>
<div class="col-md-6">
<label class="form-label" data-en="Name (AR)" data-ar="الاسم (عربي)">Name (AR)</label>
<input type="text" name="name_ar" class="form-control" required>
</div>
<div class="col-md-6">
<label class="form-label" data-en="Short Name (AR)" data-ar="الاختصار (عربي)">Short (AR)</label>
<input type="text" name="short_ar" class="form-control" required placeholder="مثلاً: كجم">
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-light" data-bs-dismiss="modal" data-en="Cancel" data-ar="إلغاء">Cancel</button>
<button type="submit" name="add_unit" class="btn btn-primary" data-en="Save" data-ar="حفظ">Save</button>
</div>
</form>
</div>
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
console.log("DOM Content Loaded - Accounting System");
try {
// Initialize Select2 for all searchable dropdowns
$('.select2').each(function() {
$(this).select2({
width: '100%',
dropdownParent: $(this).closest('.modal').length ? $(this).closest('.modal') : $(document.body)
});
});
const hasExpiryToggle = document.getElementById('hasExpiryToggle');
const expiryDateContainer = document.getElementById('expiryDateContainer');
const suggestSkuBtn = document.getElementById('suggestSkuBtn');
const skuInput = document.getElementById('skuInput');
if (suggestSkuBtn && skuInput) {
suggestSkuBtn.addEventListener('click', function() {
const sku = Math.floor(100000000000 + Math.random() * 900000000000).toString();
skuInput.value = sku;
});
}
// Toggle Expiry Date visibility
if (hasExpiryToggle && expiryDateContainer) {
hasExpiryToggle.addEventListener('change', function() {
expiryDateContainer.style.display = this.checked ? 'block' : 'none';
});
}
const isPromotionToggle = document.getElementById('isPromotionToggle');
const promotionFieldsContainer = document.getElementById('promotionFieldsContainer');
if (isPromotionToggle && promotionFieldsContainer) {
isPromotionToggle.addEventListener('change', function() {
promotionFieldsContainer.style.display = this.checked ? 'flex' : 'none';
});
}
document.querySelectorAll('.isPromotionToggleEdit').forEach(toggle => {
toggle.addEventListener('change', function() {
const id = this.getAttribute('data-id');
const container = document.getElementById('promotionFieldsContainerEdit' + id);
if (container) {
container.style.display = this.checked ? 'flex' : 'none';
}
});
});
// Status change logic for Paid Amount field
const togglePaidAmount = (statusId, containerId) => {
const statusEl = document.getElementById(statusId);
const containerEl = document.getElementById(containerId);
if (statusEl && containerEl) {
statusEl.addEventListener('change', function() {
if (this.value === 'partially_paid') {
containerEl.style.display = 'block';
} else {
containerEl.style.display = 'none';
}
});
}
};
togglePaidAmount('add_status', 'addPaidAmountContainer');
togglePaidAmount('edit_status', 'editPaidAmountContainer');
// Pay Invoice Logic
document.querySelectorAll('.pay-invoice-btn').forEach(btn => {
btn.addEventListener('click', function() {
const id = this.getAttribute('data-id');
const total = parseFloat(this.getAttribute('data-total'));
const paid = parseFloat(this.getAttribute('data-paid') || 0);
const remaining = total - paid;
document.getElementById('pay_invoice_id').value = id;
document.getElementById('pay_invoice_total').value = `OMR ${total.toFixed(3)}`;
document.getElementById('pay_remaining_amount').value = `OMR ${remaining.toFixed(3)}`;
document.getElementById('pay_amount').value = remaining.toFixed(3);
document.getElementById('pay_amount').max = remaining.toFixed(3);
});
});
// Show receipt modal if needed
<?php if (isset($_SESSION['trigger_receipt_modal'])):
$rid = (int)$_SESSION['show_receipt_id'];
unset($_SESSION['trigger_receipt_modal']);
?>
if (typeof showReceipt === 'function') {
showReceipt(<?= $rid ?>);
} else {
setTimeout(() => { if (typeof showReceipt === 'function') showReceipt(<?= $rid ?>); }, 500);
}
<?php endif; ?>
function showReceipt(paymentId) {
fetch(`index.php?action=get_payment_details&payment_id=${paymentId}`)
.then(res => res.json())
.then(data => {
if (!data) return;
document.getElementById('receiptNo').textContent = 'RCP-' + data.id.toString().padStart(5, '0');
document.getElementById('receiptDate').textContent = data.payment_date;
document.getElementById('receiptCustomer').textContent = data.customer_name || '---';
document.getElementById('receiptInvNo').textContent = 'INV-' + data.inv_id.toString().padStart(5, '0');
document.getElementById('receiptMethod').textContent = data.payment_method;
document.getElementById('receiptAmount').textContent = 'OMR ' + parseFloat(data.amount).toFixed(3);
document.getElementById('receiptAmountWords').textContent = data.amount_words;
// Update labels for Purchase vs Sale
const partyLabel = document.getElementById('receiptPartyLabel');
const againstLabel = document.getElementById('receiptAgainstLabel');
const receiptTitle = document.querySelector('#receiptModal .modal-title');
const receiptH4 = document.querySelector('.receipt-container h4.letter-spacing-2');
if (data.inv_type === 'purchase') {
partyLabel.textContent = 'Paid To';
partyLabel.setAttribute('data-en', 'Paid To');
partyLabel.setAttribute('data-ar', 'صرف إلى');
againstLabel.textContent = 'Against Purchase';
againstLabel.setAttribute('data-en', 'Against Purchase');
againstLabel.setAttribute('data-ar', 'مقابل شراء');
receiptTitle.textContent = 'Payment Voucher';
receiptTitle.setAttribute('data-en', 'Payment Voucher');
receiptTitle.setAttribute('data-ar', 'سند صرف');
receiptH4.textContent = 'PAYMENT VOUCHER';
receiptH4.setAttribute('data-en', 'PAYMENT VOUCHER');
receiptH4.setAttribute('data-ar', 'سند صرف');
} else {
partyLabel.textContent = 'Received From';
partyLabel.setAttribute('data-en', 'Received From');
partyLabel.setAttribute('data-ar', 'وصلنا من');
againstLabel.textContent = 'Against Invoice';
againstLabel.setAttribute('data-en', 'Against Invoice');
againstLabel.setAttribute('data-ar', 'مقابل فاتورة');
receiptTitle.textContent = 'Payment Receipt';
receiptTitle.setAttribute('data-en', 'Payment Receipt');
receiptTitle.setAttribute('data-ar', 'سند قبض');
receiptH4.textContent = 'PAYMENT RECEIPT';
receiptH4.setAttribute('data-en', 'PAYMENT RECEIPT');
receiptH4.setAttribute('data-ar', 'سند قبض');
}
const notesContainer = document.getElementById('receiptNotesContainer');
if (data.notes) {
document.getElementById('receiptNotes').textContent = data.notes;
notesContainer.style.display = 'block';
} else {
notesContainer.style.display = 'none';
}
const receiptModal = new bootstrap.Modal(document.getElementById('receiptModal'));
receiptModal.show();
});
};
document.querySelectorAll('.view-payments-btn').forEach(btn => {
btn.addEventListener('click', function() {
const invoiceId = this.getAttribute('data-id');
const tbody = document.getElementById('paymentsTableBody');
tbody.innerHTML = '<tr><td colspan="5" class="text-center">Loading...</td></tr>';
fetch(`index.php?action=get_payments&invoice_id=${invoiceId}`)
.then(res => res.json())
.then(data => {
tbody.innerHTML = '';
if (data.length === 0) {
tbody.innerHTML = '<tr><td colspan="5" class="text-center">No payments found.</td></tr>';
return;
}
data.forEach(p => {
const tr = document.createElement('tr');
tr.innerHTML = `
<td>RCP-${p.id.toString().padStart(5, '0')}</td>
<td>${p.payment_date}</td>
<td>${p.payment_method}</td>
<td class="text-end fw-bold">OMR ${parseFloat(p.amount).toFixed(3)}</td>
<td class="text-end">
<button class="btn btn-sm btn-outline-primary" onclick="showReceipt(${p.id})">
<i class="bi bi-printer"></i>
</button>
</td>
`;
tbody.appendChild(tr);
});
});
});
});
window.printReceipt = function() {
const content = document.getElementById('printableReceipt').innerHTML;
const originalContent = document.body.innerHTML;
document.body.innerHTML = content;
window.print();
document.body.innerHTML = originalContent;
window.location.reload();
};
// Handle Expiry toggle in Edit Modals
document.querySelectorAll('.hasExpiryToggleEdit').forEach(toggle => {
toggle.addEventListener('change', function() {
const container = this.closest('.row').querySelector('.expiryDateContainerEdit');
if (container) {
container.style.display = this.checked ? 'block' : 'none';
if (!this.checked) {
container.querySelector('input').value = '';
}
}
});
});
// Invoice Form Logic
const initInvoiceForm = (searchInputId, suggestionsId, tableBodyId, grandTotalId, subtotalId, totalVatId) => {
const searchInput = document.getElementById(searchInputId);
const suggestions = document.getElementById(suggestionsId);
const tableBody = document.getElementById(tableBodyId);
const grandTotalEl = document.getElementById(grandTotalId);
const subtotalEl = document.getElementById(subtotalId);
const totalVatEl = document.getElementById(totalVatId);
if (!searchInput || !tableBody) return;
let timeout = null;
searchInput.addEventListener('input', function() {
clearTimeout(timeout);
const q = this.value.trim();
if (q.length < 1) {
suggestions.style.display = 'none';
return;
}
timeout = setTimeout(() => {
fetch(`index.php?action=search_items&q=${encodeURIComponent(q)}`)
.then(res => res.json())
.then(data => {
suggestions.innerHTML = '';
if (data.length > 0) {
data.forEach(item => {
const btn = document.createElement('button');
btn.type = 'button';
btn.className = 'list-group-item list-group-item-action';
btn.innerHTML = `
<div class="d-flex justify-content-between">
<span><strong>${item.sku}</strong> - ${item.name_en} / ${item.name_ar}</span>
<span class="text-muted small">Stock: ${item.stock_quantity}</span>
</div>
`;
btn.onclick = () => addItemToTable(item, tableBody, searchInput, suggestions, grandTotalEl, subtotalEl, totalVatEl);
suggestions.appendChild(btn);
});
suggestions.style.display = 'block';
} else {
suggestions.style.display = 'none';
}
});
}, 300);
});
// Close suggestions when clicking outside
document.addEventListener('click', function(e) {
if (!searchInput.contains(e.target) && !suggestions.contains(e.target)) {
suggestions.style.display = 'none';
}
});
};
function addItemToTable(item, tableBody, searchInput, suggestions, grandTotalEl, subtotalEl, totalVatEl, customData = null) {
if (suggestions) suggestions.style.display = 'none';
if (searchInput) searchInput.value = '';
const allowZeroStock = (typeof companySettings !== 'undefined' && String(companySettings.allow_zero_stock_sell) === '1');
const currentStock = parseFloat(item.stock_quantity) || 0;
if (invoiceType === 'sale' && !allowZeroStock && !customData) {
const existingInTable = Array.from(tableBody.querySelectorAll('.item-row')).find(row => row.querySelector('.item-id-input').value == item.id);
let currentQtyInTable = 0;
if (existingInTable) {
currentQtyInTable = parseFloat(existingInTable.querySelector('.item-qty').value) || 0;
}
if (currentQtyInTable + 1 > currentStock) {
alert('Insufficient stock! Available: ' + currentStock);
return;
}
}
const existingRow = Array.from(tableBody.querySelectorAll('.item-id-input')).find(input => input.value == item.id);
if (existingRow && !customData) {
const row = existingRow.closest('tr');
const qtyInput = row.querySelector('.item-qty');
qtyInput.value = parseFloat(qtyInput.value) + 1;
recalculate(tableBody, grandTotalEl, subtotalEl, totalVatEl);
return;
}
const row = document.createElement('tr');
row.className = 'item-row';
const price = customData ? customData.unit_price : (invoiceType === 'sale' ? item.sale_price : item.purchase_price);
const qty = customData ? customData.quantity : 1;
const vatRate = item.vat_rate || 0;
row.innerHTML = `
<td>
<input type="hidden" name="item_ids[]" class="item-id-input" value="${item.id}">
<input type="hidden" class="item-row-stock" value="${item.stock_quantity}">
<input type="hidden" class="item-vat-rate" value="${vatRate}">
<div><strong>${item.name_en}</strong></div>
<div class="small text-muted">${item.name_ar} (${item.sku})</div>
</td>
<td><input type="number" step="0.001" name="quantities[]" class="form-control item-qty" value="${qty}" required></td>
<td><input type="number" step="0.001" name="prices[]" class="form-control item-price" value="${price}" required></td>
<td><input type="text" class="form-control bg-light" value="${vatRate}%" readonly></td>
<td><input type="number" step="0.001" class="form-control item-total" value="${(qty * price).toFixed(3)}" readonly></td>
<td><button type="button" class="btn btn-outline-danger btn-sm remove-row"><i class="bi bi-trash"></i></button></td>
`;
tableBody.appendChild(row);
attachRowListeners(row, tableBody, grandTotalEl, subtotalEl, totalVatEl);
recalculate(tableBody, grandTotalEl, subtotalEl, totalVatEl);
}
function recalculate(tableBody, grandTotalEl, subtotalEl, totalVatEl) {
let subtotal = 0;
let totalVat = 0;
tableBody.querySelectorAll('.item-row').forEach(row => {
const qty = parseFloat(row.querySelector('.item-qty').value) || 0;
const price = parseFloat(row.querySelector('.item-price').value) || 0;
const vatRate = parseFloat(row.querySelector('.item-vat-rate').value) || 0;
const total = qty * price;
const vatAmount = total * (vatRate / 100);
row.querySelector('.item-total').value = total.toFixed(3);
subtotal += total;
totalVat += vatAmount;
});
const grandTotal = subtotal + totalVat;
if (subtotalEl) subtotalEl.textContent = 'OMR ' + subtotal.toFixed(3);
if (totalVatEl) totalVatEl.textContent = 'OMR ' + totalVat.toFixed(3);
if (grandTotalEl) grandTotalEl.textContent = 'OMR ' + grandTotal.toFixed(3);
}
function attachRowListeners(row, tableBody, grandTotalEl, subtotalEl, totalVatEl) {
row.querySelector('.item-qty').addEventListener('input', function() {
const allowZeroStock = (typeof companySettings !== 'undefined' && String(companySettings.allow_zero_stock_sell) === '1');
if (invoiceType === 'sale' && !allowZeroStock) {
const stock = parseFloat(row.querySelector('.item-row-stock').value) || 0;
const qty = parseFloat(this.value) || 0;
if (qty > stock) {
alert('Insufficient stock! Available: ' + stock);
this.value = stock;
}
}
recalculate(tableBody, grandTotalEl, subtotalEl, totalVatEl);
});
row.querySelector('.item-price').addEventListener('input', () => recalculate(tableBody, grandTotalEl, subtotalEl, totalVatEl));
row.querySelector('.remove-row').addEventListener('click', function() {
row.remove();
recalculate(tableBody, grandTotalEl, subtotalEl, totalVatEl);
});
}
const invoiceType = '<?= in_array($page, ["sales", "quotations"]) ? "sale" : ($page === "purchases" ? "purchase" : "") ?>';
initInvoiceForm('productSearchInput', 'searchSuggestions', 'invoiceItemsTableBody', 'grandTotal', 'subtotal', 'totalVat');
initInvoiceForm('editProductSearchInput', 'editSearchSuggestions', 'editInvoiceItemsTableBody', 'edit_grandTotal', 'edit_subtotal', 'edit_totalVat');
// Quotation Form Logic
initInvoiceForm('quotProductSearchInput', 'quotSearchSuggestions', 'quotItemsTableBody', 'quot_grand_display', 'quot_subtotal_display', 'quot_vat_display');
initInvoiceForm('editQuotProductSearchInput', 'editQuotSearchSuggestions', 'editQuotItemsTableBody', 'edit_quot_grand_display', 'edit_quot_subtotal_display', 'edit_quot_vat_display');
document.querySelectorAll('.edit-quotation-btn').forEach(btn => {
btn.addEventListener('click', function() {
const data = JSON.parse(this.dataset.json);
document.getElementById('edit_quotation_id').value = data.id;
document.getElementById('edit_quot_customer_id').value = data.customer_id;
document.getElementById('edit_quot_date').value = data.quotation_date;
document.getElementById('edit_quot_valid').value = data.valid_until || '';
document.getElementById('edit_quot_status').value = data.status || 'pending';
const tableBody = document.getElementById('editQuotItemsTableBody');
tableBody.innerHTML = '';
data.items.forEach(item => {
addItemToTable({
id: item.item_id,
name_en: item.name_en,
name_ar: item.name_ar,
sku: '',
vat_rate: item.vat_rate || 0
}, tableBody, null, null,
document.getElementById('edit_quot_grand_display'),
document.getElementById('edit_quot_subtotal_display'),
document.getElementById('edit_quot_vat_display'),
{ quantity: item.quantity, unit_price: item.unit_price });
});
});
});
document.querySelectorAll('.convert-quotation-btn').forEach(btn => {
btn.addEventListener('click', function() {
if (confirm('Convert this quotation to an invoice? This will reduce stock.')) {
const f = document.createElement('form');
f.method = 'POST';
f.innerHTML = `<input type="hidden" name="convert_to_invoice" value="1"><input type="hidden" name="quotation_id" value="${this.dataset.id}">`;
document.body.appendChild(f);
f.submit();
}
});
});
// View Quotation Logic
window.viewAndPrintQuotation = function(data, autoPrint = false) {
const modal = new bootstrap.Modal(document.getElementById('viewQuotationModal'));
const content = document.getElementById('quotationPrintableArea');
let itemsHtml = '';
data.items.forEach((item, index) => {
itemsHtml += `
<tr>
<td>${index + 1}</td>
<td>${item.name_en}<br><small>${item.name_ar}</small></td>
<td class="text-center">${item.quantity}</td>
<td class="text-end">${parseFloat(item.unit_price).toFixed(3)}</td>
<td class="text-center">${item.vat_rate}%</td>
<td class="text-end">${parseFloat(item.total_price).toFixed(3)}</td>
</tr>
`;
});
// Company Logo and Header Construction
const logoUrl = companySettings.company_logo || '';
const logoImg = logoUrl ? `<img src="${logoUrl}" alt="Logo" class="invoice-logo mb-3">` : '';
const companyName = companySettings.company_name || 'Accounting System';
const companyAddress = (companySettings.company_address || '').replace(/\n/g, '<br>');
const companyVat = companySettings.vat_number ? `<p class="text-muted small mb-0">VAT: ${companySettings.vat_number}</p>` : '';
const companyPhone = companySettings.company_phone ? `<p class="text-muted small mb-0">Tel: ${companySettings.company_phone}</p>` : '';
// Quotation Header Construction
const quotDate = data.quotation_date;
const quotValid = data.valid_until || 'N/A';
const quotNo = 'QUO-' + data.id.toString().padStart(5, '0');
const customerName = data.customer_name || 'Walk-in Customer';
const statusBadge = `<span class="badge ${data.status === 'converted' ? 'bg-success' : 'bg-secondary'}">${data.status.toUpperCase()}</span>`;
content.innerHTML = `
<div class="p-5">
<div class="invoice-header mb-4">
<div class="row align-items-center">
<div class="col-6">
${logoImg}
<h3 class="mb-1 fw-bold">${companyName}</h3>
<p class="text-muted small mb-0">${companyAddress}</p>
${companyVat}
${companyPhone}
</div>
<div class="col-6 text-end">
<h1 class="invoice-title fw-bold mb-0 text-uppercase">Quotation</h1>
<div class="mt-2">${statusBadge}</div>
<div class="mt-3">
<p class="mb-0 fs-5">No: <strong class="text-primary">${quotNo}</strong></p>
<p class="mb-0">Date: <span class="fw-bold">${quotDate}</span></p>
<p class="mb-0">Valid Until: <span class="fw-bold">${quotValid}</span></p>
</div>
</div>
</div>
</div>
<div class="row mb-4 g-3">
<div class="col-6">
<div class="invoice-info-card">
<p class="text-muted small text-uppercase fw-bold mb-2 border-bottom pb-1">To</p>
<h5 class="mb-1 fw-bold">${customerName}</h5>
</div>
</div>
</div>
<table class="table table-bordered table-formal">
<thead class="bg-dark text-white">
<tr>
<th>#</th>
<th>Item Description</th>
<th class="text-center">Qty</th>
<th class="text-end">Unit Price</th>
<th class="text-center">VAT</th>
<th class="text-end">Total</th>
</tr>
</thead>
<tbody>${itemsHtml}</tbody>
<tfoot>
<tr>
<th colspan="5" class="text-end">Subtotal</th>
<td class="text-end fw-bold">${parseFloat(data.total_amount).toFixed(3)}</td>
</tr>
<tr>
<th colspan="5" class="text-end">VAT Amount</th>
<td class="text-end fw-bold">${parseFloat(data.vat_amount).toFixed(3)}</td>
</tr>
<tr class="table-primary">
<th colspan="5" class="text-end h5">Grand Total (OMR)</th>
<td class="text-end h5 fw-bold">${parseFloat(data.total_with_vat).toFixed(3)}</td>
</tr>
</tfoot>
</table>
<div class="mt-5 pt-3 border-top">
<div class="row">
<div class="col-6">
<p class="small text-muted text-uppercase fw-bold">Terms & Conditions:</p>
<ul class="small text-muted">
<li>Quotation is valid until the date mentioned above.</li>
<li>Prices are inclusive of VAT where applicable.</li>
</ul>
</div>
<div class="col-6 text-end pt-4">
<div class="border-top d-inline-block px-5">Authorized Signature</div>
</div>
</div>
</div>
<div class="mt-4 text-center">
<p class="text-muted x-small mb-0">Generated by ${companyName}</p>
</div>
</div>
`;
const actionButtons = document.getElementById('quotationActionButtons');
actionButtons.innerHTML = '';
if (data.status === 'pending') {
const convertBtn = document.createElement('button');
convertBtn.className = 'btn btn-success me-2';
convertBtn.innerHTML = '<i class="bi bi-receipt"></i> Convert to Invoice';
convertBtn.onclick = function() {
if (confirm('Convert this quotation to an invoice?')) {
const f = document.createElement('form');
f.method = 'POST';
f.innerHTML = `<input type="hidden" name="convert_to_invoice" value="1"><input type="hidden" name="quotation_id" value="${data.id}">`;
document.body.appendChild(f);
f.submit();
}
};
actionButtons.appendChild(convertBtn);
const editBtn = document.createElement('button');
editBtn.className = 'btn btn-primary';
editBtn.innerHTML = '<i class="bi bi-pencil-square"></i> Edit';
editBtn.onclick = function() {
const editModal = new bootstrap.Modal(document.getElementById('editQuotationModal'));
modal.hide();
const originalEditBtn = document.querySelector(`.edit-quotation-btn[data-json*='"id":${data.id},']`) ||
document.querySelector(`.edit-quotation-btn[data-json*='"id":${data.id}']`);
if (originalEditBtn) originalEditBtn.click();
};
actionButtons.appendChild(editBtn);
}
modal.show();
if (autoPrint) {
setTimeout(() => { window.print(); }, 500);
}
};
document.querySelectorAll('.view-quotation-btn').forEach(btn => {
btn.addEventListener('click', function() {
const data = JSON.parse(this.dataset.json);
window.viewAndPrintQuotation(data, false);
});
});
// Edit Invoice Logic
document.querySelectorAll('.edit-invoice-btn').forEach(btn => {
btn.addEventListener('click', function() {
const data = JSON.parse(this.dataset.json);
document.getElementById('edit_invoice_id').value = data.id;
document.getElementById('edit_customer_id').value = data.customer_id;
document.getElementById('edit_invoice_date').value = data.invoice_date;
document.getElementById('edit_payment_type').value = data.payment_type || 'cash';
document.getElementById('edit_status').value = data.status || 'unpaid';
document.getElementById('edit_paid_amount').value = parseFloat(data.paid_amount || 0).toFixed(3);
if (data.status === 'partially_paid') {
document.getElementById('editPaidAmountContainer').style.display = 'block';
} else {
document.getElementById('editPaidAmountContainer').style.display = 'none';
}
const tableBody = document.getElementById('editInvoiceItemsTableBody');
tableBody.innerHTML = '';
data.items.forEach(item => {
// We need more data than what's in invoice_items (like SKU and names, but we have them from the join in PHP)
// The dataset-json already contains name_en, name_ar etc because of the PHP logic at line 1093
const itemMeta = {
id: item.item_id,
name_en: item.name_en,
name_ar: item.name_ar,
sku: '', // Optional, or fetch if needed
vat_rate: 0 // Will be handled if we have it in the join
};
// Fetch current item details to get VAT rate if possible, or use stored if available
// For simplicity, let's assume we want to use the item's current VAT rate or store it.
// Looking at the join at line 1093, it doesn't fetch vat_rate. Let's fix that in PHP too.
addItemToTable({
id: item.item_id,
name_en: item.name_en,
name_ar: item.name_ar,
sku: '',
vat_rate: item.vat_rate || 0 // We'll add this to PHP join
}, tableBody, null, null,
document.getElementById('edit_grandTotal'),
document.getElementById('edit_subtotal'),
document.getElementById('edit_totalVat'),
{ quantity: item.quantity, unit_price: item.unit_price });
});
});
});
// View and Print Invoice Logic
document.addEventListener('click', function(e) {
if (e.target.closest('.view-invoice-btn')) {
const btn = e.target.closest('.view-invoice-btn');
const data = JSON.parse(btn.dataset.json);
if (window.viewAndPrintA4Invoice) {
window.viewAndPrintA4Invoice(data, false);
}
}
if (e.target.closest('.print-a4-btn')) {
const btn = e.target.closest('.print-a4-btn');
const data = JSON.parse(btn.dataset.json);
if (window.viewAndPrintA4Invoice) {
window.viewAndPrintA4Invoice(data, true);
}
}
});
// Return Logic (General for Sales and Purchase)
const setupReturnLogic = (selectId, containerId, tbodyId, totalDisplayId, submitBtnId) => {
const select = document.getElementById(selectId);
if (!select) return;
const calculateTotal = function() {
let total = 0;
document.querySelectorAll('#' + tbodyId + ' tr').forEach(row => {
const qtyInput = row.querySelector('.return-qty-input');
if (!qtyInput) return;
const qty = parseFloat(qtyInput.value) || 0;
const price = parseFloat(qtyInput.dataset.price) || 0;
const lineTotal = qty * price;
const lineTotalDisplay = row.querySelector('.line-total');
if (lineTotalDisplay) {
lineTotalDisplay.innerText = lineTotal.toFixed(3);
}
total += lineTotal;
});
const totalDisplay = document.getElementById(totalDisplayId);
if (totalDisplay) {
totalDisplay.innerText = 'OMR ' + total.toFixed(3);
}
const submitBtn = document.getElementById(submitBtnId);
if (submitBtn) {
submitBtn.disabled = total <= 0;
}
};
const handleInvoiceChange = async function() {
const invoiceId = select.value;
const container = document.getElementById(containerId);
const tbody = document.getElementById(tbodyId);
const submitBtn = document.getElementById(submitBtnId);
if (!invoiceId) {
if (container) container.style.display = 'none';
if (submitBtn) submitBtn.disabled = true;
return;
}
if (tbody) {
tbody.innerHTML = '<tr><td colspan="5" class="text-center"><div class="spinner-border spinner-border-sm text-primary"></div> Loading items...</td></tr>';
}
if (container) container.style.display = 'block';
try {
const resp = await fetch(`index.php?action=get_invoice_items&invoice_id=${invoiceId}`);
const items = await resp.json();
if (tbody) {
tbody.innerHTML = '';
if (items.length === 0) {
tbody.innerHTML = '<tr><td colspan="5" class="text-center text-muted">No items found for this invoice.</td></tr>';
} else {
let html = '';
items.forEach(item => {
html += `
<tr>
<td>${item.name_en}<br><small class="text-muted">${item.sku}</small></td>
<td>${parseFloat(item.quantity).toFixed(2)}</td>
<td>
<input type="number" name="quantities[]" class="form-control form-control-sm return-qty-input"
step="0.01" min="0" max="${item.quantity}" value="0"
data-price="${item.unit_price}">
<input type="hidden" name="item_ids[]" value="${item.item_id}">
<input type="hidden" name="prices[]" value="${item.unit_price}">
</td>
<td class="text-end">${parseFloat(item.unit_price).toFixed(3)}</td>
<td class="text-end line-total">0.000</td>
</tr>
`;
});
tbody.innerHTML = html;
}
}
if (submitBtn) submitBtn.disabled = true;
const qtyInputs = tbody.querySelectorAll('.return-qty-input');
qtyInputs.forEach(input => {
['input', 'change', 'keyup'].forEach(evt => input.addEventListener(evt, calculateTotal));
});
calculateTotal();
} catch (e) {
console.error(e);
if (window.Swal) Swal.fire('Error', 'Failed to fetch invoice items', 'error');
}
};
select.addEventListener('change', handleInvoiceChange);
if (window.jQuery && jQuery.fn.select2) {
$(select).on('select2:select change', handleInvoiceChange);
}
};
setupReturnLogic('return_invoice_select', 'return_items_container', 'return_items_tbody', 'return_total_display', 'submit_return_btn');
setupReturnLogic('purchase_return_invoice_select', 'purchase_return_items_container', 'purchase_return_items_tbody', 'purchase_return_total_display', 'purchase_submit_return_btn');
// Return Invoice Button from Sales/Purchases list
document.querySelectorAll('.return-invoice-btn').forEach(btn => {
btn.addEventListener('click', function() {
const invoiceId = this.dataset.id;
const targetModal = this.dataset.bsTarget;
const selectId = targetModal === '#addSalesReturnModal' ? 'return_invoice_select' : 'purchase_return_invoice_select';
const select = document.getElementById(selectId);
if (select) {
$(select).val(invoiceId).trigger('change');
}
});
});
// View Return Logic
document.querySelectorAll('.view-return-btn').forEach(btn => {
btn.addEventListener('click', async function() {
const returnId = this.dataset.id;
const type = '<?= $page === "purchase_returns" ? "purchase" : "sale" ?>';
const modal = new bootstrap.Modal(document.getElementById('viewReturnDetailsModal'));
try {
const resp = await fetch(`index.php?action=get_return_details&return_id=${returnId}&type=${type}`);
const data = await resp.json();
if (data) {
document.getElementById('view_return_no').innerText = (type === 'purchase' ? 'PRET-' : 'SRET-') + String(data.id).padStart(5, '0');
document.getElementById('view_return_party').innerText = data.party_name;
document.getElementById('view_return_date').innerText = data.return_date;
document.getElementById('view_return_invoice').innerText = 'INV-' + String(data.invoice_id).padStart(5, '0');
document.getElementById('view_return_total').innerText = 'OMR ' + parseFloat(data.total_amount).toFixed(3);
document.getElementById('view_return_notes').innerText = data.notes || 'No notes';
let itemsHtml = '';
data.items.forEach(item => {
itemsHtml += `
<tr>
<td>${item.name_en}<br><small class="text-muted">${item.sku}</small></td>
<td class="text-center">${parseFloat(item.quantity).toFixed(2)}</td>
<td class="text-end">${parseFloat(item.unit_price).toFixed(3)}</td>
<td class="text-end">${parseFloat(item.total_price).toFixed(3)}</td>
</tr>
`;
});
document.getElementById('view_return_items_tbody').innerHTML = itemsHtml;
modal.show();
}
} catch (e) {
console.error(e);
Swal.fire('Error', 'Failed to fetch return details', 'error');
}
});
});
} catch (e) { console.error("JS Error in DOMContentLoaded:", e); }
});
</script>
<!-- View Return Details Modal -->
<div class="modal fade" id="viewReturnDetailsModal" tabindex="-1">
<div class="modal-dialog modal-lg">
<div class="modal-content text-start border-0 shadow">
<div class="modal-header">
<h5 class="modal-title">Return Details <span id="view_return_no"></span></h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body">
<div class="row mb-4">
<div class="col-6">
<label class="text-muted small d-block">Party Name</label>
<div id="view_return_party" class="fw-bold"></div>
</div>
<div class="col-3">
<label class="text-muted small d-block">Return Date</label>
<div id="view_return_date"></div>
</div>
<div class="col-3">
<label class="text-muted small d-block">Against Invoice</label>
<div id="view_return_invoice"></div>
</div>
</div>
<h6>Returned Items</h6>
<div class="table-responsive">
<table class="table table-sm table-bordered">
<thead class="bg-light">
<tr>
<th>Item</th>
<th class="text-center">Returned Qty</th>
<th class="text-end">Unit Price</th>
<th class="text-end">Total Price</th>
</tr>
</thead>
<tbody id="view_return_items_tbody"></tbody>
<tfoot>
<tr>
<th colspan="3" class="text-end">Total Amount:</th>
<th class="text-end fw-bold" id="view_return_total"></th>
</tr>
</tfoot>
</table>
</div>
<div class="mt-3">
<label class="text-muted small d-block">Notes</label>
<div id="view_return_notes" class="p-2 bg-light rounded"></div>
</div>
</div>
</div>
</div>
</div>
<?php if ($page === 'sales_returns' || $page === 'purchase_returns'): ?>
<div class="modal fade" id="addPurchaseReturnModal" tabindex="-1">
<div class="modal-dialog modal-lg">
<div class="modal-content text-start border-0 shadow">
<div class="modal-header">
<h5 class="modal-title">Process Purchase Return</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<form method="POST">
<div class="modal-body">
<div class="row g-3 mb-4 text-start">
<div class="col-md-6">
<label class="form-label" data-en="Select Invoice" data-ar="اختر الفاتورة">Select Invoice</label>
<select name="invoice_id" id="purchase_return_invoice_select" class="form-select select2" required>
<option value="">Choose Invoice...</option>
<?php if (!empty($data['purchase_invoices'])): ?>
<?php foreach ($data['purchase_invoices'] as $inv): ?>
<option value="<?= $inv['id'] ?>">INV-<?= str_pad((string)$inv['id'], 5, '0', STR_PAD_LEFT) ?> (<?= $inv['invoice_date'] ?>) - OMR <?= number_format((float)$inv['total_with_vat'], 3) ?></option>
<?php endforeach; ?>
<?php endif; ?>
</select>
</div>
<div class="col-md-6">
<label class="form-label">Return Date</label>
<input type="date" name="return_date" class="form-control" value="<?= date('Y-m-d') ?>" required>
</div>
</div>
<div id="purchase_return_items_container" style="display:none;" class="text-start">
<h6>Items for Return</h6>
<div class="table-responsive">
<table class="table table-sm table-bordered">
<thead class="bg-light">
<tr>
<th>Item</th>
<th>Purchased Qty</th>
<th>Return Qty</th>
<th>Price</th>
<th>Total</th>
</tr>
</thead>
<tbody id="purchase_return_items_tbody"></tbody>
<tfoot>
<tr>
<th colspan="4" class="text-end">Total Return Amount:</th>
<th class="text-end" id="purchase_return_total_display">OMR 0.000</th>
</tr>
</tfoot>
</table>
</div>
<div class="mb-3">
<label class="form-label">Notes / Reason for Return</label>
<textarea name="notes" class="form-control" rows="2"></textarea>
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-light" data-bs-dismiss="modal">Cancel</button>
<button type="submit" name="add_purchase_return" class="btn btn-danger" id="purchase_submit_return_btn" disabled>Process Return</button>
</div>
</form>
</div>
</div>
</div>
<!-- Add Sales Return Modal -->
<div class="modal fade" id="addSalesReturnModal" tabindex="-1">
<div class="modal-dialog modal-lg">
<div class="modal-content text-start border-0 shadow">
<div class="modal-header">
<h5 class="modal-title">Process Sales Return</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<form method="POST">
<div class="modal-body">
<div class="row g-3 mb-4 text-start">
<div class="col-md-6">
<label class="form-label" data-en="Select Invoice" data-ar="اختر الفاتورة">Select Invoice</label>
<select name="invoice_id" id="return_invoice_select" class="form-select select2" required>
<option value="">Choose Invoice...</option>
<?php if (!empty($data['sales_invoices'])): ?>
<?php foreach ($data['sales_invoices'] as $inv): ?>
<option value="<?= $inv['id'] ?>">INV-<?= str_pad((string)$inv['id'], 5, '0', STR_PAD_LEFT) ?> (<?= $inv['invoice_date'] ?>) - OMR <?= number_format((float)$inv['total_with_vat'], 3) ?></option>
<?php endforeach; ?>
<?php endif; ?>
</select>
</div>
<div class="col-md-6">
<label class="form-label">Return Date</label>
<input type="date" name="return_date" class="form-control" value="<?= date('Y-m-d') ?>" required>
</div>
</div>
<div id="return_items_container" style="display:none;" class="text-start">
<h6>Items for Return</h6>
<div class="table-responsive">
<table class="table table-sm table-bordered">
<thead class="bg-light">
<tr>
<th>Item</th>
<th>Sold Qty</th>
<th>Return Qty</th>
<th>Price</th>
<th>Total</th>
</tr>
</thead>
<tbody id="return_items_tbody"></tbody>
<tfoot>
<tr>
<th colspan="4" class="text-end">Total Return Amount:</th>
<th class="text-end" id="return_total_display">OMR 0.000</th>
</tr>
</tfoot>
</table>
</div>
<div class="mb-3">
<label class="form-label">Notes / Reason for Return</label>
<textarea name="notes" class="form-control" rows="2"></textarea>
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-light" data-bs-dismiss="modal">Cancel</button>
<button type="submit" name="add_sales_return" class="btn btn-danger" id="submit_return_btn" disabled>Process Return</button>
</div>
</form>
</div>
</div>
</div>
<?php endif; ?>
<!-- Add Account Modal -->
<div class="modal fade" id="addAccountModal" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content border-0 shadow">
<div class="modal-header">
<h5 class="modal-title" data-en="Add New Account" data-ar="إضافة حساب جديد">Add New Account</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<form method="POST">
<div class="modal-body">
<div class="row g-3">
<div class="col-md-4">
<label class="form-label" data-en="Code" data-ar="الكود">Code</label>
<input type="text" name="code" class="form-control" required placeholder="e.g. 1101">
</div>
<div class="col-md-8">
<label class="form-label" data-en="Name (EN)" data-ar="الاسم (إنجليزي)">Name (EN)</label>
<input type="text" name="name_en" class="form-control" required>
</div>
<div class="col-md-12">
<label class="form-label" data-en="Name (AR)" data-ar="الاسم (عربي)">Name (AR)</label>
<input type="text" name="name_ar" class="form-control" required>
</div>
<div class="col-md-6">
<label class="form-label" data-en="Type" data-ar="النوع">Type</label>
<select name="type" class="form-select" required>
<option value="asset">Asset</option>
<option value="liability">Liability</option>
<option value="equity">Equity</option>
<option value="revenue">Revenue</option>
<option value="expense">Expense</option>
</select>
</div>
<div class="col-md-6">
<label class="form-label" data-en="Parent Account" data-ar="الحساب الأب">Parent Account</label>
<select name="parent_id" class="form-select">
<option value="">--- None ---</option>
<?php foreach ($data['accounts'] as $acc): ?>
<option value="<?= $acc['id'] ?>"><?= $acc['code'] ?> - <?= htmlspecialchars($acc['name_en']) ?></option>
<?php endforeach; ?>
</select>
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-light" data-bs-dismiss="modal">Cancel</button>
<button type="submit" name="add_account" class="btn btn-primary">Save Account</button>
</div>
</form>
</div>
</div>
</div>
<!-- Add Manual Journal Modal -->
<div class="modal fade" id="addManualJournalModal" tabindex="-1">
<div class="modal-dialog modal-lg">
<div class="modal-content border-0 shadow">
<div class="modal-header bg-success text-white">
<h5 class="modal-title" data-en="New Manual Journal Entry" data-ar="قيد يومية يدوي جديد">New Manual Journal Entry</h5>
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal"></button>
</div>
<form method="POST">
<div class="modal-body">
<div class="row g-3 mb-4">
<div class="col-md-4">
<label class="form-label" data-en="Entry Date" data-ar="تاريخ القيد">Entry Date</label>
<input type="date" name="entry_date" class="form-control" value="<?= date('Y-m-d') ?>" required>
</div>
<div class="col-md-8">
<label class="form-label" data-en="Description" data-ar="الوصف">Description</label>
<input type="text" name="description" class="form-control" required placeholder="e.g. Opening Balance or Adjustment">
</div>
<div class="col-md-4">
<label class="form-label" data-en="Reference" data-ar="المرجع">Reference</label>
<input type="text" name="reference" class="form-control" placeholder="e.g. JV-001">
</div>
</div>
<h6>Journal Details</h6>
<div class="table-responsive">
<table class="table table-bordered">
<thead class="bg-light">
<tr>
<th style="width: 50%;">Account</th>
<th style="width: 20%;">Debit</th>
<th style="width: 20%;">Credit</th>
<th style="width: 10%;"></th>
</tr>
</thead>
<tbody id="manualJournalBody">
<tr class="journal-row">
<td>
<select name="codes[]" class="form-select select2-journal" required>
<option value="">--- Select Account ---</option>
<?php foreach ($data['accounts'] as $acc): ?>
<option value="<?= $acc['code'] ?>"><?= $acc['code'] ?> - <?= htmlspecialchars($acc['name_en']) ?></option>
<?php endforeach; ?>
</select>
</td>
<td><input type="number" step="0.001" name="debits[]" class="form-control journal-debit" value="0.000"></td>
<td><input type="number" step="0.001" name="credits[]" class="form-control journal-credit" value="0.000"></td>
<td></td>
</tr>
<tr class="journal-row">
<td>
<select name="codes[]" class="form-select select2-journal" required>
<option value="">--- Select Account ---</option>
<?php foreach ($data['accounts'] as $acc): ?>
<option value="<?= $acc['code'] ?>"><?= $acc['code'] ?> - <?= htmlspecialchars($acc['name_en']) ?></option>
<?php endforeach; ?>
</select>
</td>
<td><input type="number" step="0.001" name="debits[]" class="form-control journal-debit" value="0.000"></td>
<td><input type="number" step="0.001" name="credits[]" class="form-control journal-credit" value="0.000"></td>
<td></td>
</tr>
</tbody>
<tfoot>
<tr>
<td colspan="4">
<button type="button" class="btn btn-outline-primary btn-sm" onclick="addJournalRow()">
<i class="bi bi-plus-lg"></i> Add Row
</button>
</td>
</tr>
<tr class="table-light fw-bold">
<td class="text-end">Total</td>
<td id="totalDebitDisplay">0.000</td>
<td id="totalCreditDisplay">0.000</td>
<td></td>
</tr>
</tfoot>
</table>
</div>
<div id="journalBalanceWarning" class="alert alert-danger py-2 mt-2" style="display:none;">
<small><i class="bi bi-exclamation-triangle"></i> Journal is not balanced! Difference: <span id="journalDifference">0.000</span></small>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-light" data-bs-dismiss="modal" data-en="Cancel" data-ar="إلغاء">Cancel</button>
<button type="submit" name="add_manual_journal" id="saveJournalBtn" class="btn btn-primary" data-en="Save Entry" data-ar="حفظ القيد" disabled>Save Entry</button>
</div>
</form>
</div>
</div>
</div>
<script>
function addJournalRow() {
const tbody = document.getElementById('manualJournalBody');
const row = document.createElement('tr');
row.className = 'journal-row';
row.innerHTML = `
<td>
<select name="codes[]" class="form-select select2-journal" required>
<option value="">--- Select Account ---</option>
<?php foreach ($data['accounts'] as $acc): ?>
<option value="<?= $acc['code'] ?>"><?= $acc['code'] ?> - <?= htmlspecialchars($acc['name_en']) ?></option>
<?php endforeach; ?>
</select>
</td>
<td><input type="number" step="0.001" name="debits[]" class="form-control journal-debit" value="0.000"></td>
<td><input type="number" step="0.001" name="credits[]" class="form-control journal-credit" value="0.000"></td>
<td class="text-center">
<button type="button" class="btn btn-link text-danger p-0" onclick="this.closest('tr').remove(); calculateJournalBalance();">
<i class="bi bi-trash"></i>
</button>
</td>
`;
tbody.appendChild(row);
// Init Select2 for new row
$(row).find('.select2-journal').select2({
width: '100%',
dropdownParent: $('#addManualJournalModal')
});
attachJournalListeners(row);
}
function attachJournalListeners(row) {
row.querySelectorAll('input').forEach(input => {
input.addEventListener('input', calculateJournalBalance);
});
}
function calculateJournalBalance() {
let totalDebit = 0;
let totalCredit = 0;
document.querySelectorAll('.journal-row').forEach(row => {
totalDebit += parseFloat(row.querySelector('.journal-debit').value) || 0;
totalCredit += parseFloat(row.querySelector('.journal-credit').value) || 0;
});
document.getElementById('totalDebitDisplay').innerText = totalDebit.toFixed(3);
document.getElementById('totalCreditDisplay').innerText = totalCredit.toFixed(3);
const diff = Math.abs(totalDebit - totalCredit);
const isBalanced = diff < 0.001 && (totalDebit > 0 || totalCredit > 0);
document.getElementById('saveJournalBtn').disabled = !isBalanced;
const warning = document.getElementById('journalBalanceWarning');
if (diff >= 0.001) {
warning.style.display = 'block';
document.getElementById('journalDifference').innerText = diff.toFixed(3);
} else {
warning.style.display = 'none';
}
}
document.addEventListener('DOMContentLoaded', function() {
document.querySelectorAll('.journal-row').forEach(attachJournalListeners);
$('.select2-journal').select2({
width: '100%',
dropdownParent: $('#addManualJournalModal')
});
});
</script>
<!-- View Invoice Modal -->
<!-- Add Invoice Modal -->
<div class="modal fade" id="addInvoiceModal" tabindex="-1">
<div class="modal-dialog modal-xl">
<div class="modal-content border-0 shadow">
<div class="modal-header bg-primary text-white">
<h5 class="modal-title" data-en="Create New Tax Invoice" data-ar="إنشاء فاتورة ضريبية جديدة">Create New Tax Invoice</h5>
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal"></button>
</div>
<form method="POST">
<input type="hidden" name="type" value="<?= $page === 'sales' ? 'sale' : 'purchase' ?>">
<div class="modal-body p-4">
<div class="row g-3 mb-4">
<div class="col-md-4">
<label class="form-label fw-bold" data-en="<?= $page === 'sales' ? 'Customer' : 'Supplier' ?>" data-ar="<?= $page === 'sales' ? 'العميل' : 'المورد' ?>"><?= $page === 'sales' ? 'Customer' : 'Supplier' ?></label>
<select name="customer_id" class="form-select select2" required>
<option value="">---</option>
<?php foreach ($data['customers_list'] as $c): ?>
<option value="<?= $c['id'] ?>"><?= htmlspecialchars($c['name']) ?></option>
<?php endforeach; ?>
</select>
</div>
<div class="col-md-2">
<label class="form-label fw-bold" data-en="Date" data-ar="التاريخ">Date</label>
<input type="date" name="invoice_date" class="form-control" value="<?= date('Y-m-d') ?>" required>
</div>
<div class="col-md-2">
<label class="form-label fw-bold" data-en="Payment Type" data-ar="طريقة الدفع">Payment Type</label>
<select name="payment_type" class="form-select">
<option value="cash">Cash</option>
<option value="card">Card</option>
<option value="bank_transfer">Bank Transfer</option>
<option value="credit">Credit</option>
</select>
</div>
<div class="col-md-2">
<label class="form-label fw-bold" data-en="Status" data-ar="الحالة">Status</label>
<select name="status" id="add_status" class="form-select">
<option value="unpaid">Unpaid</option>
<option value="partially_paid">Partially Paid</option>
<option value="paid">Paid</option>
</select>
</div>
<div class="col-md-2" id="addPaidAmountContainer" style="display: none;">
<label class="form-label fw-bold" data-en="Paid Amount" data-ar="المبلغ المدفوع">Paid Amount</label>
<input type="number" step="0.001" name="paid_amount" class="form-control" value="0.000">
</div>
</div>
<div class="card mb-4">
<div class="card-body bg-light">
<label class="form-label fw-bold" data-en="Search Items" data-ar="بحث عن أصناف">Search Items</label>
<div class="position-relative">
<input type="text" id="productSearchInput" class="form-control" placeholder="Search by name or SKU..." autocomplete="off">
<div id="searchSuggestions" class="list-group position-absolute w-100 shadow-sm" style="display: none; z-index: 1000;"></div>
</div>
</div>
</div>
<div class="table-responsive">
<table class="table table-bordered align-middle">
<thead class="bg-light">
<tr>
<th style="width: 40%;" data-en="Item Details" data-ar="تفاصيل الصنف">Item Details</th>
<th style="width: 15%;" data-en="Qty" data-ar="الكمية">Qty</th>
<th style="width: 15%;" data-en="Unit Price" data-ar="سعر الوحدة">Unit Price</th>
<th style="width: 10%;" data-en="VAT" data-ar="الضريبة">VAT</th>
<th style="width: 15%;" data-en="Total" data-ar="الإجمالي">Total</th>
<th style="width: 5%;"></th>
</tr>
</thead>
<tbody id="invoiceItemsTableBody"></tbody>
<tfoot>
<tr>
<td colspan="4" class="text-end fw-bold" data-en="Subtotal" data-ar="الإجمالي الفرعي">Subtotal</td>
<td class="text-end fw-bold" id="subtotal">OMR 0.000</td>
<td></td>
</tr>
<tr>
<td colspan="4" class="text-end fw-bold" data-en="Total VAT" data-ar="إجمالي الضريبة">Total VAT</td>
<td class="text-end fw-bold" id="totalVat">OMR 0.000</td>
<td></td>
</tr>
<tr class="table-primary">
<td colspan="4" class="text-end fw-bold h5" data-en="Grand Total" data-ar="الإجمالي النهائي">Grand Total</td>
<td class="text-end fw-bold h5" id="grandTotal">OMR 0.000</td>
<td></td>
</tr>
</tfoot>
</table>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-light" data-bs-dismiss="modal" data-en="Cancel" data-ar="إلغاء">Cancel</button>
<button type="submit" name="add_invoice" class="btn btn-primary" data-en="Create Invoice" data-ar="إنشاء الفاتورة">Create Invoice</button>
</div>
</form>
</div>
</div>
</div>
<!-- Edit Invoice Modal -->
<div class="modal fade" id="editInvoiceModal" tabindex="-1">
<div class="modal-dialog modal-xl">
<div class="modal-content border-0 shadow">
<div class="modal-header bg-primary text-white">
<h5 class="modal-title" data-en="Edit Invoice" data-ar="تعديل الفاتورة">Edit Invoice</h5>
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal"></button>
</div>
<form method="POST">
<input type="hidden" name="invoice_id" id="edit_invoice_id">
<div class="modal-body p-4">
<div class="row g-3 mb-4">
<div class="col-md-4">
<label class="form-label fw-bold" data-en="<?= $page === 'sales' ? 'Customer' : 'Supplier' ?>" data-ar="<?= $page === 'sales' ? 'العميل' : 'المورد' ?>"><?= $page === 'sales' ? 'Customer' : 'Supplier' ?></label>
<select name="customer_id" id="edit_customer_id" class="form-select select2" required>
<option value="">---</option>
<?php foreach ($data['customers_list'] as $c): ?>
<option value="<?= $c['id'] ?>"><?= htmlspecialchars($c['name']) ?></option>
<?php endforeach; ?>
</select>
</div>
<div class="col-md-2">
<label class="form-label fw-bold" data-en="Date" data-ar="التاريخ">Date</label>
<input type="date" name="invoice_date" id="edit_invoice_date" class="form-control" required>
</div>
<div class="col-md-2">
<label class="form-label fw-bold" data-en="Payment Type" data-ar="طريقة الدفع">Payment Type</label>
<select name="payment_type" id="edit_payment_type" class="form-select">
<option value="cash">Cash</option>
<option value="card">Card</option>
<option value="bank_transfer">Bank Transfer</option>
<option value="credit">Credit</option>
</select>
</div>
<div class="col-md-2">
<label class="form-label fw-bold" data-en="Status" data-ar="الحالة">Status</label>
<select name="status" id="edit_status" class="form-select">
<option value="unpaid">Unpaid</option>
<option value="partially_paid">Partially Paid</option>
<option value="paid">Paid</option>
</select>
</div>
<div class="col-md-2" id="editPaidAmountContainer" style="display: none;">
<label class="form-label fw-bold" data-en="Paid Amount" data-ar="المبلغ المدفوع">Paid Amount</label>
<input type="number" step="0.001" name="paid_amount" id="edit_paid_amount" class="form-control">
</div>
</div>
<div class="card mb-4">
<div class="card-body bg-light">
<label class="form-label fw-bold" data-en="Search Items" data-ar="بحث عن أصناف">Search Items</label>
<div class="position-relative">
<input type="text" id="editProductSearchInput" class="form-control" placeholder="Search by name or SKU..." autocomplete="off">
<div id="editSearchSuggestions" class="list-group position-absolute w-100 shadow-sm" style="display: none; z-index: 1000;"></div>
</div>
</div>
</div>
<div class="table-responsive">
<table class="table table-bordered align-middle">
<thead class="bg-light">
<tr>
<th style="width: 40%;" data-en="Item Details" data-ar="تفاصيل الصنف">Item Details</th>
<th style="width: 15%;" data-en="Qty" data-ar="الكمية">Qty</th>
<th style="width: 15%;" data-en="Unit Price" data-ar="سعر الوحدة">Unit Price</th>
<th style="width: 10%;" data-en="VAT" data-ar="الضريبة">VAT</th>
<th style="width: 15%;" data-en="Total" data-ar="الإجمالي">Total</th>
<th style="width: 5%;"></th>
</tr>
</thead>
<tbody id="editInvoiceItemsTableBody"></tbody>
<tfoot>
<tr>
<td colspan="4" class="text-end fw-bold" data-en="Subtotal" data-ar="الإجمالي الفرعي">Subtotal</td>
<td class="text-end fw-bold" id="edit_subtotal">OMR 0.000</td>
<td></td>
</tr>
<tr>
<td colspan="4" class="text-end fw-bold" data-en="Total VAT" data-ar="إجمالي الضريبة">Total VAT</td>
<td class="text-end fw-bold" id="edit_totalVat">OMR 0.000</td>
<td></td>
</tr>
<tr class="table-primary">
<td colspan="4" class="text-end fw-bold h5" data-en="Grand Total" data-ar="الإجمالي النهائي">Grand Total</td>
<td class="text-end fw-bold h5" id="edit_grandTotal">OMR 0.000</td>
<td></td>
</tr>
</tfoot>
</table>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-light" data-bs-dismiss="modal" data-en="Cancel" data-ar="إلغاء">Cancel</button>
<button type="submit" name="edit_invoice" class="btn btn-primary" data-en="Update Invoice" data-ar="تحديث الفاتورة">Update Invoice</button>
</div>
</form>
</div>
</div>
</div>
<!-- Add Quotation Modal -->
<div class="modal fade" id="addQuotationModal" tabindex="-1">
<div class="modal-dialog modal-xl">
<div class="modal-content border-0 shadow">
<div class="modal-header bg-primary text-white">
<h5 class="modal-title" data-en="Create New Quotation" data-ar="إنشاء عرض سعر جديد">Create New Quotation</h5>
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal"></button>
</div>
<form method="POST">
<div class="modal-body p-4">
<div class="row g-3 mb-4">
<div class="col-md-4">
<label class="form-label fw-bold" data-en="Customer" data-ar="العميل">Customer</label>
<select name="customer_id" class="form-select select2" required>
<option value="">---</option>
<?php foreach ($data['customers_list'] as $c): ?>
<option value="<?= $c['id'] ?>"><?= htmlspecialchars($c['name']) ?></option>
<?php endforeach; ?>
</select>
</div>
<div class="col-md-4">
<label class="form-label fw-bold" data-en="Date" data-ar="التاريخ">Date</label>
<input type="date" name="quotation_date" class="form-control" value="<?= date('Y-m-d') ?>" required>
</div>
<div class="col-md-4">
<label class="form-label fw-bold" data-en="Valid Until" data-ar="صالح حتى">Valid Until</label>
<input type="date" name="valid_until" class="form-control">
</div>
</div>
<div class="card mb-4">
<div class="card-body bg-light">
<label class="form-label fw-bold" data-en="Search Items" data-ar="بحث عن أصناف">Search Items</label>
<div class="position-relative">
<input type="text" id="quotProductSearchInput" class="form-control" placeholder="Search by name or SKU..." autocomplete="off">
<div id="quotSearchSuggestions" class="list-group position-absolute w-100 shadow-sm" style="display: none; z-index: 1000;"></div>
</div>
</div>
</div>
<div class="table-responsive">
<table class="table table-bordered align-middle">
<thead class="bg-light">
<tr>
<th style="width: 40%;" data-en="Item Details" data-ar="تفاصيل الصنف">Item Details</th>
<th style="width: 15%;" data-en="Qty" data-ar="الكمية">Qty</th>
<th style="width: 15%;" data-en="Unit Price" data-ar="سعر الوحدة">Unit Price</th>
<th style="width: 10%;" data-en="VAT" data-ar="الضريبة">VAT</th>
<th style="width: 15%;" data-en="Total" data-ar="الإجمالي">Total</th>
<th style="width: 5%;"></th>
</tr>
</thead>
<tbody id="quotItemsTableBody"></tbody>
<tfoot>
<tr>
<td colspan="4" class="text-end fw-bold" data-en="Subtotal" data-ar="الإجمالي الفرعي">Subtotal</td>
<td class="text-end fw-bold" id="quot_subtotal_display">OMR 0.000</td>
</tr>
<tr>
<td colspan="4" class="text-end fw-bold" data-en="Total VAT" data-ar="إجمالي الضريبة">Total VAT</td>
<td class="text-end fw-bold" id="quot_vat_display">OMR 0.000</td>
</tr>
<tr class="table-primary">
<td colspan="4" class="text-end fw-bold h5" data-en="Grand Total" data-ar="الإجمالي النهائي">Grand Total</td>
<td class="text-end fw-bold h5" id="quot_grand_display">OMR 0.000</td>
</tr>
</tfoot>
</table>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-light" data-bs-dismiss="modal" data-en="Cancel" data-ar="إلغاء">Cancel</button>
<button type="submit" name="add_quotation" class="btn btn-primary" data-en="Create Quotation" data-ar="إنشاء عرض السعر">Create Quotation</button>
</div>
</form>
</div>
</div>
</div>
<!-- Edit Quotation Modal -->
<div class="modal fade" id="editQuotationModal" tabindex="-1">
<div class="modal-dialog modal-xl">
<div class="modal-content border-0 shadow">
<div class="modal-header bg-primary text-white">
<h5 class="modal-title" data-en="Edit Quotation" data-ar="تعديل عرض السعر">Edit Quotation</h5>
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal"></button>
</div>
<form method="POST">
<input type="hidden" name="quotation_id" id="edit_quotation_id">
<div class="modal-body p-4">
<div class="row g-3 mb-4">
<div class="col-md-3">
<label class="form-label fw-bold" data-en="Customer" data-ar="العميل">Customer</label>
<select name="customer_id" id="edit_quot_customer_id" class="form-select select2" required>
<option value="">---</option>
<?php foreach ($data['customers_list'] as $c): ?>
<option value="<?= $c['id'] ?>"><?= htmlspecialchars($c['name']) ?></option>
<?php endforeach; ?>
</select>
</div>
<div class="col-md-3">
<label class="form-label fw-bold" data-en="Date" data-ar="التاريخ">Date</label>
<input type="date" name="quotation_date" id="edit_quot_date" class="form-control" required>
</div>
<div class="col-md-3">
<label class="form-label fw-bold" data-en="Valid Until" data-ar="صالح حتى">Valid Until</label>
<input type="date" name="valid_until" id="edit_quot_valid" class="form-control">
</div>
<div class="col-md-3">
<label class="form-label fw-bold" data-en="Status" data-ar="الحالة">Status</label>
<select name="status" id="edit_quot_status" class="form-select">
<option value="pending">Pending</option>
<option value="converted">Converted</option>
<option value="expired">Expired</option>
<option value="cancelled">Cancelled</option>
</select>
</div>
</div>
<div class="card mb-4">
<div class="card-body bg-light">
<label class="form-label fw-bold" data-en="Search Items" data-ar="بحث عن أصناف">Search Items</label>
<div class="position-relative">
<input type="text" id="editQuotProductSearchInput" class="form-control" placeholder="Search by name or SKU..." autocomplete="off">
<div id="editQuotSearchSuggestions" class="list-group position-absolute w-100 shadow-sm" style="display: none; z-index: 1000;"></div>
</div>
</div>
</div>
<div class="table-responsive">
<table class="table table-bordered align-middle">
<thead class="bg-light">
<tr>
<th style="width: 40%;" data-en="Item Details" data-ar="تفاصيل الصنف">Item Details</th>
<th style="width: 15%;" data-en="Qty" data-ar="الكمية">Qty</th>
<th style="width: 15%;" data-en="Unit Price" data-ar="سعر الوحدة">Unit Price</th>
<th style="width: 10%;" data-en="VAT" data-ar="الضريبة">VAT</th>
<th style="width: 15%;" data-en="Total" data-ar="الإجمالي">Total</th>
<th style="width: 5%;"></th>
</tr>
</thead>
<tbody id="editQuotItemsTableBody"></tbody>
<tfoot>
<tr>
<td colspan="4" class="text-end fw-bold" data-en="Subtotal" data-ar="الإجمالي الفرعي">Subtotal</td>
<td class="text-end fw-bold" id="edit_quot_subtotal_display">OMR 0.000</td>
</tr>
<tr>
<td colspan="4" class="text-end fw-bold" data-en="Total VAT" data-ar="إجمالي الضريبة">Total VAT</td>
<td class="text-end fw-bold" id="edit_quot_vat_display">OMR 0.000</td>
</tr>
<tr class="table-primary">
<td colspan="4" class="text-end fw-bold h5" data-en="Grand Total" data-ar="الإجمالي النهائي">Grand Total</td>
<td class="text-end fw-bold h5" id="edit_quot_grand_display">OMR 0.000</td>
</tr>
</tfoot>
</table>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-light" data-bs-dismiss="modal" data-en="Cancel" data-ar="إلغاء">Cancel</button>
<button type="submit" name="edit_quotation" class="btn btn-primary" data-en="Update Quotation" data-ar="تحديث عرض السعر">Update Quotation</button>
</div>
</form>
</div>
</div>
</div>
<!-- View Quotation Modal -->
<div class="modal fade" id="viewQuotationModal" tabindex="-1">
<div class="modal-dialog modal-lg">
<div class="modal-content border-0 shadow">
<div class="modal-header bg-info text-white d-print-none">
<h5 class="modal-title" data-en="View Quotation" data-ar="عرض سعر">View Quotation</h5>
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body p-0" id="quotationPrintableArea">
<!-- Dynamic content -->
</div>
<div class="modal-footer d-print-none">
<div id="quotationActionButtons" class="me-auto"></div>
<button type="button" class="btn btn-secondary" onclick="window.print()"><i class="bi bi-printer"></i> Print</button>
<button type="button" class="btn btn-light" data-bs-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
<style>
@media print {
.no-print, .sidebar, .topbar, .btn, .modal-header, .modal-footer, .d-print-none,
.modal-backdrop { display: none !important; }
body { background: white !important; margin: 0 !important; padding: 0 !important; }
.main-content { margin: 0 !important; padding: 0 !important; background: white !important; }
/* Hide all modals by default */
.modal { display: none !important; }
/* Show ONLY the active modal */
.modal.show {
position: absolute !important;
left: 0 !important;
top: 0 !important;
margin: 0 !important;
padding: 0 !important;
overflow: visible !important;
display: block !important;
visibility: visible !important;
background: white !important;
width: 100% !important;
height: 100% !important;
}
.modal.show .modal-dialog { max-width: 100% !important; width: 100% !important; margin: 0 !important; padding: 0 !important; }
.modal.show .modal-content { border: none !important; box-shadow: none !important; background: white !important; }
.modal.show .modal-body { padding: 0 !important; margin: 0 !important; background: white !important; }
.table-bordered th, .table-bordered td { border: 1px solid #dee2e6 !important; }
.bg-light { background-color: #f8f9fa !important; -webkit-print-color-adjust: exact; }
.text-primary { color: #0d6efd !important; -webkit-print-color-adjust: exact; }
.badge { border: 1px solid #000; color: #000 !important; }
/* Ensure the modal is the only thing visible ONLY when a modal is open */
body.modal-open > *:not(.modal) { display: none !important; }
body.modal-open .main-content { display: none !important; }
}
.invoice-logo { max-height: 80px; width: auto; }
.invoice-header { border-bottom: 2px solid #333; padding-bottom: 20px; }
.invoice-title { font-size: 2.5rem; color: #333; letter-spacing: 2px; }
.invoice-info-card { background: #f8f9fa; border-radius: 8px; padding: 15px; height: 100%; }
.table-formal thead th { background: #333; color: #fff; border: none; text-transform: uppercase; font-size: 0.85rem; }
</style>
<div class="modal fade" id="viewInvoiceModal" tabindex="-1">
<div class="modal-dialog modal-lg">
<div class="modal-content border-0 shadow">
<div class="modal-header d-print-none">
<h5 class="modal-title" data-en="View Invoice" data-ar="عرض الفاتورة">View Invoice</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body p-0" id="invoicePrintableArea">
<div class="p-5">
<div class="invoice-header mb-4">
<div class="row align-items-center">
<div class="col-6">
<?php
$logo = $data['settings']['company_logo'] ?? $_SERVER['PROJECT_IMAGE_URL'] ?? '';
if ($logo):
?>
<img src="<?= htmlspecialchars($logo) ?>" alt="Logo" class="invoice-logo mb-3">
<?php endif; ?>
<h3 class="mb-1 fw-bold"><?= htmlspecialchars($data['settings']['company_name'] ?? 'Accounting System') ?></h3>
<p class="text-muted small mb-0"><?= nl2br(htmlspecialchars($data['settings']['company_address'] ?? '')) ?></p>
<p class="text-muted small mb-0">VAT: <?= htmlspecialchars($data['settings']['vat_number'] ?? '') ?></p>
<?php if (!empty($data['settings']['company_phone'])): ?>
<p class="text-muted small mb-0">Tel: <?= htmlspecialchars($data['settings']['company_phone']) ?></p>
<?php endif; ?>
</div>
<div class="col-6 text-end">
<h1 class="invoice-title fw-bold mb-0 text-uppercase">Tax Invoice</h1>
<div class="mt-2"><span id="invoiceTypeLabel" class="badge"></span></div>
<div class="mt-3">
<p class="mb-0 fs-5">Invoice No: <strong id="invNumber" class="text-primary"></strong></p>
<p class="mb-0">Date: <span id="invDate" class="fw-bold"></span></p>
<p class="mb-0 small">Status: <span id="invoiceStatusLabel"></span></p>
</div>
</div>
</div>
</div>
<div class="row mb-4 g-3">
<div class="col-6">
<div class="invoice-info-card">
<p class="text-muted small text-uppercase fw-bold mb-2 border-bottom pb-1" id="invPartyLabel">Bill To</p>
<h5 class="mb-1 fw-bold"><span id="invCustomerName"></span></h5>
<p class="small text-muted mb-0" id="invCustomerTaxIdContainer">VAT: <span id="invCustomerTaxId"></span></p>
<p class="small text-muted mb-0" id="invCustomerPhoneContainer">Phone: <span id="invCustomerPhone"></span></p>
</div>
</div>
<div class="col-6">
<div class="invoice-info-card text-end">
<p class="text-muted small text-uppercase fw-bold mb-2 border-bottom pb-1">Payment Details</p>
<p class="mb-1">Method: <strong id="invPaymentType"></strong></p>
<p class="mb-0 small text-muted">Currency: <strong>OMR</strong></p>
</div>
</div>
</div>
<table class="table table-bordered table-formal">
<thead>
<tr>
<th>Item Description</th>
<th class="text-center" style="width: 80px;">Qty</th>
<th class="text-end" style="width: 120px;">Unit Price</th>
<th class="text-end" style="width: 100px;">VAT %</th>
<th class="text-end" style="width: 150px;">Total</th>
</tr>
</thead>
<tbody id="invItemsBody"></tbody>
</table>
<div class="row mt-4">
<div class="col-7">
<div class="p-3 bg-light rounded" style="min-height: 100px;">
<p class="text-muted small text-uppercase fw-bold mb-1">Amount in Words</p>
<p id="invAmountInWords" class="small fw-bold mb-0"></p>
</div>
<div class="mt-4">
<p class="text-muted small text-uppercase fw-bold mb-1">Terms & Conditions</p>
<ul class="small text-muted ps-3">
<li>Goods once sold will not be taken back or exchanged.</li>
<li>Payment is due within the agreed credit period.</li>
<li>This is a computer-generated invoice and does not require a physical signature.</li>
</ul>
</div>
</div>
<div class="col-5">
<div class="d-flex justify-content-between mb-2">
<span class="text-muted">Subtotal</span>
<span id="invSubtotal" class="fw-bold"></span>
</div>
<div class="d-flex justify-content-between mb-2">
<span class="text-muted">VAT Amount</span>
<span id="invVatAmount" class="fw-bold"></span>
</div>
<div class="d-flex justify-content-between mb-3 border-top pt-2">
<span class="h4 fw-bold">Grand Total</span>
<span id="invGrandTotal" class="h4 fw-bold text-primary"></span>
</div>
<div id="invPaymentsSection" class="mt-4 border-top pt-3">
<p class="text-muted small text-uppercase fw-bold mb-2">Payment Tracking</p>
<table class="table table-sm table-bordered small mb-3">
<thead class="table-light">
<tr>
<th>Date</th>
<th>Method</th>
<th class="text-end">Amount</th>
</tr>
</thead>
<tbody id="invPaymentsBody"></tbody>
</table>
<div class="bg-light p-3 rounded">
<div class="d-flex justify-content-between small mb-1">
<span>Paid Amount</span>
<span id="invPaidInfo" class="text-success fw-bold"></span>
</div>
<div class="d-flex justify-content-between small fw-bold">
<span>Balance Due</span>
<span id="invBalanceInfo" class="text-danger"></span>
</div>
</div>
</div>
</div>
</div>
<div class="mt-5 pt-4 border-top text-center">
<div class="row">
<div class="col-4">
<div class="border-top pt-2 mx-auto" style="width: 150px;">
<p class="small text-muted">Customer Signature</p>
</div>
</div>
<div class="col-4">
<div id="invQrCode" class="mb-2 d-flex justify-content-center"></div>
</div>
<div class="col-4">
<div class="border-top pt-2 mx-auto" style="width: 150px;">
<p class="small text-muted">Authorized Signatory</p>
</div>
</div>
</div>
<p class="text-muted x-small mt-4 mb-0">Generated by <?= htmlspecialchars($data['settings']['company_name'] ?? 'Accounting System') ?> | Visit us at <?= $_SERVER['HTTP_HOST'] ?></p>
</div>
</div>
</div>
<div class="modal-footer d-print-none">
<button type="button" class="btn btn-light" data-bs-dismiss="modal">Close</button>
<button type="button" class="btn btn-primary" onclick="window.print()"><i class="bi bi-printer me-2"></i>Print Invoice</button>
</div>
</div>
</div>
</div>
<!-- Pay Invoice Modal -->
<div class="modal fade" id="payInvoiceModal" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content border-0 shadow">
<div class="modal-header bg-success text-white">
<h5 class="modal-title" data-en="Record Payment" data-ar="تسجيل دفعة">Record Payment</h5>
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal"></button>
</div>
<form method="POST">
<div class="modal-body">
<input type="hidden" name="invoice_id" id="pay_invoice_id">
<div class="mb-3">
<label class="form-label fw-bold" data-en="Total Amount" data-ar="المبلغ الإجمالي">Total Amount</label>
<input type="text" id="pay_invoice_total" class="form-control" readonly>
</div>
<div class="mb-3">
<label class="form-label fw-bold" data-en="Remaining Amount" data-ar="المبلغ المتبقي">Remaining Amount</label>
<input type="text" id="pay_remaining_amount" class="form-control" readonly>
</div>
<div class="mb-3">
<label class="form-label fw-bold" data-en="Amount to Pay" data-ar="المبلغ المراد دفعه">Amount to Pay</label>
<input type="number" step="0.001" name="amount" id="pay_amount" class="form-control" required>
</div>
<div class="mb-3">
<label class="form-label fw-bold" data-en="Payment Date" data-ar="تاريخ الدفع">Payment Date</label>
<input type="date" name="payment_date" class="form-control" value="<?= date('Y-m-d') ?>" required>
</div>
<div class="mb-3">
<label class="form-label fw-bold" data-en="Payment Method" data-ar="طريقة الدفع">Payment Method</label>
<select name="payment_method" class="form-select select2" required>
<option value="Cash">Cash</option>
<option value="Card">Card</option>
<option value="Bank Transfer">Bank Transfer</option>
</select>
</div>
<div class="mb-3">
<label class="form-label fw-bold" data-en="Notes" data-ar="ملاحظات">Notes</label>
<textarea name="notes" class="form-control" rows="2"></textarea>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-light" data-bs-dismiss="modal" data-en="Cancel" data-ar="إلغاء">Cancel</button>
<button type="submit" name="record_payment" class="btn btn-success" data-en="Save Payment" data-ar="حفظ الدفعة">Save Payment</button>
</div>
</form>
</div>
</div>
</div>
<!-- Payment Receipt Modal -->
<div class="modal fade" id="receiptModal" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content border-0 shadow">
<div class="modal-header border-0 pb-0 d-print-none">
<h5 class="modal-title">Payment Receipt</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body p-0" id="printableReceipt">
<div class="receipt-container p-4">
<div class="text-center mb-4">
<h3 class="mb-1 fw-bold"><?= htmlspecialchars($data['settings']['company_name'] ?? 'Accounting System') ?></h3>
<p class="text-muted small mb-0"><?= nl2br(htmlspecialchars($data['settings']['company_address'] ?? '')) ?></p>
<hr class="my-4">
<h4 class="letter-spacing-2 fw-bold text-uppercase">Payment Receipt</h4>
</div>
<div class="row mb-4">
<div class="col-6">
<p class="mb-1 text-muted small text-uppercase fw-bold">Receipt No</p>
<p class="fw-bold h5 text-primary" id="receiptNo"></p>
</div>
<div class="col-6 text-end">
<p class="mb-1 text-muted small text-uppercase fw-bold">Date</p>
<p class="fw-bold" id="receiptDate"></p>
</div>
</div>
<div class="mb-4 p-3 bg-light rounded">
<div class="row mb-2">
<div class="col-4 text-muted small text-uppercase fw-bold" id="receiptPartyLabel">Received From</div>
<div class="col-8 fw-bold" id="receiptCustomer"></div>
</div>
<div class="row mb-2">
<div class="col-4 text-muted small text-uppercase fw-bold" id="receiptAgainstLabel">Against Invoice</div>
<div class="col-8 fw-bold" id="receiptInvNo"></div>
</div>
<div class="row mb-2">
<div class="col-4 text-muted small text-uppercase fw-bold">Payment Method</div>
<div class="col-8 fw-bold" id="receiptMethod"></div>
</div>
</div>
<div class="text-center my-4 py-4 border-top border-bottom">
<p class="mb-1 text-muted small text-uppercase fw-bold">Amount Paid</p>
<h1 class="display-5 fw-bold text-primary mb-1" id="receiptAmount"></h1>
<p class="text-muted small font-italic" id="receiptAmountWords"></p>
</div>
<div id="receiptNotesContainer" class="mb-4" style="display: none;">
<p class="mb-1 text-muted small text-uppercase fw-bold">Notes</p>
<p class="small p-2 bg-light rounded" id="receiptNotes"></p>
</div>
<div class="row mt-5 pt-4">
<div class="col-6">
<div class="border-top pt-2 text-center small text-muted">Receiver's Signature</div>
</div>
<div class="col-6">
<div class="border-top pt-2 text-center small text-muted">Authorized Signatory</div>
</div>
</div>
</div>
</div>
<div class="modal-footer border-0 d-print-none">
<button type="button" class="btn btn-light" data-bs-dismiss="modal">Close</button>
<button type="button" class="btn btn-primary" onclick="window.printReceipt()"><i class="bi bi-printer me-2"></i>Print Receipt</button>
</div>
</div>
</div>
</div>
<!-- POS Payment Modal -->
<div class="modal fade" id="posPaymentModal" tabindex="-1" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content border-0">
<div class="modal-header border-0 pb-0">
<h5 class="modal-title fw-bold">Payment</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<div class="mb-3 p-3 border rounded bg-light shadow-sm">
<div class="d-flex justify-content-between align-items-center">
<div>
<span class="small text-muted d-block">Customer</span>
<span class="h6 fw-bold m-0 text-primary" id="paymentCustomerName">Walk-in Customer</span>
</div>
<i class="bi bi-person-circle fs-3 text-secondary"></i>
</div>
<div id="creditCustomerSection" class="mt-2 pt-2 border-top" style="display:none;">
<label class="form-label smaller fw-bold mb-1">Select Credit Customer</label>
<select id="paymentCreditCustomer" class="form-select form-select-sm select2" onchange="cart.syncCustomer(this.value)">
<option value="">--- Select Customer ---</option>
<?php foreach ($customers as $c): ?>
<option value="<?= $c['id'] ?>" data-search="<?= htmlspecialchars(strtolower($c['name'] . ' ' . ($c['phone'] ?? ''))) ?>"><?= htmlspecialchars($c['name']) ?> (<?= htmlspecialchars($c['phone'] ?? '') ?>)</option>
<?php endforeach; ?>
</select>
</div>
</div>
<div class="amount-due-box mb-3">
<div class="d-flex justify-content-between px-3">
<div class="text-start">
<div class="label">Amount Due</div>
<div class="value" id="paymentAmountDue">OMR 0.000</div>
</div>
<div class="text-end">
<div class="label text-danger">Remaining</div>
<div class="value text-danger" id="paymentRemaining">OMR 0.000</div>
</div>
</div>
</div>
<div id="paymentList" class="mb-3">
<!-- Added payments will appear here -->
</div>
<div class="mb-3 p-3 border rounded bg-light">
<label class="form-label small fw-bold">Add Payment Method</label>
<div class="payment-methods-grid mb-2">
<div class="payment-method-btn active" data-method="cash" onclick="cart.selectMethod('cash', this)">
<i class="bi bi-cash-stack"></i>
<span class="small fw-bold">Cash</span>
</div>
<div class="payment-method-btn" data-method="card" onclick="cart.selectMethod('card', this)">
<i class="bi bi-credit-card"></i>
<span class="small fw-bold">Card</span>
</div>
<div class="payment-method-btn" data-method="credit" onclick="cart.selectMethod('credit', this)">
<i class="bi bi-person-badge"></i>
<span class="small fw-bold">Credit</span>
</div>
</div>
<div class="row g-2 align-items-end">
<div class="col">
<label class="form-label smaller fw-bold mb-1">Amount</label>
<div class="input-group">
<span class="input-group-text p-1 small">OMR</span>
<input type="number" step="0.001" id="partialAmount" class="form-control" placeholder="0.000" oninput="cart.updateRemaining()">
</div>
</div>
<div class="col-auto">
<button type="button" class="btn btn-primary" onclick="cart.addPaymentLine()">
<i class="bi bi-plus-lg"></i> ADD
</button>
</div>
</div>
<div class="quick-pay-grid mt-2">
<div class="quick-pay-btn" onclick="cart.fillPartial(1)">1</div>
<div class="quick-pay-btn" onclick="cart.fillPartial(5)">5</div>
<div class="quick-pay-btn" onclick="cart.fillPartial(10)">10</div>
<div class="quick-pay-btn" onclick="cart.fillPartial(20)">20</div>
<div class="quick-pay-btn" onclick="cart.fillPartial(50)">50</div>
</div>
</div>
<div id="cashPaymentSection" style="display: none;">
<div class="d-flex justify-content-between align-items-center p-3 bg-primary-subtle rounded border border-primary-subtle">
<span class="fw-bold">Total Tendered (Cash)</span>
<span class="h4 m-0 fw-bold text-primary" id="changeDue">OMR 0.000</span>
</div>
<div class="small text-muted mt-1">* Change is calculated based on cash payments only.</div>
</div>
</div>
<div class="modal-footer border-0">
<button type="button" class="btn btn-light" data-bs-dismiss="modal">Cancel</button>
<button type="button" class="btn btn-primary px-4" id="confirmPaymentBtn" onclick="cart.completeOrder()">
PAY & COMPLETE
</button>
</div>
</div>
</div>
</div>
<!-- POS Receipt Modal -->
<div class="modal fade" id="posReceiptModal" tabindex="-1" aria-hidden="true">
<div class="modal-dialog modal-sm">
<div class="modal-content border-0">
<div class="modal-header border-0 pb-0">
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body pt-0">
<div id="posReceiptContent">
<!-- Receipt content will be generated here -->
</div>
</div>
<div class="modal-footer border-0">
<button type="button" class="btn btn-primary w-100" onclick="printPosReceipt()">
<i class="bi bi-printer me-2"></i>PRINT RECEIPT
</button>
</div>
</div>
</div>
</div>
<div id="posPrintArea" class="d-none d-print-block"></div>
<!-- Barcode Print Modal -->
<div class="modal fade" id="barcodePrintModal" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content border-0 shadow">
<div class="modal-header">
<h5 class="modal-title">Print Barcode Label</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body text-center">
<div id="barcodeContainer" class="p-4 bg-white border mb-3 mx-auto" style="width: fit-content;">
<div id="barcodeLabelName" class="fw-bold small mb-1"></div>
<svg id="barcodeSvg"></svg>
<div id="barcodeLabelPrice" class="fw-bold mt-1"></div>
</div>
<div class="mb-3">
<label class="form-label small">Number of Labels</label>
<input type="number" id="barcodeQty" class="form-control form-control-sm mx-auto" value="1" min="1" style="width: 80px;">
</div>
<div class="row mb-3 mx-auto" style="max-width: 200px;">
<div class="col-6">
<label class="form-label small">Width (mm)</label>
<input type="number" id="barcodeWidth" class="form-control form-control-sm" value="40" min="10">
</div>
<div class="col-6">
<label class="form-label small">Height (mm)</label>
<input type="number" id="barcodeHeight" class="form-control form-control-sm" value="25" min="10">
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-light" data-bs-dismiss="modal">Close</button>
<button type="button" class="btn btn-primary" onclick="executeBarcodePrint()"><i class="bi bi-printer me-2"></i>Print Now</button>
</div>
</div>
</div>
</div>
<!-- Avery Labels Modal -->
<div class="modal fade" id="averyLabelsModal" tabindex="-1">
<div class="modal-dialog modal-xl">
<div class="modal-content border-0 shadow">
<div class="modal-header d-print-none">
<h5 class="modal-title">Avery Barcode Labels (A4)</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body">
<div class="row mb-4 d-print-none">
<div class="col-md-4">
<label class="form-label small">Label Layout</label>
<select id="averyLayout" class="form-select form-select-sm" onchange="updateAveryPreview()">
<option value="3x7">3 x 7 (21 Labels per sheet)</option>
<option value="3x8">3 x 8 (24 Labels per sheet)</option>
<option value="4x10">4 x 10 (40 Labels per sheet)</option>
<option value="L7651">L7651 (5 x 13 - 65 Labels)</option>
<option value="L4736">L4736 (2 x 7 - 14 Labels)</option>
</select>
</div>
<div class="col-md-4">
<label class="form-label small">Copies (Set All)</label>
<input type="number" id="averyCopies" class="form-control form-control-sm" value="1" min="1" oninput="updateAllItemQuantities()" onchange="updateAllItemQuantities()">
</div>
<div class="col-md-4 d-flex align-items-end">
<button class="btn btn-primary btn-sm w-100" onclick="window.print()"><i class="bi bi-printer me-2"></i>Print A4 Sheet</button>
</div>
</div>
<div class="row mb-3 d-print-none">
<div class="col-12">
<label class="form-label small fw-bold" data-en="Quantities per Item" data-ar="الكميات لكل صنف">Quantities per Item</label>
<div id="averyItemQuantities" class="border rounded p-2 bg-light" style="max-height: 150px; overflow-y: auto;">
<small class="text-muted">Select items to adjust quantities.</small>
</div>
</div>
</div>
<div id="averyPrintArea" class="avery-container">
<!-- Labels will be generated here -->
</div>
</div>
</div>
</div>
</div>
<style>
/* Avery Label Printing */
.avery-container {
background: white;
width: 210mm; /* A4 Width */
min-height: 297mm; /* A4 Height */
padding: 10mm 5mm;
margin: 0 auto;
display: grid;
gap: 2mm;
box-shadow: 0 0 10px rgba(0,0,0,0.1);
}
.avery-layout-3x7 { grid-template-columns: repeat(3, 1fr); grid-auto-rows: 38mm; }
.avery-layout-3x8 { grid-template-columns: repeat(3, 1fr); grid-auto-rows: 34mm; }
.avery-layout-4x10 { grid-template-columns: repeat(4, 1fr); grid-auto-rows: 27mm; }
.avery-layout-L7651 { grid-template-columns: repeat(5, 1fr); grid-auto-rows: 21mm; }
.avery-layout-L4736 { grid-template-columns: repeat(2, 1fr); grid-auto-rows: 38mm; }
.avery-layout-L7651 .avery-label { padding: 2mm; }
.avery-layout-L7651 .avery-label svg { height: 25px; }
.avery-layout-L7651 .avery-label div { font-size: 8px !important; }
.avery-label {
border: 1px dashed #eee;
padding: 5mm;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
text-align: center;
overflow: hidden;
background: white;
}
.avery-label svg {
max-width: 100%;
height: auto;
}
@media print {
body.printing-avery .sidebar,
body.printing-avery .topbar,
body.printing-avery .modal-header,
body.printing-avery .d-print-none,
body.printing-avery .modal-backdrop {
display: none !important;
}
body.printing-avery .modal {
position: absolute !important;
left: 0 !important;
top: 0 !important;
width: 100% !important;
display: block !important;
visibility: visible !important;
background: white !important;
}
body.printing-avery .modal-dialog {
max-width: 100% !important;
width: 100% !important;
margin: 0 !important;
padding: 0 !important;
}
body.printing-avery .modal-content {
border: none !important;
}
body.printing-avery .avery-label {
border: none !important;
}
.avery-container {
margin: 0 !important;
padding: 10mm 5mm !important;
box-shadow: none !important;
border: none !important;
}
}
</style>
<script>
// Avery Label Logic
const selectAllItems = document.getElementById('selectAllItems');
const bulkBarcodeBtn = document.getElementById('bulkBarcodeBtn');
if (selectAllItems) {
selectAllItems.addEventListener('change', function() {
document.querySelectorAll('.item-checkbox').forEach(cb => {
cb.checked = this.checked;
});
toggleBulkBtn();
});
}
document.addEventListener('change', function(e) {
if (e.target.classList.contains('item-checkbox')) {
toggleBulkBtn();
}
});
function toggleBulkBtn() {
const checked = document.querySelectorAll('.item-checkbox:checked').length;
if (bulkBarcodeBtn) {
bulkBarcodeBtn.style.display = checked > 0 ? 'inline-block' : 'none';
}
}
window.openAveryModal = function() {
const modal = new bootstrap.Modal(document.getElementById('averyLabelsModal'));
const checkedItems = document.querySelectorAll('.item-checkbox:checked');
const container = document.getElementById('averyItemQuantities');
const defaultCopies = parseInt(document.getElementById('averyCopies').value) || 1;
if (container) {
container.innerHTML = '';
if (checkedItems.length === 0) {
container.innerHTML = '<small class="text-muted">No items selected.</small>';
} else {
const table = document.createElement('table');
table.className = 'table table-sm table-borderless mb-0';
const tbody = document.createElement('tbody');
checkedItems.forEach(cb => {
const sku = cb.dataset.sku;
const name = cb.dataset.name;
const id = cb.dataset.id;
const tr = document.createElement('tr');
tr.innerHTML = `
<td class="align-middle" style="width: 70%; font-size: 0.9em;">${name} <span class="text-muted">(${sku})</span></td>
<td class="align-middle" style="width: 30%;">
<input type="number" class="form-control form-control-sm item-qty-input"
data-id="${id}" value="${defaultCopies}" min="0" onchange="updateAveryPreview()" onkeyup="updateAveryPreview()">
</td>
`;
tbody.appendChild(tr);
});
table.appendChild(tbody);
container.appendChild(table);
}
}
modal.show();
updateAveryPreview();
};
window.updateAllItemQuantities = function() {
const globalQty = document.getElementById('averyCopies').value;
const itemInputs = document.querySelectorAll('.item-qty-input');
itemInputs.forEach(input => {
input.value = globalQty;
});
updateAveryPreview();
};
window.updateAveryPreview = function() {
const layout = document.getElementById('averyLayout').value;
const container = document.getElementById('averyPrintArea');
const checkedItems = document.querySelectorAll('.item-checkbox:checked');
container.className = 'avery-container avery-layout-' + layout;
container.innerHTML = '';
checkedItems.forEach(cb => {
const sku = cb.dataset.sku;
const name = cb.dataset.name;
const price = cb.dataset.price;
const id = cb.dataset.id;
// Find specific quantity input
const qtyInput = document.querySelector(`.item-qty-input[data-id="${id}"]`);
let copies = 1;
if (qtyInput) {
copies = parseInt(qtyInput.value) || 0;
} else {
copies = parseInt(document.getElementById('averyCopies').value) || 1;
}
for (let i = 0; i < copies; i++) {
const label = document.createElement('div');
label.className = 'avery-label';
const uniqueId = Math.random().toString(36).substr(2, 9);
const svgId = `bc-${sku}-${uniqueId}`;
label.innerHTML = `
<div style="font-size: 10px; font-weight: bold; margin-bottom: 2px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; width: 100%;">${name}</div>
<svg id="${svgId}"></svg>
<div style="font-size: 11px; font-weight: bold; margin-top: 2px;">OMR ${price}</div>
`;
container.appendChild(label);
setTimeout(() => {
if (document.getElementById(svgId)) {
const bcHeight = layout === 'L7651' ? 20 : 35;
JsBarcode(`#${svgId}`, sku, {
format: "CODE128",
width: layout === 'L7651' ? 1.0 : 1.2,
height: bcHeight,
displayValue: true,
fontSize: layout === 'L7651' ? 8 : 10,
margin: 0
});
}
}, 0);
}
});
};
window.addEventListener('beforeprint', () => {
if (document.getElementById('averyLabelsModal') && document.getElementById('averyLabelsModal').classList.contains('show')) {
document.body.classList.add('printing-avery');
}
});
window.addEventListener('afterprint', () => {
document.body.classList.remove('printing-avery');
});
</script>
<script>
window.printItemBarcode = function(sku, name, price) {
if (!sku) {
Swal.fire('Error', 'This item has no SKU/Barcode assigned.', 'error');
return;
}
document.getElementById('barcodeLabelName').textContent = name;
document.getElementById('barcodeLabelPrice').textContent = 'OMR ' + price;
JsBarcode("#barcodeSvg", sku, {
format: "CODE128",
lineColor: "#000",
width: 2,
height: 50,
displayValue: true
});
const modal = new bootstrap.Modal(document.getElementById('barcodePrintModal'));
modal.show();
};
window.executeBarcodePrint = function() {
const qty = parseInt(document.getElementById('barcodeQty').value) || 1;
const width = parseInt(document.getElementById('barcodeWidth').value) || 40;
const height = parseInt(document.getElementById('barcodeHeight').value) || 25;
// Get content
const name = document.getElementById('barcodeLabelName').innerText;
const price = document.getElementById('barcodeLabelPrice').innerText;
const svg = document.getElementById('barcodeSvg').outerHTML;
// Create a hidden iframe
const iframe = document.createElement('iframe');
iframe.style.position = 'absolute';
iframe.style.width = '0px';
iframe.style.height = '0px';
iframe.style.border = 'none';
document.body.appendChild(iframe);
const doc = iframe.contentWindow.document;
let labelsHtml = '';
for (let i = 0; i < qty; i++) {
labelsHtml += `
<div class="label-container">
<div class="label-name">${name}</div>
${svg}
<div class="label-price">${price}</div>
</div>
`;
}
doc.open();
doc.write(`
<html>
<head>
<style>
@page { size: ${width}mm ${height}mm; margin: 0; }
body { margin: 0; padding: 0; font-family: sans-serif; }
.label-container {
width: ${width}mm;
height: ${height}mm;
page-break-after: always;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
text-align: center;
overflow: hidden;
box-sizing: border-box;
padding: 1mm;
}
.label-container:last-child { page-break-after: avoid; }
.label-name { font-size: 10px; font-weight: bold; margin-bottom: 2px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 100%; }
.label-price { font-size: 12px; font-weight: bold; margin-top: 2px; }
svg { max-width: 100%; height: auto; max-height: 70%; display: block; }
</style>
</head>
<body>
${labelsHtml}
</body>
</html>
`);
doc.close();
iframe.contentWindow.focus();
setTimeout(() => {
iframe.contentWindow.print();
setTimeout(() => {
document.body.removeChild(iframe);
}, 2000);
}, 500);
};
window.viewAndPrintA4Invoice = function(data, autoPrint = true) {
if (!data) return;
// Reuse view logic
document.getElementById('invNumber').textContent = 'INV-' + data.id.toString().padStart(5, '0');
document.getElementById('invDate').textContent = data.invoice_date;
document.getElementById('invPaymentType').textContent = data.payment_type ? data.payment_type.toUpperCase() : 'CASH';
document.getElementById('invCustomerName').textContent = data.customer_name || '---';
const phoneEl = document.getElementById('invCustomerPhone');
const phoneContainer = document.getElementById('invCustomerPhoneContainer');
if (data.customer_phone) {
phoneEl.textContent = data.customer_phone;
phoneContainer.style.display = 'block';
} else {
phoneContainer.style.display = 'none';
}
const taxIdEl = document.getElementById('invCustomerTaxId');
const taxIdContainer = document.getElementById('invCustomerTaxIdContainer');
if (data.customer_tax_id) {
taxIdEl.textContent = data.customer_tax_id;
taxIdContainer.style.display = 'block';
} else {
taxIdContainer.style.display = 'none';
}
document.getElementById('invAmountInWords').textContent = data.total_in_words || '';
document.getElementById('invPartyLabel').textContent = data.type === 'sale' ? 'Bill To' : 'Bill From';
document.getElementById('invPartyLabel').setAttribute('data-en', data.type === 'sale' ? 'Bill To' : 'Bill From');
document.getElementById('invPartyLabel').setAttribute('data-ar', data.type === 'sale' ? 'فاتورة إلى' : 'فاتورة من');
document.getElementById('invoiceTypeLabel').textContent = data.type;
document.getElementById('invoiceTypeLabel').className = 'badge text-uppercase ' + (data.type === 'sale' ? 'bg-success' : 'bg-warning');
const statusLabel = document.getElementById('invoiceStatusLabel');
let statusClass = 'bg-secondary';
let statusEn = data.status ? (data.status.charAt(0).toUpperCase() + data.status.slice(1)) : '---';
if (data.status === 'paid') statusClass = 'bg-success';
else if (data.status === 'unpaid') statusClass = 'bg-danger';
else if (data.status === 'partially_paid') {
statusClass = 'bg-warning text-dark';
statusEn = 'Partially Paid';
}
statusLabel.textContent = statusEn;
statusLabel.className = 'badge text-uppercase ' + statusClass;
const body = document.getElementById('invItemsBody');
body.innerHTML = '';
if (data.items) {
data.items.forEach(item => {
const tr = document.createElement('tr');
tr.innerHTML = `
<td>${item.name_en} / ${item.name_ar}</td>
<td class="text-center">${item.quantity}</td>
<td class="text-end">OMR ${parseFloat(item.unit_price).toFixed(3)}</td>
<td class="text-end">${parseFloat(item.vat_rate || 0).toFixed(3)}%</td>
<td class="text-end">OMR ${parseFloat(item.total_price).toFixed(3)}</td>
`;
body.appendChild(tr);
});
}
if (document.getElementById('invSubtotal')) document.getElementById('invSubtotal').textContent = 'OMR ' + parseFloat(data.total_amount).toFixed(3);
if (document.getElementById('invVatAmount')) document.getElementById('invVatAmount').textContent = 'OMR ' + (parseFloat(data.vat_amount) || 0).toFixed(3);
const grandTotalValue = (parseFloat(data.total_with_vat) || parseFloat(data.total_amount));
if (document.getElementById('invGrandTotal')) document.getElementById('invGrandTotal').textContent = 'OMR ' + grandTotalValue.toFixed(3);
if (document.getElementById('invPaidInfo')) document.getElementById('invPaidInfo').textContent = 'OMR ' + parseFloat(data.paid_amount || 0).toFixed(3);
const balance = grandTotalValue - parseFloat(data.paid_amount || 0);
if (document.getElementById('invBalanceInfo')) document.getElementById('invBalanceInfo').textContent = 'OMR ' + balance.toFixed(3);
// Generate QR Code for Zakat, Tax and Customs Authority (ZATCA) style or simple formal
const companyName = <?= json_encode($data['settings']['company_name'] ?? 'Accounting System') ?>;
const vatNo = <?= json_encode($data['settings']['vat_number'] ?? '') ?>;
const qrData = `Seller: ${companyName}\nVAT: ${vatNo}\nInvoice: INV-${data.id.toString().padStart(5, '0')}\nDate: ${data.invoice_date}\nTotal: ${grandTotalValue.toFixed(3)}`;
const qrUrl = `https://api.qrserver.com/v1/create-qr-code/?size=100x100&data=${encodeURIComponent(qrData)}`;
if (document.getElementById('invQrCode')) {
document.getElementById('invQrCode').innerHTML = `<img src="${qrUrl}" alt="QR Code" style="width: 100px; height: 100px;" class="border p-1 bg-white">`;
}
const viewModal = bootstrap.Modal.getOrCreateInstance(document.getElementById('viewInvoiceModal'));
viewModal.show();
if (autoPrint) {
setTimeout(() => { window.print(); }, 1000);
}
fetch(`index.php?action=get_payments&invoice_id=${data.id}`)
.then(res => res.json())
.then(payments => {
const paymentsBody = document.getElementById('invPaymentsBody');
const paymentsSection = document.getElementById('invPaymentsSection');
if (paymentsBody) paymentsBody.innerHTML = '';
if (payments && payments.length > 0) {
if (paymentsBody) {
payments.forEach(p => {
const tr = document.createElement('tr');
tr.innerHTML = `<td>${p.payment_date}</td><td>${p.payment_method}</td><td class="text-end fw-bold">OMR ${parseFloat(p.amount).toFixed(3)}</td>`;
paymentsBody.appendChild(tr);
});
}
if (paymentsSection) paymentsSection.style.display = 'block';
} else {
if (paymentsSection) paymentsSection.style.display = 'none';
}
}).catch(err => console.error('Error fetching payments:', err));
};
window.printPosReceiptFromInvoice = function(inv) {
const container = document.getElementById('posReceiptContent');
const itemsHtml = inv.items.map(item => `
<tr>
<td>${item.name_en}<br><small>${item.quantity} x ${parseFloat(item.unit_price).toFixed(3)}</small></td>
<td style="text-align: right; vertical-align: bottom;">${(item.unit_price * item.quantity).toFixed(3)}</td>
</tr>
`).join('');
const companyName = "<?= htmlspecialchars($data['settings']['company_name'] ?? 'Accounting System') ?>";
const companyPhone = "<?= htmlspecialchars($data['settings']['company_phone'] ?? '') ?>";
const companyVat = "<?= htmlspecialchars($data['settings']['vat_number'] ?? '') ?>";
container.innerHTML = `
<div class="thermal-receipt">
<div class="center">
<h5 class="mb-0 fw-bold">${companyName}</h5>
${companyPhone ? `<div>Tel: ${companyPhone}</div>` : ''}
${companyVat ? `<div>VAT: ${companyVat}</div>` : ''}
<div class="separator"></div>
<h6 class="fw-bold">TAX INVOICE</h6>
<div>Inv: INV-${inv.id.toString().padStart(5, '0')}</div>
<div>Date: ${inv.invoice_date}</div>
<div class="separator"></div>
</div>
<div>
<strong>Customer:</strong> ${inv.customer_name || 'Walk-in'}
</div>
<div class="separator"></div>
<table>
<thead>
<tr>
<th>ITEM</th>
<th style="text-align: right;">TOTAL</th>
</tr>
</thead>
<tbody>
${itemsHtml}
</tbody>
</table>
<div class="separator"></div>
<div class="total-row d-flex justify-content-between">
<span>TOTAL</span>
<span>OMR ${parseFloat(inv.total_with_vat).toFixed(3)}</span>
</div>
<div class="d-flex justify-content-between small">
<span>PAID</span>
<span>OMR ${parseFloat(inv.paid_amount).toFixed(3)}</span>
</div>
<div class="d-flex justify-content-between small fw-bold">
<span>BALANCE</span>
<span>OMR ${(inv.total_with_vat - inv.paid_amount).toFixed(3)}</span>
</div>
<div class="separator"></div>
<div class="center small">
<p>Thank You for your business!</p>
</div>
</div>
`;
const posModal = new bootstrap.Modal(document.getElementById('posReceiptModal'));
posModal.show();
};
function printPosReceipt() {
const content = document.getElementById('posReceiptContent').innerHTML;
const printArea = document.getElementById('posPrintArea');
printArea.innerHTML = `<div class="thermal-receipt thermal-receipt-print">${content}</div>`;
document.body.classList.add('printing-receipt');
window.print();
document.body.classList.remove('printing-receipt');
location.reload();
}
<?php if ($page === 'dashboard'): ?>
const monthlyData = <?= json_encode($data['monthly_sales']) ?>;
const yearlyData = <?= json_encode($data['yearly_sales']) ?>;
const ctx = document.getElementById('salesChart').getContext('2d');
let salesChart = new Chart(ctx, {
type: 'line',
data: {
labels: monthlyData.map(d => d.label),
datasets: [{
label: 'Sales (OMR)',
data: monthlyData.map(d => d.total),
borderColor: '#0d6efd',
backgroundColor: 'rgba(13, 110, 253, 0.1)',
fill: true,
tension: 0.4
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: { display: false }
},
scales: {
y: {
beginAtZero: true,
ticks: {
callback: function(value) { return 'OMR ' + value.toFixed(3); }
}
}
}
}
});
document.getElementById('btnMonthly').addEventListener('click', function() {
this.classList.add('active');
document.getElementById('btnYearly').classList.remove('active');
salesChart.data.labels = monthlyData.map(d => d.label);
salesChart.data.datasets[0].data = monthlyData.map(d => d.total);
salesChart.update();
});
document.getElementById('btnYearly').addEventListener('click', function() {
this.classList.add('active');
document.getElementById('btnMonthly').classList.remove('active');
salesChart.data.labels = yearlyData.map(d => d.label);
salesChart.data.datasets[0].data = yearlyData.map(d => d.total);
salesChart.update();
});
<?php endif; ?>
</script>
</body>
</html>