34878-vm/settings.php
Flatlogic Bot 8d771ec57c V1
2025-10-11 14:09:06 +00:00

181 lines
9.1 KiB
PHP

<?php
session_start();
require_once __DIR__ . '/db/config.php';
if (!isset($_SESSION['user_id']) || !isset($_SESSION['company_id']) || $_SESSION['role'] !== 'admin') {
// Redirect non-admins to the dashboard or a generic error page
header('Location: /dashboard.php');
exit;
}
$company_id = $_SESSION['company_id'];
$error_message = '';
$success_message = '';
// Define the settings keys we are managing
$setting_keys = ['napsa_rate', 'napsa_ceiling', 'nhima_rate', 'paye_brackets'];
// Handle Settings Update
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['update_settings'])) {
try {
$pdo = db();
$pdo->beginTransaction();
foreach ($setting_keys as $key) {
if (isset($_POST[$key])) {
$value = $_POST[$key];
// For PAYE brackets, we expect a JSON string, so we don't validate it beyond checking if it's set
$stmt = $pdo->prepare(
"INSERT INTO settings (company_id, setting_key, setting_value) VALUES (?, ?, ?) ON DUPLICATE KEY UPDATE setting_value = VALUES(setting_value)"
);
$stmt->execute([$company_id, $key, $value]);
}
}
$pdo->commit();
$success_message = 'Settings updated successfully!';
} catch (Exception $e) {
if ($pdo->inTransaction()) {
$pdo->rollBack();
}
$error_message = "Failed to update settings: " . $e->getMessage();
}
}
// Fetch current settings for the company
$settings = [];
$stmt = db()->prepare("SELECT setting_key, setting_value FROM settings WHERE company_id = ? AND setting_key IN ('" . implode("',\'", $setting_keys) . "')");
$stmt->execute([$company_id]);
$results = $stmt->fetchAll();
foreach ($results as $row) {
$settings[$row['setting_key']] = $row['setting_value'];
}
// Set default values if not present
$defaults = [
'napsa_rate' => '5', // 5%
'napsa_ceiling' => '2880', // ZMW 2880
'nhima_rate' => '1', // 1%
'paye_brackets' => json_encode([
['from' => 0, 'to' => 4800, 'rate' => 0],
['from' => 4800.01, 'to' => 6800, 'rate' => 20],
['from' => 6800.01, 'to' => 8900, 'rate' => 30],
['from' => 8900.01, 'to' => null, 'rate' => 37.5]
], JSON_PRETTY_PRINT)
];
foreach ($defaults as $key => $value) {
if (!isset($settings[$key])) {
$settings[$key] = $value;
}
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Payroll Settings - GPTPayroll</title>
<script src="https://cdn.tailwindcss.com"></script>
</head>
<body class="bg-gray-100 font-sans leading-normal tracking-normal">
<div class="flex md:flex-row-reverse flex-wrap">
<!-- Main Content -->
<div class="w-full md:w-4/5 bg-gray-100">
<div class="container bg-gray-100 pt-16 px-6 mx-auto">
<?php if ($error_message): ?>
<div class="bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded relative mb-4" role="alert">
<span class="block sm:inline"><?= htmlspecialchars($error_message) ?></span>
</div>
<?php endif; ?>
<?php if ($success_message): ?>
<div class="bg-green-100 border border-green-400 text-green-700 px-4 py-3 rounded relative mb-4" role="alert">
<span class="block sm:inline"><?= htmlspecialchars($success_message) ?></span>
</div>
<?php endif; ?>
<div class="bg-white shadow-md rounded p-8">
<h1 class="text-2xl font-bold text-gray-800 mb-6">Payroll Statutory Settings</h1>
<p class="text-gray-600 mb-6">Configure the statutory rates for your company according to Zambian regulations.</p>
<form action="/settings.php" method="POST">
<div class="grid grid-cols-1 md:grid-cols-2 gap-8">
<!-- NAPSA Settings -->
<div class="border p-6 rounded-lg">
<h3 class="text-lg font-semibold mb-4">NAPSA Settings</h3>
<div class="mb-4">
<label for="napsa_rate" class="block text-gray-700 text-sm font-bold mb-2">Contribution Rate (%)</label>
<input type="number" step="0.01" name="napsa_rate" id="napsa_rate" value="<?= htmlspecialchars($settings['napsa_rate']) ?>" class="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700">
<p class="text-xs text-gray-500 mt-1">Employee and employer each contribute this percentage. Default is 5%.</p>
</div>
<div class="mb-4">
<label for="napsa_ceiling" class="block text-gray-700 text-sm font-bold mb-2">Maximum Assessable Earnings (ZMW)</label>
<input type="number" step="0.01" name="napsa_ceiling" id="napsa_ceiling" value="<?= htmlspecialchars($settings['napsa_ceiling']) ?>" class="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700">
<p class="text-xs text-gray-500 mt-1">The maximum monthly salary amount on which NAPSA contributions are calculated.</p>
</div>
</div>
<!-- NHIMA Settings -->
<div class="border p-6 rounded-lg">
<h3 class="text-lg font-semibold mb-4">NHIMA Settings</h3>
<div class="mb-4">
<label for="nhima_rate" class="block text-gray-700 text-sm font-bold mb-2">Contribution Rate (%)</label>
<input type="number" step="0.01" name="nhima_rate" id="nhima_rate" value="<?= htmlspecialchars($settings['nhima_rate']) ?>" class="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700">
<p class="text-xs text-gray-500 mt-1">Employee and employer each contribute this percentage of the basic salary. Default is 1%.</p>
</div>
</div>
</div>
<!-- PAYE Brackets -->
<div class="mt-8 border p-6 rounded-lg">
<h3 class="text-lg font-semibold mb-4">PAYE Tax Brackets (Monthly)</h3>
<div class="mb-4">
<label for="paye_brackets" class="block text-gray-700 text-sm font-bold mb-2">Brackets (JSON format)</label>
<textarea name="paye_brackets" id="paye_brackets" rows="10" class="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 font-mono text-sm"><?= htmlspecialchars($settings['paye_brackets']) ?></textarea>
<p class="text-xs text-gray-500 mt-1">Use `null` for the upper limit of the last bracket. Rates are percentages.</p>
</div>
</div>
<div class="mt-8">
<button type="submit" name="update_settings" class="bg-green-500 hover:bg-green-600 text-white font-bold py-2 px-4 rounded focus:outline-none focus:shadow-outline">
Save Settings
</button>
</div>
</form>
</div>
</div>
</div>
<!-- Sidebar -->
<div class="w-full md:w-1/5 bg-gray-800 md:min-h-screen">
<div class="md:relative mx-auto lg:float-right lg:px-6">
<ul class="list-reset flex flex-row md:flex-col text-center md:text-left">
<li class="mr-3 flex-1">
<a href="/dashboard.php" class="block py-4 px-4 text-gray-400 hover:text-white no-underline">Dashboard</a>
</li>
<li class="mr-3 flex-1">
<a href="/employees.php" class="block py-4 px-4 text-gray-400 hover:text-white no-underline">Employees</a>
</li>
<li class="mr-3 flex-1">
<a href="/payroll.php" class="block py-4 px-4 text-gray-400 hover:text-white no-underline">Payroll</a>
</li>
<li class="mr-3 flex-1">
<a href="/payroll_history.php" class="block py-4 px-4 text-gray-400 hover:text-white no-underline">Payroll History</a>
</li>
<li class="mr-3 flex-1">
<a href="/settings.php" class="block py-4 px-4 text-white font-bold no-underline">Settings</a>
</li>
<li class="mr-3 flex-1">
<a href="/logout.php" class="block py-4 px-4 text-gray-400 hover:text-white no-underline">Logout</a>
</li>
</ul>
</div>
</div>
</div>
</body>
</html>