Files
ISP-Billing/system/controllers/banks.php
2026-01-16 12:28:46 +01:00

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');
}
?>