diff --git a/assets/js/main.js b/assets/js/main.js
index 896034f..a827a5d 100644
--- a/assets/js/main.js
+++ b/assets/js/main.js
@@ -30,6 +30,19 @@ document.addEventListener('DOMContentLoaded', function() {
sidebar.classList.remove('show');
overlay.classList.remove('show');
});
+
+ // Sidebar Accordion logic: Close other collapses when one is opened
+ const sidebarCollapses = document.querySelectorAll('.sidebar .collapse');
+ sidebarCollapses.forEach(collapseEl => {
+ collapseEl.addEventListener('show.bs.collapse', function () {
+ sidebarCollapses.forEach(otherCollapse => {
+ if (otherCollapse !== collapseEl && otherCollapse.classList.contains('show')) {
+ const bsCollapse = bootstrap.Collapse.getOrCreateInstance(otherCollapse);
+ bsCollapse.hide();
+ }
+ });
+ });
+ });
});
function setLanguage(lang) {
diff --git a/check_settings.php b/check_settings.php
new file mode 100644
index 0000000..864bd7e
--- /dev/null
+++ b/check_settings.php
@@ -0,0 +1,4 @@
+query("SELECT * FROM settings")->fetchAll(PDO::FETCH_KEY_PAIR);
+echo json_encode($settings, JSON_PRETTY_PRINT);
diff --git a/index.php b/index.php
index 8823d98..fb081e3 100644
--- a/index.php
+++ b/index.php
@@ -106,6 +106,27 @@ function can(string $permission): bool {
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'])) {
@@ -719,6 +740,39 @@ if (isset($_POST['add_hr_department'])) {
}
}
+ 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
@@ -1825,10 +1879,13 @@ $projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? 'Accounting System';
+
+