- reinstated 'update-licenses' task in gulp (accidentally removed in 3e844f2f89)
- updated bootstrap, bootswatch, and various dev dependencies
- refinded text across UI
- applied consistency fixes
- added 'number' and 'tel' input types to relevant settings
- improved system info layout (still room for improvement, but better)
- updated and fixed changelog
* fix: Catch mysqli_sql_exception in DB fallback handlers for fresh Docker installs
On a fresh Docker install with an empty database, the ospos_sessions
table doesn't exist yet. The CSRF filter triggers session initialization
before the login/migration page can be reached.
The existing code in Session.php, OSPOS.php, and MY_Migration.php
catches DatabaseException, but the MySQLi driver throws
mysqli_sql_exception (which extends RuntimeException, not
DatabaseException) when the table doesn't exist. This causes an
unhandled exception resulting in HTTP 500.
Fix: Change all three catch blocks from to
so that mysqli_sql_exception and any other unexpected
database errors are caught, allowing the app to fall back gracefully:
- Session.php: Falls back to FileHandler so sessions work without DB
- OSPOS.php: Falls back to empty settings so config loads work
- MY_Migration.php: Falls back to version 0 / false so the migration
check passes gracefully
This allows the login page with migration UI to be served on first
access, so the initial schema migration can run.
Fixes#4524
---------
Co-authored-by: Ollama <ollama@steganos.dev>
- Fix typo 'mayl' to 'may' in Calendar.php for lo, ka, ml, nb locales
- Improve Spanish translation in Items.php for csv_import_invalid_location
- Add trailing newlines to Calendar.php files (ka, ml, nb, lo) per PSR-12
Co-authored-by: Ollama <ollama@steganos.dev>
In PR #4250 (commit 29c3c55), orWhere was added to match items by
either item_id or item_number, but the OR condition was not wrapped
in groupStart()/groupEnd(). This causes:
1. Wrong SQL semantics: generates
WHERE item_id = ? OR item_number = ? AND deleted = 0
instead of
WHERE (item_id = ? OR item_number = ?) AND deleted = 0
Due to AND binding tighter than OR, the deleted filter only applies
to the item_number branch, allowing deleted items to match via item_id.
2. Performance: the unscoped OR causes MySQL to bypass the item_id
primary key index and fall back to full table scans when item_number
is a string column compared against a numeric parameter.
Both exists() and get_item_id() are fixed by wrapping the OR
conditions in groupStart()/groupEnd() for proper parenthesization.
Co-authored-by: Ollama <ollama@steganos.dev>
Root cause: In commit 7f9321eca, the refactoring incorrectly used object
notation ($config->language_code) on an array instead of array notation
($config['language_code']).
The settings property in OSPOS config is an array, so:
- $config->language_code returns null (object access on array)
- $config['language_code'] returns the actual value
This caused both functions to always fall back to defaults, making the
language dropdown show incorrect values.
Fix: Change both functions to use array notation:
- Line 25: $config['language_code'] (returns saved language code)
- Line 46: $config['language'] (returns saved language name)
Also fixed the wrong DEFAULT_LANGUAGE_CODE fallback on line 46 - should be
DEFAULT_LANGUAGE since current_language() returns a name not a code.
Fixes#4517
Co-authored-by: Ollama <ollama@steganos.dev>
* fix: Add missing $img_tag variable in Sales::getSendPdf()
The receipt_email.php view expects $img_tag but getSendPdf() wasn't passing it.
This caused 'Undefined variable $img_tag' error when sending receipt emails.
Closes#4514
* refactor: Extract img_tag building into helper method
Refactored duplicate img_tag building code into _build_img_tag helper method.
Both getSendPdf and getSendReceipt now use this shared method.
* refactor: Move logo-related methods to Email_lib
Moved buildLogoImgTag and getLogoMimeType methods to Email_lib library
where they logically belong alongside email-related functionality.
This removes duplicate code and centralizes email-related helpers.
Sales controller now uses email_lib->buildLogoImgTag() and
email_lib->getLogoMimeType() instead of private methods.
* fix: Address CodeRabbit review comments
- buildLogoImgTag now uses getLogoMimeType for actual MIME type instead of hardcoding image/png
- getLogoMimeType returns empty string instead of false for consistency
- Consolidated logo path/exists check logic between both methods
---------
Co-authored-by: Ollama <ollama@steganos.dev>
Root cause: In postCheckNumberLocale(), when number_locale differed from
save_number_locale (which happens during form typing/validation), the code
ignored user-provided currency values and always used locale defaults.
For example:
- User sets currency_code to "CRC" (Costa Rica Colon)
- checkNumberLocale is called with save_number_locale from hidden field
- If locale values don't match, original code overwrites with locale defaults
- This caused CRC to revert to the default currency for that locale (EUR, LAK, etc.)
Fix: Always respect user-provided currency_symbol and currency_code values
when they are non-empty, regardless of whether locale changed or not.
Fixes#4494
Co-authored-by: Ollama <ollama@steganos.dev>
- Add esc() for dynamic output in HTML attributes and URLs
- Cast numeric values to int for CSS properties
- Fix invalid 'borderspacing' CSS property to 'border-spacing'
- Add quotes around class attribute
Closes#4487
Co-authored-by: Ollama <ollama@steganos.dev>
- Wrap attribute definition and appconfig save in single transaction
- Capture return values from saveDefinition() and deleteDefinition()
- Only call batch_save() if attribute operation succeeds
- Combine success status with transStatus() for atomic result
- Prevents category_dropdown config persistence when attribute fails
Fixes#4461
Co-authored-by: Ollama <ollama@steganos.dev>
- Merge Config and Core File Changes 4.6.3 > 4.6.4
- Merge Config and Core File Changes 4.6.4 > 4.7.0
- Added app\Config\WorkerMode.php
- Merge Config and Core File Changes Not previously merged
- Added app\Config\Hostnames.php
- Corrected incorrect CSS property used in invoice.php view.
- Corrected unknown CSS properties used in register.php view.
- Used shorthand CSS in debug.css
- Corrected indentation in barcode_sheet.php view.
- Corrected indentation in footer.php view.
- Corrected indentation in invoice_email.php view.
- Replaced obsolete attributes with CSS style attributes in barcode_sheet.php
- Replaced obsolete attribute in error_exception.php
- Replaced obsolete attribute in invoice_email.php
- Replaced obsolete attribute in quote_email.php
- Replaced obsolete attributes in work_order_email.php
- Fixed indentation in system_info.php
- Replaced <strong> tag outside <p> tags, which isn't allowed, with style attributes.
- Simplified js return logic and indentation fixes in tax_categories.php
- Simplified js return logic in tax_codes.php
- Simplified js return logic in tax_jurisdictions.php
- Removed unnecessary labels in manage views.
- Rewrite JavaScript function and PHP to be more readable in bar.php, hbar.php, line.php and pie.php
- Added type declarations, return types and an import to app\Config\Services
- Updated Attribute.php parameter type
- Updated Receiving_lib.php parameter type
- Updated Receivings.php parameter types and updated PHPdocs
- Updated tabular_helper.php parameter types and updated PHPdocs
- Added type declarations and corrected PHPdocs in url_helper.php
- Added return types to functions
- Revert $objectSrc value in ContentSecurityPolicy.php
- Correct return type in Customer->get_stats()
- Correct return type in Item->get_info_by_id_or_number()
- Correct misspelling in border-spacing
- Added missing css style semicolons
- Resolve operator precedence ambiguity.
- Resolve column mismatch.
- Added missing escaping in view.
- Updated requirement for PHP 8.2
- Resolve unresolved conflicts
- Added PHP 8.2 requirement to the README.md
- Fixed bugs in display of UI
- Fixed duplicated `>` in app\Views\Expenses\manage.php
- Removed excess whitespace at the end of some lines in table_filter_persistence.php
- Added missing `>` in app\Views\Expenses\manage.php
- Corrected grammar in PHPdoc in table_filter_persistence.php
- Remove bug causing `\` to be injected into the new giftcard value
- Fix bug causing DROPDOWN Attribute Values to not save correctly
- Added check for null in $normalizedItemId
- Removing < PHP 8.2 from linting and tests
- Update Linter to not include PHP 8.2 and 8.1
- Remove PHP 8.1 unit test cycle.
- Update Bug Report Template
- Update Composer files for CodeIgniter 4.7.2
- Updated INSTALL.md to reflect changes.
---------
Signed-off-by: objec <objecttothis@gmail.com>
PSR and Readability Changes
- Removed unused import
- Corrected PHPdoc to include the correct return type
- Refactored out a function to get attribute data from the row in a CSV item import.
- refactored snake_case variables and function names to camelCase
- Refactored the naming of saveAttributeData() to better reflect the functions purpose.
- Improved PHPdocs
- Remove whitespace
- Remove unneeded comment
- Refactored abbreviated variable name for clarity
- Removed $csvHeaders as it is unused
- Corrected spacing and curly brace location
- Refactored Stock Locations validation inside general validation
Bugfixes
- Fixed bug causing attribute_id and item_id to not be properly assigned when empty() returns true.
- Fixed bug causing CSV Item import to not update barcode when changed in the import file.
- Fixed saveAttributeValue() logic causing attribute_value to be updated to a value that already exists for a different attribute_id
- Fixed bug preventing Category as dropdown functionality from working
- Fixed bug preventing barcodes from updating. in Item CSV Imports
- Corrected bug in stock_location->save_value()
- Corrected incorrect helper file references.
- Removed duplicate call to save attribute link
- Rollback transaction on failure before returning false
- Rollback transaction and return 0 on failure to save attribute link.
- Account for '0' being an acceptable TEXT or DECIMAL attributeValue.
- Corrected Business logic
- Resolved incorrect array key
- Account for 0 in column values
- Correct check empty attribute check
- Previously 0 would have been skipped even though that's a valid value for an attribute.
- Removed unused foreach loop index variables
- Corrected CodeIgniter Framework version to specific version
UnitTest Seeder and tests
- Created a seeder to automatically prepare the test database.
- Modified the Unit Test setup to properly seed the test database.
- Wrote a unit test to test deleting an attribute from an item through the CSV.
- Corrected errors in unit tests preventing them from passing. save_value() returns a bool, not the itemId
- Fix Unit Tests that were failing
- Corrected the logic in itemUpdate test
- Replaced precision test with one reflecting testing of actual value.
- This test does not test cash rounding rules. That should go into a different test.
- Correct expected value in test.
- Update app/Database/Seeds/TestDatabaseBootstrapSeeder.php
- Added check to testImportDeleteAttributeFromExistingItem
- Correct mocking of dropdowns
- Remove code depending on removed database.sql
- Removed FQN in seeder() call
- Added checks in Database seeder
- Moved the function to the attribute model where it belongs which allows testability.
Case Change Capability (CSV Import and Form)
- CSV Import and view Case Changes of `attribute_value`
- Store attribute even when just case is different.
- Add getAttributeValueByAttributeId() to assist in comparing the value
- Corrected Capitalization in File Handling Logic
CSV Import Attribute Link Deletion Capability
- Validation checks bypass magic word cells.
- Delete the attribute link for an item if the CSV contains `_DELETE_`
- Added calls to deleteOrphanedValues()
- Items CSV Import Attribute Delete
- Exclude the itemId in the check to see if the barcode number exists
Error Checking and Reporting Improvements
- Fail the import if an invalid stock location is found in the CSV
- Return false if deleteAttributeLinks fails
- Match sanitization of description field to Form submission import
- Fold errors into result and return value
- Populated $allowedStockLocations before sending it to the validation function
- Added logic to not ignore failed saveItemAttributes calls
- Add error checking to failed row insert
- Reworked &= to && logic so that it short-circuits the function call after if success is already false.
- Add transaction to storeCSVAttributeValue function to prevent deleting the attribute links before confirming the new value successfully saved.
- Modified generate_message in Db_log.php to be defensive.
Attribute Improvements
- Move ATTRIBUTE_VALUE_TYPES to the helper
- Normalize AttributeId in saveAttributeLink()
- normalize itemId in saveAttributeLink()
- Account for '0' in column values for allow_alt_description
- Remove duplicate saveAttributeValue call
- Correct return value of function
- Like other save_value() functions, the location_data variable is passed by reference.
- Unlike other save_value() functions, the location_data variable is not being updated with the primary key id.
- Added updateAttributeValue() function as part of logic fix.
- Added attribute_helper.php
- Simplified logic to store attribute values
---------
Signed-off-by: objec <objecttothis@gmail.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
* Fix: Improve allowedHostnames .env configuration and fail-fast in production
Addresses GitHub issue #4480: .env app.allowedHostnames does not work as intended
## Problem
- CodeIgniter 4 cannot override array properties from .env
- Setting app.allowedHostnames.0, app.allowedHostnames.1 did NOT populate the array
- Application always fell back to 'localhost' silently in production
- Host header injection protection was effectively disabled
## Solution
1. Support comma-separated .env values: app.allowedHostnames = 'domain1.com,domain2.com'
2. Fail explicitly in production if not configured (throws RuntimeException)
3. Allow localhost fallback in development/testing with ERROR-level logging
4. Update documentation with clear setup instructions
## Changes
- app/Config/App.php: Parse comma-separated .env values, fail in production
- .env.example: Update format documentation
- INSTALL.md: Add prominent security section
- tests/Config/AppTest.php: Comprehensive tests for new behavior
Fixes#4480
Related: GHSA-jchf-7hr6-h4f3
---------
Co-authored-by: Ollama <ollama@steganos.dev>
The get_tax_rates_data_row() function in tax_helper.php was calling
service('router') without handling cases where the router service is
unavailable, causing the form modal to fail to open.
This fix adds a fallback to 'taxes' controller name when router service
returns null or fails.
Also adds missing 'id' field in postSave() JSON response for proper
row highlighting after save operations.
Fixes#4477
Co-authored-by: Ollama <ollama@steganos.dev>
Co-authored-by: odiea <odiea@users.noreply.github.com>
- Add issue template version update back with correct 'OpenSourcePOS' casing
- Fix version list inconsistency (add 3.3.8 to feature_request.yml, align with bug report.yml)
- Fix changelog special characters issue by using temp file instead of inline sed
- Keep versions in sync between both templates
- Update [unreleased] changelog link to start from new version
- Remove misleading notes about automatic version updates from issue templates
(release workflow no longer auto-updates template version lists)
- Remove build steps (handled by build-release.yml on push)
- Remove tag creation (create tag from unstable release later)
- Remove draft release creation
- Remove SECURITY.md and issue template updates
- Keep version bumps in: App.php, package.json, docker-compose.nginx.yml, README.md, CHANGELOG.md
Workflow now:
1. Bumps version in source files
2. Commits and pushes to master
3. build-release.yml picks up the push and creates unstable release
- Add workflow_dispatch triggered release.yml with major/minor/patch options
- Auto-update version in App.php, package.json, docker-compose.nginx.yml
- Auto-update README.md and SECURITY.md version references
- Auto-update issue templates with new version dropdowns
- Generate CHANGELOG.md from git commits since last version
- Build distribution archives and create draft GitHub release
- Add draft_only input for testing without pushing changes
Issue templates improvements:
- Remove deprecated update-issue-templates.yml cron workflow
- Reorganize with clear sections and visual hierarchy
- Add emojis and improve placeholder text with examples
- Add new fields: logs, screenshots, acceptance criteria
- Add note about automatic version updates