1002 lines
50 KiB
Plaintext
1002 lines
50 KiB
Plaintext
} else {
|
|
fputcsv($output, $headers);
|
|
foreach ($rows as $row) 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 suppliers 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 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'];
|
|
}
|
|
|
|
$limit = isset($_GET["limit"]) ? max(5, (int)$_GET["limit"]) : 20;
|
|
$page_num = isset($_GET["p"]) ? (int)$_GET["p"] : 1;
|
|
if ($page_num < 1) $page_num = 1;
|
|
$offset = ($page_num - 1) * $limit;
|
|
switch ($page) {
|
|
case 'suppliers':
|
|
$where = ["1=1"];
|
|
$params = [];
|
|
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);
|
|
|
|
$countStmt = db()->prepare("SELECT COUNT(*) FROM suppliers WHERE $whereSql");
|
|
$countStmt->execute($params);
|
|
$total_records = (int)$countStmt->fetchColumn();
|
|
$data['total_pages'] = ceil($total_records / $limit);
|
|
$data['current_page'] = $page_num;
|
|
|
|
$stmt = db()->prepare("SELECT * FROM suppliers WHERE $whereSql ORDER BY id DESC LIMIT $limit OFFSET $offset");
|
|
$stmt->execute($params);
|
|
$data['customers'] = $stmt->fetchAll(); // Keep 'customers' key for template compatibility if needed, or update template
|
|
break;
|
|
case 'customers':
|
|
$where = ["1=1"];
|
|
$params = [];
|
|
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);
|
|
|
|
$countStmt = db()->prepare("SELECT COUNT(*) FROM customers WHERE $whereSql");
|
|
$countStmt->execute($params);
|
|
$total_records = (int)$countStmt->fetchColumn();
|
|
$data['total_pages'] = ceil($total_records / $limit);
|
|
$data['current_page'] = $page_num;
|
|
|
|
$stmt = db()->prepare("SELECT * FROM customers WHERE $whereSql ORDER BY id DESC LIMIT $limit OFFSET $offset");
|
|
$stmt->execute($params);
|
|
$data['customers'] = $stmt->fetchAll();
|
|
break;
|
|
case 'categories':
|
|
// Already fetched globally
|
|
break;
|
|
case 'units':
|
|
// Already fetched globally
|
|
break;
|
|
case 'items':
|
|
file_put_contents('debug.log', date('Y-m-d H:i:s') . " - Items case hit\n", FILE_APPEND);
|
|
$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);
|
|
|
|
$countStmt = db()->prepare("SELECT COUNT(*) 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 suppliers s ON i.supplier_id = s.id WHERE $whereSql");
|
|
$countStmt->execute($params);
|
|
$total_records = (int)$countStmt->fetchColumn();
|
|
$data['total_pages'] = ceil($total_records / $limit);
|
|
$data['current_page'] = $page_num;
|
|
|
|
$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 suppliers s ON i.supplier_id = s.id
|
|
WHERE $whereSql
|
|
ORDER BY i.id DESC LIMIT $limit OFFSET $offset");
|
|
$stmt->execute($params);
|
|
$data['items'] = $stmt->fetchAll();
|
|
break;
|
|
case 'quotations':
|
|
$where = ["1=1"];
|
|
$params = [];
|
|
if (!empty($_GET['search'])) {
|
|
$s = $_GET['search'];
|
|
$clean_id = preg_replace('/[^0-9]/', '', $s);
|
|
if ($clean_id !== '') {
|
|
$where[] = "(q.id LIKE ? OR c.name LIKE ? OR q.id = ?)";
|
|
$params[] = "%$s%";
|
|
$params[] = "%$s%";
|
|
$params[] = $clean_id;
|
|
} else {
|
|
$where[] = "(q.id LIKE ? OR c.name LIKE ?)";
|
|
$params[] = "%$s%";
|
|
$params[] = "%$s%";
|
|
}
|
|
}
|
|
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);
|
|
|
|
|
|
|
|
$countStmt = db()->prepare("SELECT COUNT(*) FROM quotations q JOIN customers c ON q.customer_id = c.id WHERE $whereSql");
|
|
$countStmt->execute($params);
|
|
$total_records = (int)$countStmt->fetchColumn();
|
|
$data['total_pages'] = ceil($total_records / $limit);
|
|
$data['current_page'] = $page_num;
|
|
|
|
$stmt = db()->prepare("SELECT q.*, c.name as customer_name
|
|
FROM quotations q
|
|
JOIN customers c ON q.customer_id = c.id
|
|
WHERE $whereSql
|
|
ORDER BY q.id DESC
|
|
LIMIT $limit OFFSET $offset");
|
|
$stmt->execute($params);
|
|
$data['quotations'] = $stmt->fetchAll();
|
|
break;
|
|
case 'lpos':
|
|
$where = ["1=1"];
|
|
$params = [];
|
|
if (!empty($_GET['search'])) {
|
|
$s = $_GET['search'];
|
|
$clean_id = preg_replace('/[^0-9]/', '', $s);
|
|
if ($clean_id !== '') {
|
|
$where[] = "(q.id LIKE ? OR s.name LIKE ? OR q.id = ?)";
|
|
$params[] = "%$s%";
|
|
$params[] = "%$s%";
|
|
$params[] = $clean_id;
|
|
} else {
|
|
$where[] = "(q.id LIKE ? OR s.name LIKE ?)";
|
|
$params[] = "%$s%";
|
|
$params[] = "%$s%";
|
|
}
|
|
}
|
|
if (!empty($_GET['supplier_id'])) {
|
|
$where[] = "q.supplier_id = ?";
|
|
$params[] = $_GET['supplier_id'];
|
|
}
|
|
if (!empty($_GET['start_date'])) {
|
|
$where[] = "q.lpo_date >= ?";
|
|
$params[] = $_GET['start_date'];
|
|
}
|
|
if (!empty($_GET['end_date'])) {
|
|
$where[] = "q.lpo_date <= ?";
|
|
$params[] = $_GET['end_date'];
|
|
}
|
|
$whereSql = implode(" AND ", $where);
|
|
|
|
|
|
|
|
$countStmt = db()->prepare("SELECT COUNT(*) FROM lpos q JOIN suppliers s ON q.supplier_id = s.id WHERE $whereSql");
|
|
$countStmt->execute($params);
|
|
$total_records = (int)$countStmt->fetchColumn();
|
|
$data['total_pages'] = ceil($total_records / $limit);
|
|
$data['current_page'] = $page_num;
|
|
|
|
$stmt = db()->prepare("SELECT q.*, s.name as supplier_name
|
|
FROM lpos q
|
|
JOIN suppliers s ON q.supplier_id = s.id
|
|
WHERE $whereSql
|
|
ORDER BY q.id DESC
|
|
LIMIT $limit OFFSET $offset");
|
|
$stmt->execute($params);
|
|
$data['lpos'] = $stmt->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';
|
|
$table = ($type === 'purchase') ? 'purchases' : 'invoices';
|
|
$cust_supplier_col = ($type === 'purchase') ? 'supplier_id' : 'customer_id';
|
|
$cust_supplier_table = ($type === 'purchase') ? 'suppliers' : 'customers';
|
|
|
|
$where = ["1=1"];
|
|
$params = [];
|
|
|
|
if (!empty($_GET['search'])) {
|
|
$s = $_GET['search'];
|
|
$clean_id = preg_replace('/[^0-9]/', '', $s);
|
|
if ($clean_id !== '') {
|
|
$where[] = "(v.id LIKE ? OR c.name LIKE ? OR v.id = ?)";
|
|
$params[] = "%$s%";
|
|
$params[] = "%$s%";
|
|
$params[] = $clean_id;
|
|
} else {
|
|
$where[] = "(v.id LIKE ? OR c.name LIKE ?)";
|
|
$params[] = "%$s%";
|
|
$params[] = "%$s%";
|
|
}
|
|
}
|
|
|
|
if (!empty($_GET['customer_id'])) {
|
|
$where[] = "v.$cust_supplier_col = ?";
|
|
$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);
|
|
|
|
$countStmt = db()->prepare("SELECT COUNT(*) FROM $table v LEFT JOIN $cust_supplier_table c ON v.$cust_supplier_col = c.id WHERE $whereSql");
|
|
$countStmt->execute($params);
|
|
$total_records = (int)$countStmt->fetchColumn();
|
|
$data['total_pages'] = ceil($total_records / $limit);
|
|
$data['current_page'] = $page_num;
|
|
|
|
$stmt = db()->prepare("SELECT v.*, c.name as customer_name, c.tax_id as customer_tax_id, c.phone as customer_phone
|
|
FROM $table v
|
|
LEFT JOIN $cust_supplier_table c ON v.$cust_supplier_col = c.id
|
|
WHERE $whereSql
|
|
ORDER BY v.id DESC LIMIT $limit OFFSET $offset");
|
|
$stmt->execute($params);
|
|
$data['invoices'] = $stmt->fetchAll();
|
|
foreach ($data['invoices'] as &$inv) {
|
|
$inv['total_in_words'] = numberToWordsOMR($inv['total_with_vat']);
|
|
if ($type === 'sale') {
|
|
$item_stmt = db()->prepare("SELECT ii.*, i.name_en, i.name_ar, i.vat_rate FROM invoice_items ii LEFT JOIN stock_items i ON ii.item_id = i.id WHERE ii.invoice_id = ?");
|
|
$item_stmt->execute([$inv['id']]);
|
|
$inv['items'] = $item_stmt->fetchAll(PDO::FETCH_ASSOC);
|
|
} else {
|
|
$item_stmt = db()->prepare("SELECT pi.*, i.name_en, i.name_ar, i.vat_rate FROM purchase_items pi LEFT JOIN stock_items i ON pi.item_id = i.id WHERE pi.purchase_id = ?");
|
|
$item_stmt->execute([$inv['id']]);
|
|
$inv['items'] = $item_stmt->fetchAll(PDO::FETCH_ASSOC);
|
|
}
|
|
}
|
|
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 $cust_supplier_table ORDER BY name ASC")->fetchAll();
|
|
|
|
if ($type === 'sale') {
|
|
$data['sales_invoices'] = db()->query("SELECT id, invoice_date, total_with_vat FROM invoices ORDER BY id DESC")->fetchAll();
|
|
} else {
|
|
$data['purchase_invoices'] = db()->query("SELECT id, invoice_date, total_with_vat FROM purchases ORDER BY id DESC")->fetchAll();
|
|
}
|
|
break;
|
|
|
|
case 'sales_returns':
|
|
$where = ["1=1"];
|
|
$params = [];
|
|
if (!empty($_GET['search'])) {
|
|
$s = $_GET['search'];
|
|
$clean_id = preg_replace('/[^0-9]/', '', $s);
|
|
if ($clean_id !== '') {
|
|
$where[] = "(sr.id LIKE ? OR c.name LIKE ? OR sr.invoice_id LIKE ? OR sr.id = ? OR sr.invoice_id = ?)";
|
|
$params[] = "%$s%";
|
|
$params[] = "%$s%";
|
|
$params[] = "%$s%";
|
|
$params[] = $clean_id;
|
|
$params[] = $clean_id;
|
|
} else {
|
|
$where[] = "(sr.id LIKE ? OR c.name LIKE ? OR sr.invoice_id LIKE ?)";
|
|
$params[] = "%$s%";
|
|
$params[] = "%$s%";
|
|
$params[] = "%$s%";
|
|
}
|
|
}
|
|
$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 ORDER BY id DESC")->fetchAll();
|
|
break;
|
|
|
|
case 'purchase_returns':
|
|
$where = ["1=1"];
|
|
$params = [];
|
|
if (!empty($_GET['search'])) {
|
|
$s = $_GET['search'];
|
|
$clean_id = preg_replace('/[^0-9]/', '', $s);
|
|
if ($clean_id !== '') {
|
|
$where[] = "(pr.id LIKE ? OR c.name LIKE ? OR pr.purchase_id LIKE ? OR pr.id = ? OR pr.purchase_id = ?)";
|
|
$params[] = "%$s%";
|
|
$params[] = "%$s%";
|
|
$params[] = "%$s%";
|
|
$params[] = $clean_id;
|
|
$params[] = $clean_id;
|
|
} else {
|
|
$where[] = "(pr.id LIKE ? OR c.name LIKE ? OR pr.purchase_id LIKE ?)";
|
|
$params[] = "%$s%";
|
|
$params[] = "%$s%";
|
|
$params[] = "%$s%";
|
|
}
|
|
}
|
|
$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 suppliers c ON pr.supplier_id = c.id
|
|
LEFT JOIN purchases i ON pr.purchase_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 purchases ORDER BY id DESC")->fetchAll();
|
|
break;
|
|
|
|
case 'customer_statement':
|
|
case 'supplier_statement':
|
|
$isCustomer = ($page === 'customer_statement');
|
|
$entityTable = $isCustomer ? 'customers' : 'suppliers';
|
|
$invoiceTable = $isCustomer ? 'invoices' : 'purchases';
|
|
$paymentTable = $isCustomer ? 'payments' : 'purchase_payments';
|
|
$fkColumn = $isCustomer ? 'customer_id' : 'supplier_id';
|
|
$invFkColumn = $isCustomer ? 'invoice_id' : 'purchase_id';
|
|
|
|
$data['entities'] = db()->query("SELECT id, name, balance FROM $entityTable ORDER BY name ASC")->fetchAll();
|
|
|
|
$entity_id = (int)($_GET['entity_id'] ?? 0);
|
|
if ($entity_id) {
|
|
$data['selected_entity'] = db()->query("SELECT * FROM $entityTable WHERE id = $entity_id")->fetch();
|
|
$start_date = $_GET['start_date'] ?? date('Y-m-01');
|
|
$end_date = $_GET['end_date'] ?? date('Y-m-d');
|
|
|
|
$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 $invoiceTable
|
|
WHERE $fkColumn = ? AND invoice_date BETWEEN ? AND ?");
|
|
$stmt->execute([$entity_id, $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.$invFkColumn as ref_no
|
|
FROM $paymentTable p
|
|
JOIN $invoiceTable i ON p.$invFkColumn = i.id
|
|
WHERE i.$fkColumn = ? AND p.payment_date BETWEEN ? AND ?");
|
|
$stmt->execute([$entity_id, $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');
|
|
$category_id = $_GET['category_id'] ?? '';
|
|
|
|
$where = "WHERE e.expense_date BETWEEN ? AND ?";
|
|
$params = [$start_date, $end_date];
|
|
|
|
if ($category_id !== '') {
|
|
$where .= " AND e.category_id = ?";
|
|
$params[] = $category_id;
|
|
}
|
|
|
|
$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
|
|
GROUP BY c.id
|
|
ORDER BY total DESC");
|
|
$stmt->execute($params);
|
|
$data['report_by_category'] = $stmt->fetchAll();
|
|
|
|
$stmt = db()->prepare("SELECT SUM(amount) FROM expenses e $where");
|
|
$stmt->execute($params);
|
|
$data['total_expenses'] = $stmt->fetchColumn() ?: 0;
|
|
|
|
$data['expense_categories'] = db()->query("SELECT * FROM expense_categories ORDER BY name_en ASC")->fetchAll();
|
|
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 suppliers s ON i.supplier_id = s.id
|
|
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 = [];
|
|
|
|
// Filter by user if provided and user has permission
|
|
if (isset($_GET['user_id']) && !empty($_GET['user_id'])) {
|
|
if (can('users_view')) {
|
|
$where[] = "s.user_id = ?";
|
|
$params[] = $_GET['user_id'];
|
|
}
|
|
}
|
|
|
|
if (!can('users_view')) {
|
|
$where[] = "s.user_id = ?";
|
|
$params[] = $_SESSION['user_id'];
|
|
}
|
|
|
|
// Filter by date range
|
|
if (isset($_GET['date_from']) && !empty($_GET['date_from'])) {
|
|
$where[] = "s.opened_at >= ?";
|
|
$params[] = $_GET['date_from'] . ' 00:00:00';
|
|
}
|
|
if (isset($_GET['date_to']) && !empty($_GET['date_to'])) {
|
|
$where[] = "s.opened_at <= ?";
|
|
$params[] = $_GET['date_to'] . ' 23:59:59';
|
|
}
|
|
|
|
$whereSql = implode(" AND ", $where);
|
|
$stmt = db()->prepare("SELECT s.*, r.name as register_name, u.username
|
|
FROM register_sessions s
|
|
LEFT JOIN cash_registers r ON s.register_id = r.id
|
|
LEFT 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();
|
|
$data['users'] = db()->query("SELECT id, username FROM users ORDER BY username ASC")->fetchAll();
|
|
break;
|
|
default:
|
|
if (can('dashboard_view')) {
|
|
$data['customers'] = db()->query("SELECT * FROM customers ORDER BY id DESC LIMIT 5")->fetchAll();
|
|
$data['stats'] = [
|
|
'total_customers' => db()->query("SELECT COUNT(*) FROM customers")->fetchColumn(),
|
|
'total_items' => db()->query("SELECT COUNT(*) FROM stock_items")->fetchColumn(),
|
|
'total_sales' => (db()->query("SELECT SUM(total_with_vat) FROM invoices")->fetchColumn() ?: 0) + (db()->query("SELECT SUM(net_amount) FROM pos_transactions WHERE status = 'completed'")->fetchColumn() ?: 0),
|
|
'total_received' => (db()->query("SELECT SUM(amount) FROM payments")->fetchColumn() ?: 0) + (db()->query("SELECT SUM(amount) FROM pos_payments")->fetchColumn() ?: 0),
|
|
'total_purchases' => db()->query("SELECT SUM(total_with_vat) FROM purchases")->fetchColumn() ?: 0,
|
|
'total_paid' => db()->query("SELECT SUM(amount) FROM purchase_payments")->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 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 GROUP BY label ORDER BY label ASC LIMIT 5")->fetchAll(PDO::FETCH_ASSOC);
|
|
}
|
|
break;
|
|
}
|
|
|
|
$projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? 'Accounting System';
|
|
?>
|
|
<!doctype html>
|
|
<html lang="<?= $lang ?>" dir="<?= $dir ?>">
|
|
<head>
|
|
<meta charset="utf-8" />
|
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
<title><?= __('accounting') ?> - Admin Panel</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<?= $dir === 'rtl' ? '.rtl' : '' ?>.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=<?= 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=<?= time() ?>">
|
|
<style>
|
|
/* Force RTL Sidebar Position */
|
|
[dir="rtl"] .sidebar {
|
|
right: 0 !important;
|
|
left: auto !important;
|
|
}
|
|
[dir="rtl"] .main-content {
|
|
margin-left: 0 !important;
|
|
margin-right: 210px !important;
|
|
}
|
|
@media (max-width: 1199.98px) {
|
|
[dir="rtl"] .sidebar {
|
|
right: -210px !important;
|
|
left: auto !important;
|
|
}
|
|
[dir="rtl"] .sidebar.show {
|
|
right: 0 !important;
|
|
left: auto !important;
|
|
}
|
|
[dir="rtl"] .main-content {
|
|
margin-right: 0 !important;
|
|
margin-left: 0 !important;
|
|
}
|
|
.pos-container {
|
|
flex-direction: column !important;
|
|
height: auto !important;
|
|
}
|
|
.pos-cart {
|
|
width: 100% !important;
|
|
height: auto !important;
|
|
position: sticky;
|
|
bottom: 0;
|
|
z-index: 1001;
|
|
}
|
|
.pos-products {
|
|
height: auto !important;
|
|
max-height: 500px;
|
|
}
|
|
}
|
|
|
|
/* General Responsive Helpers */
|
|
@media (max-width: 767.98px) {
|
|
.table:not(.table-borderless):not(.table-sm) {
|
|
display: block;
|
|
width: 100%;
|
|
overflow-x: auto;
|
|
-webkit-overflow-scrolling: touch;
|
|
}
|
|
.card {
|
|
padding: 1rem !important;
|
|
}
|
|
.topbar {
|
|
padding: 0.75rem 1rem !important;
|
|
margin: -1rem -1rem 1rem -1rem !important;
|
|
}
|
|
.main-content {
|
|
padding: 1rem !important;
|
|
}
|
|
.h4, h4 {
|
|
font-size: 1.1rem;
|
|
}
|
|
.btn-sm-square {
|
|
width: 32px;
|
|
height: 32px;
|
|
padding: 0;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
}
|
|
.topbar {
|
|
flex-wrap: wrap;
|
|
gap: 10px;
|
|
position: sticky;
|
|
top: 0;
|
|
z-index: 990;
|
|
}
|
|
.topbar h4 {
|
|
width: 100%;
|
|
order: 2;
|
|
font-size: 1.1rem;
|
|
margin-top: 5px !important;
|
|
}
|
|
.topbar > div:first-child {
|
|
order: 1;
|
|
}
|
|
.topbar > div:last-child {
|
|
order: 3;
|
|
width: 100%;
|
|
justify-content: space-between;
|
|
border-top: 1px solid var(--border);
|
|
padding-top: 5px;
|
|
}
|
|
.topbar .btn span {
|
|
display: none;
|
|
}
|
|
}
|
|
|
|
@media print {
|
|
.sidebar, .topbar, .d-print-none, .no-print, .btn-group, .btn, .badge i { display: none !important; }
|
|
.main-content { margin: 0 !important; padding: 0 !important; background: white !important; width: 100% !important; }
|
|
.card { border: none !important; box-shadow: none !important; padding: 0 !important; margin: 0 !important; }
|
|
.table { border-collapse: collapse !important; width: 100% !important; margin-top: 20px !important; }
|
|
.table th, .table td { border: 1px solid #000 !important; padding: 8px !important; font-size: 11px !important; color: #000 !important; }
|
|
.table thead th { background-color: #eee !important; color: #000 !important; font-weight: bold !important; text-transform: uppercase; }
|
|
.print-only { display: block !important; }
|
|
.text-success, .text-danger, .text-primary, .text-warning { color: #000 !important; }
|
|
.badge { border: none !important; padding: 0 !important; color: #000 !important; background: transparent !important; font-weight: normal !important; }
|
|
body { font-size: 12px !important; color: #000 !important; background: #fff !important; }
|
|
@page { margin: 1cm; }
|
|
}
|
|
.print-only { display: none; }
|
|
[dir="rtl"] { font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; }
|
|
</style>
|
|
</head>
|
|
<body class="theme-<?= htmlspecialchars($_SESSION['theme'] ?? 'default') ?>">
|
|
|
|
<?php if (!$is_activated && $trial_days > 0): ?>
|
|
<div class="alert alert-warning text-center mb-0 rounded-0 d-print-none py-2" style="position: sticky; top: 0; z-index: 2000; font-size: 0.85rem;">
|
|
<i class="bi bi-info-circle-fill me-2"></i>
|
|
<?= $lang === 'ar' ? "نسخة تجريبية: متبقي $trial_days يوم" : "Trial Version: $trial_days days remaining" ?>.
|
|
<a href="index.php?page=activate" class="alert-link ms-2 fw-bold"><?= __('activate_now') ?></a>
|
|
</div>
|
|
<?php endif; ?>
|
|
|
|
<div class="sidebar">
|
|
<div class="sidebar-header">
|
|
<div class="text-primary fw-bold">Accounting</div>
|
|
<div class="text-muted small" style="font-size: 0.7rem;">System v1.2.5</div>
|
|
</div>
|
|
<nav class="mt-4">
|
|
<!-- General Section -->
|
|
<a href="index.php?page=dashboard" class="nav-link <?= !isset($_GET['page']) || $_GET['page'] === 'dashboard' ? 'active' : '' ?>">
|
|
<i class="fas fa-chart-pie"></i> <span><?= __('dashboard') ?></span>
|
|
</a>
|
|
|
|
<!-- POS Section -->
|
|
<?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><?= __('pos') ?></span>
|
|
</a>
|
|
<?php endif; ?>
|
|
|
|
<!-- Inventory Section -->
|
|
<?php if (can('items_view') || can('categories_view') || can('units_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><?= __('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">
|
|
<?php if (can('items_view')): ?>
|
|
<a href="index.php?page=items" class="nav-link <?= isset($_GET['page']) && $_GET['page'] === 'items' ? 'active' : '' ?>">
|
|
<i class="fas fa-box"></i> <span><?= __('items') ?></span>
|
|
</a>
|
|
<?php endif; ?>
|
|
<?php if (can('categories_view')): ?>
|
|
<a href="index.php?page=categories" class="nav-link <?= isset($_GET['page']) && $_GET['page'] === 'categories' ? 'active' : '' ?>">
|
|
<i class="fas fa-tags"></i> <span><?= __('categories') ?></span>
|
|
</a>
|
|
<?php endif; ?>
|
|
<?php if (can('units_view')): ?>
|
|
<a href="index.php?page=units" class="nav-link <?= isset($_GET['page']) && $_GET['page'] === 'units' ? 'active' : '' ?>">
|
|
<i class="fas fa-ruler-combined"></i> <span><?= __('units') ?></span>
|
|
</a>
|
|
<?php endif; ?>
|
|
</div>
|
|
<?php endif; ?>
|
|
|
|
<!-- Customers Section -->
|
|
<?php if (can('customers_view')): ?>
|
|
<div class="nav-section-title px-4 mt-3 mb-1 text-uppercase text-muted <?= !in_array($page, ['customers']) ? 'collapsed' : '' ?>" data-bs-toggle="collapse" data-bs-target="#customers-collapse">
|
|
<span><i class="fas fa-users group-icon"></i><span><?= __('customers') ?></span></span>
|
|
<i class="fas fa-chevron-down chevron"></i>
|
|
</div>
|
|
<div class="collapse <?= in_array($page, ['customers']) ? 'show' : '' ?>" id="customers-collapse">
|
|
<a href="index.php?page=customers" class="nav-link <?= isset($_GET['page']) && $_GET['page'] === 'customers' ? 'active' : '' ?>">
|
|
<i class="fas fa-users"></i> <span><?= __('customers') ?></span>
|
|
</a>
|
|
</div>
|
|
<?php endif; ?>
|
|
|
|
<!-- Suppliers Section -->
|
|
<?php if (can('suppliers_view')): ?>
|
|
<div class="nav-section-title px-4 mt-3 mb-1 text-uppercase text-muted <?= !in_array($page, ['suppliers']) ? 'collapsed' : '' ?>" data-bs-toggle="collapse" data-bs-target="#suppliers-collapse">
|
|
<span><i class="fas fa-truck-field group-icon"></i><span><?= __('suppliers') ?></span></span>
|
|
<i class="fas fa-chevron-down chevron"></i>
|
|
</div>
|
|
<div class="collapse <?= in_array($page, ['suppliers']) ? 'show' : '' ?>" id="suppliers-collapse">
|
|
<a href="index.php?page=suppliers" class="nav-link <?= isset($_GET['page']) && $_GET['page'] === 'suppliers' ? 'active' : '' ?>">
|
|
<i class="fas fa-truck-field"></i> <span><?= __('suppliers') ?></span>
|
|
</a>
|
|
</div>
|
|
<?php endif; ?>
|
|
|
|
<!-- Sales Section -->
|
|
<?php if (can('sales_view') || can('sales_returns_view') || can('quotations_view')): ?>
|
|
<div class="nav-section-title px-4 mt-3 mb-1 text-uppercase text-muted <?= !in_array($page, ['sales', 'sales_returns', 'quotations']) ? 'collapsed' : '' ?>" data-bs-toggle="collapse" data-bs-target="#sales-collapse">
|
|
<span><i class="fas fa-file-invoice-dollar group-icon"></i><span><?= __('sales') ?></span></span>
|
|
<i class="fas fa-chevron-down chevron"></i>
|
|
</div>
|
|
<div class="collapse <?= in_array($page, ['sales', 'sales_returns', 'quotations']) ? 'show' : '' ?>" id="sales-collapse">
|
|
<?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><?= __('sales') ?></span>
|
|
</a>
|
|
<?php endif; ?>
|
|
<?php if (can('sales_returns_view')): ?>
|
|
<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><?= __('sales_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><?= __('quotations') ?></span>
|
|
</a>
|
|
<?php endif; ?>
|
|
</div>
|
|
<?php endif; ?>
|
|
|
|
<!-- Purchases Section -->
|
|
<?php if (can('purchases_view') || can('lpos_view') || can('purchase_returns_view')): ?>
|
|
<div class="nav-section-title px-4 mt-3 mb-1 text-uppercase text-muted <?= !in_array($page, ['purchases', 'lpos', 'purchase_returns']) ? 'collapsed' : '' ?>" data-bs-toggle="collapse" data-bs-target="#purchases-collapse">
|
|
<span><i class="fas fa-cart-shopping group-icon"></i><span><?= __('purchases') ?></span></span>
|
|
<i class="fas fa-chevron-down chevron"></i>
|
|
</div>
|
|
<div class="collapse <?= in_array($page, ['purchases', 'lpos', 'purchase_returns']) ? 'show' : '' ?>" id="purchases-collapse">
|
|
<?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><?= __('purchases') ?></span>
|
|
</a>
|
|
<?php endif; ?>
|
|
<?php if (can('lpos_view')): ?>
|
|
<a href="index.php?page=lpos" class="nav-link <?= isset($_GET['page']) && $_GET['page'] === 'lpos' ? 'active' : '' ?>">
|
|
<i class="fas fa-file-contract"></i> <span><?= __('lpos') ?></span>
|
|
</a>
|
|
<?php endif; ?>
|
|
<?php if (can('purchase_returns_view')): ?>
|
|
<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><?= __('purchase_returns') ?></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><?= __('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><?= __('expense_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><?= __('expenses') ?></span>
|
|
</a>
|
|
</div>
|
|
<?php endif; ?>
|
|
|