From b7384296c175ad9b0d16e72f1f7fc168d96e32aa Mon Sep 17 00:00:00 2001 From: objecttothis <17935339+objecttothis@users.noreply.github.com> Date: Fri, 22 May 2026 01:43:24 +0400 Subject: [PATCH 1/2] Bugfix: Sale search in register not handling trailing space properly (#4557) * Fix is_valid_receipt method bug Strings submitted with a trailing space and no number caused an unhandled exception because Sale::exists() expects an int but a string was passed to it. - Add guards - Minor PSR refactor Signed-off-by: objec * Address review comments Signed-off-by: objec --------- Signed-off-by: objec --- app/Controllers/Sales.php | 6 +++--- app/Models/Sale.php | 18 +++++++++--------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/app/Controllers/Sales.php b/app/Controllers/Sales.php index 1d60d44bb..55c1a5c1c 100644 --- a/app/Controllers/Sales.php +++ b/app/Controllers/Sales.php @@ -161,7 +161,7 @@ class Sales extends Secure_Controller 'only_bank_transfer'=> false, 'only_wallet' => false, 'only_invoices' => $this->config['invoice_enable'] && $this->request->getGet('only_invoices', FILTER_SANITIZE_NUMBER_INT), - 'is_valid_receipt' => $this->sale->is_valid_receipt($search) + 'is_valid_receipt' => $this->sale->isValidReceipt($search) ]; // Check if any filter is set in the multiselect dropdown @@ -198,7 +198,7 @@ class Sales extends Secure_Controller ? $this->request->getGet('term') : null; - if ($this->sale_lib->get_mode() == 'return' && $this->sale->is_valid_receipt($receipt)) { + if ($this->sale_lib->get_mode() == 'return' && $this->sale->isValidReceipt($receipt)) { // If a valid receipt or invoice was found the search term will be replaced with a receipt number (POS #) $suggestions[] = $receipt; } @@ -525,7 +525,7 @@ class Sales extends Secure_Controller $quantity = ($mode == 'return') ? -$quantity : $quantity; $item_location = $this->sale_lib->get_sale_location(); - if ($mode == 'return' && $this->sale->is_valid_receipt($item_id_or_number_or_item_kit_or_receipt)) { + if ($mode == 'return' && $this->sale->isValidReceipt($item_id_or_number_or_item_kit_or_receipt)) { $this->sale_lib->return_entire_sale($item_id_or_number_or_item_kit_or_receipt); } elseif ($this->item_kit->is_valid_item_kit($item_id_or_number_or_item_kit_or_receipt)) { // Add kit item to order if one is assigned diff --git a/app/Models/Sale.php b/app/Models/Sale.php index 2b21ea9d5..a73519d52 100644 --- a/app/Models/Sale.php +++ b/app/Models/Sale.php @@ -327,7 +327,7 @@ class Sale extends Model { $suggestions = []; - if (!$this->is_valid_receipt($search)) { + if (!$this->isValidReceipt($search)) { $builder = $this->db->table('sales'); $builder->distinct()->select('first_name, last_name'); $builder->join('people', 'people.person_id = sales.customer_id'); @@ -408,21 +408,21 @@ class Sale extends Model /** * Checks if valid receipt */ - public function is_valid_receipt(string|null &$receipt_sale_id): bool // TODO: like the others, maybe this should be an array rather than a delimited string... either that or the parameter name needs to be changed. $receipt_sale_id implies that it's an int. + public function isValidReceipt(string|null &$receiptSaleId): bool // TODO: like the others, maybe this should be an array rather than a delimited string... either that or the parameter name needs to be changed. $receipt_sale_id implies that it's an int. { $config = config(OSPOS::class)->settings; - if (!empty($receipt_sale_id)) { + if (!empty($receiptSaleId)) { // POS # - $pieces = explode(' ', $receipt_sale_id); + $pieces = explode(' ', trim($receiptSaleId)); - if (count($pieces) == 2 && preg_match('/(POS)/i', $pieces[0])) { - return $this->exists($pieces[1]); + if (count($pieces) == 2 && strtoupper($pieces[0]) === 'POS' && ctype_digit($pieces[1])) { + return $this->exists((int)$pieces[1]); } elseif ($config['invoice_enable']) { - $sale_info = $this->get_sale_by_invoice_number($receipt_sale_id); + $saleInfo = $this->get_sale_by_invoice_number($receiptSaleId); - if ($sale_info->getNumRows() > 0) { - $receipt_sale_id = 'POS ' . $sale_info->getRow()->sale_id; + if ($saleInfo->getNumRows() > 0) { + $receiptSaleId = 'POS ' . $saleInfo->getRow()->sale_id; return true; } From 5450404cb23fbba0a32d19ca19f6779639537d6f Mon Sep 17 00:00:00 2001 From: jekkos Date: Fri, 22 May 2026 16:07:21 +0200 Subject: [PATCH 2/2] fix: cast string returns to int in MY_Migration (#4560) basename() returns string and database column values are strings, but get_latest_migration() and get_current_version() declare int return types. PHP 8.0+ enforces strict return types and no longer silently coerces strings to int, causing a TypeError on fresh installs. Fixes #4559 Co-authored-by: Ollama --- app/Libraries/MY_Migration.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/Libraries/MY_Migration.php b/app/Libraries/MY_Migration.php index c27954145..98177d770 100644 --- a/app/Libraries/MY_Migration.php +++ b/app/Libraries/MY_Migration.php @@ -25,7 +25,7 @@ class MY_Migration extends MigrationRunner public function get_latest_migration(): int { $migrations = $this->findMigrations(); - return basename(end($migrations)->version); + return (int) basename(end($migrations)->version); } /** @@ -41,7 +41,7 @@ class MY_Migration extends MigrationRunner $builder = $db->table('migrations'); $builder->select('version')->orderBy('version', 'DESC')->limit(1); $result = $builder->get()->getRow(); - return $result ? $result->version : 0; + return $result ? (int) $result->version : 0; } } catch (\Exception $e) { // Database not available yet (e.g. fresh install before schema).