review code pattern consistency

This commit is contained in:
Thanakorn S
2026-05-20 13:07:57 +07:00
parent 7396db6ffc
commit 91f8bb854f
20 changed files with 93 additions and 58 deletions
+2 -1
View File
@@ -4,7 +4,8 @@ require '../../../assets/utils/db_auth.php';
require '../../../assets/utils/classes_ac/ChartOfAccounts.php'; require '../../../assets/utils/classes_ac/ChartOfAccounts.php';
if (empty($data['account_code']) || empty($data['account_name']) || empty($data['account_type'])) { if (empty($data['account_code']) || empty($data['account_name']) || empty($data['account_type'])) {
exit(json_encode(['message' => 'Account code, name, and type are required'])); $answer['message'] = 'Account code, name, and type are required';
exit(json_encode($answer));
} }
$coa = new ChartOfAccounts($pdo2, $company_id); $coa = new ChartOfAccounts($pdo2, $company_id);
@@ -4,7 +4,8 @@ require '../../../assets/utils/db_auth.php';
require '../../../assets/utils/classes_ac/DepartmentManager.php'; require '../../../assets/utils/classes_ac/DepartmentManager.php';
if (empty($data['dept_code']) || empty($data['dept_name'])) { if (empty($data['dept_code']) || empty($data['dept_name'])) {
exit(json_encode(['message' => 'Department code and name are required'])); $answer['message'] = 'Department code and name are required';
exit(json_encode($answer));
} }
$dept = new DepartmentManager($pdo2, $company_id); $dept = new DepartmentManager($pdo2, $company_id);
+2 -1
View File
@@ -5,7 +5,8 @@ require '../../../assets/utils/classes_ac/ChartOfAccounts.php';
$id = (int)($data['id'] ?? 0); $id = (int)($data['id'] ?? 0);
if (!$id) { if (!$id) {
exit(json_encode(['message' => 'Missing id'])); $answer['message'] = 'Missing id';
exit(json_encode($answer));
} }
$coa = new ChartOfAccounts($pdo2, $company_id); $coa = new ChartOfAccounts($pdo2, $company_id);
@@ -4,7 +4,7 @@ require '../../../assets/utils/db_auth.php';
require '../../../assets/utils/classes_ac/DepartmentManager.php'; require '../../../assets/utils/classes_ac/DepartmentManager.php';
$id = (int)($data['id'] ?? 0); $id = (int)($data['id'] ?? 0);
if (!$id) exit(json_encode(['message' => 'Missing id'])); if (!$id) { $answer['message'] = 'Missing id'; exit(json_encode($answer)); }
$dept = new DepartmentManager($pdo2, $company_id); $dept = new DepartmentManager($pdo2, $company_id);
$dept->delete($id); $dept->delete($id);
@@ -5,13 +5,15 @@ require '../../../assets/utils/classes_ac/ChartOfAccounts.php';
$id = (int)($data['id'] ?? 0); $id = (int)($data['id'] ?? 0);
if (!$id) { if (!$id) {
exit(json_encode(['message' => 'Missing id'])); $answer['message'] = 'Missing id';
exit(json_encode($answer));
} }
$coa = new ChartOfAccounts($pdo2, $company_id); $coa = new ChartOfAccounts($pdo2, $company_id);
$row = $coa->getById($id); $row = $coa->getById($id);
if (!$row) { if (!$row) {
exit(json_encode(['message' => 'Account not found'])); $answer['message'] = 'Account not found';
exit(json_encode($answer));
} }
$answer['output'] = $row; $answer['output'] = $row;
@@ -4,11 +4,11 @@ require '../../../assets/utils/db_auth.php';
require '../../../assets/utils/classes_ac/DepartmentManager.php'; require '../../../assets/utils/classes_ac/DepartmentManager.php';
$id = (int)($data['id'] ?? 0); $id = (int)($data['id'] ?? 0);
if (!$id) exit(json_encode(['message' => 'Missing id'])); if (!$id) { $answer['message'] = 'Missing id'; exit(json_encode($answer)); }
$dept = new DepartmentManager($pdo2, $company_id); $dept = new DepartmentManager($pdo2, $company_id);
$row = $dept->getById($id); $row = $dept->getById($id);
if (!$row) exit(json_encode(['message' => 'Department not found'])); if (!$row) { $answer['message'] = 'Department not found'; exit(json_encode($answer)); }
$answer['output'] = $row; $answer['output'] = $row;
$answer['success'] = 1; $answer['success'] = 1;
@@ -12,10 +12,12 @@ $discount = (float)($data['discount'] ?? 0);
$shipping_fee = (float)($data['shipping_fee'] ?? 0); $shipping_fee = (float)($data['shipping_fee'] ?? 0);
if (!$request_id) { if (!$request_id) {
exit(json_encode(['success' => 0, 'message' => 'Purchase request ID is required.'])); $answer['message'] = 'Purchase request ID is required.';
exit(json_encode($answer));
} }
if (!$contact_id) { if (!$contact_id) {
exit(json_encode(['success' => 0, 'message' => 'Supplier (contact_id) is required for the PO.'])); $answer['message'] = 'Supplier (contact_id) is required for the PO.';
exit(json_encode($answer));
} }
$prm = new PurchaseRequestManager($pdo2, $company_id); $prm = new PurchaseRequestManager($pdo2, $company_id);
@@ -23,16 +25,19 @@ $prm = new PurchaseRequestManager($pdo2, $company_id);
// Load PR — must be Approved // Load PR — must be Approved
$pr = $prm->getById($request_id); $pr = $prm->getById($request_id);
if (!$pr || (int)$pr['status'] !== 2) { if (!$pr || (int)$pr['status'] !== 2) {
exit(json_encode(['success' => 0, 'message' => 'Purchase request not found or not in Approved status.'])); $answer['message'] = 'Purchase request not found or not in Approved status.';
exit(json_encode($answer));
} }
$pr_items = $pr['items']; $pr_items = $pr['items'];
if (empty($pr_items)) { if (empty($pr_items)) {
exit(json_encode(['success' => 0, 'message' => 'Purchase request has no items.'])); $answer['message'] = 'Purchase request has no items.';
exit(json_encode($answer));
} }
if ((float)$pr['total_remaining'] <= 0.000001) { if ((float)$pr['total_remaining'] <= 0.000001) {
exit(json_encode(['success' => 0, 'message' => 'Purchase request is already fully converted.'])); $answer['message'] = 'Purchase request is already fully converted.';
exit(json_encode($answer));
} }
// Index by item_id for validation // Index by item_id for validation
@@ -62,7 +67,8 @@ foreach ($convert_items as $ci) {
if ($qty <= 0) continue; if ($qty <= 0) continue;
if (!isset($pr_by_id[$item_id])) { if (!isset($pr_by_id[$item_id])) {
exit(json_encode(['success' => 0, 'message' => "Item #{$item_id} not found in this purchase request."])); $answer['message'] = "Item #{$item_id} not found in this purchase request.";
exit(json_encode($answer));
} }
$pi = $pr_by_id[$item_id]; $pi = $pr_by_id[$item_id];
@@ -70,10 +76,8 @@ foreach ($convert_items as $ci) {
if ($qty - $remaining > 0.000001) { if ($qty - $remaining > 0.000001) {
$name = $pi['product_name'] ?: $pi['product_sku']; $name = $pi['product_name'] ?: $pi['product_sku'];
exit(json_encode([ $answer['message'] = "Cannot convert {$qty} for \"{$name}\": only {$remaining} remaining.";
'success' => 0, exit(json_encode($answer));
'message' => "Cannot convert {$qty} for \"{$name}\": only {$remaining} remaining.",
]));
} }
$unit_price = (float)$pi['unit_price']; $unit_price = (float)$pi['unit_price'];
@@ -95,7 +99,8 @@ foreach ($convert_items as $ci) {
} }
if (empty($po_items)) { if (empty($po_items)) {
exit(json_encode(['success' => 0, 'message' => 'No valid items to convert.'])); $answer['message'] = 'No valid items to convert.';
exit(json_encode($answer));
} }
$po_data = [ $po_data = [
@@ -10,7 +10,8 @@ if ($id > 0) {
$row = $prm->getById($id); $row = $prm->getById($id);
if (!$row) { if (!$row) {
http_response_code(404); http_response_code(404);
exit(json_encode(['success' => 0, 'message' => 'Purchase request not found.'])); $answer['message'] = 'Purchase request not found.';
exit(json_encode($answer));
} }
$answer['output'] = $row; $answer['output'] = $row;
} else { } else {
@@ -8,7 +8,8 @@ $id = (int)($data['id'] ?? 0);
$action = $data['action_type'] ?? ''; $action = $data['action_type'] ?? '';
if (!$id || !$action) { if (!$id || !$action) {
exit(json_encode(['success' => 0, 'message' => 'ID and action are required.'])); $answer['message'] = 'ID and action are required.';
exit(json_encode($answer));
} }
$prm = new PurchaseRequestManager($pdo2, $company_id); $prm = new PurchaseRequestManager($pdo2, $company_id);
+4 -2
View File
@@ -24,7 +24,8 @@ $type = $data['type'] ?? '';
if (!$id || !$warehouse_id || !in_array($type, ['in', 'out', 'transfer'])) { if (!$id || !$warehouse_id || !in_array($type, ['in', 'out', 'transfer'])) {
http_response_code(400); http_response_code(400);
exit(json_encode(['success' => 0, 'message' => 'Invalid parameters.'])); $answer['message'] = 'Invalid parameters.';
exit(json_encode($answer));
} }
$stock = new StockManager($pdo2, $company_id); $stock = new StockManager($pdo2, $company_id);
@@ -44,5 +45,6 @@ try {
} catch (Exception $e) { } catch (Exception $e) {
$pdo2->rollBack(); $pdo2->rollBack();
http_response_code(400); http_response_code(400);
exit(json_encode(['success' => 0, 'message' => $e->getMessage()])); $answer['message'] = $e->getMessage();
exit(json_encode($answer));
} }
+1 -1
View File
@@ -141,7 +141,7 @@ if (password_verify(trim($data["password"]), $temp["password"])) {
$verify_url = $base_url . '/login/verify.php?token=' . $token; $verify_url = $base_url . '/login/verify.php?token=' . $token;
try { try {
require_once $include_url . 'assets/utils/module/mailer.php'; require_once '../../../assets/utils/module/mailer.php';
$mailer = new mailer(['pdo1' => $pdo1]); $mailer = new mailer(['pdo1' => $pdo1]);
$mailer->send_email([ $mailer->send_email([
'company_id' => 0, 'company_id' => 0,
+3 -2
View File
@@ -73,7 +73,8 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$csrf = $_SERVER['HTTP_X_CSRF_TOKEN'] ?? ''; $csrf = $_SERVER['HTTP_X_CSRF_TOKEN'] ?? '';
if (empty($csrf) || $csrf !== ($_SESSION['csrf_token'] ?? '')) { if (empty($csrf) || $csrf !== ($_SESSION['csrf_token'] ?? '')) {
http_response_code(403); http_response_code(403);
exit(json_encode(['message' => 'Invalid request.'])); $answer['message'] = 'Invalid request.';
exit(json_encode($answer));
} }
} }
@@ -142,7 +143,7 @@ try {
// Sends a test email to the onboarding user's registered address. // Sends a test email to the onboarding user's registered address.
// If the mailer throws or exits, no DB records have been created yet, // If the mailer throws or exits, no DB records have been created yet,
// so the user can correct their SMTP settings and retry cleanly. // so the user can correct their SMTP settings and retry cleanly.
require_once $include_url . 'assets/utils/module/mailer.php'; require_once '../../../assets/utils/module/mailer.php';
$mailer = new mailer(['pdo1' => $pdo1]); $mailer = new mailer(['pdo1' => $pdo1]);
$mailer->send_email([ $mailer->send_email([
+3 -2
View File
@@ -60,7 +60,8 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$csrf = $_SERVER['HTTP_X_CSRF_TOKEN'] ?? ''; $csrf = $_SERVER['HTTP_X_CSRF_TOKEN'] ?? '';
if (empty($csrf) || $csrf !== ($_SESSION['csrf_token'] ?? '')) { if (empty($csrf) || $csrf !== ($_SESSION['csrf_token'] ?? '')) {
http_response_code(403); http_response_code(403);
exit(json_encode(['message' => 'Invalid request.'])); $answer['message'] = 'Invalid request.';
exit(json_encode($answer));
} }
} }
@@ -177,7 +178,7 @@ try {
// Uses $SMTP from config.php (system-level, not company SMTP) because the // Uses $SMTP from config.php (system-level, not company SMTP) because the
// user does not have a company yet at registration time. // user does not have a company yet at registration time.
// If the mailer fails it exits internally with its own error JSON response. // If the mailer fails it exits internally with its own error JSON response.
require_once $include_url . 'assets/utils/module/mailer.php'; require_once '../../../assets/utils/module/mailer.php';
$mailer = new mailer(['pdo1' => $pdo1]); $mailer = new mailer(['pdo1' => $pdo1]);
$mailer->send_email([ $mailer->send_email([
+5 -3
View File
@@ -9,7 +9,8 @@ $identifier = strtolower(trim($data['identifier'] ?? ''));
if (!$identifier) { if (!$identifier) {
http_response_code(422); http_response_code(422);
exit(json_encode(['success' => 0, 'message' => 'Please enter your username or email.'])); $answer['message'] = 'Please enter your username or email.';
exit(json_encode($answer));
} }
$sth = $pdo1->prepare( $sth = $pdo1->prepare(
@@ -20,13 +21,14 @@ $user = $sth->fetch(PDO::FETCH_ASSOC);
if (!$user) { if (!$user) {
http_response_code(404); http_response_code(404);
exit(json_encode(['success' => 0, 'message' => 'No account found with that username or email.'])); $answer['message'] = 'No account found with that username or email.';
exit(json_encode($answer));
} }
$user_id = (int)$user['user_id']; $user_id = (int)$user['user_id'];
$company_id = (int)($user['default_company'] ?? 0); $company_id = (int)($user['default_company'] ?? 0);
require_once $include_url . 'assets/utils/classes/PasswordResetManager.php'; require_once '../../../assets/utils/classes/PasswordResetManager.php';
$manager = new PasswordResetManager($pdo1, $pdo2, $include_url, $SMTP, $pinkey); $manager = new PasswordResetManager($pdo1, $pdo2, $include_url, $SMTP, $pinkey);
$manager->handleRequestOtp($user_id, $company_id); $manager->handleRequestOtp($user_id, $company_id);
+3 -2
View File
@@ -6,12 +6,13 @@ require '../../../assets/utils/db_auth.php';
if (empty($_SESSION['reset_user_id'])) { if (empty($_SESSION['reset_user_id'])) {
http_response_code(400); http_response_code(400);
exit(json_encode(['success' => 0, 'message' => 'No active reset request. Please request a new OTP.'])); $answer['message'] = 'No active reset request. Please request a new OTP.';
exit(json_encode($answer));
} }
$user_id = (int)$_SESSION['reset_user_id']; $user_id = (int)$_SESSION['reset_user_id'];
require_once $include_url . 'assets/utils/classes/PasswordResetManager.php'; require_once '../../../assets/utils/classes/PasswordResetManager.php';
$manager = new PasswordResetManager($pdo1, $pdo2, $include_url, $SMTP, $pinkey); $manager = new PasswordResetManager($pdo1, $pdo2, $include_url, $SMTP, $pinkey);
$manager->handleConfirmReset($user_id, $data); $manager->handleConfirmReset($user_id, $data);
+19 -10
View File
@@ -351,8 +351,8 @@
// Reset UI // Reset UI
$('#tbl_body').html('<tr><td colspan="9" class="text-center py-4 text-muted">Loading…</td></tr>'); $('#tbl_body').html('<tr><td colspan="9" class="text-center py-4 text-muted">Loading…</td></tr>');
$('#lazy_sentinel').hide(); $('#lazy_sentinel').hide();
$('#lazy_loader').hide();
$('#lazy_done').hide(); $('#lazy_done').hide();
$('#lazy_loader').show();
$('#result_summary').text(''); $('#result_summary').text('');
// Reset stats // Reset stats
@@ -404,6 +404,7 @@
} }
is_loading = true; is_loading = true;
$('#lazy_loader').show();
var sku = sku_queue[sku_index]; var sku = sku_queue[sku_index];
return ajax_request({ return ajax_request({
@@ -427,21 +428,29 @@
return; return;
} }
// If sentinel is still within the viewport (or above it), // If sentinel is still within the viewport keep loading immediately.
// the table hasn't filled the window yet — keep loading immediately. // Otherwise hide the spinner and wait for the IntersectionObserver to
// fire when the user scrolls close to the sentinel.
if (sentinel_is_visible()) { if (sentinel_is_visible()) {
load_next_sku(); load_next_sku();
} else {
$('#lazy_loader').hide();
} }
},
onError: function() {
is_loading = false;
$('#lazy_loader').hide();
} }
}); });
} }
// ── Returns true if the sentinel is visible in the current viewport ─── // ── Returns true if the sentinel is within one window-height of the fold ─
function sentinel_is_visible() { function sentinel_is_visible() {
var el = document.getElementById('lazy_sentinel'); var el = document.getElementById('lazy_sentinel');
var rect = el.getBoundingClientRect(); var rect = el.getBoundingClientRect();
return rect.top <= (window.innerHeight || document.documentElement.clientHeight); var vh = window.innerHeight || document.documentElement.clientHeight;
return rect.top <= vh * 2;
} }
@@ -614,10 +623,10 @@
observer.observe(document.getElementById('lazy_sentinel')); observer.observe(document.getElementById('lazy_sentinel'));
// ── Helpers ─────────────────────────────────────────────────────────── // ── Helpers ───────────────────────────────────────────────────────────
function fmt(n) { function fmt(n) {
return format_number(n, 2); return format_number(n, 2);
} }
// ── Export ─────────────────────────────────────────────────────────── // ── Export ───────────────────────────────────────────────────────────
@@ -697,4 +706,4 @@
<script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf-autotable/3.8.2/jspdf.plugin.autotable.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf-autotable/3.8.2/jspdf.plugin.autotable.min.js"></script>
</body> </body>
</html> </html>
+14 -10
View File
@@ -8,7 +8,8 @@ $quotation_id = (int)($data['quotation_id'] ?? 0);
$convert_items = $data['convert_items'] ?? []; $convert_items = $data['convert_items'] ?? [];
if (!$quotation_id) { if (!$quotation_id) {
exit(json_encode(['success' => 0, 'message' => 'Quotation ID required.'])); $answer['message'] = 'Quotation ID required.';
exit(json_encode($answer));
} }
$qm = new QuotationManager($pdo2, $company_id); $qm = new QuotationManager($pdo2, $company_id);
@@ -16,16 +17,19 @@ $qm = new QuotationManager($pdo2, $company_id);
// Load quotation — must be Accepted // Load quotation — must be Accepted
$q = $qm->getById($quotation_id); $q = $qm->getById($quotation_id);
if (!$q || (int)$q['status'] !== 2) { if (!$q || (int)$q['status'] !== 2) {
exit(json_encode(['success' => 0, 'message' => 'Quotation not found or not in Accepted status.'])); $answer['message'] = 'Quotation not found or not in Accepted status.';
exit(json_encode($answer));
} }
$qt_items = $q['items']; $qt_items = $q['items'];
if (empty($qt_items)) { if (empty($qt_items)) {
exit(json_encode(['success' => 0, 'message' => 'Quotation has no items.'])); $answer['message'] = 'Quotation has no items.';
exit(json_encode($answer));
} }
if ((float)$q['total_remaining'] <= 0.000001) { if ((float)$q['total_remaining'] <= 0.000001) {
exit(json_encode(['success' => 0, 'message' => 'Quotation is already fully converted.'])); $answer['message'] = 'Quotation is already fully converted.';
exit(json_encode($answer));
} }
// Index by item_id for validation // Index by item_id for validation
@@ -55,7 +59,8 @@ foreach ($convert_items as $ci) {
if ($qty <= 0) continue; if ($qty <= 0) continue;
if (!isset($qt_by_id[$item_id])) { if (!isset($qt_by_id[$item_id])) {
exit(json_encode(['success' => 0, 'message' => "Item #{$item_id} not found in this quotation."])); $answer['message'] = "Item #{$item_id} not found in this quotation.";
exit(json_encode($answer));
} }
$qi = $qt_by_id[$item_id]; $qi = $qt_by_id[$item_id];
@@ -63,10 +68,8 @@ foreach ($convert_items as $ci) {
if ($qty - $remaining > 0.000001) { if ($qty - $remaining > 0.000001) {
$name = $qi['product_name'] ?: $qi['product_sku']; $name = $qi['product_name'] ?: $qi['product_sku'];
exit(json_encode([ $answer['message'] = "Cannot convert {$qty} for \"{$name}\": only {$remaining} remaining.";
'success' => 0, exit(json_encode($answer));
'message' => "Cannot convert {$qty} for \"{$name}\": only {$remaining} remaining.",
]));
} }
$unit_price = (float)$qi['unit_price']; $unit_price = (float)$qi['unit_price'];
@@ -89,7 +92,8 @@ foreach ($convert_items as $ci) {
} }
if (empty($ord_items)) { if (empty($ord_items)) {
exit(json_encode(['success' => 0, 'message' => 'No valid items to convert.'])); $answer['message'] = 'No valid items to convert.';
exit(json_encode($answer));
} }
$order_data = [ $order_data = [
+4 -3
View File
@@ -7,11 +7,13 @@ $action = $data['action'] ?? '';
$data['items'] = json_decode($data['items'] ?? '[]', true) ?: []; $data['items'] = json_decode($data['items'] ?? '[]', true) ?: [];
if (!in_array($action, ['create', 'update'], true)) { if (!in_array($action, ['create', 'update'], true)) {
exit(json_encode(['success' => 0, 'message' => 'Unknown action'])); $answer['message'] = 'Unknown action';
exit(json_encode($answer));
} }
if (empty($data['items'])) { if (empty($data['items'])) {
exit(json_encode(['success' => 0, 'message' => 'At least one item is required'])); $answer['message'] = 'At least one item is required';
exit(json_encode($answer));
} }
try { try {
@@ -51,4 +53,3 @@ try {
} }
exit(json_encode($answer)); exit(json_encode($answer));
?>
@@ -10,7 +10,8 @@ if ($id) {
$row = $qm->getById($id); $row = $qm->getById($id);
if (!$row) { if (!$row) {
http_response_code(404); http_response_code(404);
exit(json_encode(['success' => 0, 'message' => 'Not found.'])); $answer['message'] = 'Not found.';
exit(json_encode($answer));
} }
$answer['output'] = $row; $answer['output'] = $row;
} else { } else {
@@ -7,7 +7,8 @@ $id = (int)($data['id'] ?? 0);
$action = $data['action_type'] ?? ''; $action = $data['action_type'] ?? '';
if (!$id || !$action) { if (!$id || !$action) {
exit(json_encode(['success' => 0, 'message' => 'ID and action are required.'])); $answer['message'] = 'ID and action are required.';
exit(json_encode($answer));
} }
$qm = new QuotationManager($pdo2, $company_id); $qm = new QuotationManager($pdo2, $company_id);