Fix stock-out boot, transfer 500, Clear buttons and uncaught engine errors
Return JSON from any uncaught engine exception, stop the empty stock-out warehouse list aborting page boot, reject non-transfer rows in the transfer lookup, define the missing reset_input helper, and remove a stale unreferenced copy of confirm_order.php.
This commit is contained in:
@@ -222,7 +222,7 @@
|
|||||||
autoPrepare: true,
|
autoPrepare: true,
|
||||||
checkRequired: 0,
|
checkRequired: 0,
|
||||||
action: 'read',
|
action: 'read',
|
||||||
data: { id: <?php echo (int)$_GET['id']; ?> },
|
data: { id: <?php echo (int)($_GET['id'] ?? 0); ?> },
|
||||||
onSuccess: function(res) {
|
onSuccess: function(res) {
|
||||||
var item = res.output;
|
var item = res.output;
|
||||||
$('#id').val(item.id);
|
$('#id').val(item.id);
|
||||||
|
|||||||
@@ -89,7 +89,7 @@
|
|||||||
autoPrepare: true,
|
autoPrepare: true,
|
||||||
checkRequired: 0,
|
checkRequired: 0,
|
||||||
action: 'read',
|
action: 'read',
|
||||||
data: { id: <?php echo (int)$_GET['id']; ?> },
|
data: { id: <?php echo (int)($_GET['id'] ?? 0); ?> },
|
||||||
onSuccess: function(res) {
|
onSuccess: function(res) {
|
||||||
var item = res.output;
|
var item = res.output;
|
||||||
$('#id').val(item.id);
|
$('#id').val(item.id);
|
||||||
|
|||||||
@@ -1074,6 +1074,36 @@ function to_iso_date(dateStr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clear every field inside a form or form-like container — the "Clear" buttons
|
||||||
|
* on the master-data pages. It was called by five pages but never defined, so
|
||||||
|
* each click threw a ReferenceError, and where the container is a <div> rather
|
||||||
|
* than a <form> (Chart of Accounts, Departments) the button did nothing at all.
|
||||||
|
* Disabled and hidden inputs are left alone: those carry the record id and
|
||||||
|
* locked values, not user input.
|
||||||
|
*/
|
||||||
|
function reset_input(selector) {
|
||||||
|
var $scope = $(selector);
|
||||||
|
if (!$scope.length) return;
|
||||||
|
|
||||||
|
$scope.find('input, textarea, select').each(function () {
|
||||||
|
if (this.disabled || this.type === 'hidden' || this.type === 'button' || this.type === 'submit') return;
|
||||||
|
|
||||||
|
if (this._flatpickr) {
|
||||||
|
this._flatpickr.clear();
|
||||||
|
} else if (this.type === 'checkbox' || this.type === 'radio') {
|
||||||
|
this.checked = this.defaultChecked;
|
||||||
|
} else if (this.tagName === 'SELECT') {
|
||||||
|
this.selectedIndex = 0;
|
||||||
|
} else {
|
||||||
|
this.value = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
$(this).removeAttr('secondary').removeClass('is-invalid is-valid');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
function round_dp(value, places) {
|
function round_dp(value, places) {
|
||||||
var factor = Math.pow(10, places);
|
var factor = Math.pow(10, places);
|
||||||
return Math.round((Number(value) + Number.EPSILON) * factor) / factor;
|
return Math.round((Number(value) + Number.EPSILON) * factor) / factor;
|
||||||
|
|||||||
@@ -307,7 +307,10 @@ class StockManager {
|
|||||||
$sth->execute([':company_id' => $this->company_id, ':id' => $id]);
|
$sth->execute([':company_id' => $this->company_id, ':id' => $id]);
|
||||||
$output = $sth->fetch(PDO::FETCH_ASSOC);
|
$output = $sth->fetch(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
if (!$output) return false;
|
// Only a transfer's outbound row names a destination. Any other row
|
||||||
|
// (a stock-in or stock-out reached through a stale or edited link) has
|
||||||
|
// no ref_warehouse, and resolving it threw "Invalid warehouse id."
|
||||||
|
if (!$output || $output['type'] !== 'transfer' || (int)$output['ref_warehouse'] <= 0) return false;
|
||||||
|
|
||||||
// Resolve the inbound (to) row via ref_warehouse + uuid
|
// Resolve the inbound (to) row via ref_warehouse + uuid
|
||||||
$to_warehouse_id = (int)$output['ref_warehouse'];
|
$to_warehouse_id = (int)$output['ref_warehouse'];
|
||||||
|
|||||||
@@ -7,6 +7,34 @@ ini_set('display_errors', 0);
|
|||||||
ini_set('log_errors', 1);
|
ini_set('log_errors', 1);
|
||||||
header('Content-Type: application/json; charset=utf-8');
|
header('Content-Type: application/json; charset=utf-8');
|
||||||
|
|
||||||
|
// Last-resort handler for exceptions an engine does not catch itself. Many
|
||||||
|
// engines call a manager with no try/catch, so any exception — including the
|
||||||
|
// managers' own deliberate validation messages — used to end as a PHP fatal
|
||||||
|
// with an empty 500 body, which the browser could only report as "Server
|
||||||
|
// error occurred." This mirrors the convention the catching engines already
|
||||||
|
// use: a manager's Exception carries a user-facing message (400); a database
|
||||||
|
// or engine fault stays generic (500) and goes to the server log.
|
||||||
|
set_exception_handler(function (Throwable $e) {
|
||||||
|
while (ob_get_level() > 0) ob_end_clean();
|
||||||
|
if (!headers_sent()) header('Content-Type: application/json; charset=utf-8');
|
||||||
|
|
||||||
|
if ($e instanceof PDOException) {
|
||||||
|
error_log('Uncaught PDOException: ' . $e->getMessage() . ' @ ' . $e->getFile() . ':' . $e->getLine());
|
||||||
|
http_response_code(500);
|
||||||
|
$message = 'Database error, please try again.';
|
||||||
|
} elseif ($e instanceof Exception) {
|
||||||
|
http_response_code(400);
|
||||||
|
$message = $e->getMessage();
|
||||||
|
} else {
|
||||||
|
// Error / TypeError: a programming fault, not something to show users.
|
||||||
|
error_log('Uncaught ' . get_class($e) . ': ' . $e->getMessage() . ' @ ' . $e->getFile() . ':' . $e->getLine());
|
||||||
|
http_response_code(500);
|
||||||
|
$message = 'Server error occurred.';
|
||||||
|
}
|
||||||
|
|
||||||
|
echo json_encode(['success' => 0, 'message' => $message]);
|
||||||
|
});
|
||||||
|
|
||||||
require_once __DIR__."/../../config.php";
|
require_once __DIR__."/../../config.php";
|
||||||
require_once __DIR__."/../../dbconn.php";
|
require_once __DIR__."/../../dbconn.php";
|
||||||
require_once __DIR__."/db_helpers.php";
|
require_once __DIR__."/db_helpers.php";
|
||||||
|
|||||||
@@ -17,11 +17,27 @@
|
|||||||
$answer['output'] = $wh->getWarehouseList($type, $sku, $id);
|
$answer['output'] = $wh->getWarehouseList($type, $sku, $id);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (empty($answer['output'])) {
|
if (!empty($answer['output'])) {
|
||||||
|
$answer['success'] = 1;
|
||||||
|
|
||||||
|
} elseif ($type === 'from' && !$id && $sku === '') {
|
||||||
|
// A source ("from") list is filtered to warehouses holding the chosen
|
||||||
|
// product, so it is empty until a product has been picked. That is the
|
||||||
|
// normal starting state of a stock-out form, not a failure. Reporting
|
||||||
|
// it as one showed "create your first warehouse" on every fresh
|
||||||
|
// stock-out, and the rejected request aborted the page's boot sequence
|
||||||
|
// before the barcode scanner was initialised.
|
||||||
|
$answer['success'] = 1;
|
||||||
|
|
||||||
|
} elseif ($type === 'from' && $sku !== '') {
|
||||||
|
$answer['success'] = 0;
|
||||||
|
$answer['message'] = $lot
|
||||||
|
? 'No approved stock of this product and lot is available in any warehouse.'
|
||||||
|
: 'No approved stock of this product is available in any warehouse.';
|
||||||
|
|
||||||
|
} else {
|
||||||
$answer['success'] = 0;
|
$answer['success'] = 0;
|
||||||
$answer['message'] = 'No warehouse found. Please go to <b>Inventory → Warehouse</b> to create your first warehouse before using this page.';
|
$answer['message'] = 'No warehouse found. Please go to <b>Inventory → Warehouse</b> to create your first warehouse before using this page.';
|
||||||
} else {
|
|
||||||
$answer['success'] = 1;
|
|
||||||
}
|
}
|
||||||
exit(json_encode($answer));
|
exit(json_encode($answer));
|
||||||
?>
|
?>
|
||||||
@@ -630,6 +630,12 @@
|
|||||||
action: 'read',
|
action: 'read',
|
||||||
onSuccess: function(res) {
|
onSuccess: function(res) {
|
||||||
var data = res.output;
|
var data = res.output;
|
||||||
|
if (!data || !data.ref) {
|
||||||
|
bootbox.alert('Stock transfer not found.', function() {
|
||||||
|
window.location.href = '<?php echo $server_url?>ics/stock_transfer.php';
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
var from_wh = data.ref.ref_warehouse;
|
var from_wh = data.ref.ref_warehouse;
|
||||||
var to_wh = data.ref_warehouse;
|
var to_wh = data.ref_warehouse;
|
||||||
|
|
||||||
|
|||||||
@@ -1,47 +0,0 @@
|
|||||||
<?php
|
|
||||||
session_start();
|
|
||||||
require '../../../assets/utils/db_auth.php';
|
|
||||||
require '../../../assets/utils/classes/OrderManager.php';
|
|
||||||
require '../../../assets/utils/classes/StockManager.php';
|
|
||||||
require '../../../assets/utils/classes/WarehouseManager.php';
|
|
||||||
require '../../../assets/utils/classes/InvoiceManager.php';
|
|
||||||
require_once '../../../assets/utils/classes/CompanySettingManager.php';
|
|
||||||
|
|
||||||
$id = (int)($data['id'] ?? 0);
|
|
||||||
|
|
||||||
if (!$id) {
|
|
||||||
$answer['message'] = 'Invalid order ID.';
|
|
||||||
http_response_code(400);
|
|
||||||
exit(json_encode($answer));
|
|
||||||
}
|
|
||||||
|
|
||||||
$csm = new CompanySettingManager($pdo1, $company_id);
|
|
||||||
$auto_approve = (int)$csm->get('default_stock_status') === 1;
|
|
||||||
$auto_invoice = (int)$csm->get('auto_invoice_and_credit_note') === 1;
|
|
||||||
|
|
||||||
try {
|
|
||||||
dbTransaction($pdo2, function($pdo) use ($id, $company_id, $logging, $uuid, $auto_approve, $auto_invoice) {
|
|
||||||
$order = new OrderManager($pdo, $company_id);
|
|
||||||
$order->confirmOrder($id, $uuid, $logging, $auto_approve);
|
|
||||||
|
|
||||||
if ($auto_invoice) {
|
|
||||||
$invMgmt = new InvoiceManager($pdo, $company_id);
|
|
||||||
$invMgmt->createFromOrder($id, $logging);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
$answer['success'] = 1;
|
|
||||||
$answer['message'] = 'Order confirmed.';
|
|
||||||
$answer['auto_approved'] = $auto_approve;
|
|
||||||
|
|
||||||
} catch (PDOException $e) {
|
|
||||||
$answer['message'] = 'Database error, please try again.';
|
|
||||||
http_response_code(500);
|
|
||||||
|
|
||||||
} catch (Exception $e) {
|
|
||||||
$answer['message'] = $e->getMessage();
|
|
||||||
http_response_code(400);
|
|
||||||
}
|
|
||||||
|
|
||||||
exit(json_encode($answer));
|
|
||||||
?>
|
|
||||||
Reference in New Issue
Block a user