482 lines
18 KiB
PHP
482 lines
18 KiB
PHP
<?php
|
|
/**
|
|
* Bank Management Controller
|
|
*
|
|
* Handles CRUD operations for bank accounts including
|
|
* STK Push configuration and management.
|
|
*/
|
|
|
|
// Register bank management menu
|
|
register_menu("Bank Management", true, "banks_list", 'SERVICES', 'fa fa-university', '', 'info');
|
|
|
|
_admin();
|
|
$ui->assign('_title', Lang::T('Bank Management'));
|
|
$ui->assign('_system_menu', 'services');
|
|
$ui->assign('_admin', $admin);
|
|
|
|
// Check permissions
|
|
if (!in_array($admin['user_type'], ['SuperAdmin', 'Admin'])) {
|
|
r2(U . "dashboard", 'e', Lang::T('You do not have permission to access this page'));
|
|
}
|
|
|
|
$action = $routes['1'] ?? 'list';
|
|
|
|
switch ($action) {
|
|
case 'list':
|
|
// List all banks
|
|
$ui->assign('xfooter', '<script type="text/javascript" src="ui/lib/c/banks.js"></script>');
|
|
|
|
// Search functionality
|
|
$search = _post('search');
|
|
$filter_stk = _post('filter_stk');
|
|
$filter_active = _post('filter_active');
|
|
|
|
// Alternative approach: Use direct PDO query for better performance
|
|
$use_direct_query = true; // Set to true for direct query, false for ORM
|
|
|
|
if ($use_direct_query) {
|
|
// Direct PDO approach - faster and more reliable
|
|
$pdo = new PDO("mysql:host=$db_host;dbname=$db_name", $db_user, $db_password);
|
|
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
|
|
|
$sql = "SELECT * FROM tbl_banks WHERE 1=1";
|
|
$params = [];
|
|
|
|
if (!empty($search)) {
|
|
$sql .= " AND (name LIKE ? OR account_number LIKE ? OR account_name LIKE ?)";
|
|
$search_term = '%' . $search . '%';
|
|
$params[] = $search_term;
|
|
$params[] = $search_term;
|
|
$params[] = $search_term;
|
|
}
|
|
|
|
if ($filter_stk !== '') {
|
|
$sql .= " AND supports_stk_push = ?";
|
|
$params[] = $filter_stk;
|
|
}
|
|
|
|
if ($filter_active !== '') {
|
|
$sql .= " AND is_active = ?";
|
|
$params[] = $filter_active;
|
|
}
|
|
|
|
$sql .= " ORDER BY is_default DESC, name ASC";
|
|
|
|
$stmt = $pdo->prepare($sql);
|
|
$stmt->execute($params);
|
|
$banks = $stmt->fetchAll(PDO::FETCH_OBJ);
|
|
} else {
|
|
// Original ORM approach
|
|
$query = ORM::for_table('tbl_banks');
|
|
|
|
if (!empty($search)) {
|
|
$query->where_raw('(name LIKE ? OR account_number LIKE ? OR account_name LIKE ?)',
|
|
['%' . $search . '%', '%' . $search . '%', '%' . $search . '%']);
|
|
}
|
|
|
|
if ($filter_stk !== '') {
|
|
$query->where('supports_stk_push', $filter_stk);
|
|
}
|
|
|
|
if ($filter_active !== '') {
|
|
$query->where('is_active', $filter_active);
|
|
}
|
|
|
|
$query->order_by_desc('is_default')->order_by_asc('name');
|
|
$banks = Paginator::findMany($query, [
|
|
'search' => $search,
|
|
'filter_stk' => $filter_stk,
|
|
'filter_active' => $filter_active
|
|
]);
|
|
|
|
// Convert ORM object to array for template compatibility
|
|
if ($banks && method_exists($banks, 'as_array')) {
|
|
$banks = $banks->as_array();
|
|
} elseif ($banks && is_object($banks)) {
|
|
$banks_array = [];
|
|
foreach ($banks as $bank) {
|
|
$banks_array[] = $bank;
|
|
}
|
|
$banks = $banks_array;
|
|
}
|
|
|
|
// Fallback: If banks is still not an array, use direct database query
|
|
if (!is_array($banks) || empty($banks)) {
|
|
$pdo = new PDO("mysql:host=$db_host;dbname=$db_name", $db_user, $db_password);
|
|
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
|
|
|
$sql = "SELECT * FROM tbl_banks WHERE 1=1";
|
|
$params = [];
|
|
|
|
if (!empty($search)) {
|
|
$sql .= " AND (name LIKE ? OR account_number LIKE ? OR account_name LIKE ?)";
|
|
$search_term = '%' . $search . '%';
|
|
$params[] = $search_term;
|
|
$params[] = $search_term;
|
|
$params[] = $search_term;
|
|
}
|
|
|
|
if ($filter_stk !== '') {
|
|
$sql .= " AND supports_stk_push = ?";
|
|
$params[] = $filter_stk;
|
|
}
|
|
|
|
if ($filter_active !== '') {
|
|
$sql .= " AND is_active = ?";
|
|
$params[] = $filter_active;
|
|
}
|
|
|
|
$sql .= " ORDER BY is_default DESC, name ASC";
|
|
|
|
$stmt = $pdo->prepare($sql);
|
|
$stmt->execute($params);
|
|
$banks = $stmt->fetchAll(PDO::FETCH_OBJ);
|
|
}
|
|
}
|
|
|
|
$ui->assign('banks', $banks);
|
|
$ui->assign('search', $search);
|
|
$ui->assign('filter_stk', $filter_stk);
|
|
$ui->assign('filter_active', $filter_active);
|
|
|
|
run_hook('view_list_banks');
|
|
$ui->display('banks_basic.tpl');
|
|
break;
|
|
|
|
case 'add':
|
|
// Show add bank form
|
|
if (!in_array($admin['user_type'], ['SuperAdmin', 'Admin'])) {
|
|
_alert(Lang::T('You do not have permission to access this page'), 'danger', "dashboard");
|
|
}
|
|
|
|
// Add JavaScript for bank add form
|
|
$xfooter = '
|
|
<script>
|
|
$(document).ready(function() {
|
|
// Form validation
|
|
$("form").on("submit", function(e) {
|
|
var name = $("input[name=\'name\']").val().trim();
|
|
var accountNumber = $("input[name=\'account_number\']").val().trim();
|
|
var accountName = $("input[name=\'account_name\']").val().trim();
|
|
|
|
if (!name || !accountNumber || !accountName) {
|
|
e.preventDefault();
|
|
alert("' . Lang::T("Please fill in all required fields") . '");
|
|
return false;
|
|
}
|
|
});
|
|
|
|
// Auto-generate account name from bank name
|
|
$("input[name=\'name\']").on("blur", function() {
|
|
var bankName = $(this).val().trim();
|
|
if (bankName && !$("input[name=\'account_name\']").val()) {
|
|
$("input[name=\'account_name\']").val(bankName + " Account");
|
|
}
|
|
});
|
|
});
|
|
</script>';
|
|
|
|
$ui->assign('xfooter', $xfooter);
|
|
run_hook('view_add_bank');
|
|
$ui->display('banks-add.tpl');
|
|
break;
|
|
|
|
case 'edit':
|
|
// Show edit bank form
|
|
if (!in_array($admin['user_type'], ['SuperAdmin', 'Admin'])) {
|
|
_alert(Lang::T('You do not have permission to access this page'), 'danger', "dashboard");
|
|
}
|
|
|
|
$id = $routes['2'] ?? 0;
|
|
if (!$id) {
|
|
r2(U . 'banks/list', 'e', Lang::T('Invalid Bank ID'));
|
|
}
|
|
|
|
$bank = ORM::for_table('tbl_banks')->find_one($id);
|
|
if (!$bank) {
|
|
r2(U . 'banks/list', 'e', Lang::T('Bank Not Found'));
|
|
}
|
|
|
|
// Add JavaScript for bank edit form
|
|
$xfooter = '
|
|
<script>
|
|
$(document).ready(function() {
|
|
// Form validation
|
|
$("form").on("submit", function(e) {
|
|
var name = $("input[name=\'name\']").val().trim();
|
|
var accountNumber = $("input[name=\'account_number\']").val().trim();
|
|
var accountName = $("input[name=\'account_name\']").val().trim();
|
|
|
|
if (!name || !accountNumber || !accountName) {
|
|
e.preventDefault();
|
|
alert("' . Lang::T("Please fill in all required fields") . '");
|
|
return false;
|
|
}
|
|
});
|
|
|
|
// Warn if disabling STK Push support on default bank
|
|
$("input[name=\'supports_stk_push\']").on("change", function() {
|
|
if (!$(this).is(":checked") && $("input[name=\'is_default\']").is(":checked")) {
|
|
if (confirm("' . Lang::T("This bank is set as default. Disabling STK Push support will also remove it as default. Continue?") . '")) {
|
|
$("input[name=\'is_default\']").prop("checked", false);
|
|
} else {
|
|
$(this).prop("checked", true);
|
|
}
|
|
}
|
|
});
|
|
|
|
// Warn if deactivating default bank
|
|
$("input[name=\'is_active\']").on("change", function() {
|
|
if (!$(this).is(":checked") && $("input[name=\'is_default\']").is(":checked")) {
|
|
if (confirm("' . Lang::T("This bank is set as default. Deactivating it will also remove it as default. Continue?") . '")) {
|
|
$("input[name=\'is_default\']").prop("checked", false);
|
|
} else {
|
|
$(this).prop("checked", true);
|
|
}
|
|
}
|
|
});
|
|
});
|
|
</script>';
|
|
|
|
$ui->assign('bank', $bank);
|
|
$ui->assign('xfooter', $xfooter);
|
|
run_hook('view_edit_bank');
|
|
$ui->display('banks-edit.tpl');
|
|
break;
|
|
|
|
case 'save':
|
|
// Save bank data (add or edit)
|
|
if (!in_array($admin['user_type'], ['SuperAdmin', 'Admin'])) {
|
|
_alert(Lang::T('You do not have permission to access this page'), 'danger', "dashboard");
|
|
}
|
|
|
|
$id = _post('id');
|
|
$name = _post('name');
|
|
$account_number = _post('account_number');
|
|
$account_name = _post('account_name');
|
|
$bank_code = _post('bank_code');
|
|
$paybill = _post('paybill');
|
|
$supports_stk_push = _post('supports_stk_push') ? 1 : 0;
|
|
$is_active = _post('is_active') ? 1 : 0;
|
|
$is_default = _post('is_default') ? 1 : 0;
|
|
|
|
// Validation
|
|
$msg = '';
|
|
if (empty($name)) {
|
|
$msg .= Lang::T('Bank name is required') . '<br>';
|
|
}
|
|
if (empty($account_number)) {
|
|
$msg .= Lang::T('Account number is required') . '<br>';
|
|
}
|
|
if (empty($account_name)) {
|
|
$msg .= Lang::T('Account name is required') . '<br>';
|
|
}
|
|
|
|
// Check for duplicate account number
|
|
$duplicate_query = ORM::for_table('tbl_banks')->where('account_number', $account_number);
|
|
if ($id) {
|
|
$duplicate_query->where_not_equal('id', $id);
|
|
}
|
|
$duplicate = $duplicate_query->find_one();
|
|
|
|
if ($duplicate) {
|
|
$msg .= Lang::T('Account number already exists') . '<br>';
|
|
}
|
|
|
|
// If setting as default, unset other defaults
|
|
if ($is_default) {
|
|
ORM::for_table('tbl_banks')->where('is_default', 1)->find_result_set()->set('is_default', 0)->save();
|
|
}
|
|
|
|
if ($msg) {
|
|
$redirect_url = $id ? U . 'banks/edit/' . $id : U . 'banks/add';
|
|
r2($redirect_url, 'e', $msg);
|
|
}
|
|
|
|
// Save bank
|
|
if ($id) {
|
|
$bank = ORM::for_table('tbl_banks')->find_one($id);
|
|
if (!$bank) {
|
|
r2(U . 'banks/list', 'e', Lang::T('Bank Not Found'));
|
|
}
|
|
} else {
|
|
$bank = ORM::for_table('tbl_banks')->create();
|
|
}
|
|
|
|
$bank->name = $name;
|
|
$bank->account_number = $account_number;
|
|
$bank->account_name = $account_name;
|
|
$bank->bank_code = $bank_code;
|
|
$bank->paybill = $paybill;
|
|
$bank->supports_stk_push = $supports_stk_push;
|
|
$bank->is_active = $is_active;
|
|
$bank->is_default = $is_default;
|
|
$bank->save();
|
|
|
|
$action_text = $id ? 'updated' : 'created';
|
|
_log('[' . $admin['username'] . ']: Bank ' . $action_text . ' - ' . $name, 'Admin', $admin['id']);
|
|
|
|
r2(U . 'banks/list', 's', Lang::T('Bank ' . ucfirst($action_text) . ' Successfully'));
|
|
break;
|
|
|
|
case 'delete':
|
|
// Delete bank
|
|
if (!in_array($admin['user_type'], ['SuperAdmin', 'Admin'])) {
|
|
_alert(Lang::T('You do not have permission to access this page'), 'danger', "dashboard");
|
|
}
|
|
|
|
$id = $routes['2'] ?? 0;
|
|
if (!$id) {
|
|
r2(U . 'banks/list', 'e', Lang::T('Invalid Bank ID'));
|
|
}
|
|
|
|
$bank = ORM::for_table('tbl_banks')->find_one($id);
|
|
if (!$bank) {
|
|
r2(U . 'banks/list', 'e', Lang::T('Bank Not Found'));
|
|
}
|
|
|
|
// Check if bank is being used in appconfig
|
|
$stk_config = ORM::for_table('tbl_appconfig')->where('setting', 'Stkbankacc')->find_one();
|
|
if ($stk_config && $stk_config->value == $id) {
|
|
r2(U . 'banks/list', 'e', Lang::T('Cannot delete bank that is currently selected for STK Push'));
|
|
}
|
|
|
|
$bank_name = $bank->name;
|
|
$bank->delete();
|
|
|
|
_log('[' . $admin['username'] . ']: Bank deleted - ' . $bank_name, 'Admin', $admin['id']);
|
|
r2(U . 'banks/list', 's', Lang::T('Bank Deleted Successfully'));
|
|
break;
|
|
|
|
case 'toggle-status':
|
|
// Toggle bank active status
|
|
if (!in_array($admin['user_type'], ['SuperAdmin', 'Admin'])) {
|
|
_alert(Lang::T('You do not have permission to access this page'), 'danger', "dashboard");
|
|
}
|
|
|
|
$id = $routes['2'] ?? 0;
|
|
if (!$id) {
|
|
r2(U . 'banks/list', 'e', Lang::T('Invalid Bank ID'));
|
|
}
|
|
|
|
$bank = ORM::for_table('tbl_banks')->find_one($id);
|
|
if (!$bank) {
|
|
r2(U . 'banks/list', 'e', Lang::T('Bank Not Found'));
|
|
}
|
|
|
|
$bank->is_active = $bank->is_active ? 0 : 1;
|
|
$bank->save();
|
|
|
|
$status_text = $bank->is_active ? 'activated' : 'deactivated';
|
|
_log('[' . $admin['username'] . ']: Bank ' . $status_text . ' - ' . $bank->name, 'Admin', $admin['id']);
|
|
|
|
r2(U . 'banks/list', 's', Lang::T('Bank ' . ucfirst($status_text) . ' Successfully'));
|
|
break;
|
|
|
|
case 'set-default':
|
|
// Set bank as default for STK Push
|
|
if (!in_array($admin['user_type'], ['SuperAdmin', 'Admin'])) {
|
|
_alert(Lang::T('You do not have permission to access this page'), 'danger', "dashboard");
|
|
}
|
|
|
|
$id = $routes['2'] ?? 0;
|
|
if (!$id) {
|
|
r2(U . 'banks/list', 'e', Lang::T('Invalid Bank ID'));
|
|
}
|
|
|
|
$bank = ORM::for_table('tbl_banks')->find_one($id);
|
|
if (!$bank) {
|
|
r2(U . 'banks/list', 'e', Lang::T('Bank Not Found'));
|
|
}
|
|
|
|
if (!$bank->supports_stk_push) {
|
|
r2(U . 'banks/list', 'e', Lang::T('Bank does not support STK Push'));
|
|
}
|
|
|
|
// Unset other defaults
|
|
ORM::for_table('tbl_banks')->where('is_default', 1)->find_result_set()->set('is_default', 0)->save();
|
|
|
|
// Set this bank as default
|
|
$bank->is_default = 1;
|
|
$bank->save();
|
|
|
|
// Update appconfig
|
|
$stk_config = ORM::for_table('tbl_appconfig')->where('setting', 'Stkbankacc')->find_one();
|
|
if ($stk_config) {
|
|
$stk_config->value = $bank->id;
|
|
$stk_config->save();
|
|
}
|
|
|
|
$stk_name_config = ORM::for_table('tbl_appconfig')->where('setting', 'Stkbankname')->find_one();
|
|
if ($stk_name_config) {
|
|
$stk_name_config->value = $bank->name;
|
|
$stk_name_config->save();
|
|
}
|
|
|
|
_log('[' . $admin['username'] . ']: Bank set as default for STK Push - ' . $bank->name, 'Admin', $admin['id']);
|
|
r2(U . 'banks/list', 's', Lang::T('Bank Set as Default Successfully'));
|
|
break;
|
|
|
|
case 'api':
|
|
// API endpoint for AJAX requests
|
|
$api_action = $routes['2'] ?? '';
|
|
|
|
switch ($api_action) {
|
|
case 'get-active-banks':
|
|
// Get banks that support STK Push and are active
|
|
$banks = ORM::for_table('tbl_banks')
|
|
->where('supports_stk_push', 1)
|
|
->where('is_active', 1)
|
|
->order_by_desc('is_default')
|
|
->order_by_asc('name')
|
|
->find_many();
|
|
|
|
$result = [];
|
|
foreach ($banks as $bank) {
|
|
$result[] = [
|
|
'id' => $bank->id,
|
|
'name' => $bank->name,
|
|
'account_number' => $bank->account_number,
|
|
'account_name' => $bank->account_name,
|
|
'is_default' => $bank->is_default
|
|
];
|
|
}
|
|
|
|
header('Content-Type: application/json');
|
|
echo json_encode($result);
|
|
exit;
|
|
|
|
case 'get-bank-details':
|
|
// Get specific bank details
|
|
$bank_id = $_GET['bank_id'] ?? 0;
|
|
$bank = ORM::for_table('tbl_banks')->find_one($bank_id);
|
|
|
|
if ($bank) {
|
|
$result = [
|
|
'id' => $bank->id,
|
|
'name' => $bank->name,
|
|
'account_number' => $bank->account_number,
|
|
'account_name' => $bank->account_name,
|
|
'bank_code' => $bank->bank_code,
|
|
'paybill' => $bank->paybill,
|
|
'supports_stk_push' => $bank->supports_stk_push,
|
|
'is_active' => $bank->is_active,
|
|
'is_default' => $bank->is_default
|
|
];
|
|
} else {
|
|
$result = ['error' => 'Bank not found'];
|
|
}
|
|
|
|
header('Content-Type: application/json');
|
|
echo json_encode($result);
|
|
exit;
|
|
}
|
|
|
|
r2(U . 'banks/list', 'e', Lang::T('Invalid API Action'));
|
|
break;
|
|
|
|
default:
|
|
$ui->display('a404.tpl');
|
|
}
|
|
?>
|