* Bugfixes to get Migration working on MySQL
Signed-off-by: objec <objecttothis@gmail.com>
* MariaDB compatibility fixes
- Drop foreign key constraints before making charset changes
- Fix dropAllForeignKeyConstraints helper function.
- Added `IF EXISTS` to DROP statements
- Do not try to readd FK constraints for tables which were dropped.
- MariaDB 11.8.x changes the default implicit collation to uca1400 which breaks the IndiaGST migration, et. al. Explicitly declare utf8_general_ci in affected migrations.
Signed-off-by: objec <objecttothis@gmail.com>
* Fix changes which break MySQL migrations
- MySQL does not support IF EXISTS in foreign key constraints. Since the PHP is now handling dropping those constraints, these lines are redundant. Remove them.
Signed-off-by: objec <objecttothis@gmail.com>
* Resolve code review recommendations
- Add try/catch around DB connect statement
- Heed result of execute_script function and throw an exception on failure.
Signed-off-by: objec <objecttothis@gmail.com>
* Refactor out duplicate code
Signed-off-by: objec <objecttothis@gmail.com>
* Initialize array variable causing potential issues
Signed-off-by: objec <objecttothis@gmail.com>
---------
Signed-off-by: objec <objecttothis@gmail.com>
* fix(ci): include hidden files in Docker build context
actions/upload-artifact@v4 excludes hidden files (dotfiles) by default,
causing .htaccess files to be missing from the Docker image. Add
include-hidden-files: true to preserve .htaccess in the build artifact.
* fix(docker): correct permissions and add barcode_type default
- Set proper permissions (750) for writable/logs, writable/uploads,
writable/cache, public/uploads, and public/uploads/item_pics
- Set permissions (640) for writable/uploads/importCustomers.csv
- Add barcode_type default value to prevent 'unknown key' error
during initial migration when database is not yet initialized
---------
Co-authored-by: Ollama <ollama@steganos.dev>
Co-authored-by: objecttothis <17935339+objecttothis@users.noreply.github.com>
Allow configuring allowed hostnames via ALLOWED_HOSTNAMES environment
variable as an alternative to app.allowedHostnames in .env file. This
is more convenient for Docker/Compose deployments where environment
variables are set directly in compose files.
The ALLOWED_HOSTNAMES variable takes precedence over app.allowedHostnames
if both are set, allowing deployment-specific overrides.
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)
Co-authored-by: Ollama <ollama@steganos.dev>
Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
- updated some files to match the official CodeIgniter 4 skeleton.
- rebuilt package.json from a clean init and modernized metadata and formatting
- rebuilt composer.json with modernized metadata and formatting
- replaced code of conduct text with markdown
- updated Dockerfile to replace deprecated instruction
- Update README.md to reflect information about routes
- Add registerAllNamespaces() function to correctly load plugin namespaces
- center text in modal title
- Properly decrypt the api key
- Refactor getAllLists to getLists
- Naming simplification of strings when mailchimp_ is redundant or unnecessary
- Do not attempt to decrypt a plaintext api_key pasted into the form
- Register namespaces early on in system init
Signed-off-by: objec <objecttothis@gmail.com>
- Move the PluginManager creation to a service.
- Move plugin discovery to creation.
- Create static discovery and namespaces variables in the PluginManager.php library
- Refactor persistent namespace declarations
- Refactor redundant code to private function.
- Remove whitespace
- Remove enable setting from MailchimpPlugin. That is handled by the PluginManager.php
- Update Events.php to call the pluginManager service
- Correct typo in enabled setting for BasePlugin to accurately reflect the database naming.
Signed-off-by: objec <objecttothis@gmail.com>
- Move Plugins controller and rename to reflect the rest of the code.
- Lazy load event registrations.
- Autoload classes so plugins are discovered.
- Remove TODO
- Remove unneeded use statement
- Correct typo in namespace of MailchimpConnector Library
- Add class names to autoload class map
- Move Plugin discovery to post_controller_constructor event
Signed-off-by: objec <objecttothis@gmail.com>
- Add plugin module to list of required admin modules.
- Don't trigger autoloader in plugin discovery.
- Delete plugins_config.php which is no longer needed for managing plugins.
- Remove references to plugins_configuration in config views.
- Correct the form submission URL path.
Signed-off-by: objec <objecttothis@gmail.com>
* 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>
- 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>
* 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>
* Fix business logic vulnerability allowing negative sale totals (GHSA-wv3j-pp8r-7q43)
Add server-side validation in postEditItem() to reject negative prices,
quantities, and discounts, as well as percentage discounts exceeding 100%
and fixed discounts exceeding the item total. Also block sale completion
with negative totals in non-return mode to prevent fraud/theft.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Fix: exempt return mode from negative quantity validation
Return mode legitimately stores items with negative quantities.
The quantity validation now skips the non-negative check in return mode,
consistent with the existing return mode exemption in postComplete().
Also use abs() for fixed discount comparison to handle return quantities.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Refactor: use $rules + validate() pattern per review feedback
Address review comments from jekkos on PR #4450:
1. Use CI4 $rules variable with custom non_negative_decimal validation
rule instead of manual if-checks for price/discount validation.
2. Add validation error strings to all 44 non-English language files
(English fallback values used until translations are contributed).
3. Use validate() method with $messages array for localized error
display, maintaining the existing controller pattern.
Additional improvements:
- Add non_negative_decimal rule to OSPOSRules.php (leverages
parse_decimals() for locale-aware decimal parsing)
- Preserve manual checks for business logic (return mode quantity
exemption, discount bounds via bccomp)
- Fix PHP 8.1+ compatibility: avoid passing method return to reset()
- Explicit empty discount handling for bc-math safety
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Fix: rename to nonNegativeDecimal (PSR), clear non-English translation strings
- Rename validation rule method non_negative_decimal → nonNegativeDecimal in
OSPOSRules.php and all $rules/$messages references in Sales.php (PSR naming
per @objecttothis review)
- Replace English fallback text with "" in 43 non-English language files so
CI4 falls back to the base language string; weblate will handle translations
(per @jekkos and @objecttothis agreement)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Paul <morimori-dev@github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: objecttothis <17935339+objecttothis@users.noreply.github.com>
- Move plugin discovery to pre_system in Events.php (allows events to be registered before they fire)
- Add plugin existence check in disablePlugin()
- Add is_subclass_of check before instantiating plugin classes
- Fix str_replace prefix removal in getPluginSettings using str_starts_with + substr
- Add down() migration to drop table on rollback
- Fix saveSettings to JSON-encode arrays/objects
- Update README to use MailchimpPlugin as reference implementation
- Remove CasposPlugin examples from documentation
Security: Prevent Host Header Injection attacks by validating HTTP_HOST
against a whitelist of allowed hostnames before constructing the baseURL.
Changes:
- Add getValidHost() method to validate HTTP_HOST against allowedHostnames
- If allowedHostnames is empty, log warning and fall back to 'localhost'
- If host not in whitelist, log warning and use first allowed hostname
- Update .env.example with allowedHostnames documentation
- Add security configuration section to INSTALL.md
- Add unit tests for host validation
This addresses the security advisory where the application constructed
baseURL from the attacker-controllable HTTP_HOST header, allowing:
- Login form phishing via manipulated form actions
- Cache poisoning via poisoned asset URLs
Fixes GHSA-jchf-7hr6-h4f3
Add event-based view hook system allowing plugins to inject UI elements
into core views without modifying core files. Includes helper functions
and example CasposPlugin demonstrating the pattern.
This implements a clean plugin architecture based on PR #4255 discussion:
Core Components:
- PluginInterface: Standard contract all plugins must implement
- BasePlugin: Abstract class with common functionality
- PluginManager: Discovers and loads plugins from app/Plugins/
- Plugin_config: Model for plugin settings storage
Architecture:
- Each plugin registers its own event listeners via registerEvents()
- No hardcoded plugin dependencies in core Events.php
- Generic event triggers (item_sale, item_change, etc.) remain in core code
- Plugins can be enabled/disabled via database settings
- Clean separation: plugin orchestrators vs MVC components
Example Implementations:
- ExamplePlugin: Simple plugin demonstrating event logging
- MailchimpPlugin: Integration with Mailchimp for customer sync
Admin UI:
- Plugin management controller at Controllers/Plugins/Manage.php
- Plugin management view at Views/plugins/manage.php
Database:
- ospos_plugin_config table for plugin settings (key-value store)
- Migration creates table with timestamps
Documentation:
- Comprehensive README with architecture patterns
- Simple vs complex plugin examples
- MVC directory structure guidance
- Move admin modules list from is_admin method to ADMIN_MODULES constant
- Rename is_admin() to isAdmin() following CodeIgniter naming conventions
- Rename can_modify_employee() to canModifyEmployee() following conventions
- Update all callers in Employees controller and tests
Complete Content-Type application/json fix for all AJAX responses
- Add missing return statements to all ->response->setJSON() calls
- Fix Items.php method calls from JSON() to setJSON()
- Convert echo statements to proper JSON responses
- Ensure consistent Content-Type headers across all controllers
- Fix 46+ instances across 12 controller files
- Change Config.php methods to : ResponseInterface (all return setJSON only):
- postSaveRewards(), postSaveBarcode(), postSaveReceipt()
- postSaveInvoice(), postRemoveLogo()
- Update PHPDoc @return tags
- Change Receivings.php _reload() to : string (only returns view)
- Change Receivings.php methods to : string (all return _reload()):
- getIndex(), postSelectSupplier(), postChangeMode(), postAdd()
- postEditItem(), getDeleteItem(), getRemoveSupplier()
- postComplete(), postRequisitionComplete(), getReceipt(), postCancelReceiving()
- Change postSave() to : ResponseInterface (returns setJSON)
- Update all PHPDoc @return tags
Fix XSS vulnerabilities in sales templates, login, and config pages
This commit addresses 5 XSS vulnerabilities by adding proper escaping
to all user-controlled configuration values in HTML contexts.
Fixed Files:
- app/Views/sales/invoice.php: Escaped company_logo (URL context) and company (HTML)
- app/Views/sales/work_order.php: Escaped company_logo (URL context)
- app/Views/sales/receipt_email.php: Added file path validation and escaping for logo
- app/Views/login.php: Escaped all config values in title, logo src, and alt
- app/Views/configs/info_config.php: Escaped company_logo (URL context)
Security Impact:
- Prevents stored XSS attacks if configuration is compromised
- Defense-in-depth principle applied to administrative interfaces
- Follows OWASP best practices for output encoding
Testing:
- Verified no script execution with XSS payloads in config values
- Confirmed proper escaping in HTML, URL, and file contexts
- All templates render correctly with valid configuration
Severity: High (4 files), Medium-High (1 file)
CVSS Score: ~6.1
CWE: CWE-79 (Improper Neutralization of Input During Web Page Generation)
Fix critical password validation bypass and add unit tests
This commit addresses a critical security vulnerability where the password
minimum length check was performed on the HASHED password (always 60
characters for bcrypt) instead of the actual password before hashing.
Vulnerability Details:
- Original code: strlen($employee_data['password']) >= 8
- This compared the hash length (always 60) instead of raw password
- Impact: Users could set 1-character passwords like "a"
- Severity: Critical (enables brute force attacks on weak passwords)
- CVE-like issue: CWE-307 (Improper Restriction of Excessive Authentication Attempts)
Fix Applied:
- Validate password length BEFORE hashing
- Clear error message when password is too short
- Added unit tests to verify minimum length enforcement
- Regression test to prevent future vulnerability re-introduction
Test Coverage:
- testPasswordMinLength_Rejects7Characters: Verify 7 chars rejected
- testPasswordMinLength_Accepts8Characters: Verify 8 chars accepted
- testPasswordMinLength_RejectsEmptyString: Verify empty rejected
- testPasswordMinLength_RejectsWhitespaceOnly: Verify whitespace rejected
- testPasswordMinLength_AcceptsSpecialCharacters: Verify special chars OK
- testPasswordMinLength_RejectsPreviousBehavior: Regression test for bug
Files Modified:
- app/Controllers/Home.php: Fixed password validation logic
- tests/Controllers/HomeTest.php: Added comprehensive unit tests
Security Impact:
- Enforces 8-character minimum password policy
- Prevents extremely weak passwords that facilitate brute-force attacks
- Critical for credential security and user account protection
Breaking Changes:
- Users with passwords < 8 characters will need to reset their password
- This is the intended security improvement
Severity: Critical
CVSS Score: ~7.5
CWE: CWE-305 (Authentication Bypass by Primary Weakness), CWE-307
Add GitHub Actions workflow to run PHPUnit tests
Move business logic from views to controllers for better separation of concerns
- Move logo URL computation from info_config view to Config::getIndex()
- Move image base64 encoding from receipt_email view to Sales controller
- Improves separation of concerns by keeping business logic in controllers
- Simplifies view templates to only handle presentation
Fix XSS vulnerabilities in report views - escape user-controllable summary data and labels
Fix base64 encoding URL issue in delete payment - properly URL encode base64 string
Fix remaining return type declarations for Sales controller
Fixed additional methods that call _reload():
- postAdd() - returns _reload($data)
- postAddPayment() - returns _reload($data)
- postEditItem() - returns _reload($data)
- postSuspend() - returns _reload($data)
- postSetPaymentType() - returns _reload()
All methods now return ResponseInterface|string to match _reload() signature.
This resolves PHP TypeError errors.
* Add show/hide cost price & profit feature
* .env should be ignored.
* js code formatted. .vscode folder ignore for vscode user settings.json
* style is replaced with bootstrap class, formatted and .env.example
* toggle button on table to like in other
* comment corrected.
* class re-factored
* minor refactor
* formatted with 4 space
---------
Co-authored-by: Lotussoft Youngtech <lotussoftyoungtech@gmail.com>
* Improve code style and PSR-12 compliance
- refactored code formatting to adhere to PSR-12 guidelines
- standardized coding conventions across the codebase
- added missing framework files and reverted markup changes
- reformatted arrays for enhanced readability
- updated language files for consistent styling and clarity
- minor miscellaneous improvements
* Replace tabs with spaces
Signed-off-by: objecttothis <objecttothis@gmail.com>
* Composer package bumps
- Bump codeigniter4/framework to 4.6.0
- Bump codeIgniter/coding-standard to ^1.8
- Bump codeigniter4/devkit to ^1.3
- Updated framework files required by CI4.6.0
- Removed Deprecated variables
- Added new file in the repo from framework
Signed-off-by: objecttothis <objecttothis@gmail.com>
* Reflect PHP 8.4 support
Updates for PHP 8.4 support introduced with the upgrade to CodeIgniter 4.6.x
* Update INSTALL.md
- Revert PHP 8.4 support for now.
- Removed extra space before comma
---------
Signed-off-by: objecttothis <objecttothis@gmail.com>
Co-authored-by: BudsieBuds <bas_hubers@hotmail.com>
- Added TODO
- Copied directives from .htaccess to the ContentSecurityPolicy.php config file.
- Left CSPEnabled set to false in App.php because there is currently no CSP3 support in CI4
- Added `img-src blob:` To Content-Security-Policy header to remove error.
Signed-off-by: objecttothis <objecttothis@gmail.com>
- Refactored code for clarity
- Created and called sanitization functions.
- Sanitize TEXT type Attributes before being sent to the view.
Signed-off-by: objecttothis <objecttothis@gmail.com>
- Bump bootstrap-table to 1.23.1 in attempt to resolve issue with sticky headers
- Sanitize attribute data in tables
- Sanitize item data with controller function.
Signed-off-by: objecttothis <objecttothis@gmail.com>
Sanitize Item data
- Sanitize category and item_number before display in forms.
- refactor check in pic_filename for empty to be best practices compliant.
- Added TODO
Signed-off-by: objecttothis <objecttothis@gmail.com>
Minor changes
- Refactored for code clarity.
- Removed extra blank lines.
- Minor reformatting.
- Added PHPdocs
- bumped bootstrap-table to 1.23.2
Signed-off-by: objecttothis <objecttothis@gmail.com>
Pre-view filtering Items Controller
- Refactored code for clarity
- Created and called sanitization functions.
- Sanitize TEXT type Attributes before being sent to the view.
Signed-off-by: objecttothis <objecttothis@gmail.com>
- Bump bootstrap-table to 1.23.1 in attempt to resolve issue with sticky headers
- Sanitize attribute data in tables
- Sanitize item data with controller function.
Signed-off-by: objecttothis <objecttothis@gmail.com>
Pre-view filtering Items Controller
- Refactored code for clarity
- Created and called sanitization functions.
- Sanitize TEXT type Attributes before being sent to the view.
Signed-off-by: objecttothis <objecttothis@gmail.com>
Sanitize Item data
- Sanitize category and item_number before display in forms.
- refactor check in pic_filename for empty to be best practices compliant.
- Added TODO
Signed-off-by: objecttothis <objecttothis@gmail.com>
Pre-view filtering Items Controller
- Refactored code for clarity
- Created and called sanitization functions.
- Sanitize TEXT type Attributes before being sent to the view.
Signed-off-by: objecttothis <objecttothis@gmail.com>
Removed unnecessary use statement
Signed-off-by: objecttothis <objecttothis@gmail.com>
* Remove HtmlPurifier calls
- All calls to Services::htmlPurifier()->purify() removed from data received from view.
- Bootstrap and bootswatch bump in package-lock.json
Signed-off-by: objecttothis <objecttothis@gmail.com>
* Pre-view filtering Items Controller
- Refactored code for clarity
- Created and called sanitization functions.
- Sanitize TEXT type Attributes before being sent to the view.
Signed-off-by: objecttothis <objecttothis@gmail.com>
* Pre-view filtering Customers Controller
- Refactored code for clarity
- Replaced == with === operator to prevent type juggling
- Added Sanitization of Customer data before being sent to the view
Signed-off-by: objecttothis <objecttothis@gmail.com>
* Bump bootstrap-table to 1.23.1
- Bump bootstrap-table to 1.23.1 in attempt to resolve issue with sticky headers
- Sanitize attribute data in tables
- Sanitize item data with controller function.
Signed-off-by: objecttothis <objecttothis@gmail.com>
* Pre-view filtering Items Controller
- Refactored code for clarity
- Created and called sanitization functions.
- Sanitize TEXT type Attributes before being sent to the view.
Signed-off-by: objecttothis <objecttothis@gmail.com>
* Sanitize Item data
- Sanitize category and item_number before display in forms.
- refactor check in pic_filename for empty to be best practices compliant.
- Added TODO
Signed-off-by: objecttothis <objecttothis@gmail.com>
* Minor changes
- Refactored for code clarity.
- Removed extra blank lines.
- Minor reformatting.
- Added PHPdocs
- bumped bootstrap-table to 1.23.2
Signed-off-by: objecttothis <objecttothis@gmail.com>
* Pre-view filtering Items Controller
- Refactored code for clarity
- Created and called sanitization functions.
- Sanitize TEXT type Attributes before being sent to the view.
Signed-off-by: objecttothis <objecttothis@gmail.com>
* Sanitize Item data
- Sanitize category and item_number before display in forms.
- refactor check in pic_filename for empty to be best practices compliant.
- Added TODO
Signed-off-by: objecttothis <objecttothis@gmail.com>
---------
Signed-off-by: objecttothis <objecttothis@gmail.com>
Co-authored-by: objecttothis <objecttothis@gmail.com>
- Added @noinspection PhpUnused to AJAX-called functions to remove weak warning that the function is unused. This will be needed for the linter.
- Referenced where the function is called in the PHPdocs.
- Removed redundant transaction. batch_save() is already being run in a transaction.
- Fixed function name in controller and view.
- Removed form helper load because it's autoloaded.
- Corrected variable reference in Secure_Controller.php
Signed-off-by: objecttothis <objecttothis@gmail.com>
- Replaced == with === to avoid type juggling
- Removed unneeded TODO
- Added HTMLPurifier to composer.json
- Added Service to allow singleton instance of purifier.
- Implemented use in Customer Controller Search function.
Signed-off-by: objecttothis <objecttothis@gmail.com>