mirror of
https://github.com/opensourcepos/opensourcepos.git
synced 2026-04-16 12:57:32 -04:00
Update to CodeIgniter 4.7.2 (#4485)
- 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>
This commit is contained in:
17
.github/ISSUE_TEMPLATE/bug report.yml
vendored
17
.github/ISSUE_TEMPLATE/bug report.yml
vendored
@@ -12,11 +12,11 @@ body:
|
||||
attributes:
|
||||
value: |
|
||||
## Thanks for taking the time to fill out this bug report! 🐜
|
||||
|
||||
|
||||
Bug reports help us identify and fix issues. Please provide as much detail as possible.
|
||||
|
||||
|
||||
> ⚠️ **Important:** Submit a separate bug report for each problem you encounter.
|
||||
>
|
||||
>
|
||||
> 🚫 Do not include personal identifying information such as email addresses or encryption keys.
|
||||
|
||||
# ─────────────────────────────────────────────────────────────────────────────
|
||||
@@ -28,7 +28,7 @@ body:
|
||||
label: 🐛 Bug Description
|
||||
description: A clear and concise description of what the bug is.
|
||||
placeholder: |
|
||||
Example: When I try to print a receipt, the application crashes
|
||||
Example: When I try to print a receipt, the application crashes
|
||||
with an error message saying "Unable to connect to printer".
|
||||
validations:
|
||||
required: true
|
||||
@@ -86,8 +86,7 @@ body:
|
||||
- PHP 8.2
|
||||
- PHP 8.1
|
||||
- PHP 7.4
|
||||
- PHP 7.3
|
||||
- PHP 7.2
|
||||
- Other
|
||||
default: 0
|
||||
validations:
|
||||
required: true
|
||||
@@ -141,7 +140,7 @@ body:
|
||||
label: 📊 System Information Report
|
||||
description: |
|
||||
Copy and paste the system information from OSPOS:
|
||||
|
||||
|
||||
**Navigation:** Configuration → Setup & Conf → System Info
|
||||
placeholder: |
|
||||
Paste the System Information Report here...
|
||||
@@ -155,7 +154,7 @@ body:
|
||||
label: 📜 Relevant Log Output
|
||||
description: |
|
||||
Please copy and paste any relevant log output.
|
||||
|
||||
|
||||
**Log locations:**
|
||||
- OSPOS logs: `writable/logs/`
|
||||
- Web server logs: `/var/log/apache2/` or `/var/log/nginx/`
|
||||
@@ -185,4 +184,4 @@ body:
|
||||
- label: I have searched existing issues to ensure this bug has not already been reported
|
||||
required: true
|
||||
- label: I have provided all the information requested above
|
||||
required: true
|
||||
required: true
|
||||
|
||||
1
.github/workflows/main.yml
vendored
1
.github/workflows/main.yml
vendored
@@ -28,7 +28,6 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
php-version:
|
||||
- '8.1'
|
||||
- '8.2'
|
||||
- '8.3'
|
||||
- '8.4'
|
||||
|
||||
8
.github/workflows/php-linter.yml
vendored
8
.github/workflows/php-linter.yml
vendored
@@ -12,14 +12,6 @@ jobs:
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: PHP Lint 8.0
|
||||
uses: dbfx/github-phplint/8.0@master
|
||||
with:
|
||||
folder-to-exclude: "! -path \"./vendor/*\" ! -path \"./folder/excluded/*\""
|
||||
- name: PHP Lint 8.1
|
||||
uses: dbfx/github-phplint/8.1@master
|
||||
with:
|
||||
folder-to-exclude: "! -path \"./vendor/*\" ! -path \"./folder/excluded/*\""
|
||||
- name: PHP Lint 8.2
|
||||
uses: dbfx/github-phplint/8.2@master
|
||||
with:
|
||||
|
||||
3
.github/workflows/phpunit.yml
vendored
3
.github/workflows/phpunit.yml
vendored
@@ -34,7 +34,6 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
php-version:
|
||||
- '8.1'
|
||||
- '8.2'
|
||||
- '8.3'
|
||||
- '8.4'
|
||||
@@ -119,4 +118,4 @@ jobs:
|
||||
|
||||
- name: Stop MariaDB
|
||||
if: always()
|
||||
run: docker stop mysql && docker rm mysql
|
||||
run: docker stop mysql && docker rm mysql
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
## Server Requirements
|
||||
|
||||
- PHP version `8.1` to `8.4` are supported, PHP version `≤7.4` is NOT supported. Please note that PHP needs to have the extensions `php-json`, `php-gd`, `php-bcmath`, `php-intl`, `php-openssl`, `php-mbstring`, `php-curl` and `php-xml` installed and enabled. An unstable master build can be downloaded in the releases section.
|
||||
- PHP version `8.2` to `8.4` are supported, PHP version `≤ 8.1` is NOT supported. Please note that PHP needs to have the extensions `php-json`, `php-gd`, `php-bcmath`, `php-intl`, `php-openssl`, `php-mbstring`, `php-curl` and `php-xml` installed and enabled. An unstable master build can be downloaded in the releases section.
|
||||
- MySQL `5.7` is supported, also MariaDB replacement `10.x` is supported and might offer better performance.
|
||||
- Apache `2.4` is supported. Nginx should work fine too, see [wiki page here](https://github.com/opensourcepos/opensourcepos/wiki/Local-Deployment-using-LEMP).
|
||||
- Raspberry PI based installations proved to work, see [wiki page here](<https://github.com/opensourcepos/opensourcepos/wiki/Installing-on-Raspberry-PI---Orange-PI-(Headless-OSPOS)>).
|
||||
|
||||
@@ -102,7 +102,7 @@ NOTE: If you're running non-release code, please make sure you always run the la
|
||||
|
||||
- If you have suhosin installed and face an issue with CSRF, please make sure you read [issue #1492](https://github.com/opensourcepos/opensourcepos/issues/1492).
|
||||
|
||||
- PHP `≥ 8.1` is required to run this app.
|
||||
- PHP `≥ 8.2` is required to run this app.
|
||||
|
||||
## 🏃 Keep the Machine Running
|
||||
|
||||
|
||||
@@ -55,21 +55,13 @@ class App extends BaseConfig
|
||||
public string $baseURL; // Defined in the constructor
|
||||
|
||||
/**
|
||||
* Allowed Hostnames for the Site URL.
|
||||
*
|
||||
* Security: This is used to validate the HTTP Host header to prevent
|
||||
* Host Header Injection attacks. If the Host header doesn't match
|
||||
* an entry in this list, the request will use the first allowed hostname.
|
||||
*
|
||||
* IMPORTANT: This MUST be configured for production deployments.
|
||||
* If empty in production, the application will fail to start.
|
||||
* In development, it will fall back to 'localhost' with a warning.
|
||||
*
|
||||
* Configure via .env file (comma-separated list):
|
||||
* app.allowedHostnames = 'example.com,www.example.com'
|
||||
*
|
||||
* For local development:
|
||||
* app.allowedHostnames = 'localhost'
|
||||
* Allowed Hostnames in the Site URL other than the hostname in the baseURL.
|
||||
* If you want to accept multiple Hostnames, set this.
|
||||
*
|
||||
* E.g.,
|
||||
* When your site URL ($baseURL) is 'http://example.com/', and your site
|
||||
* also accepts 'http://media.example.com/' and 'http://accounts.example.com/':
|
||||
* ['media.example.com', 'accounts.example.com']
|
||||
*
|
||||
* @var list<string>
|
||||
*/
|
||||
@@ -125,7 +117,7 @@ class App extends BaseConfig
|
||||
| DO NOT CHANGE THIS UNLESS YOU FULLY UNDERSTAND THE REPERCUSSIONS!!
|
||||
|
|
||||
*/
|
||||
public string $permittedURIChars = 'a-z 0-9~%.:_\-=';
|
||||
public string $permittedURIChars = 'a-z 0-9~%.:_\-';
|
||||
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
@@ -286,12 +278,12 @@ class App extends BaseConfig
|
||||
* @see http://www.html5rocks.com/en/tutorials/security/content-security-policy/
|
||||
* @see http://www.w3.org/TR/CSP/
|
||||
*/
|
||||
public bool $CSPEnabled = false; // TODO: Currently CSP3 tags are not supported so enabling this causes problems with script-src-elem, style-src-attr and style-src-elem
|
||||
public bool $CSPEnabled = false;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
|
||||
// Solution for CodeIgniter 4 limitation: arrays cannot be set from .env
|
||||
// See: https://github.com/codeigniter4/CodeIgniter4/issues/7311
|
||||
$envAllowedHostnames = getenv('app.allowedHostnames');
|
||||
@@ -301,9 +293,9 @@ class App extends BaseConfig
|
||||
static fn (string $hostname): bool => $hostname !== ''
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
$this->https_on = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') || (isset($_ENV['FORCE_HTTPS']) && $_ENV['FORCE_HTTPS'] == 'true');
|
||||
|
||||
|
||||
$host = $this->getValidHost();
|
||||
$this->baseURL = $this->https_on ? 'https' : 'http';
|
||||
$this->baseURL .= '://' . $host . '/';
|
||||
@@ -312,39 +304,39 @@ class App extends BaseConfig
|
||||
|
||||
/**
|
||||
* Validates and returns a trusted hostname.
|
||||
*
|
||||
*
|
||||
* Security: Prevents Host Header Injection attacks (GHSA-jchf-7hr6-h4f3)
|
||||
* by validating the HTTP_HOST against a whitelist of allowed hostnames.
|
||||
*
|
||||
*
|
||||
* In production: Fails fast if allowedHostnames is not configured.
|
||||
* In development: Allows localhost fallback with an error log.
|
||||
*
|
||||
*
|
||||
* @return string A validated hostname
|
||||
* @throws \RuntimeException If allowedHostnames is not configured in production
|
||||
*/
|
||||
private function getValidHost(): string
|
||||
{
|
||||
$httpHost = $_SERVER['HTTP_HOST'] ?? 'localhost';
|
||||
|
||||
|
||||
// Determine environment
|
||||
// CodeIgniter's test bootstrap sets $_SERVER['CI_ENVIRONMENT'] = 'testing'
|
||||
// Check $_SERVER first, then $_ENV, then fall back to 'production'
|
||||
$environment = $_SERVER['CI_ENVIRONMENT'] ?? $_ENV['CI_ENVIRONMENT'] ?? getenv('CI_ENVIRONMENT') ?: 'production';
|
||||
|
||||
if (empty($this->allowedHostnames)) {
|
||||
$errorMessage =
|
||||
$errorMessage =
|
||||
'Security: allowedHostnames is not configured. ' .
|
||||
'Host header injection protection is disabled. ' .
|
||||
'Set app.allowedHostnames in your .env file. ' .
|
||||
'Example: app.allowedHostnames = "example.com,www.example.com" ' .
|
||||
'Received Host: ' . $httpHost;
|
||||
|
||||
|
||||
// Production: Fail explicitly to prevent silent security vulnerabilities
|
||||
// Testing and development: Allow localhost fallback
|
||||
if ($environment === 'production') {
|
||||
throw new \RuntimeException($errorMessage);
|
||||
}
|
||||
|
||||
|
||||
log_message('error', $errorMessage . ' Using localhost fallback (development only).');
|
||||
return 'localhost';
|
||||
}
|
||||
@@ -354,7 +346,7 @@ class App extends BaseConfig
|
||||
}
|
||||
|
||||
// Host not in whitelist - use first configured hostname as fallback
|
||||
log_message('warning',
|
||||
log_message('warning',
|
||||
'Security: Rejected HTTP_HOST "' . $httpHost . '" - not in allowedHostnames whitelist. ' .
|
||||
'Using fallback: ' . $this->allowedHostnames[0]
|
||||
);
|
||||
|
||||
@@ -17,8 +17,6 @@ use CodeIgniter\Config\AutoloadConfig;
|
||||
*
|
||||
* NOTE: This class is required prior to Autoloader instantiation,
|
||||
* and does not extend BaseConfig.
|
||||
*
|
||||
* @immutable
|
||||
*/
|
||||
class Autoload extends AutoloadConfig
|
||||
{
|
||||
|
||||
@@ -1,23 +1,38 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* The environment testing is reserved for PHPUnit testing. It has special
|
||||
* conditions built into the framework at various places to assist with that.
|
||||
* You can’t use it for your development.
|
||||
*/
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| ERROR DISPLAY
|
||||
| ERROR DISPLAY
|
||||
|--------------------------------------------------------------------------
|
||||
*/
|
||||
| In development, we want to show as many errors as possible to help
|
||||
| make sure they don't make it to production. And save us hours of
|
||||
| painful debugging.
|
||||
*/
|
||||
error_reporting(E_ALL);
|
||||
ini_set('display_errors', '1');
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| DEBUG BACKTRACES
|
||||
| DEBUG BACKTRACES
|
||||
|--------------------------------------------------------------------------
|
||||
*/
|
||||
| If true, this constant will tell the error screens to display debug
|
||||
| backtraces along with the other error information. If you would
|
||||
| prefer to not see this, set this value to false.
|
||||
*/
|
||||
defined('SHOW_DEBUG_BACKTRACE') || define('SHOW_DEBUG_BACKTRACE', true);
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| DEBUG MODE
|
||||
| DEBUG MODE
|
||||
|--------------------------------------------------------------------------
|
||||
*/
|
||||
defined('CI_DEBUG') || define('CI_DEBUG', true);
|
||||
| Debug mode is an experimental flag that can allow changes throughout
|
||||
| the system. It's not widely used currently, and may not survive
|
||||
| release of the framework.
|
||||
*/
|
||||
defined('CI_DEBUG') || define('CI_DEBUG', true);
|
||||
|
||||
@@ -6,6 +6,22 @@ use CodeIgniter\Config\BaseConfig;
|
||||
|
||||
class CURLRequest extends BaseConfig
|
||||
{
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* CURLRequest Share Connection Options
|
||||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* Share connection options between requests.
|
||||
*
|
||||
* @var list<int>
|
||||
*
|
||||
* @see https://www.php.net/manual/en/curl.constants.php#constant.curl-lock-data-connect
|
||||
*/
|
||||
public array $shareConnectionOptions = [
|
||||
CURL_LOCK_DATA_CONNECT,
|
||||
CURL_LOCK_DATA_DNS,
|
||||
];
|
||||
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* CURLRequest Share Options
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
namespace Config;
|
||||
|
||||
use CodeIgniter\Cache\CacheInterface;
|
||||
use CodeIgniter\Cache\Handlers\ApcuHandler;
|
||||
use CodeIgniter\Cache\Handlers\DummyHandler;
|
||||
use CodeIgniter\Cache\Handlers\FileHandler;
|
||||
use CodeIgniter\Cache\Handlers\MemcachedHandler;
|
||||
@@ -78,7 +79,7 @@ class Cache extends BaseConfig
|
||||
* Your file storage preferences can be specified below, if you are using
|
||||
* the File driver.
|
||||
*
|
||||
* @var array<string, int|string|null>
|
||||
* @var array{storePath?: string, mode?: int}
|
||||
*/
|
||||
public array $file = [
|
||||
'storePath' => WRITEPATH . 'cache/',
|
||||
@@ -95,7 +96,7 @@ class Cache extends BaseConfig
|
||||
*
|
||||
* @see https://codeigniter.com/user_guide/libraries/caching.html#memcached
|
||||
*
|
||||
* @var array<string, bool|int|string>
|
||||
* @var array{host?: string, port?: int, weight?: int, raw?: bool}
|
||||
*/
|
||||
public array $memcached = [
|
||||
'host' => '127.0.0.1',
|
||||
@@ -108,17 +109,28 @@ class Cache extends BaseConfig
|
||||
* -------------------------------------------------------------------------
|
||||
* Redis settings
|
||||
* -------------------------------------------------------------------------
|
||||
*
|
||||
* Your Redis server can be specified below, if you are using
|
||||
* the Redis or Predis drivers.
|
||||
*
|
||||
* @var array<string, int|string|null>
|
||||
* @var array{
|
||||
* host?: string,
|
||||
* password?: string|null,
|
||||
* port?: int,
|
||||
* timeout?: int,
|
||||
* async?: bool,
|
||||
* persistent?: bool,
|
||||
* database?: int
|
||||
* }
|
||||
*/
|
||||
public array $redis = [
|
||||
'host' => '127.0.0.1',
|
||||
'password' => null,
|
||||
'port' => 6379,
|
||||
'timeout' => 0,
|
||||
'database' => 0,
|
||||
'host' => '127.0.0.1',
|
||||
'password' => null,
|
||||
'port' => 6379,
|
||||
'timeout' => 0,
|
||||
'async' => false, // specific to Predis and ignored by the native Redis extension
|
||||
'persistent' => false,
|
||||
'database' => 0,
|
||||
];
|
||||
|
||||
/**
|
||||
@@ -132,6 +144,7 @@ class Cache extends BaseConfig
|
||||
* @var array<string, class-string<CacheInterface>>
|
||||
*/
|
||||
public array $validHandlers = [
|
||||
'apcu' => ApcuHandler::class,
|
||||
'dummy' => DummyHandler::class,
|
||||
'file' => FileHandler::class,
|
||||
'memcached' => MemcachedHandler::class,
|
||||
@@ -158,4 +171,28 @@ class Cache extends BaseConfig
|
||||
* @var bool|list<string>
|
||||
*/
|
||||
public $cacheQueryString = false;
|
||||
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* Web Page Caching: Cache Status Codes
|
||||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* HTTP status codes that are allowed to be cached. Only responses with
|
||||
* these status codes will be cached by the PageCache filter.
|
||||
*
|
||||
* Default: [] - Cache all status codes (backward compatible)
|
||||
*
|
||||
* Recommended: [200] - Only cache successful responses
|
||||
*
|
||||
* You can also use status codes like:
|
||||
* [200, 404, 410] - Cache successful responses and specific error codes
|
||||
* [200, 201, 202, 203, 204] - All 2xx successful responses
|
||||
*
|
||||
* WARNING: Using [] may cache temporary error pages (404, 500, etc).
|
||||
* Consider restricting to [200] for production applications to avoid
|
||||
* caching errors that should be temporary.
|
||||
*
|
||||
* @var list<int>
|
||||
*/
|
||||
public array $cacheStatusCodes = [];
|
||||
}
|
||||
|
||||
@@ -30,6 +30,11 @@ class ContentSecurityPolicy extends BaseConfig
|
||||
*/
|
||||
public ?string $reportURI = null;
|
||||
|
||||
/**
|
||||
* Specifies a reporting endpoint to which violation reports ought to be sent.
|
||||
*/
|
||||
public ?string $reportTo = null;
|
||||
|
||||
/**
|
||||
* Instructs user agents to rewrite URL schemes, changing
|
||||
* HTTP to HTTPS. This directive is for websites with
|
||||
@@ -38,12 +43,12 @@ class ContentSecurityPolicy extends BaseConfig
|
||||
public bool $upgradeInsecureRequests = false;
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Sources allowed
|
||||
// CSP DIRECTIVES SETTINGS
|
||||
// NOTE: once you set a policy to 'none', it cannot be further restricted
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Will default to self if not overridden
|
||||
* Will default to `'self'` if not overridden
|
||||
*
|
||||
* @var list<string>|string|null
|
||||
*/
|
||||
@@ -64,6 +69,21 @@ class ContentSecurityPolicy extends BaseConfig
|
||||
'www.google.com www.gstatic.com'
|
||||
];
|
||||
|
||||
/**
|
||||
* Specifies valid sources for JavaScript <script> elements.
|
||||
*
|
||||
* @var list<string>|string
|
||||
*/
|
||||
public array|string $scriptSrcElem = 'self';
|
||||
|
||||
/**
|
||||
* Specifies valid sources for JavaScript inline event
|
||||
* handlers and JavaScript URLs.
|
||||
*
|
||||
* @var list<string>|string
|
||||
*/
|
||||
public array|string $scriptSrcAttr = 'self';
|
||||
|
||||
/**
|
||||
* Lists allowed stylesheets' URLs.
|
||||
*
|
||||
@@ -76,6 +96,21 @@ class ContentSecurityPolicy extends BaseConfig
|
||||
'https://fonts.googleapis.com',
|
||||
];
|
||||
|
||||
/**
|
||||
* Specifies valid sources for stylesheets <link> elements.
|
||||
*
|
||||
* @var list<string>|string
|
||||
*/
|
||||
public array|string $styleSrcElem = 'self';
|
||||
|
||||
/**
|
||||
* Specifies valid sources for stylesheets inline
|
||||
* style attributes and `<style>` elements.
|
||||
*
|
||||
* @var list<string>|string
|
||||
*/
|
||||
public array|string $styleSrcAttr = 'self';
|
||||
|
||||
/**
|
||||
* Defines the origins from which images can be loaded.
|
||||
*
|
||||
@@ -169,6 +204,11 @@ class ContentSecurityPolicy extends BaseConfig
|
||||
*/
|
||||
public $manifestSrc;
|
||||
|
||||
/**
|
||||
* @var list<string>|string
|
||||
*/
|
||||
public array|string $workerSrc = [];
|
||||
|
||||
/**
|
||||
* Limits the kinds of plugins a page may invoke.
|
||||
*
|
||||
@@ -184,17 +224,17 @@ class ContentSecurityPolicy extends BaseConfig
|
||||
public $sandbox;
|
||||
|
||||
/**
|
||||
* Nonce tag for style
|
||||
* Nonce placeholder for style tags.
|
||||
*/
|
||||
public string $styleNonceTag = '{csp-style-nonce}';
|
||||
|
||||
/**
|
||||
* Nonce tag for script
|
||||
* Nonce placeholder for script tags.
|
||||
*/
|
||||
public string $scriptNonceTag = '{csp-script-nonce}';
|
||||
|
||||
/**
|
||||
* Replace nonce tag automatically
|
||||
* Replace nonce tag automatically?
|
||||
*/
|
||||
public bool $autoNonce = true;
|
||||
}
|
||||
|
||||
@@ -85,7 +85,7 @@ class Cookie extends BaseConfig
|
||||
* (empty string) means default SameSite attribute set by browsers (`Lax`)
|
||||
* will be set on cookies. If set to `None`, `$secure` must also be set.
|
||||
*
|
||||
* @phpstan-var 'None'|'Lax'|'Strict'|''
|
||||
* @var ''|'Lax'|'None'|'Strict'
|
||||
*/
|
||||
public string $samesite = 'Lax';
|
||||
|
||||
|
||||
@@ -42,6 +42,8 @@ class Database extends Config
|
||||
'strictOn' => false,
|
||||
'failover' => [],
|
||||
'port' => 3306,
|
||||
'numberNative' => false,
|
||||
'foundRows' => false,
|
||||
'dateFormat' => [
|
||||
'date' => 'Y-m-d',
|
||||
'datetime' => 'Y-m-d H:i:s',
|
||||
@@ -55,26 +57,27 @@ class Database extends Config
|
||||
* @var array<string, mixed>
|
||||
*/
|
||||
public array $tests = [
|
||||
'DSN' => '',
|
||||
'hostname' => 'localhost',
|
||||
'username' => 'admin',
|
||||
'password' => 'pointofsale',
|
||||
'database' => 'ospos',
|
||||
'DBDriver' => 'MySQLi',
|
||||
'DBPrefix' => 'ospos_',
|
||||
'pConnect' => false,
|
||||
'DBDebug' => (ENVIRONMENT !== 'production'),
|
||||
'charset' => 'utf8mb4',
|
||||
'DBCollat' => 'utf8mb4_general_ci',
|
||||
'swapPre' => '',
|
||||
'encrypt' => false,
|
||||
'compress' => false,
|
||||
'strictOn' => false,
|
||||
'failover' => [],
|
||||
'port' => 3306,
|
||||
'foreignKeys' => true,
|
||||
'busyTimeout' => 1000,
|
||||
'dateFormat' => [
|
||||
'DSN' => '',
|
||||
'hostname' => 'localhost',
|
||||
'username' => 'admin',
|
||||
'password' => 'pointofsale',
|
||||
'database' => 'ospos',
|
||||
'DBDriver' => 'MySQLi',
|
||||
'DBPrefix' => 'ospos_',
|
||||
'pConnect' => false,
|
||||
'DBDebug' => (ENVIRONMENT !== 'production'),
|
||||
'charset' => 'utf8mb4',
|
||||
'DBCollat' => 'utf8mb4_general_ci',
|
||||
'swapPre' => '',
|
||||
'encrypt' => false,
|
||||
'compress' => false,
|
||||
'strictOn' => false,
|
||||
'failover' => [],
|
||||
'port' => 3306,
|
||||
'foreignKeys' => true,
|
||||
'busyTimeout' => 1000,
|
||||
'synchronous' => null,
|
||||
'dateFormat' => [
|
||||
'date' => 'Y-m-d',
|
||||
'datetime' => 'Y-m-d H:i:s',
|
||||
'time' => 'H:i:s',
|
||||
|
||||
@@ -2,9 +2,6 @@
|
||||
|
||||
namespace Config;
|
||||
|
||||
/**
|
||||
* @immutable
|
||||
*/
|
||||
class DocTypes
|
||||
{
|
||||
/**
|
||||
|
||||
@@ -30,6 +30,11 @@ class Email extends BaseConfig
|
||||
*/
|
||||
public string $SMTPHost = 'mail.mxserver.com';
|
||||
|
||||
/**
|
||||
* Which SMTP authentication method to use: login, plain
|
||||
*/
|
||||
public string $SMTPAuthMethod = 'login';
|
||||
|
||||
/**
|
||||
* SMTP Username
|
||||
*/
|
||||
|
||||
@@ -23,6 +23,23 @@ class Encryption extends BaseConfig
|
||||
*/
|
||||
public string $key = '';
|
||||
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* Previous Encryption Keys
|
||||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* When rotating encryption keys, add old keys here to maintain ability
|
||||
* to decrypt data encrypted with previous keys. Encryption always uses
|
||||
* the current $key. Decryption tries current key first, then falls back
|
||||
* to previous keys if decryption fails.
|
||||
*
|
||||
* In .env file, use comma-separated string:
|
||||
* encryption.previousKeys = hex2bin:9be8c64fcea509867...,hex2bin:3f5a1d8e9c2b7a4f6...
|
||||
*
|
||||
* @var list<string>|string
|
||||
*/
|
||||
public array|string $previousKeys = '';
|
||||
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* Encryption Driver to Use
|
||||
|
||||
@@ -65,7 +65,10 @@ class Filters extends BaseFilters
|
||||
* List of filter aliases that are always
|
||||
* applied before and after every request.
|
||||
*
|
||||
* @var array<string, array<string, array<string, string>>>|array<string, list<string>>
|
||||
* @var array{
|
||||
* before: array<string, array{except: list<string>|string}>|list<string>,
|
||||
* after: array<string, array{except: list<string>|string}>|list<string>
|
||||
* }
|
||||
*/
|
||||
public array $globals = [
|
||||
'before' => [
|
||||
@@ -100,7 +103,7 @@ class Filters extends BaseFilters
|
||||
* before or after URI patterns.
|
||||
*
|
||||
* Example:
|
||||
* isLoggedIn' => ['before' => ['account/*', 'profiles/*']]
|
||||
* 'isLoggedIn' => ['before' => ['account/*', 'profiles/*']]
|
||||
*
|
||||
* @var array<string, array<string, list<string>>>
|
||||
*/
|
||||
|
||||
@@ -61,4 +61,13 @@ class Format extends BaseConfig
|
||||
'application/xml' => 0,
|
||||
'text/xml' => 0,
|
||||
];
|
||||
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* Maximum depth for JSON encoding.
|
||||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* This value determines how deep the JSON encoder will traverse nested structures.
|
||||
*/
|
||||
public int $jsonEncodeDepth = 512;
|
||||
}
|
||||
|
||||
40
app/Config/Hostnames.php
Normal file
40
app/Config/Hostnames.php
Normal file
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
namespace Config;
|
||||
|
||||
class Hostnames
|
||||
{
|
||||
// List of known two-part TLDs for subdomain extraction
|
||||
public const TWO_PART_TLDS = [
|
||||
'co.uk', 'org.uk', 'gov.uk', 'ac.uk', 'sch.uk', 'ltd.uk', 'plc.uk',
|
||||
'com.au', 'net.au', 'org.au', 'edu.au', 'gov.au', 'asn.au', 'id.au',
|
||||
'co.jp', 'ac.jp', 'go.jp', 'or.jp', 'ne.jp', 'gr.jp',
|
||||
'co.nz', 'org.nz', 'govt.nz', 'ac.nz', 'net.nz', 'geek.nz', 'maori.nz', 'school.nz',
|
||||
'co.in', 'net.in', 'org.in', 'ind.in', 'ac.in', 'gov.in', 'res.in',
|
||||
'com.cn', 'net.cn', 'org.cn', 'gov.cn', 'edu.cn',
|
||||
'com.sg', 'net.sg', 'org.sg', 'gov.sg', 'edu.sg', 'per.sg',
|
||||
'co.za', 'org.za', 'gov.za', 'ac.za', 'net.za',
|
||||
'co.kr', 'or.kr', 'go.kr', 'ac.kr', 'ne.kr', 'pe.kr',
|
||||
'co.th', 'or.th', 'go.th', 'ac.th', 'net.th', 'in.th',
|
||||
'com.my', 'net.my', 'org.my', 'edu.my', 'gov.my', 'mil.my', 'name.my',
|
||||
'com.mx', 'org.mx', 'net.mx', 'edu.mx', 'gob.mx',
|
||||
'com.br', 'net.br', 'org.br', 'gov.br', 'edu.br', 'art.br', 'eng.br',
|
||||
'co.il', 'org.il', 'ac.il', 'gov.il', 'net.il', 'muni.il',
|
||||
'co.id', 'or.id', 'ac.id', 'go.id', 'net.id', 'web.id', 'my.id',
|
||||
'com.hk', 'edu.hk', 'gov.hk', 'idv.hk', 'net.hk', 'org.hk',
|
||||
'com.tw', 'net.tw', 'org.tw', 'edu.tw', 'gov.tw', 'idv.tw',
|
||||
'com.sa', 'net.sa', 'org.sa', 'gov.sa', 'edu.sa', 'sch.sa', 'med.sa',
|
||||
'co.ae', 'net.ae', 'org.ae', 'gov.ae', 'ac.ae', 'sch.ae',
|
||||
'com.tr', 'net.tr', 'org.tr', 'gov.tr', 'edu.tr', 'av.tr', 'gen.tr',
|
||||
'co.ke', 'or.ke', 'go.ke', 'ac.ke', 'sc.ke', 'me.ke', 'mobi.ke', 'info.ke',
|
||||
'com.ng', 'org.ng', 'gov.ng', 'edu.ng', 'net.ng', 'sch.ng', 'name.ng',
|
||||
'com.pk', 'net.pk', 'org.pk', 'gov.pk', 'edu.pk', 'fam.pk',
|
||||
'com.eg', 'edu.eg', 'gov.eg', 'org.eg', 'net.eg',
|
||||
'com.cy', 'net.cy', 'org.cy', 'gov.cy', 'ac.cy',
|
||||
'com.lk', 'org.lk', 'edu.lk', 'gov.lk', 'net.lk', 'int.lk',
|
||||
'com.bd', 'net.bd', 'org.bd', 'ac.bd', 'gov.bd', 'mil.bd',
|
||||
'com.ar', 'net.ar', 'org.ar', 'gov.ar', 'edu.ar', 'mil.ar',
|
||||
'gob.cl', 'com.pl', 'net.pl', 'org.pl', 'gov.pl', 'edu.pl',
|
||||
'co.ir', 'ac.ir', 'org.ir', 'id.ir', 'gov.ir', 'sch.ir', 'net.ir',
|
||||
];
|
||||
}
|
||||
@@ -16,6 +16,8 @@ class Images extends BaseConfig
|
||||
/**
|
||||
* The path to the image library.
|
||||
* Required for ImageMagick, GraphicsMagick, or NetPBM.
|
||||
*
|
||||
* @deprecated 4.7.0 No longer used.
|
||||
*/
|
||||
public string $libraryPath = '/usr/local/bin/convert';
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ namespace Config;
|
||||
|
||||
use CodeIgniter\Config\BaseConfig;
|
||||
use CodeIgniter\Log\Handlers\FileHandler;
|
||||
use CodeIgniter\Log\Handlers\HandlerInterface;
|
||||
|
||||
class Logger extends BaseConfig
|
||||
{
|
||||
@@ -73,7 +74,7 @@ class Logger extends BaseConfig
|
||||
* Handlers are executed in the order defined in this array, starting with
|
||||
* the handler on top and continuing down.
|
||||
*
|
||||
* @var array<class-string, array<string, int|list<string>|string>>
|
||||
* @var array<class-string<HandlerInterface>, array<string, int|list<string>|string>>
|
||||
*/
|
||||
public array $handlers = [
|
||||
/*
|
||||
|
||||
@@ -47,4 +47,19 @@ class Migrations extends BaseConfig
|
||||
* - Y_m_d_His_
|
||||
*/
|
||||
public string $timestampFormat = 'YmdHis_';
|
||||
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* Enable/Disable Migration Lock
|
||||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* Locking is disabled by default.
|
||||
*
|
||||
* When enabled, it will prevent multiple migration processes
|
||||
* from running at the same time by using a lock mechanism.
|
||||
*
|
||||
* This is useful in production environments to avoid conflicts
|
||||
* or race conditions during concurrent deployments.
|
||||
*/
|
||||
public bool $lock = false;
|
||||
}
|
||||
|
||||
@@ -3,8 +3,6 @@
|
||||
namespace Config;
|
||||
|
||||
/**
|
||||
* Mimes
|
||||
*
|
||||
* This file contains an array of mime types. It is used by the
|
||||
* Upload class to help identify allowed file types.
|
||||
*
|
||||
@@ -15,8 +13,6 @@ namespace Config;
|
||||
*
|
||||
* When working with mime types, please make sure you have the ´fileinfo´
|
||||
* extension enabled to reliably detect the media types.
|
||||
*
|
||||
* @immutable
|
||||
*/
|
||||
class Mimes
|
||||
{
|
||||
@@ -482,13 +478,16 @@ class Mimes
|
||||
'application/sla',
|
||||
'application/vnd.ms-pki.stl',
|
||||
'application/x-navistyle',
|
||||
'model/stl',
|
||||
'application/octet-stream',
|
||||
],
|
||||
];
|
||||
|
||||
/**
|
||||
* Attempts to determine the best mime type for the given file extension.
|
||||
*
|
||||
* @return string|null The mime type found, or none if unable to determine.
|
||||
* @param string $extension
|
||||
* @return array|string|null The mime type found, or none if unable to determine.
|
||||
*/
|
||||
public static function guessTypeFromExtension(string $extension): array|string|null
|
||||
{
|
||||
@@ -524,7 +523,7 @@ class Mimes
|
||||
}
|
||||
|
||||
// Reverse check the mime type list if no extension was proposed.
|
||||
// This search is order sensitive!
|
||||
// This search is order-sensitive!
|
||||
foreach (static::$mimes as $ext => $types) {
|
||||
if (in_array($type, (array) $types, true)) {
|
||||
return $ext;
|
||||
|
||||
@@ -9,8 +9,6 @@ use CodeIgniter\Modules\Modules as BaseModules;
|
||||
*
|
||||
* NOTE: This class is required prior to Autoloader instantiation,
|
||||
* and does not extend BaseConfig.
|
||||
*
|
||||
* @immutable
|
||||
*/
|
||||
class Modules extends BaseModules
|
||||
{
|
||||
|
||||
@@ -8,7 +8,7 @@ namespace Config;
|
||||
* NOTE: This class does not extend BaseConfig for performance reasons.
|
||||
* So you cannot replace the property values with Environment Variables.
|
||||
*
|
||||
* @immutable
|
||||
* WARNING: Do not use these options when running the app in the Worker Mode.
|
||||
*/
|
||||
class Optimize
|
||||
{
|
||||
|
||||
@@ -15,8 +15,6 @@ namespace Config;
|
||||
*
|
||||
* NOTE: This class is required prior to Autoloader instantiation,
|
||||
* and does not extend BaseConfig.
|
||||
*
|
||||
* @immutable
|
||||
*/
|
||||
class Paths
|
||||
{
|
||||
@@ -77,4 +75,16 @@ class Paths
|
||||
* is used when no value is provided to `Services::renderer()`.
|
||||
*/
|
||||
public string $viewDirectory = __DIR__ . '/../Views';
|
||||
|
||||
/**
|
||||
* ---------------------------------------------------------------
|
||||
* ENVIRONMENT DIRECTORY NAME
|
||||
* ---------------------------------------------------------------
|
||||
*
|
||||
* This variable must contain the name of the directory where
|
||||
* the .env file is located.
|
||||
* Please consider security implications when changing this
|
||||
* value - the directory should not be publicly accessible.
|
||||
*/
|
||||
public string $envDirectory = __DIR__ . '/../../';
|
||||
}
|
||||
|
||||
@@ -96,6 +96,15 @@ class Routing extends BaseRouting
|
||||
*/
|
||||
public bool $autoRoute = true;
|
||||
|
||||
/**
|
||||
* If TRUE, the system will look for attributes on controller
|
||||
* class and methods that can run before and after the
|
||||
* controller/method.
|
||||
*
|
||||
* If FALSE, will ignore any attributes.
|
||||
*/
|
||||
public bool $useControllerAttributes = true;
|
||||
|
||||
/**
|
||||
* For Defined Routes.
|
||||
* If TRUE, will enable the use of the 'prioritize' option
|
||||
|
||||
@@ -13,9 +13,9 @@ class Security extends BaseConfig
|
||||
*
|
||||
* Protection Method for Cross Site Request Forgery protection.
|
||||
*
|
||||
* @var string|false 'cookie', 'session', or false
|
||||
* @var string 'cookie' or 'session'
|
||||
*/
|
||||
public string|false $csrfProtection = 'session';
|
||||
public string $csrfProtection = 'session';
|
||||
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace Config;
|
||||
|
||||
use App\Libraries\MY_Language;
|
||||
use Locale;
|
||||
use HTMLPurifier;
|
||||
use HTMLPurifier_Config;
|
||||
@@ -38,9 +39,11 @@ class Services extends BaseService
|
||||
/**
|
||||
* Responsible for loading the language string translations.
|
||||
*
|
||||
* @param string|null $locale
|
||||
* @param bool $getShared
|
||||
* @return MY_Language
|
||||
*/
|
||||
public static function language(?string $locale = null, bool $getShared = true)
|
||||
public static function language(?string $locale = null, bool $getShared = true): MY_Language
|
||||
{
|
||||
if ($getShared) {
|
||||
return static::getSharedInstance('language', $locale)->setLocale($locale);
|
||||
@@ -55,12 +58,12 @@ class Services extends BaseService
|
||||
// Use '?:' for empty string check
|
||||
$locale = $locale ?: $requestLocale;
|
||||
|
||||
return new \App\Libraries\MY_Language($locale);
|
||||
return new MY_Language($locale);
|
||||
}
|
||||
|
||||
private static $htmlPurifier;
|
||||
private static HTMLPurifier $htmlPurifier;
|
||||
|
||||
public static function htmlPurifier($getShared = true)
|
||||
public static function htmlPurifier($getShared = true): object
|
||||
{
|
||||
if ($getShared) {
|
||||
return static::getSharedInstance('htmlPurifier');
|
||||
|
||||
@@ -3,10 +3,10 @@
|
||||
namespace Config;
|
||||
|
||||
use CodeIgniter\Config\BaseConfig;
|
||||
use CodeIgniter\Database\Exceptions\DatabaseException;
|
||||
use CodeIgniter\Session\Handlers\BaseHandler;
|
||||
use CodeIgniter\Session\Handlers\DatabaseHandler;
|
||||
use CodeIgniter\Session\Handlers\FileHandler;
|
||||
use Config\Database;
|
||||
|
||||
class Session extends BaseConfig
|
||||
{
|
||||
@@ -139,7 +139,7 @@ class Session extends BaseConfig
|
||||
$this->driver = FileHandler::class;
|
||||
$this->savePath = WRITEPATH . 'session';
|
||||
}
|
||||
} catch (\CodeIgniter\Database\Exceptions\DatabaseException $e) {
|
||||
} catch (DatabaseException $e) {
|
||||
$this->driver = FileHandler::class;
|
||||
$this->savePath = WRITEPATH . 'session';
|
||||
}
|
||||
|
||||
@@ -119,4 +119,29 @@ class Toolbar extends BaseConfig
|
||||
public array $watchedExtensions = [
|
||||
'php', 'css', 'js', 'html', 'svg', 'json', 'env',
|
||||
];
|
||||
|
||||
/**
|
||||
* --------------------------------------------------------------------------
|
||||
* Ignored HTTP Headers
|
||||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* CodeIgniter Debug Toolbar normally injects HTML and JavaScript into every
|
||||
* HTML response. This is correct for full page loads, but it breaks requests
|
||||
* that expect only a clean HTML fragment.
|
||||
*
|
||||
* Libraries like HTMX, Unpoly, and Hotwire (Turbo) update parts of the page or
|
||||
* manage navigation on the client side. Injecting the Debug Toolbar into their
|
||||
* responses can cause invalid HTML, duplicated scripts, or JavaScript errors
|
||||
* (such as infinite loops or "Maximum call stack size exceeded").
|
||||
*
|
||||
* Any request containing one of the following headers is treated as a
|
||||
* client-managed or partial request, and the Debug Toolbar injection is skipped.
|
||||
*
|
||||
* @var array<string, string|null>
|
||||
*/
|
||||
public array $disableOnHeaders = [
|
||||
'X-Requested-With' => 'xmlhttprequest', // AJAX requests
|
||||
'HX-Request' => 'true', // HTMX requests
|
||||
'X-Up-Version' => null, // Unpoly partial requests
|
||||
];
|
||||
}
|
||||
|
||||
@@ -230,9 +230,13 @@ class UserAgents extends BaseConfig
|
||||
*/
|
||||
public array $robots = [
|
||||
'googlebot' => 'Googlebot',
|
||||
'google-pagerenderer' => 'Google Page Renderer',
|
||||
'google-read-aloud' => 'Google Read Aloud',
|
||||
'google-safety' => 'Google Safety Bot',
|
||||
'msnbot' => 'MSNBot',
|
||||
'baiduspider' => 'Baiduspider',
|
||||
'bingbot' => 'Bing',
|
||||
'bingpreview' => 'BingPreview',
|
||||
'slurp' => 'Inktomi Slurp',
|
||||
'yahoo' => 'Yahoo',
|
||||
'ask jeeves' => 'Ask Jeeves',
|
||||
@@ -248,5 +252,11 @@ class UserAgents extends BaseConfig
|
||||
'ia_archiver' => 'Alexa Crawler',
|
||||
'MJ12bot' => 'Majestic-12',
|
||||
'Uptimebot' => 'Uptimebot',
|
||||
'duckduckbot' => 'DuckDuckBot',
|
||||
'sogou' => 'Sogou Spider',
|
||||
'exabot' => 'Exabot',
|
||||
'bot' => 'Generic Bot',
|
||||
'crawler' => 'Generic Crawler',
|
||||
'spider' => 'Generic Spider',
|
||||
];
|
||||
}
|
||||
|
||||
@@ -59,4 +59,21 @@ class View extends BaseView
|
||||
* @var list<class-string<ViewDecoratorInterface>>
|
||||
*/
|
||||
public array $decorators = [];
|
||||
|
||||
/**
|
||||
* Subdirectory within app/Views for namespaced view overrides.
|
||||
*
|
||||
* Namespaced views will be searched in:
|
||||
*
|
||||
* app/Views/{$appOverridesFolder}/{Namespace}/{view_path}.{php|html...}
|
||||
*
|
||||
* This allows application-level overrides for package or module views
|
||||
* without modifying vendor source files.
|
||||
*
|
||||
* Examples:
|
||||
* 'overrides' -> app/Views/overrides/Example/Blog/post/card.php
|
||||
* 'vendor' -> app/Views/vendor/Example/Blog/post/card.php
|
||||
* '' -> app/Views/Example/Blog/post/card.php (direct mapping)
|
||||
*/
|
||||
public string $appOverridesFolder = 'overrides';
|
||||
}
|
||||
|
||||
62
app/Config/WorkerMode.php
Normal file
62
app/Config/WorkerMode.php
Normal file
@@ -0,0 +1,62 @@
|
||||
<?php
|
||||
|
||||
namespace Config;
|
||||
|
||||
/**
|
||||
* This configuration controls how CodeIgniter behaves when running
|
||||
* in worker mode (with FrankenPHP).
|
||||
*/
|
||||
class WorkerMode
|
||||
{
|
||||
/**
|
||||
* Persistent Services
|
||||
*
|
||||
* List of service names that should persist across requests.
|
||||
* These services will NOT be reset between requests.
|
||||
*
|
||||
* Services not in this list will be reset for each request to prevent
|
||||
* state leakage.
|
||||
*
|
||||
* Recommended persistent services:
|
||||
* - `autoloader`: PSR-4 autoloading configuration
|
||||
* - `locator`: File locator
|
||||
* - `exceptions`: Exception handler
|
||||
* - `commands`: CLI commands registry
|
||||
* - `codeigniter`: Main application instance
|
||||
* - `superglobals`: Superglobals wrapper
|
||||
* - `routes`: Router configuration
|
||||
* - `cache`: Cache instance
|
||||
*
|
||||
* @var list<string>
|
||||
*/
|
||||
public array $persistentServices = [
|
||||
'autoloader',
|
||||
'locator',
|
||||
'exceptions',
|
||||
'commands',
|
||||
'codeigniter',
|
||||
'superglobals',
|
||||
'routes',
|
||||
'cache',
|
||||
];
|
||||
|
||||
/**
|
||||
* Reset Event Listeners
|
||||
*
|
||||
* List of event names whose listeners should be removed between requests.
|
||||
* Use this if you register event listeners inside other event callbacks
|
||||
* (rather than at the top level of Config/Events.php), which would cause
|
||||
* them to accumulate across requests in worker mode.
|
||||
*
|
||||
* @var list<string>
|
||||
*/
|
||||
public array $resetEventListeners = [];
|
||||
|
||||
/**
|
||||
* Force Garbage Collection
|
||||
*
|
||||
* Whether to force garbage collection after each request.
|
||||
* Helps prevent memory leaks at a small performance cost.
|
||||
*/
|
||||
public bool $forceGarbageCollection = true;
|
||||
}
|
||||
@@ -3,56 +3,46 @@
|
||||
namespace App\Controllers;
|
||||
|
||||
use CodeIgniter\Controller;
|
||||
use CodeIgniter\HTTP\CLIRequest;
|
||||
use CodeIgniter\HTTP\IncomingRequest;
|
||||
use CodeIgniter\HTTP\RequestInterface;
|
||||
use CodeIgniter\HTTP\ResponseInterface;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
/**
|
||||
* Class BaseController
|
||||
*
|
||||
* BaseController provides a convenient place for loading components
|
||||
* and performing functions that are needed by all your controllers.
|
||||
* Extend this class in any new controllers:
|
||||
* class Home extends BaseController
|
||||
*
|
||||
* For security be sure to declare any new methods as protected or private.
|
||||
* Extend this class in any new controllers:
|
||||
* ```
|
||||
* class Home extends BaseController
|
||||
* ```
|
||||
*
|
||||
* For security, be sure to declare any new methods as protected or private.
|
||||
*/
|
||||
abstract class BaseController extends Controller
|
||||
{
|
||||
/**
|
||||
* Instance of the main Request object.
|
||||
*
|
||||
* @var CLIRequest|IncomingRequest
|
||||
*/
|
||||
protected $request;
|
||||
|
||||
/**
|
||||
* An array of helpers to be loaded automatically upon
|
||||
* class instantiation. These helpers will be available
|
||||
* to all other controllers that extend BaseController.
|
||||
*
|
||||
* @var list<string>
|
||||
*/
|
||||
protected $helpers = [];
|
||||
|
||||
/**
|
||||
* Be sure to declare properties for any property fetch you initialized.
|
||||
* The creation of dynamic property is deprecated in PHP 8.2.
|
||||
*/
|
||||
|
||||
// protected $session;
|
||||
|
||||
/**
|
||||
* @param RequestInterface $request
|
||||
* @param ResponseInterface $response
|
||||
* @param LoggerInterface $logger
|
||||
* @return void
|
||||
*/
|
||||
public function initController(RequestInterface $request, ResponseInterface $response, LoggerInterface $logger)
|
||||
public function initController(RequestInterface $request, ResponseInterface $response, LoggerInterface $logger): void
|
||||
{
|
||||
// Do Not Edit This Line
|
||||
// Load here all helpers you want to be available in your controllers that extend BaseController.
|
||||
// Caution: Do not put the this below the parent::initController() call below.
|
||||
// $this->helpers = ['form', 'url'];
|
||||
|
||||
// Caution: Do not edit this line.
|
||||
parent::initController($request, $response, $logger);
|
||||
|
||||
// Preload any models, libraries, etc, here.
|
||||
|
||||
// E.g.: $this->session = service('session');
|
||||
// $this->session = service('session');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,12 +35,12 @@ class Home extends Secure_Controller
|
||||
}
|
||||
|
||||
/**
|
||||
* Load "change employee password" form
|
||||
* Load the "change employee password" form
|
||||
*
|
||||
* @param int $employeeId
|
||||
* @return ResponseInterface|string
|
||||
* @noinspection PhpUnused
|
||||
*/
|
||||
public function getChangePassword(int $employeeId = NEW_ENTRY)
|
||||
public function getChangePassword(int $employeeId = NEW_ENTRY): ResponseInterface|string
|
||||
{
|
||||
$loggedInEmployee = $this->employee->get_logged_in_employee_info();
|
||||
$currentPersonId = $loggedInEmployee->person_id;
|
||||
|
||||
@@ -190,11 +190,11 @@ class Receivings extends Secure_Controller
|
||||
/**
|
||||
* Edit line item in current receiving. Used in app/Views/receivings/receiving.php
|
||||
*
|
||||
* @param string|int|null $item_id
|
||||
* @param int|string|null $item_id
|
||||
* @return string
|
||||
* @noinspection PhpUnused
|
||||
*/
|
||||
public function postEditItem($item_id): string
|
||||
public function postEditItem(int|string|null $item_id): string
|
||||
{
|
||||
$data = [];
|
||||
|
||||
@@ -242,7 +242,7 @@ class Receivings extends Secure_Controller
|
||||
}
|
||||
|
||||
$receiving_info = $this->receiving->get_info($receiving_id)->getRowArray();
|
||||
|
||||
|
||||
$current_employee_id = $this->employee->get_logged_in_employee_info()->person_id;
|
||||
$can_assign_employee = $this->employee->has_grant('employees', $current_employee_id);
|
||||
|
||||
@@ -280,8 +280,10 @@ class Receivings extends Secure_Controller
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws ReflectionException
|
||||
* @param int $receiving_id
|
||||
* @param bool $update_inventory
|
||||
* @return ResponseInterface
|
||||
* @throws ReflectionException
|
||||
*/
|
||||
public function postDelete(int $receiving_id = -1, bool $update_inventory = true): ResponseInterface
|
||||
{
|
||||
|
||||
@@ -425,7 +425,7 @@ class Sales extends Secure_Controller
|
||||
$new_giftcard_value = $giftcard->get_giftcard_value($giftcard_num) - $this->sale_lib->get_amount_due();
|
||||
$new_giftcard_value = max($new_giftcard_value, 0);
|
||||
$this->sale_lib->set_giftcard_remainder($new_giftcard_value);
|
||||
$new_giftcard_value = str_replace('$', '\$', to_currency($new_giftcard_value));
|
||||
$new_giftcard_value = to_currency($new_giftcard_value);
|
||||
$data['warning'] = lang('Giftcards.remaining_balance', [$giftcard_num, $new_giftcard_value]);
|
||||
$amount_tendered = min($this->sale_lib->get_amount_due(), $giftcard->get_giftcard_value($giftcard_num));
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ use App\Models\Employee;
|
||||
use App\Models\Item_taxes;
|
||||
use App\Models\Tax_category;
|
||||
use CodeIgniter\Database\ResultInterface;
|
||||
use CodeIgniter\HTTP\IncomingRequest;
|
||||
use CodeIgniter\Session\Session;
|
||||
use Config\OSPOS;
|
||||
use Config\Services;
|
||||
@@ -577,8 +578,8 @@ function item_kit_headers(): array
|
||||
['item_kit_number' => lang('Item_kits.item_kit_number')],
|
||||
['name' => lang('Item_kits.name')],
|
||||
['description' => lang('Item_kits.description')],
|
||||
['total_cost_price' => lang('Items.cost_price'), 'sortable' => FALSE],
|
||||
['total_unit_price' => lang('Items.unit_price'), 'sortable' => FALSE]
|
||||
['total_cost_price' => lang('Items.cost_price'), 'sortable' => false],
|
||||
['total_unit_price' => lang('Items.unit_price'), 'sortable' => false]
|
||||
];
|
||||
}
|
||||
|
||||
@@ -654,7 +655,7 @@ function expand_attribute_values(array $definition_names, array $row): array
|
||||
foreach ($definition_names as $definition_id => $definitionInfo) {
|
||||
if (isset($indexed_values[$definition_id])) {
|
||||
$raw_value = $indexed_values[$definition_id];
|
||||
|
||||
|
||||
// Format DECIMAL attributes according to locale
|
||||
if (is_array($definitionInfo) && isset($definitionInfo['type']) && $definitionInfo['type'] === DECIMAL) {
|
||||
$attribute_values["$definition_id"] = to_decimals($raw_value);
|
||||
@@ -742,7 +743,7 @@ function get_expense_category_manage_table_headers(): string
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the html data row for the expenses category
|
||||
* Gets the html data row for the expense category
|
||||
*/
|
||||
function get_expense_category_data_row(object $expense_category): array
|
||||
{
|
||||
@@ -841,7 +842,7 @@ function get_expenses_data_last_row(object $expense): array
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the expenses payments summary
|
||||
* Get the expense payments summary
|
||||
*/
|
||||
function get_expenses_manage_payments_summary(array $payments, ResultInterface $expenses): string // TODO: $expenses is passed but never used.
|
||||
{
|
||||
@@ -933,22 +934,22 @@ function get_controller(): string
|
||||
}
|
||||
|
||||
/**
|
||||
* Restores filter values from URL query string.
|
||||
*
|
||||
* @param CodeIgniter\HTTP\IncomingRequest $request The request object
|
||||
* Restores filter values from the URL query string.
|
||||
*
|
||||
* @param IncomingRequest $request The request object
|
||||
* @return array Array with 'start_date', 'end_date', and 'selected_filters' keys
|
||||
*/
|
||||
function restoreTableFilters($request): array
|
||||
function restoreTableFilters(IncomingRequest $request): array
|
||||
{
|
||||
$startDate = $request->getGet('start_date', FILTER_SANITIZE_FULL_SPECIAL_CHARS);
|
||||
$endDate = $request->getGet('end_date', FILTER_SANITIZE_FULL_SPECIAL_CHARS);
|
||||
$urlFilters = $request->getGet('filters', FILTER_SANITIZE_FULL_SPECIAL_CHARS);
|
||||
|
||||
|
||||
return array_filter([
|
||||
'start_date' => $startDate ?: null,
|
||||
'end_date' => $endDate ?: null,
|
||||
'selected_filters' => $urlFilters ?? []
|
||||
], function($value) {
|
||||
], function ($value) {
|
||||
return $value !== null && $value !== [];
|
||||
});
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ if (!function_exists('base64url_encode')) {
|
||||
* @param string $data
|
||||
* @return string
|
||||
*/
|
||||
function base64url_encode($data)
|
||||
function base64url_encode(string $data): string
|
||||
{
|
||||
return rtrim(strtr(base64_encode($data), '+/', '-_'), '=');
|
||||
}
|
||||
@@ -20,7 +20,7 @@ if (!function_exists('base64url_decode')) {
|
||||
* @param string $data
|
||||
* @return string|false
|
||||
*/
|
||||
function base64url_decode($data)
|
||||
function base64url_decode(string $data): false|string
|
||||
{
|
||||
$remainder = strlen($data) % 4;
|
||||
if ($remainder) {
|
||||
@@ -28,4 +28,4 @@ if (!function_exists('base64url_decode')) {
|
||||
}
|
||||
return base64_decode(strtr($data, '-_', '+/'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,8 +6,7 @@ use CodeIgniter\Language\Language;
|
||||
|
||||
class MY_Language extends Language
|
||||
{
|
||||
|
||||
public function getLine(string $line, array $args = [])
|
||||
public function getLine(string $line, array $args = []): array|string
|
||||
{
|
||||
// If no file is given, just parse the line
|
||||
if (! str_contains($line, '.')) {
|
||||
@@ -20,7 +19,7 @@ class MY_Language extends Language
|
||||
|
||||
$output = $this->getTranslationOutput($this->locale, $file, $parsedLine);
|
||||
|
||||
if ($output === NULL && strpos($this->locale, '-')) {
|
||||
if ($output === null && strpos($this->locale, '-')) {
|
||||
[$locale] = explode('-', $this->locale, 2);
|
||||
|
||||
[$file, $parsedLine] = $this->parseLine($line, $locale);
|
||||
@@ -29,7 +28,7 @@ class MY_Language extends Language
|
||||
}
|
||||
|
||||
// If still not found, try English
|
||||
if ($output === NULL || $output === "") {
|
||||
if ($output === null || $output === "") {
|
||||
[$file, $parsedLine] = $this->parseLine($line, 'en');
|
||||
|
||||
$output = $this->getTranslationOutput('en', $file, $parsedLine);
|
||||
|
||||
@@ -394,7 +394,7 @@ class Receiving_lib
|
||||
/**
|
||||
* @param $line int|string The item_number or item_id of the item to be removed from the receiving.
|
||||
*/
|
||||
public function delete_item($line): void
|
||||
public function delete_item(int|string $line): void
|
||||
{
|
||||
$items = $this->get_cart();
|
||||
unset($items[$line]);
|
||||
|
||||
@@ -575,10 +575,10 @@ class Attribute extends Model
|
||||
|
||||
/**
|
||||
* @param string $definition_name
|
||||
* @param $definition_type
|
||||
* @param string|bool $definition_type
|
||||
* @return array
|
||||
*/
|
||||
public function get_definition_by_name(string $definition_name, $definition_type = false): array
|
||||
public function get_definition_by_name(string $definition_name, string|bool $definition_type = false): array
|
||||
{
|
||||
$builder = $this->db->table('attribute_definitions');
|
||||
$builder->where('definition_name', $definition_name);
|
||||
@@ -606,22 +606,43 @@ class Attribute extends Model
|
||||
|
||||
$this->db->transStart();
|
||||
|
||||
$definitionType = $this->getAttributeInfo($definitionId)->definition_type ?? '';
|
||||
|
||||
$builder = $this->db->table('attribute_links');
|
||||
|
||||
if ($this->attributeLinkExists($normalizedItemId, $definitionId)) {
|
||||
$builder->set(['attribute_id' => $normalizedAttributeId]);
|
||||
$builder->where('definition_id', $definitionId);
|
||||
if ($definitionType === DROPDOWN && $normalizedItemId === null) {
|
||||
$builder->where('item_id', $normalizedItemId);
|
||||
$builder->where('definition_id', $definitionId);
|
||||
$builder->where('attribute_id', $normalizedAttributeId);
|
||||
$builder->where('sale_id', null);
|
||||
$builder->where('receiving_id', null);
|
||||
$builder->update();
|
||||
|
||||
$dropdownAttributeLinkExists = $builder->countAllResults(false) !== 0;
|
||||
|
||||
if (!$dropdownAttributeLinkExists) {
|
||||
$data = [
|
||||
'attribute_id' => $normalizedAttributeId,
|
||||
'item_id' => $normalizedItemId,
|
||||
'definition_id' => $definitionId
|
||||
];
|
||||
$builder->insert($data);
|
||||
}
|
||||
} else {
|
||||
$data = [
|
||||
'attribute_id' => $normalizedAttributeId,
|
||||
'item_id' => $normalizedItemId,
|
||||
'definition_id' => $definitionId
|
||||
];
|
||||
$builder->insert($data);
|
||||
if ($this->attributeLinkExists($normalizedItemId, $definitionId)) {
|
||||
$builder->set(['attribute_id' => $normalizedAttributeId]);
|
||||
$builder->where('definition_id', $definitionId);
|
||||
$builder->where('item_id', $normalizedItemId);
|
||||
$builder->where('sale_id', null);
|
||||
$builder->where('receiving_id', null);
|
||||
$builder->update();
|
||||
} else {
|
||||
$data = [
|
||||
'attribute_id' => $normalizedAttributeId,
|
||||
'item_id' => $normalizedItemId,
|
||||
'definition_id' => $definitionId
|
||||
];
|
||||
$builder->insert($data);
|
||||
}
|
||||
}
|
||||
|
||||
$this->db->transComplete();
|
||||
|
||||
@@ -4,6 +4,7 @@ namespace App\Models;
|
||||
|
||||
use CodeIgniter\Database\ResultInterface;
|
||||
use Config\OSPOS;
|
||||
use stdClass;
|
||||
|
||||
/**
|
||||
* Customer class
|
||||
@@ -128,7 +129,7 @@ class Customer extends Person
|
||||
/**
|
||||
* Gets stats about a particular customer
|
||||
*/
|
||||
public function get_stats(int $customer_id)
|
||||
public function get_stats(int $customer_id): ?stdClass
|
||||
{
|
||||
$db_prefix = $this->db->getPrefix();
|
||||
$totals_decimals = totals_decimals();
|
||||
|
||||
@@ -4,6 +4,7 @@ namespace App\Models;
|
||||
|
||||
use CodeIgniter\Database\ResultInterface;
|
||||
use CodeIgniter\Session\Session;
|
||||
use stdClass;
|
||||
|
||||
/**
|
||||
* Employee class
|
||||
@@ -407,7 +408,7 @@ class Employee extends Person
|
||||
/**
|
||||
* Gets information about the currently logged in employee.
|
||||
*/
|
||||
public function get_logged_in_employee_info()
|
||||
public function get_logged_in_employee_info(): float|false|array|int|string|stdClass|null
|
||||
{
|
||||
if ($this->is_logged_in()) {
|
||||
return $this->get_info($this->session->get('person_id'));
|
||||
|
||||
@@ -352,7 +352,7 @@ class Item extends Model
|
||||
/**
|
||||
* Gets information about a particular item by item id or number
|
||||
*/
|
||||
public function get_info_by_id_or_number(string $item_id, bool $include_deleted = true)
|
||||
public function get_info_by_id_or_number(string $item_id, bool $include_deleted = true): stdClass|string
|
||||
{
|
||||
$builder = $this->db->table('items');
|
||||
$builder->groupStart();
|
||||
@@ -547,9 +547,9 @@ class Item extends Model
|
||||
public function get_search_suggestion_format(?string $seed = null): string
|
||||
{
|
||||
$config = config(OSPOS::class)->settings;
|
||||
|
||||
|
||||
$suggestionsFirstColumn = $this->suggestionColumnIsAllowed($config['suggestions_first_column'])
|
||||
? $config['suggestions_first_column']
|
||||
? $config['suggestions_first_column']
|
||||
: 'name';
|
||||
$seed .= ',' . $suggestionsFirstColumn;
|
||||
|
||||
@@ -573,14 +573,14 @@ class Item extends Model
|
||||
$config = config(OSPOS::class)->settings;
|
||||
|
||||
$label = '';
|
||||
$label1 = $this->suggestionColumnIsAllowed($config['suggestions_first_column'])
|
||||
? $config['suggestions_first_column']
|
||||
$label1 = $this->suggestionColumnIsAllowed($config['suggestions_first_column'])
|
||||
? $config['suggestions_first_column']
|
||||
: 'name';
|
||||
$label2 = $this->suggestionColumnIsAllowed($config['suggestions_second_column'])
|
||||
? $config['suggestions_second_column']
|
||||
$label2 = $this->suggestionColumnIsAllowed($config['suggestions_second_column'])
|
||||
? $config['suggestions_second_column']
|
||||
: '';
|
||||
$label3 = $this->suggestionColumnIsAllowed($config['suggestions_third_column'])
|
||||
? $config['suggestions_third_column']
|
||||
$label3 = $this->suggestionColumnIsAllowed($config['suggestions_third_column'])
|
||||
? $config['suggestions_third_column']
|
||||
: '';
|
||||
|
||||
$this->format_result_numbers($result_row);
|
||||
|
||||
@@ -11,34 +11,31 @@ $barcode_lib = new Barcode_lib();
|
||||
|
||||
<!doctype html>
|
||||
<html lang="<?= current_language_code() ?>">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title><?= lang('Items.generate_barcodes') ?></title>
|
||||
<link rel="stylesheet" href="<?= base_url() ?>css/barcode_font.css">
|
||||
<style>
|
||||
.barcode svg {
|
||||
height: <?= $barcode_config['barcode_height'] ?>px;
|
||||
width: <?= $barcode_config['barcode_width'] ?>px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body class=<?= 'font_' . $barcode_lib->get_font_name($barcode_config['barcode_font']) ?> style="font-size: <?= $barcode_config['barcode_font_size'] ?>px;">
|
||||
<table cellspacing="<?= $barcode_config['barcode_page_cellspacing'] ?>" width="<?= $barcode_config['barcode_page_width'] . '%' ?>">
|
||||
<tr>
|
||||
<?php
|
||||
$count = 0;
|
||||
foreach ($items as $item) {
|
||||
if ($count % $barcode_config['barcode_num_in_row'] == 0 && $count != 0) {
|
||||
echo '</tr><tr>';
|
||||
}
|
||||
echo '<td>' . $barcode_lib->display_barcode($item, $barcode_config) . '</td>';
|
||||
$count++;
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title><?= lang('Items.generate_barcodes') ?></title>
|
||||
<link rel="stylesheet" href="<?= base_url() ?>css/barcode_font.css">
|
||||
<style>
|
||||
.barcode svg {
|
||||
height: <?= $barcode_config['barcode_height'] ?>px;
|
||||
width: <?= $barcode_config['barcode_width'] ?>px;
|
||||
}
|
||||
?>
|
||||
</tr>
|
||||
</table>
|
||||
</body>
|
||||
|
||||
</style>
|
||||
</head>
|
||||
<body class=<?= 'font_' . $barcode_lib->get_font_name($barcode_config['barcode_font']) ?> style="font-size: <?= $barcode_config['barcode_font_size'] ?>px;">
|
||||
<table style="border-spacing: <?= $barcode_config['barcode_page_cellspacing'] ?>; width: <?= $barcode_config['barcode_page_width'] ?>%;">
|
||||
<tr>
|
||||
<?php
|
||||
$count = 0;
|
||||
foreach ($items as $item) {
|
||||
if ($count % $barcode_config['barcode_num_in_row'] == 0 && $count != 0) {
|
||||
echo '</tr><tr>';
|
||||
}
|
||||
echo '<td>' . $barcode_lib->display_barcode($item, $barcode_config) . '</td>';
|
||||
$count++;
|
||||
}
|
||||
?>
|
||||
</tr>
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -47,7 +47,7 @@
|
||||
<?= view('partial/print_receipt', ['print_after_sale' => false, 'selected_printer' => 'takings_printer']) ?>
|
||||
|
||||
<div id="title_bar" class="print_hide btn-toolbar">
|
||||
<button onclick="javascript:printdoc()" class="btn btn-info btn-sm pull-right">
|
||||
<button onclick="printdoc()" class="btn btn-info btn-sm pull-right">
|
||||
<span class="glyphicon glyphicon-print"> </span><?= lang('Common.print') ?>
|
||||
</button>
|
||||
<button class="btn btn-info btn-sm pull-right modal-dlg" data-btn-submit="<?= lang('Common.submit') ?>" data-href="<?= "$controller_name/view" ?>" title="<?= lang(ucfirst($controller_name) . ".new") ?>">
|
||||
|
||||
@@ -25,11 +25,9 @@ use Config\OSPOS;
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-sm-2" style="text-align: left;"><br>
|
||||
<strong>
|
||||
<p style="min-height: 14.7em;">General Info</p>
|
||||
<p style="min-height: 10.5em;">User Setup</p><br>
|
||||
<p>Permissions</p>
|
||||
</strong>
|
||||
<p style="min-height: 14.7em; font-weight: bold;">General Info</p>
|
||||
<p style="min-height: 10.5em; font-weight: bold;">User Setup</p><br>
|
||||
<p style="font-weight: bold;">Permissions</p>
|
||||
</div>
|
||||
<div class="col-sm-8" id="issuetemplate" style="text-align: left;"><br>
|
||||
<?= lang('Config.ospos_info') . ':' ?>
|
||||
@@ -38,14 +36,14 @@ use Config\OSPOS;
|
||||
<div id="TimeError"></div>
|
||||
Extensions & Modules:<br>
|
||||
<?php
|
||||
echo "» GD: ", extension_loaded('gd') ? '<span style="color: green;">Enabled ✓</span>' : '<span style="color: red;">Disabled ✗</span>', '<br>';
|
||||
echo "» BC Math: ", extension_loaded('bcmath') ? '<span style="color: green;">Enabled ✓</span>' : '<span style="color: red">Disabled ✗</span>', '<br>';
|
||||
echo "» INTL: ", extension_loaded('intl') ? '<span style="color: green;">Enabled ✓</span>' : '<span style="color: red">Disabled ✗</span>', '<br>';
|
||||
echo "» OpenSSL: ", extension_loaded('openssl') ? '<span style="color: green;">Enabled ✓</span>' : '<span style="color: red">Disabled ✗</span>', '<br>';
|
||||
echo "» MBString: ", extension_loaded('mbstring') ? '<span style="color: green;">Enabled ✓</span>' : '<span style="color: red">Disabled ✗</span>', '<br>';
|
||||
echo "» Curl: ", extension_loaded('curl') ? '<span style="color: green;">Enabled ✓</span>' : '<span style="color: red">Disabled ✗</span>', '<br>';
|
||||
echo "» Json: ", extension_loaded('json') ? '<span style="color: green;">Enabled ✓</span>' : '<span style="color: red">Disabled ✗</span>', '<br><br>';
|
||||
echo "» Xml: ", extension_loaded('xml') ? '<span style="color: green;">Enabled ✓</span>' : '<span style="color: red">Disabled ✗</span>', '<br><br>';
|
||||
echo "» GD: ", extension_loaded('gd') ? '<span style="color: green;">Enabled ✓</span>' : '<span style="color: red;">Disabled ✗</span>', '<br>';
|
||||
echo "» BC Math: ", extension_loaded('bcmath') ? '<span style="color: green;">Enabled ✓</span>' : '<span style="color: red;">Disabled ✗</span>', '<br>';
|
||||
echo "» INTL: ", extension_loaded('intl') ? '<span style="color: green;">Enabled ✓</span>' : '<span style="color: red;">Disabled ✗</span>', '<br>';
|
||||
echo "» OpenSSL: ", extension_loaded('openssl') ? '<span style="color: green;">Enabled ✓</span>' : '<span style="color: red;">Disabled ✗</span>', '<br>';
|
||||
echo "» MBString: ", extension_loaded('mbstring') ? '<span style="color: green;">Enabled ✓</span>' : '<span style="color: red;">Disabled ✗</span>', '<br>';
|
||||
echo "» Curl: ", extension_loaded('curl') ? '<span style="color: green;">Enabled ✓</span>' : '<span style="color: red;">Disabled ✗</span>', '<br>';
|
||||
echo "» Json: ", extension_loaded('json') ? '<span style="color: green;">Enabled ✓</span>' : '<span style="color: red;">Disabled ✗</span>', '<br><br>';
|
||||
echo "» Xml: ", extension_loaded('xml') ? '<span style="color: green;">Enabled ✓</span>' : '<span style="color: red;">Disabled ✗</span>', '<br><br>';
|
||||
?>
|
||||
User Configuration:<br>
|
||||
.Browser:
|
||||
|
||||
@@ -57,7 +57,7 @@ if (defined('SHOW_DEBUG_BACKTRACE') && SHOW_DEBUG_BACKTRACE) {
|
||||
$args = implode(', ', array_map(static fn ($value): string => match (true) {
|
||||
is_object($value) => 'Object(' . $value::class . ')',
|
||||
is_array($value) => $value !== [] ? '[...]' : '[]',
|
||||
$value === null => 'null', // Return the lowercased version
|
||||
$value === null => 'null', // return the lowercased version
|
||||
default => var_export($value, true),
|
||||
}, array_values($error['args'] ?? [])));
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
--main-text-color: #555;
|
||||
--dark-text-color: #222;
|
||||
--light-text-color: #c7c7c7;
|
||||
--brand-primary-color: #E06E3F;
|
||||
--brand-primary-color: #DC4814;
|
||||
--light-bg-color: #ededee;
|
||||
--dark-bg-color: #404040;
|
||||
}
|
||||
@@ -71,7 +71,7 @@ p.lead {
|
||||
text-align: center;
|
||||
padding: calc(4px + 0.2083vw);
|
||||
width: 100%;
|
||||
margin-top: -2.14rem;
|
||||
top: 0;
|
||||
position: fixed;
|
||||
}
|
||||
|
||||
@@ -101,11 +101,9 @@ p.lead {
|
||||
}
|
||||
|
||||
.tabs {
|
||||
list-style: none;
|
||||
list-style-position: inside;
|
||||
margin: 0;
|
||||
list-style: none inside none;
|
||||
padding: 0;
|
||||
margin-bottom: -1px;
|
||||
margin: 0 0 -1px;
|
||||
}
|
||||
.tabs li {
|
||||
display: inline;
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
<!doctype html>
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title><?= lang('Errors.badRequest') ?></title>
|
||||
@@ -16,7 +15,6 @@
|
||||
left: 50%;
|
||||
margin-left: -73px;
|
||||
}
|
||||
|
||||
body {
|
||||
height: 100%;
|
||||
background: #fafafa;
|
||||
@@ -24,7 +22,6 @@
|
||||
color: #777;
|
||||
font-weight: 300;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-weight: lighter;
|
||||
letter-spacing: normal;
|
||||
@@ -33,7 +30,6 @@
|
||||
margin-bottom: 0;
|
||||
color: #222;
|
||||
}
|
||||
|
||||
.wrap {
|
||||
max-width: 1024px;
|
||||
margin: 5rem auto;
|
||||
@@ -44,12 +40,10 @@
|
||||
border-radius: 0.5rem;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
pre {
|
||||
white-space: normal;
|
||||
margin-top: 1.5rem;
|
||||
}
|
||||
|
||||
code {
|
||||
background: #fafafa;
|
||||
border: 1px solid #efefef;
|
||||
@@ -57,11 +51,9 @@
|
||||
border-radius: 5px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
p {
|
||||
margin-top: 1.5rem;
|
||||
}
|
||||
|
||||
.footer {
|
||||
margin-top: 2rem;
|
||||
border-top: 1px solid #efefef;
|
||||
@@ -69,7 +61,6 @@
|
||||
font-size: 85%;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
a:active,
|
||||
a:link,
|
||||
a:visited {
|
||||
@@ -77,19 +68,17 @@
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="wrap">
|
||||
<h1>400</h1>
|
||||
<div class="wrap">
|
||||
<h1>400</h1>
|
||||
|
||||
<p>
|
||||
<?php if (ENVIRONMENT !== 'production') : ?>
|
||||
<?= nl2br(esc($message)) ?>
|
||||
<?php else : ?>
|
||||
<?= lang('Errors.sorryBadRequest') ?>
|
||||
<?php endif; ?>
|
||||
</p>
|
||||
</div>
|
||||
<p>
|
||||
<?php if (ENVIRONMENT !== 'production') : ?>
|
||||
<?= nl2br(esc($message)) ?>
|
||||
<?php else : ?>
|
||||
<?= lang('Errors.sorryBadRequest') ?>
|
||||
<?php endif; ?>
|
||||
</p>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
||||
@@ -1,10 +1,4 @@
|
||||
<?php
|
||||
/**
|
||||
* @var string $message
|
||||
*/
|
||||
?>
|
||||
|
||||
<!doctype html>
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
|
||||
@@ -14,421 +14,424 @@ $errorId = uniqid('error', true);
|
||||
?>
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="robots" content="noindex">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="robots" content="noindex">
|
||||
|
||||
<title><?= esc($title) ?></title>
|
||||
<style>
|
||||
<?= preg_replace('#[\r\n\t ]+#', ' ', file_get_contents(__DIR__ . DIRECTORY_SEPARATOR . 'debug.css')) ?>
|
||||
</style>
|
||||
<title><?= esc($title) ?></title>
|
||||
<style>
|
||||
<?= preg_replace('#[\r\n\t ]+#', ' ', file_get_contents(__DIR__ . DIRECTORY_SEPARATOR . 'debug.css')) ?>
|
||||
</style>
|
||||
|
||||
<script type="text/javascript">
|
||||
<?= file_get_contents(__DIR__ . DIRECTORY_SEPARATOR . 'debug.js') ?>
|
||||
</script>
|
||||
</head>
|
||||
<body onload="init()">
|
||||
<script type="text/javascript">
|
||||
<?= file_get_contents(__DIR__ . DIRECTORY_SEPARATOR . 'debug.js') ?>
|
||||
</script>
|
||||
</head>
|
||||
<body onload="init()">
|
||||
|
||||
<!-- Header -->
|
||||
<div class="header">
|
||||
<div class="environment">
|
||||
Displayed at <?= esc(date('H:i:sa')) ?> —
|
||||
PHP: <?= esc(PHP_VERSION) ?> —
|
||||
CodeIgniter: <?= esc(CodeIgniter::CI_VERSION) ?> --
|
||||
Environment: <?= ENVIRONMENT ?>
|
||||
<!-- Header -->
|
||||
<div class="header">
|
||||
<div class="environment">
|
||||
Displayed at <?= esc(date('H:i:s')) ?> —
|
||||
PHP: <?= esc(PHP_VERSION) ?> —
|
||||
CodeIgniter: <?= esc(CodeIgniter::CI_VERSION) ?> --
|
||||
Environment: <?= ENVIRONMENT ?>
|
||||
</div>
|
||||
<div class="container">
|
||||
<h1><?= esc($title), esc($exception->getCode() ? ' #' . $exception->getCode() : '') ?></h1>
|
||||
<p>
|
||||
<?= nl2br(esc($exception->getMessage())) ?>
|
||||
<a href="https://www.duckduckgo.com/?q=<?= urlencode($title . ' ' . preg_replace('#\'.*\'|".*"#Us', '', $exception->getMessage())) ?>"
|
||||
rel="noreferrer" target="_blank">search →</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Source -->
|
||||
<div class="container">
|
||||
<h1><?= esc($title), esc($exception->getCode() ? ' #' . $exception->getCode() : '') ?></h1>
|
||||
<p>
|
||||
<?= nl2br(esc($exception->getMessage())) ?>
|
||||
<a href="https://www.duckduckgo.com/?q=<?= urlencode($title . ' ' . preg_replace('#\'.*\'|".*"#Us', '', $exception->getMessage())) ?>"
|
||||
rel="noreferrer" target="_blank">search →</a>
|
||||
</p>
|
||||
<p><b><?= esc(clean_path($file)) ?></b> at line <b><?= esc($line) ?></b></p>
|
||||
|
||||
<?php if (is_file($file)) : ?>
|
||||
<div class="source">
|
||||
<?= static::highlightFile($file, $line, 15); ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Source -->
|
||||
<div class="container">
|
||||
<p><b><?= esc(clean_path($file)) ?></b> at line <b><?= esc($line) ?></b></p>
|
||||
|
||||
<?php if (is_file($file)) : ?>
|
||||
<div class="source">
|
||||
<?= static::highlightFile($file, $line, 15); ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<div class="container">
|
||||
<?php
|
||||
$last = $exception;
|
||||
|
||||
while ($prevException = $last->getPrevious()) {
|
||||
$last = $prevException;
|
||||
?>
|
||||
|
||||
<pre>
|
||||
Caused by:
|
||||
<?= esc($prevException::class), esc($prevException->getCode() ? ' #' . $prevException->getCode() : '') ?>
|
||||
|
||||
<?= nl2br(esc($prevException->getMessage())) ?>
|
||||
<a href="https://www.duckduckgo.com/?q=<?= urlencode($prevException::class . ' ' . preg_replace('#\'.*\'|".*"#Us', '', $prevException->getMessage())) ?>" rel="noreferrer" target="_blank">search →</a>
|
||||
<?= esc(clean_path($prevException->getFile()) . ':' . $prevException->getLine()) ?>
|
||||
</pre>
|
||||
|
||||
<?php } ?>
|
||||
</div>
|
||||
|
||||
<?php if (defined('SHOW_DEBUG_BACKTRACE') && SHOW_DEBUG_BACKTRACE) : ?>
|
||||
<div class="container">
|
||||
|
||||
<ul class="tabs" id="tabs">
|
||||
<li><a href="#backtrace">Backtrace</a></li>
|
||||
<li><a href="#server">Server</a></li>
|
||||
<li><a href="#request">Request</a></li>
|
||||
<li><a href="#response">Response</a></li>
|
||||
<li><a href="#files">Files</a></li>
|
||||
<li><a href="#memory">Memory</a></li>
|
||||
</ul>
|
||||
|
||||
<div class="tab-content">
|
||||
|
||||
<!-- Backtrace -->
|
||||
<div class="content" id="backtrace">
|
||||
|
||||
<ol class="trace">
|
||||
<?php foreach ($trace as $index => $row) : ?>
|
||||
|
||||
<li>
|
||||
<p>
|
||||
<!-- Trace info -->
|
||||
<?php if (isset($row['file']) && is_file($row['file'])) : ?>
|
||||
<?php
|
||||
if (isset($row['function']) && in_array($row['function'], ['include', 'include_once', 'require', 'require_once'], true)) {
|
||||
echo esc($row['function'] . ' ' . clean_path($row['file']));
|
||||
} else {
|
||||
echo esc(clean_path($row['file']) . ' : ' . $row['line']);
|
||||
}
|
||||
?>
|
||||
<?php else: ?>
|
||||
{PHP internal code}
|
||||
<?php endif; ?>
|
||||
|
||||
<!-- Class/Method -->
|
||||
<?php if (isset($row['class'])) : ?>
|
||||
— <?= esc($row['class'] . $row['type'] . $row['function']) ?>
|
||||
<?php if (! empty($row['args'])) : ?>
|
||||
<?php $argsId = $errorId . 'args' . $index ?>
|
||||
( <a href="#" onclick="return toggle('<?= esc($argsId, 'attr') ?>');">arguments</a> )
|
||||
<div class="args" id="<?= esc($argsId, 'attr') ?>">
|
||||
<table cellspacing="0">
|
||||
|
||||
<?php
|
||||
$params = null;
|
||||
// Reflection by name is not available for closure function
|
||||
if (! str_ends_with($row['function'], '}')) {
|
||||
$mirror = isset($row['class']) ? new ReflectionMethod($row['class'], $row['function']) : new ReflectionFunction($row['function']);
|
||||
$params = $mirror->getParameters();
|
||||
}
|
||||
|
||||
foreach ($row['args'] as $key => $value) : ?>
|
||||
<tr>
|
||||
<td><code><?= esc(isset($params[$key]) ? '$' . $params[$key]->name : "#{$key}") ?></code></td>
|
||||
<td><pre><?= esc(print_r($value, true)) ?></pre></td>
|
||||
</tr>
|
||||
<?php endforeach ?>
|
||||
|
||||
</table>
|
||||
</div>
|
||||
<?php else : ?>
|
||||
()
|
||||
<?php endif; ?>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if (! isset($row['class']) && isset($row['function'])) : ?>
|
||||
— <?= esc($row['function']) ?>()
|
||||
<?php endif; ?>
|
||||
</p>
|
||||
|
||||
<!-- Source? -->
|
||||
<?php if (isset($row['file']) && is_file($row['file']) && isset($row['class'])) : ?>
|
||||
<div class="source">
|
||||
<?= static::highlightFile($row['file'], $row['line']) ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</li>
|
||||
|
||||
<?php endforeach; ?>
|
||||
</ol>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- Server -->
|
||||
<div class="content" id="server">
|
||||
<?php foreach (['_SERVER', '_SESSION'] as $var) : ?>
|
||||
<?php
|
||||
if (empty($GLOBALS[$var]) || ! is_array($GLOBALS[$var])) {
|
||||
continue;
|
||||
} ?>
|
||||
|
||||
<h3>$<?= esc($var) ?></h3>
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Key</th>
|
||||
<th>Value</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($GLOBALS[$var] as $key => $value) : ?>
|
||||
<tr>
|
||||
<td><?= esc($key) ?></td>
|
||||
<td>
|
||||
<?php if (is_string($value)) : ?>
|
||||
<?= esc($value) ?>
|
||||
<?php else: ?>
|
||||
<pre><?= esc(print_r($value, true)) ?></pre>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<?php endforeach ?>
|
||||
|
||||
<!-- Constants -->
|
||||
<?php $constants = get_defined_constants(true); ?>
|
||||
<?php if (! empty($constants['user'])) : ?>
|
||||
<h3>Constants</h3>
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Key</th>
|
||||
<th>Value</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($constants['user'] as $key => $value) : ?>
|
||||
<tr>
|
||||
<td><?= esc($key) ?></td>
|
||||
<td>
|
||||
<?php if (is_string($value)) : ?>
|
||||
<?= esc($value) ?>
|
||||
<?php else: ?>
|
||||
<pre><?= esc(print_r($value, true)) ?></pre>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<!-- Request -->
|
||||
<div class="content" id="request">
|
||||
<?php $request = service('request'); ?>
|
||||
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td style="width: 10em">Path</td>
|
||||
<td><?= esc($request->getUri()) ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>HTTP Method</td>
|
||||
<td><?= esc($request->getMethod()) ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>IP Address</td>
|
||||
<td><?= esc($request->getIPAddress()) ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="width: 10em">Is AJAX Request?</td>
|
||||
<td><?= $request->isAJAX() ? 'yes' : 'no' ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Is CLI Request?</td>
|
||||
<td><?= $request->isCLI() ? 'yes' : 'no' ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Is Secure Request?</td>
|
||||
<td><?= $request->isSecure() ? 'yes' : 'no' ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>User Agent</td>
|
||||
<td><?= esc($request->getUserAgent()->getAgentString()) ?></td>
|
||||
</tr>
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
||||
<?php $empty = true; ?>
|
||||
<?php foreach (['_GET', '_POST', '_COOKIE'] as $var) : ?>
|
||||
<?php
|
||||
if (empty($GLOBALS[$var]) || ! is_array($GLOBALS[$var])) {
|
||||
continue;
|
||||
} ?>
|
||||
|
||||
<?php $empty = false; ?>
|
||||
|
||||
<h3>$<?= esc($var) ?></h3>
|
||||
|
||||
<table style="width: 100%">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Key</th>
|
||||
<th>Value</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($GLOBALS[$var] as $key => $value) : ?>
|
||||
<tr>
|
||||
<td><?= esc($key) ?></td>
|
||||
<td>
|
||||
<?php if (is_string($value)) : ?>
|
||||
<?= esc($value) ?>
|
||||
<?php else: ?>
|
||||
<pre><?= esc(print_r($value, true)) ?></pre>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<?php endforeach ?>
|
||||
|
||||
<?php if ($empty) : ?>
|
||||
|
||||
<div class="alert">
|
||||
No $_GET, $_POST, or $_COOKIE Information to show.
|
||||
</div>
|
||||
|
||||
<?php endif; ?>
|
||||
|
||||
<?php $headers = $request->headers(); ?>
|
||||
<?php if (! empty($headers)) : ?>
|
||||
|
||||
<h3>Headers</h3>
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Header</th>
|
||||
<th>Value</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($headers as $name => $value) : ?>
|
||||
<tr>
|
||||
<td><?= esc($name, 'html') ?></td>
|
||||
<td>
|
||||
<?php
|
||||
if ($value instanceof Header) {
|
||||
echo esc($value->getValueLine(), 'html');
|
||||
} else {
|
||||
foreach ($value as $i => $header) {
|
||||
echo ' ('. $i+1 . ') ' . esc($header->getValueLine(), 'html');
|
||||
}
|
||||
}
|
||||
?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<!-- Response -->
|
||||
<div class="container">
|
||||
<?php
|
||||
$response = service('response');
|
||||
$response->setStatusCode(http_response_code());
|
||||
?>
|
||||
<div class="content" id="response">
|
||||
<table>
|
||||
<tr>
|
||||
<td style="width: 15em">Response Status</td>
|
||||
<td><?= esc($response->getStatusCode() . ' - ' . $response->getReasonPhrase()) ?></td>
|
||||
</tr>
|
||||
</table>
|
||||
$last = $exception;
|
||||
|
||||
<?php $headers = $response->headers(); ?>
|
||||
<?php if (! empty($headers)) : ?>
|
||||
<h3>Headers</h3>
|
||||
while ($prevException = $last->getPrevious()) {
|
||||
$last = $prevException;
|
||||
?>
|
||||
|
||||
<pre>
|
||||
Caused by:
|
||||
<?= esc($prevException::class), esc($prevException->getCode() ? ' #' . $prevException->getCode() : '') ?>
|
||||
|
||||
<?= nl2br(esc($prevException->getMessage())) ?>
|
||||
<a href="https://www.duckduckgo.com/?q=<?= urlencode($prevException::class . ' ' . preg_replace('#\'.*\'|".*"#Us', '', $prevException->getMessage())) ?>"
|
||||
rel="noreferrer" target="_blank">search →</a>
|
||||
<?= esc(clean_path($prevException->getFile()) . ':' . $prevException->getLine()) ?>
|
||||
</pre>
|
||||
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
|
||||
<?php if (defined('SHOW_DEBUG_BACKTRACE') && SHOW_DEBUG_BACKTRACE) : ?>
|
||||
<div class="container">
|
||||
|
||||
<ul class="tabs" id="tabs">
|
||||
<li><a href="#backtrace">Backtrace</a></li>
|
||||
<li><a href="#server">Server</a></li>
|
||||
<li><a href="#request">Request</a></li>
|
||||
<li><a href="#response">Response</a></li>
|
||||
<li><a href="#files">Files</a></li>
|
||||
<li><a href="#memory">Memory</a></li>
|
||||
</ul>
|
||||
|
||||
<div class="tab-content">
|
||||
|
||||
<!-- Backtrace -->
|
||||
<div class="content" id="backtrace">
|
||||
|
||||
<ol class="trace">
|
||||
<?php foreach ($trace as $index => $row) : ?>
|
||||
|
||||
<li>
|
||||
<p>
|
||||
<!-- Trace info -->
|
||||
<?php if (isset($row['file']) && is_file($row['file'])) : ?>
|
||||
<?php
|
||||
if (isset($row['function']) && in_array($row['function'], ['include', 'include_once', 'require', 'require_once'], true)) {
|
||||
echo esc($row['function'] . ' ' . clean_path($row['file']));
|
||||
} else {
|
||||
echo esc(clean_path($row['file']) . ' : ' . $row['line']);
|
||||
}
|
||||
?>
|
||||
<?php else: ?>
|
||||
{PHP internal code}
|
||||
<?php endif; ?>
|
||||
|
||||
<!-- Class/Method -->
|
||||
<?php if (isset($row['class'])) : ?>
|
||||
— <?= esc($row['class'] . $row['type'] . $row['function']) ?>
|
||||
<?php if (! empty($row['args'])) : ?>
|
||||
<?php $argsId = $errorId . 'args' . $index ?>
|
||||
( <a href="#" onclick="return toggle('<?= esc($argsId, 'attr') ?>');">arguments</a> )
|
||||
<div class="args" id="<?= esc($argsId, 'attr') ?>">
|
||||
<table style="border-spacing: 0;">
|
||||
|
||||
<?php
|
||||
$params = null;
|
||||
// Reflection by name is not available for closure function
|
||||
if (! str_ends_with($row['function'], '}')) {
|
||||
$mirror = isset($row['class']) ? new ReflectionMethod($row['class'], $row['function']) : new ReflectionFunction($row['function']);
|
||||
$params = $mirror->getParameters();
|
||||
}
|
||||
|
||||
foreach ($row['args'] as $key => $value) : ?>
|
||||
<tr>
|
||||
<td><code><?= esc(isset($params[$key]) ? '$' . $params[$key]->name : "#{$key}") ?></code></td>
|
||||
<td><pre><?= esc(print_r($value, true)) ?></pre></td>
|
||||
</tr>
|
||||
<?php endforeach ?>
|
||||
|
||||
</table>
|
||||
</div>
|
||||
<?php else : ?>
|
||||
()
|
||||
<?php endif; ?>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if (! isset($row['class']) && isset($row['function'])) : ?>
|
||||
— <?= esc($row['function']) ?>()
|
||||
<?php endif; ?>
|
||||
</p>
|
||||
|
||||
<!-- Source? -->
|
||||
<?php if (isset($row['file']) && is_file($row['file']) && isset($row['class'])) : ?>
|
||||
<div class="source">
|
||||
<?= static::highlightFile($row['file'], $row['line']) ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</li>
|
||||
|
||||
<?php endforeach; ?>
|
||||
</ol>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- Server -->
|
||||
<div class="content" id="server">
|
||||
<?php foreach (['_SERVER', '_SESSION'] as $var) : ?>
|
||||
<?php
|
||||
if (empty($GLOBALS[$var]) || ! is_array($GLOBALS[$var])) {
|
||||
continue;
|
||||
} ?>
|
||||
|
||||
<h3>$<?= esc($var) ?></h3>
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Key</th>
|
||||
<th>Value</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($GLOBALS[$var] as $key => $value) : ?>
|
||||
<tr>
|
||||
<td><?= esc($key) ?></td>
|
||||
<td>
|
||||
<?php if (is_string($value)) : ?>
|
||||
<?= esc($value) ?>
|
||||
<?php else: ?>
|
||||
<pre><?= esc(print_r($value, true)) ?></pre>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<?php endforeach ?>
|
||||
|
||||
<!-- Constants -->
|
||||
<?php $constants = get_defined_constants(true); ?>
|
||||
<?php if (! empty($constants['user'])) : ?>
|
||||
<h3>Constants</h3>
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Key</th>
|
||||
<th>Value</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($constants['user'] as $key => $value) : ?>
|
||||
<tr>
|
||||
<td><?= esc($key) ?></td>
|
||||
<td>
|
||||
<?php if (is_string($value)) : ?>
|
||||
<?= esc($value) ?>
|
||||
<?php else: ?>
|
||||
<pre><?= esc(print_r($value, true)) ?></pre>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<!-- Request -->
|
||||
<div class="content" id="request">
|
||||
<?php $request = service('request'); ?>
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Header</th>
|
||||
<th>Value</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($headers as $name => $value) : ?>
|
||||
<tr>
|
||||
<td><?= esc($name, 'html') ?></td>
|
||||
<td>
|
||||
<?php
|
||||
if ($value instanceof Header) {
|
||||
echo esc($response->getHeaderLine($name), 'html');
|
||||
} else {
|
||||
foreach ($value as $i => $header) {
|
||||
echo ' ('. $i+1 . ') ' . esc($header->getValueLine(), 'html');
|
||||
}
|
||||
}
|
||||
?>
|
||||
</td>
|
||||
<td style="width: 10em">Path</td>
|
||||
<td><?= esc($request->getUri()) ?></td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
<tr>
|
||||
<td>HTTP Method</td>
|
||||
<td><?= esc($request->getMethod()) ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>IP Address</td>
|
||||
<td><?= esc($request->getIPAddress()) ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="width: 10em">Is AJAX Request?</td>
|
||||
<td><?= $request->isAJAX() ? 'yes' : 'no' ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Is CLI Request?</td>
|
||||
<td><?= $request->isCLI() ? 'yes' : 'no' ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Is Secure Request?</td>
|
||||
<td><?= $request->isSecure() ? 'yes' : 'no' ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>User Agent</td>
|
||||
<td><?= esc($request->getUserAgent()->getAgentString()) ?></td>
|
||||
</tr>
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<!-- Files -->
|
||||
<div class="content" id="files">
|
||||
<?php $files = get_included_files(); ?>
|
||||
<?php $empty = true; ?>
|
||||
<?php foreach (['_GET', '_POST', '_COOKIE'] as $var) : ?>
|
||||
<?php
|
||||
if (empty($GLOBALS[$var]) || ! is_array($GLOBALS[$var])) {
|
||||
continue;
|
||||
} ?>
|
||||
|
||||
<ol>
|
||||
<?php foreach ($files as $file) :?>
|
||||
<li><?= esc(clean_path($file)) ?></li>
|
||||
<?php endforeach ?>
|
||||
</ol>
|
||||
</div>
|
||||
<?php $empty = false; ?>
|
||||
|
||||
<!-- Memory -->
|
||||
<div class="content" id="memory">
|
||||
<h3>$<?= esc($var) ?></h3>
|
||||
|
||||
<table>
|
||||
<tbody>
|
||||
<table style="width: 100%">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Key</th>
|
||||
<th>Value</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($GLOBALS[$var] as $key => $value) : ?>
|
||||
<tr>
|
||||
<td><?= esc($key) ?></td>
|
||||
<td>
|
||||
<?php if (is_string($value)) : ?>
|
||||
<?= esc($value) ?>
|
||||
<?php else: ?>
|
||||
<pre><?= esc(print_r($value, true)) ?></pre>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<?php endforeach ?>
|
||||
|
||||
<?php if ($empty) : ?>
|
||||
|
||||
<div class="alert">
|
||||
No $_GET, $_POST, or $_COOKIE Information to show.
|
||||
</div>
|
||||
|
||||
<?php endif; ?>
|
||||
|
||||
<?php $headers = $request->headers(); ?>
|
||||
<?php if (! empty($headers)) : ?>
|
||||
|
||||
<h3>Headers</h3>
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Header</th>
|
||||
<th>Value</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($headers as $name => $value) : ?>
|
||||
<tr>
|
||||
<td><?= esc($name, 'html') ?></td>
|
||||
<td>
|
||||
<?php
|
||||
if ($value instanceof Header) {
|
||||
echo esc($value->getValueLine(), 'html');
|
||||
} else {
|
||||
foreach ($value as $i => $header) {
|
||||
echo ' (' . ($i + 1) . ') ' . esc($header->getValueLine(), 'html');
|
||||
}
|
||||
}
|
||||
?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<!-- Response -->
|
||||
<?php
|
||||
$response = service('response');
|
||||
$response->setStatusCode(http_response_code());
|
||||
?>
|
||||
<div class="content" id="response">
|
||||
<table>
|
||||
<tr>
|
||||
<td>Memory Usage</td>
|
||||
<td><?= esc(static::describeMemory(memory_get_usage(true))) ?></td>
|
||||
<td style="width: 15em">Response Status</td>
|
||||
<td><?= esc($response->getStatusCode() . ' - ' . $response->getReasonPhrase()) ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="width: 12em">Peak Memory Usage:</td>
|
||||
<td><?= esc(static::describeMemory(memory_get_peak_usage(true))) ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Memory Limit:</td>
|
||||
<td><?= esc(ini_get('memory_limit')) ?></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</table>
|
||||
|
||||
</div>
|
||||
<?php $headers = $response->headers(); ?>
|
||||
<?php if (! empty($headers)) : ?>
|
||||
<h3>Headers</h3>
|
||||
|
||||
</div> <!-- /tab-content -->
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Header</th>
|
||||
<th>Value</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($headers as $name => $value) : ?>
|
||||
<tr>
|
||||
<td><?= esc($name, 'html') ?></td>
|
||||
<td>
|
||||
<?php
|
||||
if ($value instanceof Header) {
|
||||
echo esc($response->getHeaderLine($name), 'html');
|
||||
} else {
|
||||
foreach ($value as $i => $header) {
|
||||
echo ' (' . ($i + 1) . ') ' . esc($header->getValueLine(), 'html');
|
||||
}
|
||||
}
|
||||
?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
</div> <!-- /container -->
|
||||
<?php endif; ?>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
<!-- Files -->
|
||||
<div class="content" id="files">
|
||||
<?php $files = get_included_files(); ?>
|
||||
|
||||
<ol>
|
||||
<?php foreach ($files as $file) :?>
|
||||
<li><?= esc(clean_path($file)) ?></li>
|
||||
<?php endforeach ?>
|
||||
</ol>
|
||||
</div>
|
||||
|
||||
<!-- Memory -->
|
||||
<div class="content" id="memory">
|
||||
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Memory Usage</td>
|
||||
<td><?= esc(static::describeMemory(memory_get_usage(true))) ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="width: 12em">Peak Memory Usage:</td>
|
||||
<td><?= esc(static::describeMemory(memory_get_peak_usage(true))) ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Memory Limit:</td>
|
||||
<td><?= esc(ini_get('memory_limit')) ?></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
</div>
|
||||
|
||||
</div> <!-- /tab-content -->
|
||||
|
||||
</div> <!-- /container -->
|
||||
<?php endif; ?>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -49,13 +49,13 @@
|
||||
});
|
||||
|
||||
});
|
||||
</script
|
||||
<?= view('partial/table_filter_persistence') ?>>
|
||||
</script>
|
||||
<?= view('partial/table_filter_persistence') ?>
|
||||
|
||||
<?= view('partial/print_receipt', ['print_after_sale' => false, 'selected_printer' => 'takings_printer']) ?>
|
||||
|
||||
<div id="title_bar" class="print_hide btn-toolbar">
|
||||
<button onclick="javascript:printdoc()" class="btn btn-info btn-sm pull-right">
|
||||
<button onclick="printdoc()" class="btn btn-info btn-sm pull-right">
|
||||
<span class="glyphicon glyphicon-print"> </span><?= lang('Common.print') ?>
|
||||
</button>
|
||||
<button class="btn btn-info btn-sm pull-right modal-dlg" data-btn-submit="<?= lang('Common.submit') ?>" data-href="<?= "$controller_name/view" ?>" title="<?= lang(ucfirst($controller_name) . '.new') ?>">
|
||||
|
||||
@@ -4,21 +4,20 @@ use Config\OSPOS;
|
||||
|
||||
?>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="footer">
|
||||
<div class="jumbotron push-spaces">
|
||||
<strong>
|
||||
<?= lang('Common.copyrights', [date('Y')]) ?> ·
|
||||
<a href="https://opensourcepos.org" target="_blank"><?= lang('Common.website') ?></a> ·
|
||||
<?= esc(config('App')->application_version) ?> -
|
||||
<a target="_blank" href="https://github.com/opensourcepos/opensourcepos/commit/<?= esc(config(OSPOS::class)->commit_sha1) ?>">
|
||||
<?= esc(substr(config(OSPOS::class)->commit_sha1, 0, 6)); ?>
|
||||
</a>
|
||||
</strong>.
|
||||
<div id="footer">
|
||||
<div class="jumbotron push-spaces">
|
||||
<strong>
|
||||
<?= lang('Common.copyrights', [date('Y')]) ?> ·
|
||||
<a href="https://opensourcepos.org" target="_blank"><?= lang('Common.website') ?></a> ·
|
||||
<?= esc(config('App')->application_version) ?> -
|
||||
<a target="_blank" href="https://github.com/opensourcepos/opensourcepos/commit/<?= esc(config(OSPOS::class)->commit_sha1) ?>">
|
||||
<?= esc(substr(config(OSPOS::class)->commit_sha1, 0, 6)); ?>
|
||||
</a>
|
||||
</strong>.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
<?php
|
||||
/**
|
||||
* Table Filter Persistence
|
||||
*
|
||||
* This partial updates the URL when filters change, allowing users to
|
||||
*
|
||||
* This partially updates the URL when filters change, allowing users to
|
||||
* share/bookmark filtered views and maintain state on back navigation.
|
||||
*
|
||||
*
|
||||
* Filter restoration from URL is handled server-side in the controller.
|
||||
*
|
||||
*
|
||||
* @param array $options Additional filter options
|
||||
* - 'additional_params': Array of additional parameter names to track (e.g., ['stock_location'])
|
||||
* - 'filter_select_id': Filter multiselect element ID (default: 'filters')
|
||||
@@ -20,10 +20,10 @@ $filter_select_id = $options['filter_select_id'] ?? 'filters';
|
||||
$(document).ready(function() {
|
||||
var additional_params = <?= json_encode($additional_params) ?>;
|
||||
var filter_select_id = '<?= esc($filter_select_id) ?>';
|
||||
|
||||
|
||||
function update_url() {
|
||||
var params = new URLSearchParams();
|
||||
|
||||
|
||||
// Add dates
|
||||
if (typeof start_date !== 'undefined') {
|
||||
params.set('start_date', start_date);
|
||||
@@ -31,7 +31,7 @@ $filter_select_id = $options['filter_select_id'] ?? 'filters';
|
||||
if (typeof end_date !== 'undefined') {
|
||||
params.set('end_date', end_date);
|
||||
}
|
||||
|
||||
|
||||
// Add filters
|
||||
var filters = $('#' + filter_select_id).val();
|
||||
if (filters) {
|
||||
@@ -39,7 +39,7 @@ $filter_select_id = $options['filter_select_id'] ?? 'filters';
|
||||
params.append('filters[]', filter);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// Add additional params
|
||||
additional_params.forEach(function(param) {
|
||||
var element = $('#' + param);
|
||||
@@ -54,7 +54,7 @@ $filter_select_id = $options['filter_select_id'] ?? 'filters';
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// Update URL without page reload
|
||||
var new_url = window.location.pathname;
|
||||
var params_str = params.toString();
|
||||
@@ -63,22 +63,22 @@ $filter_select_id = $options['filter_select_id'] ?? 'filters';
|
||||
}
|
||||
window.history.replaceState({}, '', new_url);
|
||||
}
|
||||
|
||||
|
||||
// Update URL when filter dropdown changes
|
||||
$('#' + filter_select_id).on('hidden.bs.select', function(e) {
|
||||
update_url();
|
||||
});
|
||||
|
||||
|
||||
// Update URL when stock location changes (if exists)
|
||||
if ($('#stock_location').length) {
|
||||
$("#stock_location").change(function() {
|
||||
update_url();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// Update URL when daterangepicker changes
|
||||
$("#daterangepicker").on('apply.daterangepicker', function(ev, picker) {
|
||||
update_url();
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</script>
|
||||
|
||||
@@ -47,24 +47,26 @@
|
||||
offset: 60,
|
||||
// The label interpolation function enables you to modify the values
|
||||
// used for the labels on each axis.
|
||||
labelInterpolationFnc: function(value) {
|
||||
<?php
|
||||
<?php
|
||||
$currency_symbol = esc($config['currency_symbol'], 'js');
|
||||
$currency_prefix = '';
|
||||
$currency_suffix = '';
|
||||
|
||||
if ($show_currency) {
|
||||
if (is_right_side_currency_symbol()) {
|
||||
?>
|
||||
return value + '<?= esc($config['currency_symbol'], 'js') ?>';
|
||||
<?php } else { ?>
|
||||
return '<?= esc($config['currency_symbol'], 'js') ?>' + value;
|
||||
<?php
|
||||
$currency_suffix = $currency_symbol;
|
||||
} else {
|
||||
$currency_prefix = $currency_symbol;
|
||||
}
|
||||
} else {
|
||||
?>
|
||||
return value;
|
||||
<?php } ?>
|
||||
}
|
||||
?>
|
||||
|
||||
labelInterpolationFnc: function(value) {
|
||||
return '<?= $currency_prefix ?>' + value + '<?= $currency_suffix ?>';
|
||||
}
|
||||
},
|
||||
|
||||
// Plugins configuration
|
||||
// Plugin configuration
|
||||
plugins: [
|
||||
Chartist.plugins.ctAxisTitle({
|
||||
axisX: {
|
||||
|
||||
@@ -44,30 +44,32 @@
|
||||
position: 'end',
|
||||
// The label interpolation function enables you to modify the values
|
||||
// used for the labels on each axis.
|
||||
labelInterpolationFnc: function(value) {
|
||||
<?php
|
||||
<?php
|
||||
$currency_symbol = esc($config['currency_symbol'], 'js');
|
||||
$currency_prefix = '';
|
||||
$currency_suffix = '';
|
||||
|
||||
if ($show_currency) {
|
||||
if (is_right_side_currency_symbol()) {
|
||||
?>
|
||||
return value + '<?= esc($config['currency_symbol'], 'js') ?>';
|
||||
<?php } else { ?>
|
||||
return '<?= esc($config['currency_symbol'], 'js') ?>' + value;
|
||||
<?php
|
||||
$currency_suffix = $currency_symbol;
|
||||
} else {
|
||||
$currency_prefix = $currency_symbol;
|
||||
}
|
||||
} else {
|
||||
?>
|
||||
return value;
|
||||
<?php } ?>
|
||||
}
|
||||
?>
|
||||
|
||||
labelInterpolationFnc: function(value) {
|
||||
return '<?= $currency_prefix ?>' + value + '<?= $currency_suffix ?>';
|
||||
}
|
||||
},
|
||||
|
||||
// Y-Axis specific configuration
|
||||
axisY: {
|
||||
// Lets offset the chart a bit from the labels
|
||||
// Let's offset the chart a bit from the labels
|
||||
offset: 120
|
||||
},
|
||||
|
||||
// Plugins configuration
|
||||
// Plugin configuration
|
||||
plugins: [
|
||||
Chartist.plugins.ctAxisTitle({
|
||||
axisX: {
|
||||
|
||||
@@ -63,24 +63,26 @@
|
||||
},
|
||||
// The label interpolation function enables you to modify the values
|
||||
// used for the labels on each axis.
|
||||
labelInterpolationFnc: function(value) {
|
||||
<?php
|
||||
<?php
|
||||
$currency_symbol = esc($config['currency_symbol'], 'js');
|
||||
$currency_prefix = '';
|
||||
$currency_suffix = '';
|
||||
|
||||
if ($show_currency) {
|
||||
if (is_right_side_currency_symbol()) {
|
||||
?>
|
||||
return value + '<?= esc($config['currency_symbol'], 'js') ?>';
|
||||
<?php } else { ?>
|
||||
return '<?= esc($config['currency_symbol'], 'js') ?>' + value;
|
||||
<?php
|
||||
$currency_suffix = $currency_symbol;
|
||||
} else {
|
||||
$currency_prefix = $currency_symbol;
|
||||
}
|
||||
} else {
|
||||
?>
|
||||
return value;
|
||||
<?php } ?>
|
||||
}
|
||||
?>
|
||||
|
||||
labelInterpolationFnc: function(value) {
|
||||
return '<?= $currency_prefix ?>' + value + '<?= $currency_suffix ?>';
|
||||
}
|
||||
},
|
||||
|
||||
// Plugins configuration
|
||||
// Plugin configuration
|
||||
plugins: [
|
||||
Chartist.plugins.ctAxisTitle({
|
||||
axisX: {
|
||||
@@ -104,41 +106,45 @@
|
||||
}
|
||||
}),
|
||||
|
||||
<?php
|
||||
$currency_symbol = esc($config['currency_symbol'], 'js');
|
||||
$currency_prefix = '';
|
||||
$currency_suffix = '';
|
||||
|
||||
if ($show_currency) {
|
||||
if (is_right_side_currency_symbol()) {
|
||||
$currency_suffix = $currency_symbol;
|
||||
} else {
|
||||
$currency_prefix = $currency_symbol;
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
Chartist.plugins.ctPointLabels({
|
||||
textAnchor: 'middle',
|
||||
labelInterpolationFnc: function(value) {
|
||||
<?php
|
||||
if ($show_currency) {
|
||||
if (is_right_side_currency_symbol()) {
|
||||
?>
|
||||
return value + '<?= esc($config['currency_symbol'], 'js') ?>';
|
||||
<?php } else { ?>
|
||||
return '<?= esc($config['currency_symbol'], 'js') ?>' + value;
|
||||
<?php
|
||||
}
|
||||
} else {
|
||||
?>
|
||||
return value;
|
||||
<?php } ?>
|
||||
return '<?= $currency_prefix ?>' + value + '<?= $currency_suffix ?>';
|
||||
}
|
||||
}),
|
||||
|
||||
<?php
|
||||
$currency_symbol = esc($config['currency_symbol'], 'js');
|
||||
$currency_prefix = '';
|
||||
$currency_suffix = '';
|
||||
|
||||
if ($show_currency) {
|
||||
if (is_right_side_currency_symbol()) {
|
||||
$currency_suffix = $currency_symbol;
|
||||
} else {
|
||||
$currency_prefix = $currency_symbol;
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
Chartist.plugins.tooltip({
|
||||
pointClass: 'ct-tooltip-point',
|
||||
transformTooltipTextFnc: function(value) {
|
||||
<?php
|
||||
if ($show_currency) {
|
||||
if (is_right_side_currency_symbol()) {
|
||||
?>
|
||||
return value + '<?= esc($config['currency_symbol'], 'js') ?>';
|
||||
<?php } else { ?>
|
||||
return '<?= esc($config['currency_symbol'], 'js') ?>' + value;
|
||||
<?php
|
||||
}
|
||||
} else {
|
||||
?>
|
||||
return value;
|
||||
<?php } ?>
|
||||
return '<?= $currency_prefix ?>' + value + '<?= $currency_suffix ?>';
|
||||
}
|
||||
})
|
||||
]
|
||||
|
||||
@@ -31,26 +31,27 @@
|
||||
labelPosition: 'outside',
|
||||
labelDirection: 'explode',
|
||||
|
||||
<?php
|
||||
$currency_symbol = esc($config['currency_symbol'], 'js');
|
||||
$currency_prefix = '';
|
||||
$currency_suffix = '';
|
||||
|
||||
if ($show_currency) {
|
||||
if (is_right_side_currency_symbol()) {
|
||||
$currency_suffix = $currency_symbol;
|
||||
} else {
|
||||
$currency_prefix = $currency_symbol;
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
plugins: [
|
||||
Chartist.plugins.tooltip({
|
||||
transformTooltipTextFnc: function(value) {
|
||||
<?php
|
||||
if ($show_currency) {
|
||||
if (is_right_side_currency_symbol()) {
|
||||
?>
|
||||
return value + '<?= esc($config['currency_symbol'], 'js') ?>';
|
||||
<?php } else { ?>
|
||||
return '<?= esc($config['currency_symbol'], 'js') ?>' + value;
|
||||
<?php
|
||||
}
|
||||
} else {
|
||||
?>
|
||||
return value;
|
||||
<?php } ?>
|
||||
return '<?= $currency_prefix ?>' + value + '<?= $currency_suffix ?>';
|
||||
}
|
||||
})
|
||||
]
|
||||
};
|
||||
] };
|
||||
|
||||
var responsiveOptions = [
|
||||
['screen and (min-width: 640px)', {
|
||||
|
||||
@@ -63,7 +63,7 @@ if (isset($error_message)) {
|
||||
/* This line will allow to print and go back to sales automatically.
|
||||
* echo anchor('sales', '<span class="glyphicon glyphicon-print"> </span>' . lang('Common.print'), ['class' => 'btn btn-info btn-sm', 'id' => 'show_print_button', 'onclick' => 'window.print();'));
|
||||
*/
|
||||
?>
|
||||
?>
|
||||
<?php if (isset($customer_email) && !empty($customer_email)): ?>
|
||||
<a href="javascript:void(0);">
|
||||
<div class="btn btn-info btn-sm" id="show_email_button"><?= '<span class="glyphicon glyphicon-envelope"> </span>' . lang('Sales.send_invoice') ?></div>
|
||||
@@ -115,10 +115,10 @@ if (isset($error_message)) {
|
||||
<tr>
|
||||
<th><?= lang('Sales.item_number') ?></th>
|
||||
<?php
|
||||
$invoice_columns = 6;
|
||||
if ($include_hsn) {
|
||||
$invoice_columns += 1;
|
||||
?>
|
||||
$invoice_columns = 6;
|
||||
if ($include_hsn) {
|
||||
$invoice_columns += 1;
|
||||
?>
|
||||
<th><?= lang('Sales.hsn') ?></th>
|
||||
<?php } ?>
|
||||
<th><?= lang('Sales.item_name') ?></th>
|
||||
@@ -126,9 +126,9 @@ if (isset($error_message)) {
|
||||
<th><?= lang('Sales.price') ?></th>
|
||||
<th><?= lang('Sales.discount') ?></th>
|
||||
<?php
|
||||
if ($discount > 0) {
|
||||
$invoice_columns += 1;
|
||||
?>
|
||||
if ($discount > 0) {
|
||||
$invoice_columns += 1;
|
||||
?>
|
||||
<th><?= lang('Sales.customer_discount') ?></th>
|
||||
<?php } ?>
|
||||
<th><?= lang('Sales.total') ?></th>
|
||||
@@ -137,7 +137,7 @@ if (isset($error_message)) {
|
||||
<?php
|
||||
foreach ($cart as $line => $item) {
|
||||
if ($item['print_option'] == PRINT_YES) {
|
||||
?>
|
||||
?>
|
||||
<tr class="item-row">
|
||||
<td><?= esc($item['item_number']) ?></td>
|
||||
<?php if ($include_hsn): ?>
|
||||
@@ -146,7 +146,7 @@ if (isset($error_message)) {
|
||||
<td class="item-name"><?= ($item['is_serialized'] || $item['allow_alt_description']) && !empty($item['description']) ? esc($item['description']) : esc($item['name'] . ' ' . $item['attribute_values']) ?></td>
|
||||
<td style="text-align: center;"><?= to_quantity_decimals($item['quantity']) ?></td>
|
||||
<td><?= to_currency($item['price']) ?></td>
|
||||
<td style="height: center;"><?= ($item['discount_type'] == FIXED) ? to_currency($item['discount']) : to_decimals($item['discount']) . '%' ?></td>
|
||||
<td style="text-align: center;"><?= ($item['discount_type'] == FIXED) ? to_currency($item['discount']) : to_decimals($item['discount']) . '%' ?></td>
|
||||
<?php if ($discount > 0): ?>
|
||||
<td style="text-align: center;"><?= to_currency($item['discounted_total'] / $item['quantity']) ?></td>
|
||||
<?php endif; ?>
|
||||
@@ -155,13 +155,13 @@ if (isset($error_message)) {
|
||||
<?php if ($item['is_serialized']) { ?>
|
||||
<tr class="item-row">
|
||||
<td class="item-description" colspan="<?= $invoice_columns - 1 ?>"></td>
|
||||
<td style="text-align: center;"><?= esc($item['serialnumber']) // TODO: serialnumber does not match variable naming conventions for this project ?></td>
|
||||
<td style="text-align: center;"><?= esc($item['serialnumber']) // TODO: `serialnumber` does not match variable naming conventions for this project. Should be `serialNumber`?></td>
|
||||
</tr>
|
||||
<?php
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
?>
|
||||
|
||||
<tr>
|
||||
<td class="blank" colspan="<?= $invoice_columns ?>" style="text-align: center;"><?= ' ' ?></td>
|
||||
@@ -188,13 +188,13 @@ if (isset($error_message)) {
|
||||
</tr>
|
||||
|
||||
<?php
|
||||
$only_sale_check = false;
|
||||
$show_giftcard_remainder = false;
|
||||
foreach ($payments as $payment_id => $payment) {
|
||||
$only_sale_check |= $payment['payment_type'] == lang('Sales.check');
|
||||
$splitpayment = explode(':', $payment['payment_type']); // TODO: $splitpayment does not meet variable naming standards for this project
|
||||
$show_giftcard_remainder |= $splitpayment[0] == lang('Sales.giftcard');
|
||||
?>
|
||||
$only_sale_check = false;
|
||||
$show_giftcard_remainder = false;
|
||||
foreach ($payments as $payment_id => $payment) {
|
||||
$only_sale_check |= $payment['payment_type'] == lang('Sales.check');
|
||||
$splitpayment = explode(':', $payment['payment_type']); // TODO: $splitpayment does not meet variable naming standards for this project
|
||||
$show_giftcard_remainder |= $splitpayment[0] == lang('Sales.giftcard');
|
||||
?>
|
||||
<tr>
|
||||
<td colspan="<?= $invoice_columns - 3 ?>" class="blank"> </td>
|
||||
<td colspan="2" class="total-line"><?= esc($splitpayment[0]) ?></td>
|
||||
|
||||
@@ -20,171 +20,167 @@
|
||||
?>
|
||||
|
||||
<!doctype html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title><?= lang('Sales.email_receipt') ?></title>
|
||||
<link rel="stylesheet" href="<?= base_url('css/invoice_email.css') ?>">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<?php
|
||||
if (isset($error_message)) {
|
||||
echo '<div class="alert alert-dismissible alert-danger">' . esc($error_message) . '</div>';
|
||||
exit;
|
||||
}
|
||||
?>
|
||||
|
||||
<div id="page-wrap">
|
||||
<div id="header"><?= lang('Sales.invoice') ?></div>
|
||||
<table id="info">
|
||||
<tr>
|
||||
<td id="logo">
|
||||
<?php if ($config['company_logo'] != '') { ?>
|
||||
<img id="image" src="data:<?= esc($mimetype, 'attr') ?>;base64,<?= base64_encode(file_get_contents('uploads/' . esc($config['company_logo']))) ?>" alt="company_logo">
|
||||
<?php } ?>
|
||||
</td>
|
||||
<td id="customer-title" id="customer">
|
||||
<?php if (isset($customer)) {
|
||||
echo nl2br(esc($customer_info));
|
||||
} ?>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td id="company-title" id="company">
|
||||
<?= esc($config['company']) ?><br>
|
||||
<?= nl2br(esc($company_info)) ?>
|
||||
</td>
|
||||
<td id="meta">
|
||||
<table id="meta-content" align="right">
|
||||
<tr>
|
||||
<td class="meta-head"><?= lang('Sales.invoice_number') ?></td>
|
||||
<td><?= esc($invoice_number) ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="meta-head"><?= lang('Common.date') ?></td>
|
||||
<td><?= esc($transaction_date) ?></td>
|
||||
</tr>
|
||||
<?php if ($amount_due > 0) { ?>
|
||||
<tr>
|
||||
<td class="meta-head"><?= lang('Sales.amount_due') ?></td>
|
||||
<td class="due"><?= to_currency($total) ?></td>
|
||||
</tr>
|
||||
<?php } ?>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<table id="items">
|
||||
<tr>
|
||||
<th><?= lang('Sales.item_number') ?></th>
|
||||
<th><?= lang('Sales.item_name') ?></th>
|
||||
<th><?= lang('Sales.quantity') ?></th>
|
||||
<th><?= lang('Sales.price') ?></th>
|
||||
<th><?= lang('Sales.discount') ?></th>
|
||||
<?php
|
||||
$invoice_columns = 6;
|
||||
if ($discount > 0) {
|
||||
$invoice_columns = $invoice_columns + 1;
|
||||
?>
|
||||
<th><?= lang('Sales.customer_discount') ?></th>
|
||||
<?php } ?>
|
||||
<th><?= lang('Sales.total') ?></th>
|
||||
</tr>
|
||||
|
||||
<?php
|
||||
foreach ($cart as $line => $item) {
|
||||
if ($item['print_option'] == PRINT_YES) {
|
||||
?>
|
||||
<tr class="item-row">
|
||||
<td><?= esc($item['item_number']) ?></td>
|
||||
<td class="item-name"><?= esc($item['name']) ?></td>
|
||||
<td><?= to_quantity_decimals($item['quantity']) ?></td>
|
||||
<td><?= to_currency($item['price']) ?></td>
|
||||
<td><?= ($item['discount_type'] == FIXED) ? to_currency($item['discount']) : to_decimals($item['discount']) . '%' ?></td>
|
||||
<?php if ($item['discount'] > 0): ?>
|
||||
<td><?= to_currency($item['discounted_total'] / $item['quantity']) ?></td>
|
||||
<?php endif; ?>
|
||||
<td class="total-line"><?= to_currency($item['discounted_total']) ?></td>
|
||||
</tr>
|
||||
<?php
|
||||
}
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title><?= lang('Sales.email_receipt') ?></title>
|
||||
<link rel="stylesheet" href="<?= base_url('css/invoice_email.css') ?>">
|
||||
</head>
|
||||
<body>
|
||||
<?php
|
||||
if (isset($error_message)) {
|
||||
echo '<div class="alert alert-dismissible alert-danger">' . esc($error_message) . '</div>';
|
||||
exit;
|
||||
}
|
||||
?>
|
||||
?>
|
||||
|
||||
<tr>
|
||||
<td colspan="<?= $invoice_columns ?>" align="center"><?= ' ' ?></td>
|
||||
</tr>
|
||||
<div id="page-wrap">
|
||||
<div id="header"><?= lang('Sales.invoice') ?></div>
|
||||
<table id="info">
|
||||
<tr>
|
||||
<td id="logo">
|
||||
<?php if ($config['company_logo'] != '') { ?>
|
||||
<img id="image" src="data:<?= esc($mimetype, 'attr') ?>;base64,<?= base64_encode(file_get_contents('uploads/' . esc($config['company_logo']))) ?>" alt="company_logo">
|
||||
<?php } ?>
|
||||
</td>
|
||||
<td id="customer-title" id="customer">
|
||||
<?php if (isset($customer)) {
|
||||
echo nl2br(esc($customer_info));
|
||||
} ?>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td id="company-title" id="company">
|
||||
<?= esc($config['company']) ?><br>
|
||||
<?= nl2br(esc($company_info)) ?>
|
||||
</td>
|
||||
<td id="meta">
|
||||
<table id="meta-content" style="text-align: right;">
|
||||
<tr>
|
||||
<td class="meta-head"><?= lang('Sales.invoice_number') ?></td>
|
||||
<td><?= esc($invoice_number) ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="meta-head"><?= lang('Common.date') ?></td>
|
||||
<td><?= esc($transaction_date) ?></td>
|
||||
</tr>
|
||||
<?php if ($amount_due > 0) { ?>
|
||||
<tr>
|
||||
<td class="meta-head"><?= lang('Sales.amount_due') ?></td>
|
||||
<td class="due"><?= to_currency($total) ?></td>
|
||||
</tr>
|
||||
<?php } ?>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<tr>
|
||||
<td colspan="<?= $invoice_columns - 3 ?>" class="blank"> </td>
|
||||
<td colspan="2" class="total-line"><?= lang('Sales.sub_total') ?></td>
|
||||
<td id="subtotal" class="total-value"><?= to_currency($subtotal) ?></td>
|
||||
</tr>
|
||||
<table id="items">
|
||||
<tr>
|
||||
<th><?= lang('Sales.item_number') ?></th>
|
||||
<th><?= lang('Sales.item_name') ?></th>
|
||||
<th><?= lang('Sales.quantity') ?></th>
|
||||
<th><?= lang('Sales.price') ?></th>
|
||||
<th><?= lang('Sales.discount') ?></th>
|
||||
<?php
|
||||
$invoice_columns = 6;
|
||||
if ($discount > 0) {
|
||||
$invoice_columns = $invoice_columns + 1;
|
||||
?>
|
||||
<th><?= lang('Sales.customer_discount') ?></th>
|
||||
<?php } ?>
|
||||
<th><?= lang('Sales.total') ?></th>
|
||||
</tr>
|
||||
|
||||
<?php
|
||||
foreach ($cart as $line => $item) {
|
||||
if ($item['print_option'] == PRINT_YES) {
|
||||
?>
|
||||
<tr class="item-row">
|
||||
<td><?= esc($item['item_number']) ?></td>
|
||||
<td class="item-name"><?= esc($item['name']) ?></td>
|
||||
<td><?= to_quantity_decimals($item['quantity']) ?></td>
|
||||
<td><?= to_currency($item['price']) ?></td>
|
||||
<td><?= ($item['discount_type'] == FIXED) ? to_currency($item['discount']) : to_decimals($item['discount']) . '%' ?></td>
|
||||
<?php if ($discount > 0): ?>
|
||||
<td><?= to_currency($item['discounted_total'] / $item['quantity']) ?></td>
|
||||
<?php endif; ?>
|
||||
<td class="total-line"><?= to_currency($item['discounted_total']) ?></td>
|
||||
</tr>
|
||||
<?php
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
<tr>
|
||||
<td colspan="<?= $invoice_columns ?>" style="text-align: center;"><?= ' ' ?></td>
|
||||
</tr>
|
||||
|
||||
<?php foreach ($taxes as $tax_group_index => $tax) { ?>
|
||||
<tr>
|
||||
<td colspan="<?= $invoice_columns - 3 ?>" class="blank"> </td>
|
||||
<td colspan="2" class="total-line"><?= (float)$tax['tax_rate'] . '% ' . esc($tax['tax_group']) ?></td>
|
||||
<td id="taxes" class="total-value"><?= to_currency_tax($tax['sale_tax_amount']) ?></td>
|
||||
<td colspan="2" class="total-line"><?= lang('Sales.sub_total') ?></td>
|
||||
<td id="subtotal" class="total-value"><?= to_currency($subtotal) ?></td>
|
||||
</tr>
|
||||
<?php } ?>
|
||||
|
||||
<tr>
|
||||
<td colspan="<?= $invoice_columns - 3 ?>" class="blank"> </td>
|
||||
<td colspan="2" class="total-line"><?= lang('Sales.total') ?></td>
|
||||
<td id="total" class="total-value"><?= to_currency($total) ?></td>
|
||||
</tr>
|
||||
<?php foreach ($taxes as $tax_group_index => $tax) { ?>
|
||||
<tr>
|
||||
<td colspan="<?= $invoice_columns - 3 ?>" class="blank"> </td>
|
||||
<td colspan="2" class="total-line"><?= (float)$tax['tax_rate'] . '% ' . esc($tax['tax_group']) ?></td>
|
||||
<td id="taxes" class="total-value"><?= to_currency_tax($tax['sale_tax_amount']) ?></td>
|
||||
</tr>
|
||||
<?php } ?>
|
||||
|
||||
<?php
|
||||
$only_sale_check = false;
|
||||
$show_giftcard_remainder = false;
|
||||
|
||||
foreach ($payments as $payment_id => $payment) {
|
||||
$only_sale_check |= $payment['payment_type'] == lang('Sales.check');
|
||||
$splitpayment = explode(':', $payment['payment_type']); // TODO: $splitpayment does not meet the variable naming conventions for this project
|
||||
$show_giftcard_remainder |= $splitpayment[0] == lang('Sales.giftcard');
|
||||
?>
|
||||
<tr>
|
||||
<td colspan="<?= $invoice_columns - 3 ?>" class="blank"> </td>
|
||||
<td colspan="2" class="total-line"><?= esc($splitpayment[0]) ?></td>
|
||||
<td class="total-value"><?= to_currency(-$payment['payment_amount']) ?></td>
|
||||
<td colspan="2" class="total-line"><?= lang('Sales.total') ?></td>
|
||||
<td id="total" class="total-value"><?= to_currency($total) ?></td>
|
||||
</tr>
|
||||
<?php } ?>
|
||||
|
||||
<?php if (isset($cur_giftcard_value) && $show_giftcard_remainder) { ?>
|
||||
<tr>
|
||||
<td colspan="<?= $invoice_columns - 3 ?>" class="blank"> </td>
|
||||
<td colspan="2" class="total-line"><?= lang('Sales.giftcard_balance') ?></td>
|
||||
<td class="total-value" id="giftcard"><?= to_currency($cur_giftcard_value) ?></td>
|
||||
</tr>
|
||||
<?php } ?>
|
||||
<?php
|
||||
$only_sale_check = false;
|
||||
$show_giftcard_remainder = false;
|
||||
|
||||
<?php if (!empty($payments)) { ?>
|
||||
<tr>
|
||||
<td colspan="<?= $invoice_columns - 3 ?>" class="blank"> </td>
|
||||
<td colspan="2" class="total-line"><?= lang($amount_change >= 0 ? ($only_sale_check ? 'Sales.check_balance' : 'Sales.change_due') : 'Sales.amount_due') ?></td>
|
||||
<td class="total-value"><?= to_currency($amount_change) ?></td>
|
||||
</tr>
|
||||
<?php } ?>
|
||||
</table>
|
||||
foreach ($payments as $payment_id => $payment) {
|
||||
$only_sale_check |= $payment['payment_type'] == lang('Sales.check');
|
||||
$splitpayment = explode(':', $payment['payment_type']); // TODO: $splitpayment does not meet the variable naming conventions for this project
|
||||
$show_giftcard_remainder |= $splitpayment[0] == lang('Sales.giftcard');
|
||||
?>
|
||||
<tr>
|
||||
<td colspan="<?= $invoice_columns - 3 ?>" class="blank"> </td>
|
||||
<td colspan="2" class="total-line"><?= esc($splitpayment[0]) ?></td>
|
||||
<td class="total-value"><?= to_currency(-$payment['payment_amount']) ?></td>
|
||||
</tr>
|
||||
<?php } ?>
|
||||
|
||||
<div id="terms">
|
||||
<div id="sale_return_policy">
|
||||
<h5>
|
||||
<span><?= nl2br($config['payment_message']) ?></span>
|
||||
<span><?= lang('Sales.comments') . ': ' . (empty($comments) ? esc($config['invoice_default_comments']) : esc($comments)) ?></span>
|
||||
</h5>
|
||||
<?= nl2br(esc($config['return_policy'])) ?>
|
||||
</div>
|
||||
<div id="barcode">
|
||||
<img alt="<?= esc($sale_id) ?>" src="data:image/svg+xml;base64,<?= base64_encode($barcode) ?>"><br>
|
||||
<?= esc($sale_id) ?>
|
||||
<?php if (isset($cur_giftcard_value) && $show_giftcard_remainder) { ?>
|
||||
<tr>
|
||||
<td colspan="<?= $invoice_columns - 3 ?>" class="blank"> </td>
|
||||
<td colspan="2" class="total-line"><?= lang('Sales.giftcard_balance') ?></td>
|
||||
<td class="total-value" id="giftcard"><?= to_currency($cur_giftcard_value) ?></td>
|
||||
</tr>
|
||||
<?php } ?>
|
||||
|
||||
<?php if (!empty($payments)) { ?>
|
||||
<tr>
|
||||
<td colspan="<?= $invoice_columns - 3 ?>" class="blank"> </td>
|
||||
<td colspan="2" class="total-line"><?= lang($amount_change >= 0 ? ($only_sale_check ? 'Sales.check_balance' : 'Sales.change_due') : 'Sales.amount_due') ?></td>
|
||||
<td class="total-value"><?= to_currency($amount_change) ?></td>
|
||||
</tr>
|
||||
<?php } ?>
|
||||
</table>
|
||||
|
||||
<div id="terms">
|
||||
<div id="sale_return_policy">
|
||||
<h5>
|
||||
<span><?= nl2br(esc($config['payment_message'])) ?></span>
|
||||
<span><?= lang('Sales.comments') . ': ' . (empty($comments) ? esc($config['invoice_default_comments']) : esc($comments)) ?></span>
|
||||
</h5>
|
||||
<?= nl2br(esc($config['return_policy'])) ?>
|
||||
</div>
|
||||
<div id="barcode">
|
||||
<img alt="<?= esc($sale_id) ?>" src="data:image/svg+xml;base64,<?= base64_encode($barcode) ?>"><br>
|
||||
<?= esc($sale_id) ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -73,7 +73,7 @@
|
||||
<?= view('partial/print_receipt', ['print_after_sale' => false, 'selected_printer' => 'takings_printer']) ?>
|
||||
|
||||
<div id="title_bar" class="print_hide btn-toolbar">
|
||||
<button onclick="javascript:printdoc()" class="btn btn-info btn-sm pull-right">
|
||||
<button onclick="printdoc()" class="btn btn-info btn-sm pull-right">
|
||||
<span class="glyphicon glyphicon-print"> </span><?= lang('Common.print') ?>
|
||||
</button>
|
||||
<?= anchor("sales", '<span class="glyphicon glyphicon-shopping-cart"> </span>' . lang('Sales.register'), ['class' => 'btn btn-info btn-sm pull-right', 'id' => 'show_sales_button']) ?>
|
||||
|
||||
@@ -58,7 +58,7 @@
|
||||
</div>
|
||||
</td>
|
||||
<td id="meta">
|
||||
<table id="meta-content" align="right">
|
||||
<table id="meta-content" style="text-align: right;">
|
||||
<tr>
|
||||
<td class="meta-head"><?= lang('Sales.quote_number') ?> </td>
|
||||
<td><?= esc($quote_number) ?></td>
|
||||
@@ -116,7 +116,7 @@
|
||||
?>
|
||||
|
||||
<tr>
|
||||
<td colspan="<?= $quote_columns ?>" align="center"><?= ' ' //TODO: Replace the php echo for nbsp with just straight html? ?></td>
|
||||
<td colspan="<?= $quote_columns ?>" style="text-align: center;"><?= ' ' //TODO: Replace the php echo for nbsp with just straight html? ?></td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
|
||||
@@ -173,12 +173,12 @@ helper('url');
|
||||
</td>
|
||||
<?php if ($item['item_type'] == ITEM_TEMP) { ?>
|
||||
<td><?= form_input(['name' => 'item_number', 'id' => 'item_number', 'class' => 'form-control input-sm', 'value' => $item['item_number'], 'tabindex' => ++$tabindex]) ?></td>
|
||||
<td style="align: center;">
|
||||
<td style="text-align: center;">
|
||||
<?= form_input(['name' => 'name', 'id' => 'name', 'class' => 'form-control input-sm', 'value' => $item['name'], 'tabindex' => ++$tabindex]) ?>
|
||||
</td>
|
||||
<?php } else { ?>
|
||||
<td><?= esc($item['item_number']) ?></td>
|
||||
<td style="align: center;">
|
||||
<td style="text-align: center;">
|
||||
<?= esc($item['name']) . ' ' . implode(' ', [$item['attribute_values'], $item['attribute_dtvalues']]) ?>
|
||||
<br>
|
||||
<?php if ($item['stock_type'] == '0'): echo '[' . to_quantity_decimals($item['in_stock']) . ' in ' . esc($item['stock_name']) . ']';
|
||||
@@ -236,7 +236,7 @@ helper('url');
|
||||
<tr>
|
||||
<?php if ($item['item_type'] == ITEM_TEMP) { ?>
|
||||
<td><?= form_input(['type' => 'hidden', 'name' => 'item_id', 'value' => $item['item_id']]) ?></td>
|
||||
<td style="align: center;" colspan="6">
|
||||
<td style="text-align: center;" colspan="6">
|
||||
<?= form_input(['name' => 'item_description', 'id' => 'item_description', 'class' => 'form-control input-sm', 'value' => $item['description'], 'tabindex' => ++$tabindex]) ?>
|
||||
</td>
|
||||
<td> </td>
|
||||
|
||||
@@ -55,7 +55,7 @@
|
||||
<pre><?= esc($company_info) ?></pre>
|
||||
</td>
|
||||
<td id="meta">
|
||||
<table align="right">
|
||||
<table style="text-align: right;">
|
||||
<tr>
|
||||
<td class="meta-head"><?= lang('Sales.work_order_number') ?> </td>
|
||||
<td><?= esc($work_order_number) ?></td>
|
||||
@@ -103,7 +103,7 @@
|
||||
?>
|
||||
|
||||
<tr>
|
||||
<td colspan="6" align="center"><?= ' ' ?></td>
|
||||
<td colspan="6" style="text-align: center;"><?= ' ' ?></td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
|
||||
@@ -79,24 +79,18 @@
|
||||
$('input[name="tax_category[]"]').each(function() {
|
||||
value_count = $(this).val() == value ? value_count + 1 : value_count;
|
||||
});
|
||||
if (value_count > 1) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
return value_count <= 1;
|
||||
|
||||
}, "<?= lang('Taxes.tax_category_duplicate') ?>");
|
||||
|
||||
$.validator.addMethod('validateTaxCategoryCharacters', function(value, element) {
|
||||
if ((value.indexOf('_') != -1)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
return (value.indexOf('_') == -1);
|
||||
|
||||
}, "<?= lang('Taxes.tax_category_invalid_chars') ?>");
|
||||
|
||||
$.validator.addMethod('requireTaxCategory', function(value, element) {
|
||||
if (value.trim() == '') {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
return value.trim() != '';
|
||||
|
||||
}, "<?= lang('Taxes.tax_category_required') ?>");
|
||||
|
||||
$('#tax_categories_form').validate($.extend(form_support.handler, {
|
||||
@@ -120,8 +114,8 @@
|
||||
}));
|
||||
|
||||
<?php
|
||||
$i = 0;
|
||||
foreach ($tax_categories as $tax_category => $tax_category_data) {
|
||||
$i = 0;
|
||||
foreach ($tax_categories as $tax_category => $tax_category_data) {
|
||||
?>
|
||||
$('<?= '#tax_category_' . ++$i ?>').rules("add", {
|
||||
requireTaxCategory: true,
|
||||
|
||||
@@ -79,24 +79,18 @@
|
||||
$("input[name='tax_code[]']").each(function() {
|
||||
value_count = $(this).val() == value ? value_count + 1 : value_count;
|
||||
});
|
||||
if (value_count > 1) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
return value_count <= 1;
|
||||
|
||||
}, "<?= lang('Taxes.tax_code_duplicate') ?>");
|
||||
|
||||
$.validator.addMethod('validateTaxCodeCharacters', function(value, element) {
|
||||
if ((value.indexOf('_') != -1)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
return (value.indexOf('_') == -1);
|
||||
|
||||
}, "<?= lang('Taxes.tax_code_invalid_chars') ?>");
|
||||
|
||||
$.validator.addMethod('requireTaxCode', function(value, element) {
|
||||
if (value.trim() == '') {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
return value.trim() != '';
|
||||
|
||||
}, "<?= lang('Taxes.tax_code_required') ?>");
|
||||
|
||||
$('#tax_codes_form').validate($.extend(form_support.handler, {
|
||||
|
||||
@@ -83,24 +83,18 @@
|
||||
$("input[name='jurisdiction_name[]']").each(function() {
|
||||
value_count = $(this).val() == value ? value_count + 1 : value_count;
|
||||
});
|
||||
if (value_count > 1) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
return value_count <= 1;
|
||||
|
||||
}, "<?= lang('Taxes.tax_jurisdiction_duplicate') ?>");
|
||||
|
||||
$.validator.addMethod('validateTaxJurisdictionCharacters', function(value, element) {
|
||||
if ((value.indexOf('_') != -1)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
return (value.indexOf('_') == -1);
|
||||
|
||||
}, "<?= lang('Taxes.tax_jurisdiction_invalid_chars') ?>");
|
||||
|
||||
$.validator.addMethod('requireTaxJurisdiction', function(value, element) {
|
||||
if (value.trim() == '') {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
return value.trim() != '';
|
||||
|
||||
}, "<?= lang('Taxes.tax_jurisdiction_required') ?>");
|
||||
|
||||
$('#tax_jurisdictions_form').validate($.extend(form_support.handler, {
|
||||
|
||||
@@ -32,11 +32,11 @@
|
||||
},
|
||||
"require": {
|
||||
"ext-intl": "*",
|
||||
"php": "^8.1",
|
||||
"codeigniter4/framework": "4.6.3",
|
||||
"php": "^8.2",
|
||||
"codeigniter4/framework": "4.7.2",
|
||||
"dompdf/dompdf": "^2.0.3",
|
||||
"ezyang/htmlpurifier": "^4.17",
|
||||
"laminas/laminas-escaper": "2.17.0",
|
||||
"laminas/laminas-escaper": "2.18.0",
|
||||
"paragonie/random_compat": "^2.0.21",
|
||||
"picqer/php-barcode-generator": "^2.4.0",
|
||||
"tamtamchik/namecase": "^3.0.0"
|
||||
|
||||
43
composer.lock
generated
43
composer.lock
generated
@@ -4,40 +4,41 @@
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "9cf76605c1b45f81c547fefc5a29f101",
|
||||
"content-hash": "e95f6e5e86d323370ddb0df57c4d3fb3",
|
||||
"packages": [
|
||||
{
|
||||
"name": "codeigniter4/framework",
|
||||
"version": "v4.6.3",
|
||||
"version": "v4.7.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/codeigniter4/framework.git",
|
||||
"reference": "68d1a5896106f869452dd369a690dd5bc75160fb"
|
||||
"reference": "b3359be849be29394660c3aed909aa32b6c45cf6"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/codeigniter4/framework/zipball/68d1a5896106f869452dd369a690dd5bc75160fb",
|
||||
"reference": "68d1a5896106f869452dd369a690dd5bc75160fb",
|
||||
"url": "https://api.github.com/repos/codeigniter4/framework/zipball/b3359be849be29394660c3aed909aa32b6c45cf6",
|
||||
"reference": "b3359be849be29394660c3aed909aa32b6c45cf6",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-intl": "*",
|
||||
"ext-mbstring": "*",
|
||||
"laminas/laminas-escaper": "^2.17",
|
||||
"php": "^8.1",
|
||||
"laminas/laminas-escaper": "^2.18",
|
||||
"php": "^8.2",
|
||||
"psr/log": "^3.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"codeigniter/coding-standard": "^1.7",
|
||||
"fakerphp/faker": "^1.24",
|
||||
"friendsofphp/php-cs-fixer": "^3.47.1",
|
||||
"kint-php/kint": "^6.0",
|
||||
"kint-php/kint": "^6.1",
|
||||
"mikey179/vfsstream": "^1.6.12",
|
||||
"nexusphp/cs-config": "^3.6",
|
||||
"phpunit/phpunit": "^10.5.16 || ^11.2",
|
||||
"predis/predis": "^3.0"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-apcu": "If you use Cache class ApcuHandler",
|
||||
"ext-curl": "If you use CURLRequest class",
|
||||
"ext-dom": "If you use TestResponse",
|
||||
"ext-exif": "If you run Image class tests",
|
||||
@@ -49,7 +50,9 @@
|
||||
"ext-memcached": "If you use Cache class MemcachedHandler with Memcached",
|
||||
"ext-mysqli": "If you use MySQL",
|
||||
"ext-oci8": "If you use Oracle Database",
|
||||
"ext-pcntl": "If you use Signals",
|
||||
"ext-pgsql": "If you use PostgreSQL",
|
||||
"ext-posix": "If you use Signals",
|
||||
"ext-readline": "Improves CLI::input() usability",
|
||||
"ext-redis": "If you use Cache class RedisHandler",
|
||||
"ext-simplexml": "If you format XML",
|
||||
@@ -78,7 +81,7 @@
|
||||
"slack": "https://codeigniterchat.slack.com",
|
||||
"source": "https://github.com/codeigniter4/CodeIgniter4"
|
||||
},
|
||||
"time": "2025-08-02T13:36:13+00:00"
|
||||
"time": "2026-03-24T18:26:09+00:00"
|
||||
},
|
||||
{
|
||||
"name": "dompdf/dompdf",
|
||||
@@ -205,32 +208,32 @@
|
||||
},
|
||||
{
|
||||
"name": "laminas/laminas-escaper",
|
||||
"version": "2.17.0",
|
||||
"version": "2.18.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/laminas/laminas-escaper.git",
|
||||
"reference": "df1ef9503299a8e3920079a16263b578eaf7c3ba"
|
||||
"reference": "06f211dfffff18d91844c1f55250d5d13c007e18"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/laminas/laminas-escaper/zipball/df1ef9503299a8e3920079a16263b578eaf7c3ba",
|
||||
"reference": "df1ef9503299a8e3920079a16263b578eaf7c3ba",
|
||||
"url": "https://api.github.com/repos/laminas/laminas-escaper/zipball/06f211dfffff18d91844c1f55250d5d13c007e18",
|
||||
"reference": "06f211dfffff18d91844c1f55250d5d13c007e18",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-ctype": "*",
|
||||
"ext-mbstring": "*",
|
||||
"php": "~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0"
|
||||
"php": "~8.2.0 || ~8.3.0 || ~8.4.0 || ~8.5.0"
|
||||
},
|
||||
"conflict": {
|
||||
"zendframework/zend-escaper": "*"
|
||||
},
|
||||
"require-dev": {
|
||||
"infection/infection": "^0.29.8",
|
||||
"laminas/laminas-coding-standard": "~3.0.1",
|
||||
"phpunit/phpunit": "^10.5.45",
|
||||
"psalm/plugin-phpunit": "^0.19.2",
|
||||
"vimeo/psalm": "^6.6.2"
|
||||
"infection/infection": "^0.31.0",
|
||||
"laminas/laminas-coding-standard": "~3.1.0",
|
||||
"phpunit/phpunit": "^11.5.42",
|
||||
"psalm/plugin-phpunit": "^0.19.5",
|
||||
"vimeo/psalm": "^6.13.1"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
@@ -262,7 +265,7 @@
|
||||
"type": "community_bridge"
|
||||
}
|
||||
],
|
||||
"time": "2025-05-06T19:29:36+00:00"
|
||||
"time": "2025-10-14T18:31:13+00:00"
|
||||
},
|
||||
{
|
||||
"name": "masterminds/html5",
|
||||
|
||||
12
preload.php
12
preload.php
@@ -9,6 +9,9 @@
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
use CodeIgniter\Boot;
|
||||
use Config\Paths;
|
||||
|
||||
/*
|
||||
*---------------------------------------------------------------
|
||||
* Sample file for Preloading
|
||||
@@ -54,6 +57,7 @@ class preload
|
||||
'/system/Config/Routes.php',
|
||||
'/system/Language/',
|
||||
'/system/bootstrap.php',
|
||||
'/system/util_bootstrap.php',
|
||||
'/system/rewrite.php',
|
||||
'/Views/',
|
||||
// Errors occur.
|
||||
@@ -69,10 +73,10 @@ class preload
|
||||
|
||||
private function loadAutoloader(): void
|
||||
{
|
||||
$paths = new Config\Paths();
|
||||
$paths = new Paths();
|
||||
require rtrim($paths->systemDirectory, '\\/ ') . DIRECTORY_SEPARATOR . 'Boot.php';
|
||||
|
||||
CodeIgniter\Boot::preload($paths);
|
||||
Boot::preload($paths);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -97,7 +101,9 @@ class preload
|
||||
}
|
||||
|
||||
require_once $file[0];
|
||||
echo 'Loaded: ' . $file[0] . "\n";
|
||||
// Uncomment only for debugging (to inspect which files are included).
|
||||
// Never use this in production - preload scripts must not generate output.
|
||||
// echo 'Loaded: ' . $file[0] . "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user