mirror of
https://github.com/opensourcepos/opensourcepos.git
synced 2026-05-25 08:44:42 -04:00
Compare commits
4 Commits
fix/4559-m
...
issue-4459
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
196d1e4d3a | ||
|
|
a4c0d081a2 | ||
|
|
e7daa7a9db | ||
|
|
baf135dd42 |
1
.github/workflows/build-release.yml
vendored
1
.github/workflows/build-release.yml
vendored
@@ -123,7 +123,6 @@ jobs:
|
||||
.
|
||||
!.git
|
||||
!node_modules
|
||||
include-hidden-files: true
|
||||
retention-days: 1
|
||||
|
||||
docker:
|
||||
|
||||
33
CHANGELOG.md
33
CHANGELOG.md
@@ -1,4 +1,5 @@
|
||||
[unreleased]: https://github.com/opensourcepos/opensourcepos/compare/3.4.1...HEAD
|
||||
[unreleased]: https://github.com/opensourcepos/opensourcepos/compare/3.4.0...HEAD
|
||||
[3.4.2]: https://github.com/opensourcepos/opensourcepos/compare/3.4.1...3.4.2
|
||||
[3.4.1]: https://github.com/opensourcepos/opensourcepos/compare/3.4.0...3.4.1
|
||||
[3.4.0]: https://github.com/opensourcepos/opensourcepos/compare/3.3.9...3.4.0
|
||||
[3.3.9]: https://github.com/opensourcepos/opensourcepos/compare/3.3.8...3.3.9
|
||||
@@ -33,36 +34,10 @@ All notable changes to this project will be documented in this file.
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
## [3.4.1] - 2025-06-05
|
||||
- Feature: PSR-12 Compliant Indentation by @objecttothis in ([#4196](https://github.com/opensourcepos/opensourcepos/pull/4196))
|
||||
- Add .env to dist zip by @jekkos in ([#4199](https://github.com/opensourcepos/opensourcepos/pull/4199))
|
||||
- Add CI4 coding standards linter ([#3708](https://github.com/opensourcepos/opensourcepos/issues/3708)) by @jekkos in ([#4198](https://github.com/opensourcepos/opensourcepos/pull/4198))
|
||||
- Bump canvg from 3.0.10 to 3.0.11 by @dependabot in ([#4189](https://github.com/opensourcepos/opensourcepos/pull/4189))
|
||||
- Bump jspdf and jspdf-autotable by @dependabot in ([#4190](https://github.com/opensourcepos/opensourcepos/pull/4190))
|
||||
- Feature bump ci to 4.6.0 by @objecttothis in ([#4197](https://github.com/opensourcepos/opensourcepos/pull/4197))
|
||||
- Add Kurdish language option to UI by @BudsieBuds in ([#4210](https://github.com/opensourcepos/opensourcepos/pull/4210))
|
||||
- Convert language ku to ckb by @BudsieBuds in ([#4211](https://github.com/opensourcepos/opensourcepos/pull/4211))
|
||||
- Fix PHP 8.4 errors by @BudsieBuds in ([#4215](https://github.com/opensourcepos/opensourcepos/pull/4215))
|
||||
- Add default bootstrap to themes by @BudsieBuds in ([#4219](https://github.com/opensourcepos/opensourcepos/pull/4219))
|
||||
- Update language names by @BudsieBuds in ([#4218](https://github.com/opensourcepos/opensourcepos/pull/4218))
|
||||
- Update install docs by @BudsieBuds in ([#4217](https://github.com/opensourcepos/opensourcepos/pull/4217))
|
||||
- Convert menu icons to SVG by @BudsieBuds in ([#4220](https://github.com/opensourcepos/opensourcepos/pull/4220))
|
||||
- Enhance license handling by @BudsieBuds in ([#4223](https://github.com/opensourcepos/opensourcepos/pull/4223))
|
||||
- Fix datetime rendering ([#4226](https://github.com/opensourcepos/opensourcepos/issues/4226)) by @jekkos in ([#4227](https://github.com/opensourcepos/opensourcepos/pull/4227))
|
||||
- Fix datetime rendering by @jekkos in ([#4228](https://github.com/opensourcepos/opensourcepos/pull/4228))
|
||||
- Fix null error when sending by email a receipt of a sale that has no invoice by @diego-ramos in ([#4229](https://github.com/opensourcepos/opensourcepos/pull/4229))
|
||||
- Update Receivings.php to save form. by @odiea in ([#4231](https://github.com/opensourcepos/opensourcepos/pull/4231))
|
||||
- Update Cashups.php for ajax cashup total to work. by @odiea in ([#4238](https://github.com/opensourcepos/opensourcepos/pull/4238))
|
||||
- Coding style updates for PSR-12 compliance & improved readability by @BudsieBuds in ([#4204](https://github.com/opensourcepos/opensourcepos/pull/4204))
|
||||
- Fix Codeigniter disallowed characters error with payment types that have accents by @diego-ramos in ([#4232](https://github.com/opensourcepos/opensourcepos/pull/4232))
|
||||
- Fixed broken escape string for success & warning messages by @Franchovy in ([#4253](https://github.com/opensourcepos/opensourcepos/pull/4253))
|
||||
- Bugfix constraint migration fix by @objecttothis in ([#4230](https://github.com/opensourcepos/opensourcepos/pull/4230))
|
||||
- Fix item number lookup in sales/receivings ([#4212](https://github.com/opensourcepos/opensourcepos/issues/4212)) by @jekkos in ([#4250](https://github.com/opensourcepos/opensourcepos/pull/4250))
|
||||
|
||||
## [3.4.0] - 2025-03-23
|
||||
## [3.4.0] - 2025-02-06
|
||||
|
||||
- Translation updates (Spanish, Indonesian, Swedish, Urdu, Chinese, Thai, French, Dutch)
|
||||
- PHP `8.x` support
|
||||
- PHP 8.x support
|
||||
- Security fixes (XSS, SQLi)
|
||||
- Migration to Gulp as buildsystem
|
||||
- Decimal validation fix
|
||||
|
||||
@@ -1,85 +1,98 @@
|
||||
[comment]: # (Contributor Covenant 2.1 - from https://www.contributor-covenant.org/version/2/1/code_of_conduct/code_of_conduct.md)
|
||||
|
||||
# Contributor Covenant Code of Conduct
|
||||
|
||||
## Our Pledge
|
||||
|
||||
We as members, contributors, and leaders pledge to make participation in our community a harassment-free experience for everyone, regardless of age, body size, visible or invisible disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, caste, color, religion, or sexual identity and orientation.
|
||||
|
||||
We pledge to act and interact in ways that contribute to an open, welcoming, diverse, inclusive, and healthy community.
|
||||
|
||||
## Our Standards
|
||||
|
||||
Examples of behavior that contributes to a positive environment for our community include:
|
||||
Contributor Covenant Code of Conduct
|
||||
Our Pledge
|
||||
We as members, contributors, and leaders pledge to make participation in our
|
||||
community a harassment-free experience for everyone, regardless of age, body
|
||||
size, visible or invisible disability, ethnicity, sex characteristics, gender
|
||||
identity and expression, level of experience, education, socio-economic status,
|
||||
nationality, personal appearance, race, caste, color, religion, or sexual
|
||||
identity and orientation.
|
||||
We pledge to act and interact in ways that contribute to an open, welcoming,
|
||||
diverse, inclusive, and healthy community.
|
||||
Our Standards
|
||||
Examples of behavior that contributes to a positive environment for our
|
||||
community include:
|
||||
|
||||
* Demonstrating empathy and kindness toward other people
|
||||
* Being respectful of differing opinions, viewpoints, and experiences
|
||||
* Giving and gracefully accepting constructive feedback
|
||||
* Accepting responsibility and apologizing to those affected by our mistakes, and learning from the experience
|
||||
* Focusing on what is best not just for us as individuals, but for the overall community
|
||||
* Accepting responsibility and apologizing to those affected by our mistakes,
|
||||
and learning from the experience
|
||||
* Focusing on what is best not just for us as individuals, but for the overall
|
||||
community
|
||||
|
||||
Examples of unacceptable behavior include:
|
||||
|
||||
* The use of sexualized language or imagery, and sexual attention or advances of any kind
|
||||
* The use of sexualized language or imagery, and sexual attention or advances of
|
||||
any kind
|
||||
* Trolling, insulting or derogatory comments, and personal or political attacks
|
||||
* Public or private harassment
|
||||
* Publishing others' private information, such as a physical or email address, without their explicit permission
|
||||
* Other conduct which could reasonably be considered inappropriate in a professional setting
|
||||
* Publishing others’ private information, such as a physical or email address,
|
||||
without their explicit permission
|
||||
* Other conduct which could reasonably be considered inappropriate in a
|
||||
professional setting
|
||||
|
||||
## Enforcement Responsibilities
|
||||
Enforcement Responsibilities
|
||||
Community leaders are responsible for clarifying and enforcing our standards of
|
||||
acceptable behavior and will take appropriate and fair corrective action in
|
||||
response to any behavior that they deem inappropriate, threatening, offensive,
|
||||
or harmful.
|
||||
Community leaders have the right and responsibility to remove, edit, or reject
|
||||
comments, commits, code, wiki edits, issues, and other contributions that are
|
||||
not aligned to this Code of Conduct, and will communicate reasons for moderation
|
||||
decisions when appropriate.
|
||||
Scope
|
||||
This Code of Conduct applies within all community spaces, and also applies when
|
||||
an individual is officially representing the community in public spaces.
|
||||
Examples of representing our community include using an official email address,
|
||||
posting via an official social media account, or acting as an appointed
|
||||
representative at an online or offline event.
|
||||
Enforcement
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
||||
reported to the community leaders responsible for enforcement at
|
||||
[INSERT CONTACT METHOD].
|
||||
All complaints will be reviewed and investigated promptly and fairly.
|
||||
All community leaders are obligated to respect the privacy and security of the
|
||||
reporter of any incident.
|
||||
Enforcement Guidelines
|
||||
Community leaders will follow these Community Impact Guidelines in determining
|
||||
the consequences for any action they deem in violation of this Code of Conduct:
|
||||
1. Correction
|
||||
Community Impact: Use of inappropriate language or other behavior deemed
|
||||
unprofessional or unwelcome in the community.
|
||||
Consequence: A private, written warning from community leaders, providing
|
||||
clarity around the nature of the violation and an explanation of why the
|
||||
behavior was inappropriate. A public apology may be requested.
|
||||
2. Warning
|
||||
Community Impact: A violation through a single incident or series of
|
||||
actions.
|
||||
Consequence: A warning with consequences for continued behavior. No
|
||||
interaction with the people involved, including unsolicited interaction with
|
||||
those enforcing the Code of Conduct, for a specified period of time. This
|
||||
includes avoiding interactions in community spaces as well as external channels
|
||||
like social media. Violating these terms may lead to a temporary or permanent
|
||||
ban.
|
||||
3. Temporary Ban
|
||||
Community Impact: A serious violation of community standards, including
|
||||
sustained inappropriate behavior.
|
||||
Consequence: A temporary ban from any sort of interaction or public
|
||||
communication with the community for a specified period of time. No public or
|
||||
private interaction with the people involved, including unsolicited interaction
|
||||
with those enforcing the Code of Conduct, is allowed during this period.
|
||||
Violating these terms may lead to a permanent ban.
|
||||
4. Permanent Ban
|
||||
Community Impact: Demonstrating a pattern of violation of community
|
||||
standards, including sustained inappropriate behavior, harassment of an
|
||||
individual, or aggression toward or disparagement of classes of individuals.
|
||||
Consequence: A permanent ban from any sort of public interaction within the
|
||||
community.
|
||||
Attribution
|
||||
This Code of Conduct is adapted from the Contributor Covenant,
|
||||
version 2.1, available at
|
||||
https://www.contributor-covenant.org/version/2/1/code_of_conduct.html.
|
||||
Community Impact Guidelines were inspired by
|
||||
Mozilla’s code of conduct enforcement ladder.
|
||||
For answers to common questions about this code of conduct, see the FAQ at
|
||||
https://www.contributor-covenant.org/faq. Translations are available at
|
||||
https://www.contributor-covenant.org/translations.
|
||||
|
||||
Community leaders are responsible for clarifying and enforcing our standards of acceptable behavior and will take appropriate and fair corrective action in response to any behavior that they deem inappropriate, threatening, offensive, or harmful.
|
||||
|
||||
Community leaders have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, and will communicate reasons for moderation decisions when appropriate.
|
||||
|
||||
## Scope
|
||||
|
||||
This Code of Conduct applies within all community spaces, and also applies when an individual is officially representing the community in public spaces. Examples of representing our community include using an official e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event.
|
||||
|
||||
## Enforcement
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported to the community leaders responsible for enforcement at [INSERT CONTACT METHOD]. All complaints will be reviewed and investigated promptly and fairly.
|
||||
|
||||
All community leaders are obligated to respect the privacy and security of the reporter of any incident.
|
||||
|
||||
## Enforcement Guidelines
|
||||
|
||||
Community leaders will follow these Community Impact Guidelines in determining the consequences for any action they deem in violation of this Code of Conduct:
|
||||
|
||||
### 1. Correction
|
||||
|
||||
**Community Impact**: Use of inappropriate language or other behavior deemed unprofessional or unwelcome in the community.
|
||||
|
||||
**Consequence**: A private, written warning from community leaders, providing clarity around the nature of the violation and an explanation of why the behavior was inappropriate. A public apology may be requested.
|
||||
|
||||
### 2. Warning
|
||||
|
||||
**Community Impact**: A violation through a single incident or series of actions.
|
||||
|
||||
**Consequence**: A warning with consequences for continued behavior. No interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, for a specified period of time. This includes avoiding interactions in community spaces as well as external channels like social media. Violating these terms may lead to a temporary or permanent ban.
|
||||
|
||||
### 3. Temporary Ban
|
||||
|
||||
**Community Impact**: A serious violation of community standards, including sustained inappropriate behavior.
|
||||
|
||||
**Consequence**: A temporary ban from any sort of interaction or public communication with the community for a specified period of time. No public or private interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, is allowed during this period. Violating these terms may lead to a permanent ban.
|
||||
|
||||
### 4. Permanent Ban
|
||||
|
||||
**Community Impact**: Demonstrating a pattern of violation of community standards, including sustained inappropriate behavior, harassment of an individual, or aggression toward or disparagement of classes of individuals.
|
||||
|
||||
**Consequence**: A permanent ban from any sort of public interaction within the community.
|
||||
|
||||
## Attribution
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 2.1, available at [https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1].
|
||||
|
||||
Community Impact Guidelines were inspired by [Mozilla's code of conduct enforcement ladder][Mozilla CoC].
|
||||
|
||||
For answers to common questions about this code of conduct, see the FAQ at [https://www.contributor-covenant.org/faq][FAQ]. Translations are available at [https://www.contributor-covenant.org/translations][translations].
|
||||
|
||||
[homepage]: https://www.contributor-covenant.org
|
||||
[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html
|
||||
[Mozilla CoC]: https://github.com/mozilla/diversity
|
||||
[FAQ]: https://www.contributor-covenant.org/faq
|
||||
[translations]: https://www.contributor-covenant.org/translations
|
||||
|
||||
@@ -486,9 +486,10 @@ class Mimes
|
||||
/**
|
||||
* 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)
|
||||
public static function guessTypeFromExtension(string $extension): array|string|null
|
||||
{
|
||||
$extension = trim(strtolower($extension), '. ');
|
||||
|
||||
@@ -506,7 +507,7 @@ class Mimes
|
||||
*
|
||||
* @return string|null The extension determined, or null if unable to match.
|
||||
*/
|
||||
public static function guessExtensionFromType(string $type, ?string $proposedExtension = null)
|
||||
public static function guessExtensionFromType(string $type, ?string $proposedExtension = null): ?string
|
||||
{
|
||||
$type = trim(strtolower($type), '. ');
|
||||
|
||||
@@ -522,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;
|
||||
|
||||
@@ -5,6 +5,7 @@ namespace Config;
|
||||
use App\Models\Appconfig;
|
||||
use CodeIgniter\Cache\CacheInterface;
|
||||
use CodeIgniter\Config\BaseConfig;
|
||||
use CodeIgniter\Database\Exceptions\DatabaseException;
|
||||
|
||||
/**
|
||||
* This class holds the configuration options stored from the database so that on launch those settings can be cached
|
||||
@@ -40,11 +41,9 @@ class OSPOS extends BaseConfig
|
||||
$this->settings[$app_config->key] = $app_config->value;
|
||||
}
|
||||
$this->cache->save('settings', encode_array($this->settings));
|
||||
} catch (\Exception $e) {
|
||||
} catch (DatabaseException $e) {
|
||||
// Database table doesn't exist yet (migrations haven't run)
|
||||
// or database connection failed. Return empty settings to
|
||||
// allow migration page to display. Catches mysqli_sql_exception
|
||||
// which is not a subclass of DatabaseException.
|
||||
// Return empty settings to allow migration page to display
|
||||
$this->settings = [
|
||||
'language' => 'english',
|
||||
'language_code' => 'en',
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
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;
|
||||
@@ -138,11 +139,7 @@ class Session extends BaseConfig
|
||||
$this->driver = FileHandler::class;
|
||||
$this->savePath = WRITEPATH . 'session';
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
// Database not available yet (e.g. fresh install before migrations).
|
||||
// Fall back to file-based sessions so the login/migration page
|
||||
// can still be served. Catches mysqli_sql_exception which is
|
||||
// not a subclass of DatabaseException but is a RuntimeException.
|
||||
} catch (DatabaseException $e) {
|
||||
$this->driver = FileHandler::class;
|
||||
$this->savePath = WRITEPATH . 'session';
|
||||
}
|
||||
|
||||
@@ -28,9 +28,12 @@ abstract class BaseController extends Controller
|
||||
// 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
|
||||
{
|
||||
// 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.
|
||||
|
||||
@@ -82,7 +82,7 @@ class Config extends Secure_Controller
|
||||
$npmDev = false;
|
||||
$license = [];
|
||||
|
||||
$license[$i]['title'] = 'Open Source Point of Sale ' . config('App')->application_version;
|
||||
$license[$i]['title'] = 'Open Source Point Of Sale ' . config('App')->application_version;
|
||||
|
||||
if (file_exists('license/LICENSE')) {
|
||||
$license[$i]['text'] = file_get_contents('license/LICENSE', false, null, 0, 3000);
|
||||
@@ -221,7 +221,6 @@ class Config extends Secure_Controller
|
||||
*/
|
||||
public function getIndex(): string
|
||||
{
|
||||
$data['config'] = $this->config;
|
||||
$data['stock_locations'] = $this->stock_location->get_all()->getResultArray();
|
||||
$data['dinner_tables'] = $this->dinner_table->get_all()->getResultArray();
|
||||
$data['customer_rewards'] = $this->customer_rewards->get_all()->getResultArray();
|
||||
@@ -232,8 +231,6 @@ class Config extends Secure_Controller
|
||||
$data['line_sequence_options'] = $this->sale_lib->get_line_sequence_options();
|
||||
$data['register_mode_options'] = $this->sale_lib->get_register_mode_options();
|
||||
$data['invoice_type_options'] = $this->sale_lib->get_invoice_type_options();
|
||||
$data['keyboardShortcutOptions'] = $this->sale_lib->getKeyShortcutsOptions();
|
||||
$data['keyboardShortcuts'] = $this->sale_lib->getKeyShortcuts();
|
||||
$data['rounding_options'] = rounding_mode::get_rounding_options();
|
||||
$data['tax_code_options'] = $this->tax_lib->get_tax_code_options();
|
||||
$data['tax_category_options'] = $this->tax_lib->get_tax_category_options();
|
||||
@@ -401,9 +398,6 @@ class Config extends Secure_Controller
|
||||
|
||||
$this->module->set_show_office_group($this->request->getPost('show_office_group') != null);
|
||||
|
||||
$this->db->transStart();
|
||||
|
||||
$attributeSuccess = true;
|
||||
if ($batchSaveData['category_dropdown']) {
|
||||
$definitionData['definition_name'] = 'ospos_category';
|
||||
$definitionData['definition_flags'] = 0;
|
||||
@@ -411,16 +405,12 @@ class Config extends Secure_Controller
|
||||
$definitionData['definition_id'] = CATEGORY_DEFINITION_ID;
|
||||
$definitionData['deleted'] = 0;
|
||||
|
||||
$attributeSuccess = $this->attribute->saveDefinition($definitionData, CATEGORY_DEFINITION_ID);
|
||||
$this->attribute->saveDefinition($definitionData, CATEGORY_DEFINITION_ID);
|
||||
} elseif ($batchSaveData['category_dropdown'] == NO_DEFINITION_ID) {
|
||||
$attributeSuccess = $this->attribute->deleteDefinition(CATEGORY_DEFINITION_ID);
|
||||
$this->attribute->deleteDefinition(CATEGORY_DEFINITION_ID);
|
||||
}
|
||||
|
||||
$success = $attributeSuccess && $this->appconfig->batch_save($batchSaveData);
|
||||
|
||||
$this->db->transComplete();
|
||||
|
||||
$success = $success && $this->db->transStatus();
|
||||
$success = $this->appconfig->batch_save($batchSaveData);
|
||||
|
||||
return $this->response->setJSON(['success' => $success, 'message' => lang('Config.saved_' . ($success ? '' : 'un') . 'successfully')]);
|
||||
}
|
||||
@@ -433,35 +423,32 @@ class Config extends Secure_Controller
|
||||
*/
|
||||
public function postCheckNumberLocale(): ResponseInterface
|
||||
{
|
||||
$numberLocale = $this->request->getPost('number_locale');
|
||||
$saveNumberLocale = $this->request->getPost('save_number_locale');
|
||||
$postedCurrencySymbol = $this->request->getPost('currency_symbol');
|
||||
$postedCurrencyCode = $this->request->getPost('currency_code');
|
||||
$number_locale = $this->request->getPost('number_locale');
|
||||
$save_number_locale = $this->request->getPost('save_number_locale');
|
||||
|
||||
$fmt = new NumberFormatter($numberLocale, NumberFormatter::CURRENCY);
|
||||
|
||||
// Use posted values if provided, otherwise fall back to locale defaults
|
||||
$currencySymbol = $postedCurrencySymbol !== '' ? $postedCurrencySymbol : $fmt->getSymbol(NumberFormatter::CURRENCY_SYMBOL);
|
||||
$currencyCode = $postedCurrencyCode !== '' ? $postedCurrencyCode : $fmt->getTextAttribute(NumberFormatter::CURRENCY_CODE);
|
||||
|
||||
// Update saved locale if it changed
|
||||
if ($numberLocale !== $saveNumberLocale) {
|
||||
$saveNumberLocale = $numberLocale;
|
||||
$fmt = new NumberFormatter($number_locale, NumberFormatter::CURRENCY);
|
||||
if ($number_locale != $save_number_locale) {
|
||||
$currency_symbol = $fmt->getSymbol(NumberFormatter::CURRENCY_SYMBOL);
|
||||
$currency_code = $fmt->getTextAttribute(NumberFormatter::CURRENCY_CODE);
|
||||
$save_number_locale = $number_locale;
|
||||
} else {
|
||||
$currency_symbol = empty($this->request->getPost('currency_symbol')) ? $fmt->getSymbol(NumberFormatter::CURRENCY_SYMBOL) : $this->request->getPost('currency_symbol');
|
||||
$currency_code = empty($this->request->getPost('currency_code')) ? $fmt->getTextAttribute(NumberFormatter::CURRENCY_CODE) : $this->request->getPost('currency_code');
|
||||
}
|
||||
|
||||
if ($this->request->getPost('thousands_separator') == 'false') {
|
||||
$fmt->setTextAttribute(NumberFormatter::GROUPING_SEPARATOR_SYMBOL, '');
|
||||
}
|
||||
|
||||
$fmt->setSymbol(NumberFormatter::CURRENCY_SYMBOL, $currencySymbol);
|
||||
$numberLocaleExample = $fmt->format(1234567890.12300);
|
||||
$fmt->setSymbol(NumberFormatter::CURRENCY_SYMBOL, $currency_symbol);
|
||||
$number_local_example = $fmt->format(1234567890.12300);
|
||||
|
||||
return $this->response->setJSON([
|
||||
'success' => $numberLocaleExample != false,
|
||||
'save_number_locale' => $saveNumberLocale,
|
||||
'number_locale_example' => $numberLocaleExample,
|
||||
'currency_symbol' => $currencySymbol,
|
||||
'currency_code' => $currencyCode,
|
||||
'success' => $number_local_example != false,
|
||||
'save_number_locale' => $save_number_locale,
|
||||
'number_locale_example' => $number_local_example,
|
||||
'currency_symbol' => $currency_symbol,
|
||||
'currency_code' => $currency_code,
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -949,44 +936,6 @@ class Config extends Secure_Controller
|
||||
return $this->response->setJSON(['success' => $success, 'message' => lang('Config.saved_' . ($success ? '' : 'un') . 'successfully')]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves keyboard shortcut bindings.
|
||||
*
|
||||
* @return ResponseInterface
|
||||
* @noinspection PhpUnused
|
||||
*/
|
||||
public function postSaveShortcuts(): ResponseInterface
|
||||
{
|
||||
$allowedShortcuts = array_keys($this->sale_lib->getKeyShortcutsOptions());
|
||||
$currentShortcuts = $this->sale_lib->getKeyShortcuts();
|
||||
$batchSaveData = [];
|
||||
|
||||
foreach ($currentShortcuts as $name => $shortcut) {
|
||||
$postedValue = trim((string)$this->request->getPost('key_' . $name));
|
||||
|
||||
if (!in_array($postedValue, $allowedShortcuts, true)) {
|
||||
$postedValue = $shortcut['value'];
|
||||
}
|
||||
|
||||
$batchSaveData['key_' . $name] = $postedValue;
|
||||
}
|
||||
|
||||
$duplicateValues = array_filter(array_count_values($batchSaveData), static fn(int $count): bool => $count > 1);
|
||||
if (!empty($duplicateValues)) {
|
||||
return $this->response->setJSON([
|
||||
'success' => false,
|
||||
'message' => lang('Config.shortcuts_duplicate_bindings')
|
||||
]);
|
||||
}
|
||||
|
||||
$success = $this->appconfig->batch_save($batchSaveData);
|
||||
|
||||
return $this->response->setJSON([
|
||||
'success' => $success,
|
||||
'message' => lang('Config.saved_' . ($success ? '' : 'un') . 'successfully')
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves invoice configuration. Used in app/Views/configs/invoice_config.php.
|
||||
*
|
||||
|
||||
@@ -43,7 +43,7 @@ class Home extends Secure_Controller
|
||||
public function getChangePassword(int $employeeId = NEW_ENTRY): ResponseInterface|string
|
||||
{
|
||||
$loggedInEmployee = $this->employee->get_logged_in_employee_info();
|
||||
$currentPersonId = (int) $loggedInEmployee->person_id;
|
||||
$currentPersonId = $loggedInEmployee->person_id;
|
||||
|
||||
$employeeId = $employeeId === NEW_ENTRY ? $currentPersonId : $employeeId;
|
||||
|
||||
@@ -68,11 +68,10 @@ class Home extends Secure_Controller
|
||||
public function postSave(int $employeeId = NEW_ENTRY): ResponseInterface
|
||||
{
|
||||
$currentUser = $this->employee->get_logged_in_employee_info();
|
||||
$currentPersonId = (int) $currentUser->person_id;
|
||||
|
||||
$employeeId = $employeeId === NEW_ENTRY ? $currentPersonId : $employeeId;
|
||||
$employeeId = $employeeId === NEW_ENTRY ? $currentUser->person_id : $employeeId;
|
||||
|
||||
if (!$this->employee->isAdmin($currentPersonId) && $employeeId !== $currentPersonId) {
|
||||
if (!$this->employee->isAdmin($currentUser->person_id) && $employeeId !== $currentUser->person_id) {
|
||||
return $this->response->setStatusCode(403)->setJSON([
|
||||
'success' => false,
|
||||
'message' => lang('Employees.unauthorized_modify')
|
||||
|
||||
@@ -482,9 +482,9 @@ class Items extends Secure_Controller
|
||||
foreach ($result as &$item) {
|
||||
if (isset($item['item_number']) && empty($item['item_number']) && $this->config['barcode_generate_if_empty']) {
|
||||
if (isset($item['item_id'])) {
|
||||
$save_item = ['item_number' => $item['item_number']];
|
||||
$this->item->save_value($save_item, $item['item_id']);
|
||||
}
|
||||
$save_item = ['item_number' => $item['item_number'], 'item_id' => $item['item_id']];
|
||||
$this->item->saveValue($save_item);
|
||||
}
|
||||
}
|
||||
}
|
||||
$data['items'] = $result;
|
||||
@@ -663,7 +663,12 @@ class Items extends Secure_Controller
|
||||
|
||||
$employee_id = $this->employee->get_logged_in_employee_info()->person_id;
|
||||
|
||||
if ($this->item->save_value($item_data, $item_id)) {
|
||||
// For updates, include item_id in data array
|
||||
if ($item_id !== NEW_ENTRY) {
|
||||
$item_data['item_id'] = $item_id;
|
||||
}
|
||||
|
||||
if ($this->item->saveValue($item_data)) {
|
||||
$success = true;
|
||||
$new_item = false;
|
||||
|
||||
@@ -826,8 +831,8 @@ class Items extends Secure_Controller
|
||||
*/
|
||||
public function getRemoveLogo($item_id): ResponseInterface
|
||||
{
|
||||
$item_data = ['pic_filename' => null];
|
||||
$result = $this->item->save_value($item_data, $item_id);
|
||||
$item_data = ['pic_filename' => null, 'item_id' => $item_id];
|
||||
$result = $this->item->saveValue($item_data);
|
||||
|
||||
return $this->response->setJSON(['success' => $result]);
|
||||
}
|
||||
@@ -1039,7 +1044,7 @@ class Items extends Secure_Controller
|
||||
return $value !== null && strlen($value);
|
||||
});
|
||||
|
||||
if (!$isFailedRow && $this->item->save_value($itemData, $itemId)) {
|
||||
if (!$isFailedRow && $this->item->saveValue($itemData)) {
|
||||
$this->save_tax_data($row, $itemData);
|
||||
$this->save_inventory_quantities($row, $itemData, $allowedStockLocations, $employeeId);
|
||||
$csvAttributeValues = $this->extractAttributeData($row);
|
||||
@@ -1312,8 +1317,8 @@ class Items extends Secure_Controller
|
||||
$images = glob(FCPATH . "uploads/item_pics/$item->pic_filename.*");
|
||||
if (sizeof($images) > 0) {
|
||||
$new_pic_filename = pathinfo($images[0], PATHINFO_BASENAME);
|
||||
$item_data = ['pic_filename' => $new_pic_filename];
|
||||
$this->item->save_value($item_data, $item->item_id);
|
||||
$item_data = ['pic_filename' => $new_pic_filename, 'item_id' => $item->item_id];
|
||||
$this->item->saveValue($item_data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -937,10 +937,7 @@ class Sales extends Secure_Controller
|
||||
new Token_customer((array)$sale_data)
|
||||
];
|
||||
$text = $this->token_lib->render($text, $tokens);
|
||||
$sale_data['mimetype'] = $this->email_lib->getLogoMimeType();
|
||||
|
||||
// Build img_tag for email views that need it (receipt_email.php)
|
||||
$sale_data['img_tag'] = $this->email_lib->buildLogoImgTag();
|
||||
$sale_data['mimetype'] = mime_content_type(FCPATH . 'uploads/' . $this->config['company_logo']);
|
||||
|
||||
// Generate email attachment: invoice in PDF format
|
||||
$view = Services::renderer();
|
||||
@@ -977,7 +974,13 @@ class Sales extends Secure_Controller
|
||||
|
||||
if (!empty($sale_data['customer_email'])) {
|
||||
$sale_data['barcode'] = $this->barcode_lib->generate_receipt_barcode($sale_data['sale_id']);
|
||||
$sale_data['img_tag'] = $this->email_lib->buildLogoImgTag();
|
||||
$sale_data['img_tag'] = '';
|
||||
|
||||
$logo_path = FCPATH . 'uploads/' . $this->config['company_logo'];
|
||||
if (!empty($this->config['company_logo']) && file_exists($logo_path)) {
|
||||
$logo_data = base64_encode(file_get_contents($logo_path));
|
||||
$sale_data['img_tag'] = '<img id="image" src="data:image/png;base64,' . $logo_data . '" alt="company_logo">';
|
||||
}
|
||||
|
||||
$to = $sale_data['customer_email'];
|
||||
$subject = lang('Sales.receipt');
|
||||
@@ -1253,7 +1256,6 @@ class Sales extends Secure_Controller
|
||||
|
||||
$data['quote_number'] = $this->sale_lib->get_quote_number();
|
||||
$data['work_order_number'] = $this->sale_lib->get_work_order_number();
|
||||
$data['keyboardShortcuts'] = $this->sale_lib->getKeyShortcuts();
|
||||
|
||||
// TODO: the if/else set below should be converted to a switch
|
||||
if ($this->sale_lib->get_mode() == 'sale_invoice') { // TODO: Duplicated code.
|
||||
@@ -1642,9 +1644,7 @@ class Sales extends Secure_Controller
|
||||
*/
|
||||
public function getSalesKeyboardHelp(): string
|
||||
{
|
||||
return view('sales/help', [
|
||||
'keyboardShortcuts' => $this->sale_lib->getKeyShortcuts()
|
||||
]);
|
||||
return view('sales/help');
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
FROM alpine:3.14
|
||||
LABEL maintainer="jekkos"
|
||||
MAINTAINER jekkos
|
||||
|
||||
ADD database.sql /docker-entrypoint-initdb.d/database.sql
|
||||
VOLUME /docker-entrypoint-initdb.d
|
||||
|
||||
@@ -1,46 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Database\Migrations;
|
||||
|
||||
use CodeIgniter\Database\Migration;
|
||||
|
||||
class AddShortcutKeys extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
$shortcutValues = [
|
||||
['key' => 'key_cancel', 'value' => '27 | ESC'],
|
||||
['key' => 'key_items', 'value' => '49 | ALT + 1'],
|
||||
['key' => 'key_customers', 'value' => '50 | ALT + 2'],
|
||||
['key' => 'key_suspend', 'value' => '51 | ALT + 3'],
|
||||
['key' => 'key_suspended', 'value' => '52 | ALT + 4'],
|
||||
['key' => 'key_amount', 'value' => '53 | ALT + 5'],
|
||||
['key' => 'key_payment', 'value' => '54 | ALT + 6'],
|
||||
['key' => 'key_complete', 'value' => '55 | ALT + 7'],
|
||||
['key' => 'key_finish', 'value' => '56 | ALT + 8'],
|
||||
['key' => 'key_help', 'value' => '57 | ALT + 9'],
|
||||
];
|
||||
|
||||
$this->db->table('app_config')->ignore(true)->insertBatch($shortcutValues);
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
$shortcutKeys = [
|
||||
'key_cancel',
|
||||
'key_items',
|
||||
'key_customers',
|
||||
'key_suspend',
|
||||
'key_suspended',
|
||||
'key_amount',
|
||||
'key_payment',
|
||||
'key_complete',
|
||||
'key_finish',
|
||||
'key_help',
|
||||
];
|
||||
|
||||
$this->db->table('app_config')
|
||||
->whereIn('key', $shortcutKeys)
|
||||
->delete();
|
||||
}
|
||||
}
|
||||
@@ -22,7 +22,7 @@ function current_language_code(bool $load_system_language = false): string
|
||||
}
|
||||
}
|
||||
|
||||
return $config['language_code'] ?? DEFAULT_LANGUAGE_CODE;
|
||||
return $config->language_code ?? DEFAULT_LANGUAGE_CODE;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -43,7 +43,7 @@ function current_language(bool $load_system_language = false): string
|
||||
}
|
||||
}
|
||||
|
||||
return $config['language'] ?? DEFAULT_LANGUAGE;
|
||||
return $config->language ?? DEFAULT_LANGUAGE_CODE;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -302,10 +302,6 @@ return [
|
||||
"suggestions_layout" => "Search Suggestions Layout",
|
||||
"suggestions_second_column" => "Column 2",
|
||||
"suggestions_third_column" => "Column 3",
|
||||
"shortcuts" => "Shortcuts",
|
||||
"shortcuts_configuration" => "Sales Keyboard Shortcut Configuration",
|
||||
"shortcuts_duplicate_bindings" => "Shortcut bindings must be unique.",
|
||||
"shortcuts_save_error" => "Unable to save shortcut settings.",
|
||||
"system_conf" => "Setup & Conf",
|
||||
"system_info" => "System Info",
|
||||
"table" => "Table",
|
||||
|
||||
@@ -26,7 +26,7 @@ return [
|
||||
"cost_price_required" => "Precio al Por Mayor es un campo requerido.",
|
||||
"count" => "Actualizar Inventario",
|
||||
"csv_import_failed" => "Falló la importación de Hoja de Cálculo",
|
||||
"csv_import_invalid_location" => "Se encontraron ubicaciones de stock no válidas: {0}. Solo se permiten ubicaciones de stock válidas.",
|
||||
"csv_import_invalid_location" => "Ubicación(es) de stock inválida(s) encontrada(s): {0}. Solo ubicaciones de stock válidas son permitidas.",
|
||||
"csv_import_nodata_wrongformat" => "El archivo subido no tiene datos o el formato es incorrecto.",
|
||||
"csv_import_partially_failed" => "Hubo {0} falla(s) en la importación de producto(s) en la(s) línea(s): {1}. Ninguna fila ha sido importada.",
|
||||
"csv_import_success" => "Se importaron los articulos exitosamente.",
|
||||
|
||||
@@ -38,7 +38,7 @@ return [
|
||||
"february" => "",
|
||||
"march" => "",
|
||||
"april" => "",
|
||||
"may" => "",
|
||||
"mayl" => "",
|
||||
"june" => "",
|
||||
"july" => "",
|
||||
"august" => "",
|
||||
@@ -46,4 +46,4 @@ return [
|
||||
"october" => "",
|
||||
"november" => "",
|
||||
"december" => "",
|
||||
];
|
||||
];
|
||||
@@ -38,7 +38,7 @@ return [
|
||||
"february" => "",
|
||||
"march" => "",
|
||||
"april" => "",
|
||||
"may" => "",
|
||||
"mayl" => "",
|
||||
"june" => "",
|
||||
"july" => "",
|
||||
"august" => "",
|
||||
@@ -46,4 +46,4 @@ return [
|
||||
"october" => "",
|
||||
"november" => "",
|
||||
"december" => "",
|
||||
];
|
||||
];
|
||||
@@ -38,7 +38,7 @@ return [
|
||||
"february" => "ഫെബ്രുവരി",
|
||||
"march" => "മാർച്ച്",
|
||||
"april" => "ഏപ്രിൽ",
|
||||
"may" => "മേയ്",
|
||||
"mayl" => "മേയ്",
|
||||
"june" => "ജൂൺ",
|
||||
"july" => "ജൂലൈ",
|
||||
"august" => "ആഗസ്റ്റ്",
|
||||
@@ -46,4 +46,4 @@ return [
|
||||
"october" => "ഒക്ടോബർ",
|
||||
"november" => "നവംബർ",
|
||||
"december" => "ഡിസംബർ",
|
||||
];
|
||||
];
|
||||
@@ -38,7 +38,7 @@ return [
|
||||
"february" => "Februar",
|
||||
"march" => "Mars",
|
||||
"april" => "April",
|
||||
"may" => "Mai",
|
||||
"mayl" => "Mai",
|
||||
"june" => "Juni",
|
||||
"july" => "Juli",
|
||||
"august" => "August",
|
||||
@@ -46,4 +46,4 @@ return [
|
||||
"october" => "Oktober",
|
||||
"november" => "November",
|
||||
"december" => "Desember",
|
||||
];
|
||||
];
|
||||
@@ -1,12 +1,12 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'all' => "ทั้งหมด",
|
||||
'columns' => "คอลัมน์",
|
||||
'hide_show_pagination' => "ซ่อน/แสดง รายการหน้า",
|
||||
'loading' => "กำลังดำเนินการ รอสักครู่ ...",
|
||||
'page_from_to' => "แสดง {0} ถึง {1} จาก {2} รายการ",
|
||||
'refresh' => "Refresh ข้อมูล",
|
||||
'rows_per_page' => "{0} รายการ/หน้า",
|
||||
'toggle' => "ซ่อน/แสดง",
|
||||
"all" => "ทั้งหมด",
|
||||
"columns" => "คอลัมน์",
|
||||
"hide_show_pagination" => "ซ่อน/แสดง รายการหน้า",
|
||||
"loading" => "กำลังดำเนินการ รอสักครู่",
|
||||
"page_from_to" => "แสดง {0} ถึง {1} จาก {2} รายการ",
|
||||
"refresh" => "Refresh ข้อมูล",
|
||||
"rows_per_page" => "{0} รายการ/หน้า",
|
||||
"toggle" => "ซ่อน/แสดง",
|
||||
];
|
||||
|
||||
@@ -9,9 +9,7 @@ return [
|
||||
"login" => "ลงชื่อเข้าใช้",
|
||||
"logout" => "ออกจากระบบ",
|
||||
"migration_needed" => "การย้ายฐานข้อมูลไปยัง {0} จะเริ่มต้นหลังจากเข้าสู่ระบบ",
|
||||
"migration_required" => "จําเป็นต้องมีการปรับปรุงฐานข้อมูล",
|
||||
"migration_auth_message" => "ผู้ดูแลระบบจำเป็นต้องมีสิทธิ์ในการปรับปรุงฐานข้อมูลเวอร์ชั่น {0} กรุณาเข้าระบบเพื่อดำเนินการต่อ",
|
||||
"migration_complete_redirect" => "ทำการปรับปรุงฐานข้อมูลเรียบร้อย กำลังดำเนินการไปหน้าเข้าสู่ระบบ ...",
|
||||
"migration_required" => "",
|
||||
"migration_auth_message" => "",
|
||||
"migration_initializing" => "",
|
||||
"migration_running" => "",
|
||||
@@ -19,6 +17,7 @@ return [
|
||||
"migration_complete_login" => "",
|
||||
"migration_failed" => "",
|
||||
"migration_error_connection" => "",
|
||||
"migration_complete_redirect" => "",
|
||||
"password" => "รหัสผ่าน",
|
||||
"required_username" => "จำเป็นต้องระบุชื่อผู้ใช้งาน",
|
||||
"username" => "ชื่อผู้ใช้",
|
||||
|
||||
@@ -1,232 +1,232 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'customers_available_points' => "คะแนนที่มี",
|
||||
'rewards_package' => "คะแนนสะสม",
|
||||
'rewards_remaining_balance' => "คะแนนสะสมคงเหลือ ",
|
||||
'account_number' => "บัญชี #",
|
||||
'add_payment' => "เพิ่มบิล",
|
||||
'amount_due' => "ยอดค้างชำระ",
|
||||
'amount_tendered' => "ชำระเข้ามา",
|
||||
'authorized_signature' => "ลายเซ็นผู้มีอำนาจ",
|
||||
'cancel_sale' => "ยกเลิกการขาย",
|
||||
'cash' => "เงินสด",
|
||||
'cash_1' => "",
|
||||
'cash_2' => "",
|
||||
'cash_3' => "",
|
||||
'cash_4' => "",
|
||||
'cash_adjustment' => "การปรับเงินสดขาย",
|
||||
'cash_deposit' => "ฝากเงินสด",
|
||||
'cash_filter' => "เงินสด",
|
||||
'change_due' => "เงินทอน",
|
||||
'change_price' => "เปลี่ยนราคาขาย",
|
||||
'check' => "โอนเงิน/พร้อมเพย์/เช็ค",
|
||||
'check_balance' => "เช็คยอดคงเหลือ",
|
||||
'check_filter' => "ตรวจสอบ",
|
||||
'close' => "",
|
||||
'comment' => "หมายเหตุ",
|
||||
'comments' => "หมายเหตุ",
|
||||
'company_name' => "",
|
||||
'complete' => "",
|
||||
'complete_sale' => "จบการขาย",
|
||||
'confirm_cancel_sale' => "แน่ใจหรือไม่ที่จะล้างการขายนี้? ทุกรายการจะถูกลบทั้งหมด",
|
||||
'confirm_delete' => "โปรดยืนยันการลบรายการขายที่เลือกไว้ ?",
|
||||
'confirm_restore' => "คุณแน่ใจหรือไม่ว่าต้องการยกเลิกการขายที่เลือกไว้?",
|
||||
'credit' => "เครดิตการ์ด",
|
||||
'credit_deposit' => "เงินฝากเครดิต",
|
||||
'credit_filter' => "บัตรเครติด",
|
||||
'current_table' => "",
|
||||
'customer' => "ลูกค้า",
|
||||
'customer_address' => "Customer Address",
|
||||
'customer_discount' => "ส่วนลด",
|
||||
'customer_email' => "Customer Email",
|
||||
'customer_location' => "Customer Location",
|
||||
'customer_mailchimp_status' => "สถานะของระบบส่งเมล์เมล์ชิม",
|
||||
'customer_optional' => "(ต้องระบุวันที่ชำระเงิน)",
|
||||
'customer_required' => "(ต้องระบุ)",
|
||||
'customer_total' => "Total",
|
||||
'customer_total_spent' => "",
|
||||
'daily_sales' => "",
|
||||
'date' => "วันที่ขาย",
|
||||
'date_range' => "ระหว่างวันที่",
|
||||
'date_required' => "กรุณากรอกวันที่ให้ถูกต้อง",
|
||||
'date_type' => "กรุณากรอกข้อมูลในช่องวันที่",
|
||||
'debit' => "บัตรประชารัฐ/เดบิตการ์ด",
|
||||
'debit_filter' => "",
|
||||
'delete' => "อนุญาตให้ลบ",
|
||||
'delete_confirmation' => "แน่ใจหรือไม่ที่จะลบรายการขายนี้, ลบแล้วไม่สามารถเรียกกลับคืนใด้",
|
||||
'delete_entire_sale' => "ลบการขายทั้งหมด",
|
||||
'delete_successful' => "คุณลบการขายสำเร็จ",
|
||||
'delete_unsuccessful' => "คุณลบการขายไม่สำเร็จ",
|
||||
'description_abbrv' => "รายละเอียด",
|
||||
'discard' => "ยกเลิก",
|
||||
'discard_quote' => "",
|
||||
'discount' => "ส่วนลด %",
|
||||
'discount_included' => "% ส่วนลด",
|
||||
'discount_short' => "%",
|
||||
'due' => "วันครบกำหนด",
|
||||
'due_filter' => "วันที่ครบกำหนด",
|
||||
'edit' => "แก้ไข",
|
||||
'edit_item' => "แก้ไขสินค้า",
|
||||
'edit_sale' => "แก้ไขการขาย",
|
||||
'email_receipt' => "อีเมลบิล",
|
||||
'employee' => "พนักงาน",
|
||||
'entry' => "การนำเข้า",
|
||||
'error_editing_item' => "แก้ไขสินค้าล้มเหลว",
|
||||
'negative_price_invalid' => "ราคาไม่สามารถเป็นค่าติดลบได้",
|
||||
'negative_quantity_invalid' => "จำนวนไม่สามารถเป็นค่าติดลบได้",
|
||||
'negative_discount_invalid' => "ส่วนลดไม่สามารถเป็นค่าติดลบได้",
|
||||
'discount_percent_exceeds_100' => "ส่วนลดเปอร์เซ็นต์มีค่าได้ไม่เกิน 100%",
|
||||
'discount_exceeds_item_total' => "ส่วนลดต้องไม่เกินจำนวนรายการขายทั้งหมด",
|
||||
'negative_total_invalid' => "",
|
||||
'find_or_scan_item' => "ค้นหาสินค้า",
|
||||
'find_or_scan_item_or_receipt' => "ค้นหา หรือ แสกนรายการ หรือ ใบเสร็จ",
|
||||
'giftcard' => "บัตรของขวัญ",
|
||||
'giftcard_balance' => "ยอดคงเหลือบัตรของขวัญ",
|
||||
'giftcard_filter' => "",
|
||||
'giftcard_number' => "เลขที่บัตรของขวัญ",
|
||||
'group_by_category' => "กลุ่มตามหมวดหมู่",
|
||||
'group_by_type' => "กลุ่มตามประเภท",
|
||||
'hsn' => "HSN",
|
||||
'id' => "เลขที่ขาย",
|
||||
'include_prices' => "รวมในราคา?",
|
||||
'invoice' => "ใบแจ้งหนี้",
|
||||
'invoice_confirm' => "ใบแจ้งหนี้นี้จะถูกส่งไปที่",
|
||||
'invoice_enable' => "เลขที่ใบแจ้งหนี้",
|
||||
'invoice_filter' => "ใบแจ้งหนี้",
|
||||
'invoice_no_email' => "ลูกค้ารายนี้ไม่มีที่อยู่อีเมล",
|
||||
'invoice_number' => "เลขใบแจ้งหนี้ #",
|
||||
'invoice_number_duplicate' => "ใบแจ้งหนี้หมายเลข {0} จะต้องไม่ซ้ำกัน",
|
||||
'invoice_sent' => "ส่งใบแจ้งหนี้ไปที่",
|
||||
'invoice_total' => "ยอดรวมในใบแจ้งหนี้",
|
||||
'invoice_type_custom_invoice' => "ใบแจ้งหนี้ที่กำหนดเอง (custom_invoice.php)",
|
||||
'invoice_type_custom_tax_invoice' => "ใบกำกับภาษีที่กำหนดเอง (custom_tax_invoice.php)",
|
||||
'invoice_type_invoice' => "ใบแจ้งหนี้ (invoice.php)",
|
||||
'invoice_type_tax_invoice' => "ใบกำกับภาษี (tax_invoice.php)",
|
||||
'invoice_unsent' => "ไม่สามารถส่งใบแจ้งหนี้ถึง",
|
||||
'invoice_update' => "คำนวณใหม่",
|
||||
'item_insufficient_of_stock' => "จำนวนสินค้าไม่เพียงพอ",
|
||||
'item_name' => "ชื่อสินค้า",
|
||||
'item_number' => "สินค้า #",
|
||||
'item_out_of_stock' => "สินค้าจำหน่ายหมด",
|
||||
'key_browser' => "ความช่วยเหลือ",
|
||||
'key_cancel' => "ยกเลิกใบเสนอราคา/ใบแจ้งหนี้ /ใบการขาย นี้",
|
||||
'key_customer_search' => "ค้นหาลูกค้า",
|
||||
'key_finish_quote' => "จบใบเสนอราคา/ใบแจ้งหนี้โดยไม่ต้องชำระเงิน",
|
||||
'key_finish_sale' => "เพิ่มการชำระเงินและใบแจ้งหนี้ /ใบรายการขาย",
|
||||
'key_full' => "เปิดแบบเต็มหน้าจอ",
|
||||
'key_function' => "ฟังก์ชั่น",
|
||||
'key_help' => "คำสั่งลัดงานขาย",
|
||||
'key_help_modal' => "เปิดหน้าต่างคำสั่งลัดงานขาย",
|
||||
'key_in' => "ขยายเข้า",
|
||||
'key_item_search' => "ค้นหารายการขาย",
|
||||
'key_out' => "ขยายออก",
|
||||
'key_payment' => "เพิ่มการชำระเงิน",
|
||||
'key_print' => "พิมพ์หน้านี้",
|
||||
'key_restore' => "คืนการแสดงผลแบบดั้งเดิม/ขยาย",
|
||||
'key_search' => "ค้นหาตารางรายงาน",
|
||||
'key_suspend' => "พักรายการขายปัจจุบัน",
|
||||
'key_suspended' => "แสดงรายการขายที่พักไว้",
|
||||
'key_system' => "ทางลัดระบบ",
|
||||
'key_tendered' => "แก้ไขจำนวนเงินรับมา",
|
||||
'key_title' => "ทางลัดคียบอร์ดงานขาย",
|
||||
'mc' => "",
|
||||
'mode' => "รูปแบบการลงทะเบียน",
|
||||
'must_enter_numeric' => "จำนวนที่ถุกประมูลต้องใส่ข้อมุลที่เปนตัวเลข",
|
||||
'must_enter_numeric_giftcard' => "เลขที่บัตรของขวัญ ต้องใส่ตัวเลขเท่านั้น",
|
||||
'new_customer' => "ลูกค้าใหม่",
|
||||
'new_item' => "สินค้าใหม่",
|
||||
'no_description' => "ไม่ระบุรายละเอียด",
|
||||
'no_filter' => "ทั้งหมด",
|
||||
'no_items_in_cart' => "ไม่พบสินค้าในตระกร้า",
|
||||
'no_sales_to_display' => "ไม่มีการขายที่จะแสดง",
|
||||
'none_selected' => "คุณยังไม่ได้เลือกการขายที่จะลบ",
|
||||
'nontaxed_ind' => " . ",
|
||||
'not_authorized' => "การกระทำนี้ไม่ได้รับอนุญาต",
|
||||
'one_or_multiple' => "การขาย",
|
||||
'payment' => "รูปแบบชำระเงิน",
|
||||
'payment_amount' => "จำนวน",
|
||||
'payment_not_cover_total' => "จำนวนเงินที่ชำระต้องมากกว่าหรือเท่ากับยอดรวม",
|
||||
'payment_type' => "ชำระโดย",
|
||||
'payments' => "",
|
||||
'payments_total' => "ยอดชำระแล้ว",
|
||||
'price' => "ราคา",
|
||||
'print_after_sale' => "พิมพ์บิลหลังการขาย",
|
||||
'quantity' => "จำนวน",
|
||||
'quantity_less_than_reorder_level' => "คำเตือน ถ้าจำนวนของไม่เพียงพอกับความต้องการหรือไม่ตรงกับยอดในบันชี ก็สามารถทำการขายได้ แต่ต้องเชคปริมานสินค้าคงคลัง",
|
||||
'quantity_less_than_zero' => "คำเตือน: ถ้าจำนวนของไม่เพียงพอกับความต้องการหรือไม่ตรงกับยอดในบัญชี ก็สามารถทำการขายได้ แต่ต้องตรวจสอบปริมาญสินค้าคงคลังก่อน",
|
||||
'quantity_of_items' => "ปริมาณของ {0} รายการ",
|
||||
'quote' => "ใบเสนอราคา",
|
||||
'quote_number' => "หมายเลขอ้างอิง",
|
||||
'quote_number_duplicate' => "หมายเลขอ้างอิงต้องไม่ซ้ำกัน",
|
||||
'quote_sent' => "ส่งการอ้างอิงถึง",
|
||||
'quote_unsent' => "ส่งการอ้างอิงถึงผิดพลาด",
|
||||
'receipt' => "บิลขาย",
|
||||
'receipt_no_email' => "ลูกค้านี้ไม่มีที่อยู่อีเมล์",
|
||||
'receipt_number' => "จุดขาย#",
|
||||
'receipt_sent' => "ส่งใบเสร็จไปที่",
|
||||
'receipt_unsent' => "ไม่สามารถส่งใบเสร็จไปที่",
|
||||
'refund' => "ประเภทการยกเลิกการขาย",
|
||||
'register' => "ลงทะเบียนขาย",
|
||||
'remove_customer' => "ลบลูกค้า",
|
||||
'remove_discount' => "",
|
||||
'return' => "คืน",
|
||||
'rewards' => "คะแนนสะสม",
|
||||
'rewards_balance' => "คะแนนสะสมคงเหลือ",
|
||||
'sale' => "ขาย",
|
||||
'sale_by_invoice' => "การขายโดยใบแจ้งหนี้",
|
||||
'sale_for_customer' => "ลูกค้า:",
|
||||
'sale_time' => "เวลา",
|
||||
'sales_tax' => "ภาษีการขาย",
|
||||
'sales_total' => "",
|
||||
'select_customer' => "เลือกลูกค้า (Optional)",
|
||||
'send_invoice' => "ส่งใบแจ้งหนี้",
|
||||
'send_quote' => "ส่งใบเสนอราคา",
|
||||
'send_receipt' => "ส่งใบเสร็จ",
|
||||
'send_work_order' => "ส่งคำสั่งงาน",
|
||||
'serial' => "หมายเลขซีเรียล",
|
||||
'service_charge' => "",
|
||||
'show_due' => "",
|
||||
'show_invoice' => "ใบแจ้งหนี้",
|
||||
'show_receipt' => "ใบเสร็จ",
|
||||
'start_typing_customer_name' => "เริ่มต้นพิมพ์ชื่อลูกค้า...",
|
||||
'start_typing_item_name' => "เริ่มต้นพิมพ์ชื่อสินค้า หรือ สแกนบาร์โค๊ด...",
|
||||
'stock' => "คลังสินค้า",
|
||||
'stock_location' => "ที่เก็บ",
|
||||
'sub_total' => "ยอดรวมย่อย",
|
||||
'successfully_deleted' => "ลบการขายสมยูรณ์",
|
||||
'successfully_restored' => "คุณกู้คืนสำเร็จแล้ว",
|
||||
'successfully_suspended_sale' => "การขายของคุณถูกระงับเรียบร้อย",
|
||||
'successfully_updated' => "อัพเดทการขายสมบูรณ์",
|
||||
'suspend_sale' => "พักรายการ",
|
||||
'suspended_doc_id' => "รหัสเอกสาร",
|
||||
'suspended_sale_id' => "รหัสการขายที่ถูกพัก",
|
||||
'suspended_sales' => "การขายที่พักไว้",
|
||||
'table' => "โต๊ะ",
|
||||
'takings' => "การขายประจำวัน",
|
||||
'tax' => "ภาษี",
|
||||
'tax_id' => "รหัสภาษี",
|
||||
'tax_invoice' => "ใบกำกับภาษี",
|
||||
'tax_percent' => "ภาษี %",
|
||||
'taxed_ind' => "ภ",
|
||||
'total' => "ยอดรวม",
|
||||
'total_tax_exclusive' => "ยอดไม่รวมภาษี",
|
||||
'transaction_failed' => "การดำเนินการขายล้มเหลว",
|
||||
'unable_to_add_item' => "เพิ่มรายการไปยังการขายล้มเหลว",
|
||||
'unsuccessfully_deleted' => "ลบการขายไม่สำเร็จ",
|
||||
'unsuccessfully_restored' => "การคืนค่ารายการขายล้มเหลว",
|
||||
'unsuccessfully_suspended_sale' => "การขายของคุณถูกระงับเรียบร้อย",
|
||||
'unsuccessfully_updated' => "อัพเดทการขายไม่สมบูรณ์",
|
||||
'unsuspend' => "ยกเลิกการระงับ",
|
||||
'unsuspend_and_delete' => "ยกเลิกการระงับ และ ลบ",
|
||||
'update' => "แก้ไข",
|
||||
'upi' => "ยูพีไอ",
|
||||
'visa' => "",
|
||||
'wholesale' => "",
|
||||
'work_order' => "คำสั่งงาน",
|
||||
'work_order_number' => "หมายเลขคำสั่งงาน",
|
||||
'work_order_number_duplicate' => "หมายเลขคำสั่งงานต้องไม่ซ้ำกัน",
|
||||
'work_order_sent' => "คำสั่งงานส่งถึง",
|
||||
'work_order_unsent' => "ส่งคำสั่งงานล้มเหลว",
|
||||
'selected_customer' => "ลูกค้าที่เลือก",
|
||||
"customers_available_points" => "คะแนนที่มี",
|
||||
"rewards_package" => "คะแนนสะสม",
|
||||
"rewards_remaining_balance" => "คะแนนสะสมคงเหลือ ",
|
||||
"account_number" => "บัญชี #",
|
||||
"add_payment" => "เพิ่มบิล",
|
||||
"amount_due" => "ยอดค้างชำระ",
|
||||
"amount_tendered" => "ชำระเข้ามา",
|
||||
"authorized_signature" => "ลายเซ็นผู้มีอำนาจ",
|
||||
"cancel_sale" => "ยกเลิกการขาย",
|
||||
"cash" => "เงินสด",
|
||||
"cash_1" => "",
|
||||
"cash_2" => "",
|
||||
"cash_3" => "",
|
||||
"cash_4" => "",
|
||||
"cash_adjustment" => "การปรับเงินสดขาย",
|
||||
"cash_deposit" => "ฝากเงินสด",
|
||||
"cash_filter" => "เงินสด",
|
||||
"change_due" => "เงินทอน",
|
||||
"change_price" => "เปลี่ยนราคาขาย",
|
||||
"check" => "โอนเงิน/พร้อมเพย์/เช็ค",
|
||||
"check_balance" => "เช็คยอดคงเหลือ",
|
||||
"check_filter" => "ตรวจสอบ",
|
||||
"close" => "",
|
||||
"comment" => "หมายเหตุ",
|
||||
"comments" => "หมายเหตุ",
|
||||
"company_name" => "",
|
||||
"complete" => "",
|
||||
"complete_sale" => "จบการขาย",
|
||||
"confirm_cancel_sale" => "แน่ใจหรือไม่ที่จะล้างการขายนี้? ทุกรายการจะถูกลบทั้งหมด",
|
||||
"confirm_delete" => "โปรดยืนยันการลบรายการขายที่เลือกไว้ ?",
|
||||
"confirm_restore" => "คุณแน่ใจหรือไม่ว่าต้องการยกเลิกการขายที่เลือกไว้?",
|
||||
"credit" => "เครดิตการ์ด",
|
||||
"credit_deposit" => "เงินฝากเครดิต",
|
||||
"credit_filter" => "บัตรเครติด",
|
||||
"current_table" => "",
|
||||
"customer" => "ลูกค้า",
|
||||
"customer_address" => "Customer Address",
|
||||
"customer_discount" => "ส่วนลด",
|
||||
"customer_email" => "Customer Email",
|
||||
"customer_location" => "Customer Location",
|
||||
"customer_mailchimp_status" => "สถานะของระบบส่งเมล์เมล์ชิม",
|
||||
"customer_optional" => "(ต้องระบุวันที่ชำระเงิน)",
|
||||
"customer_required" => "(ต้องระบุ)",
|
||||
"customer_total" => "Total",
|
||||
"customer_total_spent" => "",
|
||||
"daily_sales" => "",
|
||||
"date" => "วันที่ขาย",
|
||||
"date_range" => "ระหว่างวันที่",
|
||||
"date_required" => "กรุณากรอกวันที่ให้ถูกต้อง",
|
||||
"date_type" => "กรุณากรอกข้อมูลในช่องวันที่",
|
||||
"debit" => "บัตรประชารัฐ/เดบิตการ์ด",
|
||||
"debit_filter" => "",
|
||||
"delete" => "อนุญาตให้ลบ",
|
||||
"delete_confirmation" => "แน่ใจหรือไม่ที่จะลบรายการขายนี้, ลบแล้วไม่สามารถเรียกกลับคืนใด้",
|
||||
"delete_entire_sale" => "ลบการขายทั้งหมด",
|
||||
"delete_successful" => "คุณลบการขายสำเร็จ",
|
||||
"delete_unsuccessful" => "คุณลบการขายไม่สำเร็จ",
|
||||
"description_abbrv" => "รายละเอียด",
|
||||
"discard" => "ยกเลิก",
|
||||
"discard_quote" => "",
|
||||
"discount" => "ส่วนลด %",
|
||||
"discount_included" => "% ส่วนลด",
|
||||
"discount_short" => "%",
|
||||
"due" => "วันครบกำหนด",
|
||||
"due_filter" => "วันที่ครบกำหนด",
|
||||
"edit" => "แก้ไข",
|
||||
"edit_item" => "แก้ไขสินค้า",
|
||||
"edit_sale" => "แก้ไขการขาย",
|
||||
"email_receipt" => "อีเมลบิล",
|
||||
"employee" => "พนักงาน",
|
||||
"entry" => "การนำเข้า",
|
||||
"error_editing_item" => "แก้ไขสินค้าล้มเหลว",
|
||||
"negative_price_invalid" => "",
|
||||
"negative_quantity_invalid" => "",
|
||||
"negative_discount_invalid" => "",
|
||||
"discount_percent_exceeds_100" => "",
|
||||
"discount_exceeds_item_total" => "",
|
||||
"negative_total_invalid" => "",
|
||||
"find_or_scan_item" => "ค้นหาสินค้า",
|
||||
"find_or_scan_item_or_receipt" => "ค้นหา หรือ แสกนรายการ หรือ ใบเสร็จ",
|
||||
"giftcard" => "บัตรของขวัญ",
|
||||
"giftcard_balance" => "ยอดคงเหลือบัตรของขวัญ",
|
||||
"giftcard_filter" => "",
|
||||
"giftcard_number" => "เลขที่บัตรของขวัญ",
|
||||
"group_by_category" => "กลุ่มตามหมวดหมู่",
|
||||
"group_by_type" => "กลุ่มตามประเภท",
|
||||
"hsn" => "HSN",
|
||||
"id" => "เลขที่ขาย",
|
||||
"include_prices" => "รวมในราคา?",
|
||||
"invoice" => "ใบแจ้งหนี้",
|
||||
"invoice_confirm" => "ใบแจ้งหนี้นี้จะถูกส่งไปที่",
|
||||
"invoice_enable" => "เลขที่ใบแจ้งหนี้",
|
||||
"invoice_filter" => "ใบแจ้งหนี้",
|
||||
"invoice_no_email" => "ลูกค้ารายนี้ไม่มีที่อยู่อีเมล",
|
||||
"invoice_number" => "เลขใบแจ้งหนี้ #",
|
||||
"invoice_number_duplicate" => "ใบแจ้งหนี้หมายเลข {0} จะต้องไม่ซ้ำกัน",
|
||||
"invoice_sent" => "ส่งใบแจ้งหนี้ไปที่",
|
||||
"invoice_total" => "ยอดรวมในใบแจ้งหนี้",
|
||||
"invoice_type_custom_invoice" => "ใบแจ้งหนี้ที่กำหนดเอง (custom_invoice.php)",
|
||||
"invoice_type_custom_tax_invoice" => "ใบกำกับภาษีที่กำหนดเอง (custom_tax_invoice.php)",
|
||||
"invoice_type_invoice" => "ใบแจ้งหนี้ (invoice.php)",
|
||||
"invoice_type_tax_invoice" => "ใบกำกับภาษี (tax_invoice.php)",
|
||||
"invoice_unsent" => "ไม่สามารถส่งใบแจ้งหนี้ถึง",
|
||||
"invoice_update" => "คำนวณใหม่",
|
||||
"item_insufficient_of_stock" => "จำนวนสินค้าไม่เพียงพอ",
|
||||
"item_name" => "ชื่อสินค้า",
|
||||
"item_number" => "สินค้า #",
|
||||
"item_out_of_stock" => "สินค้าจำหน่ายหมด",
|
||||
"key_browser" => "ความช่วยเหลือ",
|
||||
"key_cancel" => "ยกเลิกใบเสนอราคา/ใบแจ้งหนี้ /ใบการขาย นี้",
|
||||
"key_customer_search" => "ค้นหาลูกค้า",
|
||||
"key_finish_quote" => "จบใบเสนอราคา/ใบแจ้งหนี้โดยไม่ต้องชำระเงิน",
|
||||
"key_finish_sale" => "เพิ่มการชำระเงินและใบแจ้งหนี้ /ใบรายการขาย",
|
||||
"key_full" => "เปิดแบบเต็มหน้าจอ",
|
||||
"key_function" => "ฟังก์ชั่น",
|
||||
"key_help" => "คำสั่งลัดงานขาย",
|
||||
"key_help_modal" => "เปิดหน้าต่างคำสั่งลัดงานขาย",
|
||||
"key_in" => "ขยายเข้า",
|
||||
"key_item_search" => "ค้นหารายการขาย",
|
||||
"key_out" => "ขยายออก",
|
||||
"key_payment" => "เพิ่มการชำระเงิน",
|
||||
"key_print" => "พิมพ์หน้านี้",
|
||||
"key_restore" => "คืนการแสดงผลแบบดั้งเดิม/ขยาย",
|
||||
"key_search" => "ค้นหาตารางรายงาน",
|
||||
"key_suspend" => "พักรายการขายปัจจุบัน",
|
||||
"key_suspended" => "แสดงรายการขายที่พักไว้",
|
||||
"key_system" => "ทางลัดระบบ",
|
||||
"key_tendered" => "แก้ไขจำนวนเงินรับมา",
|
||||
"key_title" => "ทางลัดคียบอร์ดงานขาย",
|
||||
"mc" => "",
|
||||
"mode" => "รูปแบบการลงทะเบียน",
|
||||
"must_enter_numeric" => "จำนวนที่ถุกประมูลต้องใส่ข้อมุลที่เปนตัวเลข",
|
||||
"must_enter_numeric_giftcard" => "เลขที่บัตรของขวัญ ต้องใส่ตัวเลขเท่านั้น",
|
||||
"new_customer" => "ลูกค้าใหม่",
|
||||
"new_item" => "สินค้าใหม่",
|
||||
"no_description" => "ไม่ระบุรายละเอียด",
|
||||
"no_filter" => "ทั้งหมด",
|
||||
"no_items_in_cart" => "ไม่พบสินค้าในตระกร้า",
|
||||
"no_sales_to_display" => "ไม่มีการขายที่จะแสดง",
|
||||
"none_selected" => "คุณยังไม่ได้เลือกการขายที่จะลบ",
|
||||
"nontaxed_ind" => " . ",
|
||||
"not_authorized" => "การกระทำนี้ไม่ได้รับอนุญาต",
|
||||
"one_or_multiple" => "การขาย",
|
||||
"payment" => "รูปแบบชำระเงิน",
|
||||
"payment_amount" => "จำนวน",
|
||||
"payment_not_cover_total" => "จำนวนเงินที่ชำระต้องมากกว่าหรือเท่ากับยอดรวม",
|
||||
"payment_type" => "ชำระโดย",
|
||||
"payments" => "",
|
||||
"payments_total" => "ยอดชำระแล้ว",
|
||||
"price" => "ราคา",
|
||||
"print_after_sale" => "พิมพ์บิลหลังการขาย",
|
||||
"quantity" => "จำนวน",
|
||||
"quantity_less_than_reorder_level" => "คำเตือน ถ้าจำนวนของไม่เพียงพอกับความต้องการหรือไม่ตรงกับยอดในบันชี ก็สามารถทำการขายได้ แต่ต้องเชคปริมานสินค้าคงคลัง",
|
||||
"quantity_less_than_zero" => "คำเตือน: ถ้าจำนวนของไม่เพียงพอกับความต้องการหรือไม่ตรงกับยอดในบัญชี ก็สามารถทำการขายได้ แต่ต้องตรวจสอบปริมาญสินค้าคงคลังก่อน",
|
||||
"quantity_of_items" => "ปริมาณของ {0} รายการ",
|
||||
"quote" => "ใบเสนอราคา",
|
||||
"quote_number" => "หมายเลขอ้างอิง",
|
||||
"quote_number_duplicate" => "หมายเลขอ้างอิงต้องไม่ซ้ำกัน",
|
||||
"quote_sent" => "ส่งการอ้างอิงถึง",
|
||||
"quote_unsent" => "ส่งการอ้างอิงถึงผิดพลาด",
|
||||
"receipt" => "บิลขาย",
|
||||
"receipt_no_email" => "ลูกค้านี้ไม่มีที่อยู่อีเมล์",
|
||||
"receipt_number" => "จุดขาย#",
|
||||
"receipt_sent" => "ส่งใบเสร็จไปที่",
|
||||
"receipt_unsent" => "ไม่สามารถส่งใบเสร็จไปที่",
|
||||
"refund" => "ประเภทการยกเลิกการขาย",
|
||||
"register" => "ลงทะเบียนขาย",
|
||||
"remove_customer" => "ลบลูกค้า",
|
||||
"remove_discount" => "",
|
||||
"return" => "คืน",
|
||||
"rewards" => "คะแนนสะสม",
|
||||
"rewards_balance" => "คะแนนสะสมคงเหลือ",
|
||||
"sale" => "ขาย",
|
||||
"sale_by_invoice" => "การขายโดยใบแจ้งหนี้",
|
||||
"sale_for_customer" => "ลูกค้า:",
|
||||
"sale_time" => "เวลา",
|
||||
"sales_tax" => "ภาษีการขาย",
|
||||
"sales_total" => "",
|
||||
"select_customer" => "เลือกลูกค้า (Optional)",
|
||||
"send_invoice" => "ส่งใบแจ้งหนี้",
|
||||
"send_quote" => "ส่งใบเสนอราคา",
|
||||
"send_receipt" => "ส่งใบเสร็จ",
|
||||
"send_work_order" => "ส่งคำสั่งงาน",
|
||||
"serial" => "หมายเลขซีเรียล",
|
||||
"service_charge" => "",
|
||||
"show_due" => "",
|
||||
"show_invoice" => "ใบแจ้งหนี้",
|
||||
"show_receipt" => "ใบเสร็จ",
|
||||
"start_typing_customer_name" => "เริ่มต้นพิมพ์ชื่อลูกค้า...",
|
||||
"start_typing_item_name" => "เริ่มต้นพิมพ์ชื่อสินค้า หรือ สแกนบาร์โค๊ด...",
|
||||
"stock" => "คลังสินค้า",
|
||||
"stock_location" => "ที่เก็บ",
|
||||
"sub_total" => "ยอดรวมย่อย",
|
||||
"successfully_deleted" => "ลบการขายสมยูรณ์",
|
||||
"successfully_restored" => "คุณกู้คืนสำเร็จแล้ว",
|
||||
"successfully_suspended_sale" => "การขายของคุณถูกระงับเรียบร้อย",
|
||||
"successfully_updated" => "อัพเดทการขายสมบูรณ์",
|
||||
"suspend_sale" => "พักรายการ",
|
||||
"suspended_doc_id" => "รหัสเอกสาร",
|
||||
"suspended_sale_id" => "รหัสการขายที่ถูกพัก",
|
||||
"suspended_sales" => "การขายที่พักไว้",
|
||||
"table" => "โต๊ะ",
|
||||
"takings" => "การขายประจำวัน",
|
||||
"tax" => "ภาษี",
|
||||
"tax_id" => "รหัสภาษี",
|
||||
"tax_invoice" => "ใบกำกับภาษี",
|
||||
"tax_percent" => "ภาษี %",
|
||||
"taxed_ind" => "ภ",
|
||||
"total" => "ยอดรวม",
|
||||
"total_tax_exclusive" => "ยอดไม่รวมภาษี",
|
||||
"transaction_failed" => "การดำเนินการขายล้มเหลว",
|
||||
"unable_to_add_item" => "เพิ่มรายการไปยังการขายล้มเหลว",
|
||||
"unsuccessfully_deleted" => "ลบการขายไม่สำเร็จ",
|
||||
"unsuccessfully_restored" => "การคืนค่ารายการขายล้มเหลว",
|
||||
"unsuccessfully_suspended_sale" => "การขายของคุณถูกระงับเรียบร้อย",
|
||||
"unsuccessfully_updated" => "อัพเดทการขายไม่สมบูรณ์",
|
||||
"unsuspend" => "ยกเลิกการระงับ",
|
||||
"unsuspend_and_delete" => "ยกเลิกการระงับ และ ลบ",
|
||||
"update" => "แก้ไข",
|
||||
"upi" => "ยูพีไอ",
|
||||
"visa" => "",
|
||||
"wholesale" => "",
|
||||
"work_order" => "คำสั่งงาน",
|
||||
"work_order_number" => "หมายเลขคำสั่งงาน",
|
||||
"work_order_number_duplicate" => "หมายเลขคำสั่งงานต้องไม่ซ้ำกัน",
|
||||
"work_order_sent" => "คำสั่งงานส่งถึง",
|
||||
"work_order_unsent" => "ส่งคำสั่งงานล้มเหลว",
|
||||
"selected_customer" => "ลูกค้าที่เลือก",
|
||||
];
|
||||
|
||||
@@ -82,40 +82,4 @@ class Email_lib
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the mime type of the company logo file.
|
||||
*
|
||||
* @return string Mime type or empty string if logo doesn't exist
|
||||
*/
|
||||
public function getLogoMimeType(): string
|
||||
{
|
||||
$logo_path = FCPATH . 'uploads/' . $this->config['company_logo'];
|
||||
|
||||
if (!empty($this->config['company_logo']) && file_exists($logo_path)) {
|
||||
$mimeType = mime_content_type($logo_path);
|
||||
return $mimeType !== false ? $mimeType : '';
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds an img tag for the company logo to use in email templates.
|
||||
*
|
||||
* @return string HTML img tag with base64-encoded logo, or empty string if no logo
|
||||
*/
|
||||
public function buildLogoImgTag(): string
|
||||
{
|
||||
$mimeType = $this->getLogoMimeType();
|
||||
|
||||
if ($mimeType === '') {
|
||||
return '';
|
||||
}
|
||||
|
||||
$logo_path = FCPATH . 'uploads/' . $this->config['company_logo'];
|
||||
$logo_data = base64_encode(file_get_contents($logo_path));
|
||||
|
||||
return '<img id="image" src="data:' . $mimeType . ';base64,' . $logo_data . '" alt="company_logo">';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace App\Libraries;
|
||||
|
||||
use CodeIgniter\Database\Exceptions\DatabaseException;
|
||||
use CodeIgniter\Database\MigrationRunner;
|
||||
use Config\Database;
|
||||
use stdClass;
|
||||
@@ -25,7 +26,7 @@ class MY_Migration extends MigrationRunner
|
||||
public function get_latest_migration(): int
|
||||
{
|
||||
$migrations = $this->findMigrations();
|
||||
return (int) basename(end($migrations)->version);
|
||||
return basename(end($migrations)->version);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -41,11 +42,9 @@ class MY_Migration extends MigrationRunner
|
||||
$builder = $db->table('migrations');
|
||||
$builder->select('version')->orderBy('version', 'DESC')->limit(1);
|
||||
$result = $builder->get()->getRow();
|
||||
return $result ? (int) $result->version : 0;
|
||||
return $result ? $result->version : 0;
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
// Database not available yet (e.g. fresh install before schema).
|
||||
// Catches mysqli_sql_exception which is not a DatabaseException.
|
||||
} catch (DatabaseException $e) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -77,9 +76,8 @@ class MY_Migration extends MigrationRunner
|
||||
$result = $builder->get()->getRow();
|
||||
return $result ? $result->version : false;
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
// Database not available yet (e.g. fresh install before schema).
|
||||
// Catches mysqli_sql_exception which is not a DatabaseException.
|
||||
} catch (DatabaseException $e) {
|
||||
// Database doesn't exist yet or connection failed
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
@@ -23,19 +23,6 @@ use ReflectionException;
|
||||
*/
|
||||
class Sale_lib
|
||||
{
|
||||
private const KEY_SHORTCUT_DEFAULTS = [
|
||||
'cancel' => ['value' => '27 | ESC', 'code' => 27, 'label' => 'ESC'],
|
||||
'items' => ['value' => '49 | ALT + 1', 'code' => 49, 'label' => 'ALT + 1'],
|
||||
'customers' => ['value' => '50 | ALT + 2', 'code' => 50, 'label' => 'ALT + 2'],
|
||||
'suspend' => ['value' => '51 | ALT + 3', 'code' => 51, 'label' => 'ALT + 3'],
|
||||
'suspended' => ['value' => '52 | ALT + 4', 'code' => 52, 'label' => 'ALT + 4'],
|
||||
'amount' => ['value' => '53 | ALT + 5', 'code' => 53, 'label' => 'ALT + 5'],
|
||||
'payment' => ['value' => '54 | ALT + 6', 'code' => 54, 'label' => 'ALT + 6'],
|
||||
'complete' => ['value' => '55 | ALT + 7', 'code' => 55, 'label' => 'ALT + 7'],
|
||||
'finish' => ['value' => '56 | ALT + 8', 'code' => 56, 'label' => 'ALT + 8'],
|
||||
'help' => ['value' => '57 | ALT + 9', 'code' => 57, 'label' => 'ALT + 9'],
|
||||
];
|
||||
|
||||
private Attribute $attribute;
|
||||
private Customer $customer;
|
||||
private Dinner_table $dinner_table;
|
||||
@@ -118,44 +105,6 @@ class Sale_lib
|
||||
return $invoice_types;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the available keyboard shortcut choices for the configuration screen.
|
||||
*
|
||||
* @return array<string, string>
|
||||
*/
|
||||
public function getKeyShortcutsOptions(): array
|
||||
{
|
||||
$keyShortcuts = [];
|
||||
|
||||
foreach (self::KEY_SHORTCUT_DEFAULTS as $shortcut) {
|
||||
$keyShortcuts[$shortcut['value']] = $shortcut['label'];
|
||||
}
|
||||
|
||||
return $keyShortcuts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns parsed shortcut bindings from app_config with sensible defaults.
|
||||
*
|
||||
* @return array<string, array{value:string,code:int,label:string}>
|
||||
*/
|
||||
public function getKeyShortcuts(): array
|
||||
{
|
||||
$keyboardShortcuts = [];
|
||||
|
||||
foreach (self::KEY_SHORTCUT_DEFAULTS as $name => $default) {
|
||||
$value = $this->config["key_$name"] ?? $default['value'];
|
||||
$parts = array_map('trim', explode('|', $value, 2));
|
||||
$keyboardShortcuts[$name] = [
|
||||
'value' => $value,
|
||||
'code' => (int)($parts[0] ?? $default['code']),
|
||||
'label' => $parts[1] ?? $default['label']
|
||||
];
|
||||
}
|
||||
|
||||
return $keyboardShortcuts;
|
||||
}
|
||||
|
||||
public static function isValidInvoiceType(string $invoice_type): bool
|
||||
{
|
||||
return in_array($invoice_type, self::ALLOWED_INVOICE_TYPES, true);
|
||||
|
||||
@@ -65,10 +65,8 @@ class Item extends Model
|
||||
public function exists(string $item_id, bool $ignore_deleted = false, bool $deleted = false): bool
|
||||
{
|
||||
$builder = $this->db->table('items');
|
||||
$builder->groupStart();
|
||||
$builder->where('item_id', $item_id);
|
||||
$builder->orWhere('item_number', $item_id);
|
||||
$builder->groupEnd();
|
||||
|
||||
if (!$ignore_deleted) {
|
||||
$builder->where('deleted', $deleted);
|
||||
@@ -391,10 +389,9 @@ class Item extends Model
|
||||
public function get_item_id(string $item_number, bool $ignore_deleted = false, bool $deleted = false): bool|int
|
||||
{
|
||||
$builder = $this->db->table('items');
|
||||
$builder->groupStart();
|
||||
$builder->join('suppliers', 'suppliers.person_id = items.supplier_id', 'left');
|
||||
$builder->where('item_number', $item_number);
|
||||
$builder->orWhere('item_id', $item_number);
|
||||
$builder->groupEnd();
|
||||
|
||||
if (!$ignore_deleted) {
|
||||
$builder->where('items.deleted', $deleted);
|
||||
@@ -439,32 +436,62 @@ class Item extends Model
|
||||
|
||||
/**
|
||||
* Inserts or updates an item
|
||||
*
|
||||
* If the primary key (item_id) is present in the data array and the record exists,
|
||||
* it will update the existing record. Otherwise, it will insert a new record.
|
||||
*
|
||||
* @param array $data The item data to save (passed by reference to set item_id on insert)
|
||||
* @return bool True on success, false on failure
|
||||
*/
|
||||
public function save_value(array &$item_data, int $item_id = NEW_ENTRY): bool // TODO: need to bring this in line with parent or change the name
|
||||
public function saveValue(array &$data): bool
|
||||
{
|
||||
$builder = $this->db->table('items');
|
||||
$primaryKey = $this->primaryKey;
|
||||
$id = $data[$primaryKey] ?? NEW_ENTRY;
|
||||
|
||||
if ($item_id < 1 || !$this->exists($item_id, true)) {
|
||||
if ($builder->insert($item_data)) {
|
||||
$item_data['item_id'] = (int)$this->db->insertID();
|
||||
if ($item_id < 1) {
|
||||
$builder = $this->db->table('items');
|
||||
$builder->where('item_id', $item_data['item_id']);
|
||||
$builder->update(['low_sell_item_id' => $item_data['item_id']]);
|
||||
}
|
||||
|
||||
return true;
|
||||
// If id > 0 and record exists by primary key only, update it
|
||||
if ($id > 0) {
|
||||
// Check existence strictly by primary key (regardless of soft-delete status)
|
||||
$builder = $this->db->table('items');
|
||||
$builder->where($primaryKey, $id);
|
||||
$exists = $builder->countAllResults() > 0;
|
||||
|
||||
if ($exists) {
|
||||
// Remove primary key from data array for update
|
||||
$updateData = $data;
|
||||
unset($updateData[$primaryKey]);
|
||||
|
||||
$builder = $this->db->table('items');
|
||||
$builder->where($primaryKey, $id);
|
||||
return $builder->update($updateData);
|
||||
}
|
||||
|
||||
return false;
|
||||
} else {
|
||||
$item_data['item_id'] = $item_id;
|
||||
}
|
||||
|
||||
// Insert new record with transaction for atomicity
|
||||
$this->db->transBegin();
|
||||
|
||||
// Remove primary key from insert payload if present
|
||||
$insertData = $data;
|
||||
unset($insertData[$primaryKey]);
|
||||
|
||||
$builder = $this->db->table('items');
|
||||
$builder->where('item_id', $item_id);
|
||||
|
||||
return $builder->update($item_data);
|
||||
$success = $builder->insert($insertData);
|
||||
|
||||
if ($success) {
|
||||
$data[$primaryKey] = (int)$this->db->insertID();
|
||||
|
||||
// Update low_sell_item_id for new items
|
||||
$builder = $this->db->table('items');
|
||||
$builder->where($primaryKey, $data[$primaryKey]);
|
||||
$success = $builder->update(['low_sell_item_id' => $data[$primaryKey]]);
|
||||
}
|
||||
|
||||
if ($success) {
|
||||
$this->db->transCommit();
|
||||
return true;
|
||||
}
|
||||
|
||||
$this->db->transRollback();
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1082,9 +1109,9 @@ class Item extends Model
|
||||
$total_quantity = $old_total_quantity + $items_received;
|
||||
$average_price = bcdiv(bcadd(bcmul((string)$items_received, (string)$new_price), bcmul((string)$old_total_quantity, (string)$old_price)), (string)$total_quantity);
|
||||
|
||||
$data = ['cost_price' => $average_price];
|
||||
$data = ['cost_price' => $average_price, 'item_id' => $item_id];
|
||||
|
||||
return $this->save_value($data, $item_id);
|
||||
return $this->saveValue($data);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -11,34 +11,31 @@ $barcode_lib = new Barcode_lib();
|
||||
|
||||
<!doctype html>
|
||||
<html lang="<?= current_language_code() ?>">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title><?= esc(lang('Items.generate_barcodes')) ?></title>
|
||||
<link rel="stylesheet" href="<?= esc(base_url('css/barcode_font.css'), 'url') ?>">
|
||||
<style>
|
||||
.barcode svg {
|
||||
height: <?= (int) $barcode_config['barcode_height'] ?>px;
|
||||
width: <?= (int) $barcode_config['barcode_width'] ?>px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body class="<?= esc('font_' . $barcode_lib->get_font_name($barcode_config['barcode_font']), 'attr') ?>" style="font-size: <?= (int) $barcode_config['barcode_font_size'] ?>px;">
|
||||
<table style="border-spacing: <?= (int) $barcode_config['barcode_page_cellspacing'] ?>px; width: <?= (int) $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>';
|
||||
<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 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++;
|
||||
}
|
||||
echo '<td>' . $barcode_lib->display_barcode($item, $barcode_config) . '</td>';
|
||||
$count++;
|
||||
}
|
||||
?>
|
||||
</tr>
|
||||
</table>
|
||||
</body>
|
||||
|
||||
?>
|
||||
</tr>
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -204,7 +204,6 @@
|
||||
<?= form_label(lang('Config.barcode_number_in_row'), 'barcode_num_in_row', ['class' => 'control-label col-xs-2 required']) ?>
|
||||
<div class="col-xs-2">
|
||||
<?= form_input([
|
||||
'type' => 'number',
|
||||
'name' => 'barcode_num_in_row',
|
||||
'id' => 'barcode_num_in_row',
|
||||
'class' => 'form-control input-sm required',
|
||||
@@ -218,9 +217,6 @@
|
||||
<div class="col-sm-2">
|
||||
<div class="input-group">
|
||||
<?= form_input([
|
||||
'type' => 'number',
|
||||
'min' => '0',
|
||||
'max' => '100',
|
||||
'name' => 'barcode_page_width',
|
||||
'id' => 'barcode_page_width',
|
||||
'class' => 'form-control input-sm required',
|
||||
@@ -236,7 +232,6 @@
|
||||
<div class="col-sm-2">
|
||||
<div class="input-group">
|
||||
<?= form_input([
|
||||
'type' => 'number',
|
||||
'name' => 'barcode_page_cellspacing',
|
||||
'id' => 'barcode_page_cellspacing',
|
||||
'class' => 'form-control input-sm required',
|
||||
|
||||
@@ -17,9 +17,9 @@
|
||||
<?= form_dropdown(
|
||||
'protocol',
|
||||
[
|
||||
'mail' => 'Mail',
|
||||
'sendmail' => 'Sendmail',
|
||||
'smtp' => 'SMTP'
|
||||
'mail' => 'mail',
|
||||
'sendmail' => 'sendmail',
|
||||
'smtp' => 'smtp'
|
||||
],
|
||||
$config['protocol'],
|
||||
'class="form-control input-sm" id="protocol"'
|
||||
@@ -55,7 +55,6 @@
|
||||
<?= form_label(lang('Config.email_smtp_port'), 'smtp_port', ['class' => 'control-label col-xs-2']) ?>
|
||||
<div class="col-xs-2">
|
||||
<?= form_input([
|
||||
'type' => 'number',
|
||||
'name' => 'smtp_port',
|
||||
'id' => 'smtp_port',
|
||||
'class' => 'form-control input-sm',
|
||||
@@ -84,7 +83,6 @@
|
||||
<?= form_label(lang('Config.email_smtp_timeout'), 'smtp_timeout', ['class' => 'control-label col-xs-2']) ?>
|
||||
<div class="col-xs-2">
|
||||
<?= form_input([
|
||||
'type' => 'number',
|
||||
'name' => 'smtp_timeout',
|
||||
'id' => 'smtp_timeout',
|
||||
'class' => 'form-control input-sm',
|
||||
|
||||
@@ -105,7 +105,6 @@
|
||||
<span class="glyphicon glyphicon-phone-alt"></span>
|
||||
</span>
|
||||
<?= form_input([
|
||||
'type' => 'tel',
|
||||
'name' => 'phone',
|
||||
'id' => 'phone',
|
||||
'class' => 'form-control input-sm required',
|
||||
@@ -123,7 +122,6 @@
|
||||
<span class="glyphicon glyphicon-phone-alt"></span>
|
||||
</span>
|
||||
<?= form_input([
|
||||
'type' => 'tel',
|
||||
'name' => 'fax',
|
||||
'id' => 'fax',
|
||||
'class' => 'form-control input-sm',
|
||||
|
||||
@@ -29,9 +29,6 @@
|
||||
<li role="presentation">
|
||||
<a data-toggle="tab" href="#invoice_tab" title="<?= lang('Config.invoice_configuration') ?>"><?= lang('Config.invoice') ?></a>
|
||||
</li>
|
||||
<li role="presentation">
|
||||
<a data-toggle="tab" href="#shortcuts_tab" title="<?= lang('Config.shortcuts_configuration') ?>"><?= lang('Config.shortcuts') ?></a>
|
||||
</li>
|
||||
<li role="presentation">
|
||||
<a data-toggle="tab" href="#reward_tab" title="<?= lang('Config.reward_configuration') ?>"><?= lang('Config.reward') ?></a>
|
||||
</li>
|
||||
@@ -68,9 +65,6 @@
|
||||
<div class="tab-pane" id="invoice_tab">
|
||||
<?= view('configs/invoice_config') ?>
|
||||
</div>
|
||||
<div class="tab-pane" id="shortcuts_tab">
|
||||
<?= view('configs/shortcuts_config') ?>
|
||||
</div>
|
||||
<div class="tab-pane" id="reward_tab">
|
||||
<?= view('configs/reward_config') ?>
|
||||
</div>
|
||||
|
||||
@@ -1,88 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* @var array $config
|
||||
* @var array $keyboardShortcutOptions
|
||||
* @var array $keyboardShortcuts
|
||||
*/
|
||||
|
||||
$keyboardShortcuts ??= [];
|
||||
$keyboardShortcutOptions ??= [];
|
||||
$config ??= [];
|
||||
|
||||
$shortcutLabels = [
|
||||
'cancel' => lang('Sales.key_cancel'),
|
||||
'items' => lang('Sales.key_item_search'),
|
||||
'customers' => lang('Sales.key_customer_search'),
|
||||
'suspend' => lang('Sales.key_suspend'),
|
||||
'suspended' => lang('Sales.key_suspended'),
|
||||
'amount' => lang('Sales.key_tendered'),
|
||||
'payment' => lang('Sales.key_payment'),
|
||||
'complete' => lang('Sales.key_finish_sale'),
|
||||
'finish' => lang('Sales.key_finish_quote'),
|
||||
'help' => lang('Sales.key_help_modal')
|
||||
];
|
||||
?>
|
||||
|
||||
<?= form_open('config/saveShortcuts', ['id' => 'shortcuts_config_form', 'class' => 'form-horizontal']) ?>
|
||||
<div id="config_wrapper">
|
||||
<div class="row">
|
||||
<fieldset id="config_info">
|
||||
<div class="col-md-8">
|
||||
<div id="required_fields_message"><?= esc(lang('Common.fields_required_message')) ?></div>
|
||||
<ul id="shortcuts_error_message_box" class="error_message_box"></ul>
|
||||
|
||||
<?php foreach ($shortcutLabels as $name => $label): ?>
|
||||
<div class="form-group form-group-sm">
|
||||
<?= form_label($label, 'key_' . $name, ['class' => 'control-label col-xs-3']) ?>
|
||||
<div class="col-xs-4">
|
||||
<?php $keyboardShortcutSelectedValue = $keyboardShortcuts[$name]['value'] ?? ''; ?>
|
||||
<?= form_dropdown(
|
||||
'key_' . $name,
|
||||
$keyboardShortcutOptions,
|
||||
$keyboardShortcutSelectedValue,
|
||||
'class="form-control input-sm"'
|
||||
) ?>
|
||||
</div>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
|
||||
<div class="col-xs-12 clearfix">
|
||||
<?= form_submit([
|
||||
'name' => 'submit_shortcuts',
|
||||
'id' => 'submit_shortcuts',
|
||||
'value' => lang('Common.submit'),
|
||||
'class' => 'btn btn-primary btn-sm pull-right'
|
||||
]) ?>
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
</div>
|
||||
</div>
|
||||
<?= form_close() ?>
|
||||
|
||||
<script type="text/javascript">
|
||||
$('#shortcuts_config_form').validate($.extend(form_support.handler, {
|
||||
submitHandler: function(form) {
|
||||
$(form).ajaxSubmit({
|
||||
success: function(response) {
|
||||
$.notify({
|
||||
message: response.message
|
||||
}, {
|
||||
type: response.success ? 'success' : 'danger'
|
||||
});
|
||||
},
|
||||
error: function(xhr) {
|
||||
const rawMessage = xhr.responseJSON?.message ?? xhr.responseText ?? <?= json_encode(lang('Config.shortcuts_save_error')) ?>;
|
||||
$.notify({
|
||||
message: DOMPurify.sanitize(rawMessage)
|
||||
}, {
|
||||
type: 'danger'
|
||||
});
|
||||
},
|
||||
dataType: 'json'
|
||||
});
|
||||
},
|
||||
|
||||
errorLabelContainer: '#shortcuts_error_message_box'
|
||||
}));
|
||||
</script>
|
||||
@@ -25,8 +25,8 @@ use Config\OSPOS;
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-sm-2" style="text-align: left;"><br>
|
||||
<p style="min-height: 17.7em; font-weight: bold;">General Info</p>
|
||||
<p style="min-height: 12.2em; font-weight: bold;">User Setup</p><br>
|
||||
<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>
|
||||
@@ -42,7 +42,7 @@ use Config\OSPOS;
|
||||
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>';
|
||||
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>
|
||||
|
||||
@@ -51,10 +51,6 @@
|
||||
</div>
|
||||
<div class="col-xs-1 input-group">
|
||||
<?= form_input([
|
||||
'type' => 'number',
|
||||
'step' => 'any',
|
||||
'min' => '0',
|
||||
'max' => '100',
|
||||
'name' => 'default_tax_1_rate',
|
||||
'id' => 'default_tax_1_rate',
|
||||
'class' => 'form-control input-sm',
|
||||
@@ -76,10 +72,6 @@
|
||||
</div>
|
||||
<div class="col-xs-1 input-group">
|
||||
<?= form_input([
|
||||
'type' => 'number',
|
||||
'step' => 'any',
|
||||
'min' => '0',
|
||||
'max' => '100',
|
||||
'name' => 'default_tax_2_rate',
|
||||
'id' => 'default_tax_2_rate',
|
||||
'class' => 'form-control input-sm',
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -5,14 +5,9 @@
|
||||
* @var bool $is_new_install
|
||||
* @var string $latest_version
|
||||
* @var bool $gcaptcha_enabled
|
||||
* @var CodeIgniter\HTTP\IncomingRequest $request
|
||||
* @var array $config
|
||||
* @var $validation
|
||||
*/
|
||||
|
||||
use Config\Services;
|
||||
|
||||
$request = Services::request();
|
||||
?>
|
||||
|
||||
<!doctype html>
|
||||
@@ -159,6 +154,11 @@ $request = Services::request();
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<?php
|
||||
use Config\Services;
|
||||
$request = Services::request();
|
||||
?>
|
||||
|
||||
<?php if (ENVIRONMENT == 'development' || get_cookie('debug') == 'true' || $request->getGet('debug') == 'true') : ?>
|
||||
<!-- inject:login:debug:js -->
|
||||
<!-- endinject -->
|
||||
|
||||
@@ -12,16 +12,14 @@ $request = Services::request();
|
||||
?>
|
||||
|
||||
<!doctype html>
|
||||
<html lang="<?= current_language_code() ?>">
|
||||
<html lang="<?= $request->getLocale() ?>">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<base href="<?= base_url() ?>">
|
||||
<title><?= esc($config['company']) . ' | ' . lang('Common.powered_by') . ' OSPOS ' . esc(config('App')->application_version) ?></title>
|
||||
<meta name="robots" content="noindex, nofollow">
|
||||
<link rel="shortcut icon" type="image/x-icon" href="images/favicon.ico">
|
||||
<?php $theme = (empty($config['theme']) ? 'flatly' : esc($config['theme'])); ?>
|
||||
<link rel="stylesheet" href="resources/bootswatch/<?= "$theme" ?>/bootstrap.min.css">
|
||||
<link rel="stylesheet" href="<?= 'resources/bootswatch/' . (empty($config['theme']) ? 'flatly' : esc($config['theme'])) . '/bootstrap.min.css' ?>">
|
||||
|
||||
<?php if (ENVIRONMENT == 'development' || get_cookie('debug') == 'true' || $request->getGet('debug') == 'true') : ?>
|
||||
<!-- inject:debug:css -->
|
||||
|
||||
@@ -1,24 +1,3 @@
|
||||
<?php
|
||||
/**
|
||||
* @var array $keyboardShortcuts
|
||||
*/
|
||||
|
||||
$keyboardShortcuts ??= [];
|
||||
|
||||
$shortcut_labels = [
|
||||
'cancel' => lang('Sales.key_cancel'),
|
||||
'items' => lang('Sales.key_item_search'),
|
||||
'customers' => lang('Sales.key_customer_search'),
|
||||
'suspend' => lang('Sales.key_suspend'),
|
||||
'suspended' => lang('Sales.key_suspended'),
|
||||
'amount' => lang('Sales.key_tendered'),
|
||||
'payment' => lang('Sales.key_payment'),
|
||||
'complete' => lang('Sales.key_finish_sale'),
|
||||
'finish' => lang('Sales.key_finish_quote'),
|
||||
'help' => lang('Sales.key_help_modal')
|
||||
];
|
||||
?>
|
||||
|
||||
<div class="container-fluid">
|
||||
|
||||
<ul class="nav nav-tabs" id="SCTabs" data-toggle="tab">
|
||||
@@ -36,13 +15,46 @@ $shortcut_labels = [
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($shortcut_labels as $name => $label): ?>
|
||||
<?php $shortcut = $keyboardShortcuts[$name] ?? ['label' => '', 'code' => '']; ?>
|
||||
<tr>
|
||||
<td><code><?= esc($shortcut['label'] !== '' ? $shortcut['label'] : $shortcut['code']) ?></code></td>
|
||||
<td><?= esc($label) ?></td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
<tr>
|
||||
<td><code>ESC</code></td>
|
||||
<td><?= lang('Sales.key_cancel'); ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>ALT + 1</code></td>
|
||||
<td><?= lang('Sales.key_item_search'); ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>ALT + 2</code></td>
|
||||
<td><?= lang('Sales.key_customer_search'); ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>ALT + 3</code></td>
|
||||
<td><?= lang('Sales.key_suspend'); ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>ALT + 4</code></td>
|
||||
<td><?= lang('Sales.key_suspended'); ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>ALT + 5</code></td>
|
||||
<td><?= lang('Sales.key_tendered'); ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>ALT + 6</code></td>
|
||||
<td><?= lang('Sales.key_payment'); ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>ALT + 7</code></td>
|
||||
<td><?= lang('Sales.key_finish_sale'); ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>ALT + 8</code></td>
|
||||
<td><?= lang('Sales.key_finish_quote'); ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>ALT + 9</code></td>
|
||||
<td><?= lang('Sales.key_help_modal'); ?></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
?>
|
||||
|
||||
<!doctype html>
|
||||
<html lang="<?= current_language_code() ?>">
|
||||
<html lang="<?= $this->request->getLocale() ?>">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
|
||||
@@ -405,7 +405,6 @@ helper('url');
|
||||
<div id="payment_details">
|
||||
<?php if ($payments_cover_total) { // Show Complete sale button instead of Add Payment if there is no amount due left ?>
|
||||
<?= form_open("$controller_name/addPayment", ['id' => 'add_payment_form', 'class' => 'form-horizontal']) ?>
|
||||
<input type="hidden" name="complete_after_payment" value="0">
|
||||
<table class="sales_table_100">
|
||||
<tr>
|
||||
<td><?= lang(ucfirst($controller_name) . '.payment') ?></td>
|
||||
@@ -446,7 +445,6 @@ helper('url');
|
||||
?>
|
||||
<?php } else { ?>
|
||||
<?= form_open("$controller_name/addPayment", ['id' => 'add_payment_form', 'class' => 'form-horizontal']) ?>
|
||||
<input type="hidden" name="complete_after_payment" value="0">
|
||||
<table class="sales_table_100">
|
||||
<tr>
|
||||
<td><?= lang(ucfirst($controller_name) . '.payment') ?></td>
|
||||
@@ -567,21 +565,6 @@ helper('url');
|
||||
</div>
|
||||
|
||||
<script type="text/javascript">
|
||||
const keyboardShortcuts = <?= json_encode($keyboardShortcuts ?? []) ?>;
|
||||
const paymentsCoverTotal = <?= json_encode((bool) $payments_cover_total) ?>;
|
||||
const shortcutCodes = {
|
||||
items: keyboardShortcuts?.items?.code ?? null,
|
||||
customers: keyboardShortcuts?.customers?.code ?? null,
|
||||
suspend: keyboardShortcuts?.suspend?.code ?? null,
|
||||
suspended: keyboardShortcuts?.suspended?.code ?? null,
|
||||
amount: keyboardShortcuts?.amount?.code ?? null,
|
||||
payment: keyboardShortcuts?.payment?.code ?? null,
|
||||
complete: keyboardShortcuts?.complete?.code ?? null,
|
||||
finish: keyboardShortcuts?.finish?.code ?? null,
|
||||
help: keyboardShortcuts?.help?.code ?? null,
|
||||
cancel: keyboardShortcuts?.cancel?.code ?? null
|
||||
};
|
||||
|
||||
$(document).ready(function() {
|
||||
const redirect = function() {
|
||||
window.location.href = "<?= site_url('sales'); ?>";
|
||||
@@ -767,7 +750,6 @@ helper('url');
|
||||
});
|
||||
|
||||
$('#add_payment_button').click(function() {
|
||||
$('#add_payment_form').find('input[name="complete_after_payment"]').val('0');
|
||||
$('#add_payment_form').submit();
|
||||
});
|
||||
|
||||
@@ -857,51 +839,43 @@ helper('url');
|
||||
}
|
||||
|
||||
// Add Keyboard Shortcuts/Hotkeys to Sale Register
|
||||
document.body.onkeyup = function(event) {
|
||||
if ($(event.target).closest('.modal').length || $('.modal.in').length) {
|
||||
return;
|
||||
}
|
||||
if (event.altKey) {
|
||||
switch (event.keyCode) {
|
||||
case shortcutCodes.items:
|
||||
$("#item").focus();
|
||||
$("#item").select();
|
||||
break;
|
||||
case shortcutCodes.customers:
|
||||
$("#customer").focus();
|
||||
$("#customer").select();
|
||||
break;
|
||||
case shortcutCodes.suspend:
|
||||
$("#suspend_sale_button").click();
|
||||
break;
|
||||
case shortcutCodes.suspended:
|
||||
$("#show_suspended_sales_button").click();
|
||||
break;
|
||||
case shortcutCodes.amount:
|
||||
$("#amount_tendered").focus();
|
||||
$("#amount_tendered").select();
|
||||
break;
|
||||
case shortcutCodes.payment:
|
||||
$("#add_payment_button").click();
|
||||
break;
|
||||
case shortcutCodes.complete:
|
||||
if (paymentsCoverTotal && $("#finish_sale_button").length) {
|
||||
$("#finish_sale_button").click();
|
||||
} else {
|
||||
$("#add_payment_button").click();
|
||||
}
|
||||
break;
|
||||
case shortcutCodes.finish:
|
||||
$("#finish_invoice_quote_button").click();
|
||||
break;
|
||||
case shortcutCodes.help:
|
||||
$("#show_keyboard_help").click();
|
||||
break;
|
||||
}
|
||||
document.body.onkeyup = function(e) {
|
||||
switch (event.altKey && event.keyCode) {
|
||||
case 49: // Alt + 1 Items Seach
|
||||
$("#item").focus();
|
||||
$("#item").select();
|
||||
break;
|
||||
case 50: // Alt + 2 Customers Search
|
||||
$("#customer").focus();
|
||||
$("#customer").select();
|
||||
break;
|
||||
case 51: // Alt + 3 Suspend Current Sale
|
||||
$("#suspend_sale_button").click();
|
||||
break;
|
||||
case 52: // Alt + 4 Check Suspended
|
||||
$("#show_suspended_sales_button").click();
|
||||
break;
|
||||
case 53: // Alt + 5 Edit Amount Tendered Value
|
||||
$("#amount_tendered").focus();
|
||||
$("#amount_tendered").select();
|
||||
break;
|
||||
case 54: // Alt + 6 Add Payment
|
||||
$("#add_payment_button").click();
|
||||
break;
|
||||
case 55: // Alt + 7 Add Payment and Complete Sales/Invoice
|
||||
$("#add_payment_button").click();
|
||||
window.location.href = "<?= 'sales/complete' ?>";
|
||||
break;
|
||||
case 56: // Alt + 8 Finish Quote/Invoice without payment
|
||||
$("#finish_invoice_quote_button").click();
|
||||
break;
|
||||
case 57: // Alt + 9 Open Shortcuts Help Modal
|
||||
$("#show_keyboard_help").click();
|
||||
break;
|
||||
}
|
||||
|
||||
switch (event.keyCode) {
|
||||
case shortcutCodes.cancel:
|
||||
case 27: // ESC Cancel Current Sale
|
||||
$("#cancel_sale_button").click();
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
?>
|
||||
|
||||
<!doctype html>
|
||||
<html lang="<?= current_language_code() ?>">
|
||||
<html lang="<?= $this->request->getLocale() ?>">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
|
||||
@@ -2,19 +2,25 @@
|
||||
"name": "opensourcepos/opensourcepos",
|
||||
"description": "Open Source Point of Sale is a web based POS system written in the PHP language. It uses MySQL as backend and has a simple user interface",
|
||||
"license": "MIT",
|
||||
"type": "project",
|
||||
"keywords": [
|
||||
"point-of-sale",
|
||||
"POS"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "jekkos"
|
||||
},
|
||||
{
|
||||
"name": "FrancescoUK"
|
||||
},
|
||||
{
|
||||
"name": "objecttothis"
|
||||
},
|
||||
{
|
||||
"name": "steveireland"
|
||||
}
|
||||
],
|
||||
"type": "project",
|
||||
"keywords": [
|
||||
"point-of-sale",
|
||||
"POS"
|
||||
],
|
||||
"homepage": "https://opensourcepos.org",
|
||||
"support": {
|
||||
"issues": "https://github.com/opensourcepos/opensourcepos/issues",
|
||||
@@ -25,8 +31,8 @@
|
||||
"matrix": "https://matrix.to/#/#opensourcepos_Lobby:gitter.im"
|
||||
},
|
||||
"require": {
|
||||
"php": "^8.2",
|
||||
"ext-intl": "*",
|
||||
"php": "^8.2",
|
||||
"codeigniter4/framework": "4.7.2",
|
||||
"dompdf/dompdf": "^2.0.3",
|
||||
"ezyang/htmlpurifier": "^4.17",
|
||||
@@ -50,7 +56,7 @@
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"App\\": "app/",
|
||||
"App\\": "app/",
|
||||
"CodeIgniter\\": "vendor/codeigniter4/framework/system/"
|
||||
},
|
||||
"exclude-from-classmap": [
|
||||
@@ -67,8 +73,5 @@
|
||||
},
|
||||
"scripts": {
|
||||
"test": "phpunit"
|
||||
},
|
||||
"scripts-descriptions": {
|
||||
"test": "Run unit tests"
|
||||
}
|
||||
}
|
||||
|
||||
8
composer.lock
generated
8
composer.lock
generated
@@ -4,7 +4,7 @@
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "eabbc14aefdea4c933869069d6eadadb",
|
||||
"content-hash": "e95f6e5e86d323370ddb0df57c4d3fb3",
|
||||
"packages": [
|
||||
{
|
||||
"name": "codeigniter4/framework",
|
||||
@@ -5382,9 +5382,9 @@
|
||||
"prefer-stable": false,
|
||||
"prefer-lowest": false,
|
||||
"platform": {
|
||||
"php": "^8.2",
|
||||
"ext-intl": "*"
|
||||
"ext-intl": "*",
|
||||
"php": "^8.1"
|
||||
},
|
||||
"platform-dev": {},
|
||||
"plugin-api-version": "2.9.0"
|
||||
"plugin-api-version": "2.6.0"
|
||||
}
|
||||
|
||||
@@ -300,7 +300,6 @@ gulp.task('copy-menubar', function() {
|
||||
// Run all required tasks
|
||||
gulp.task('default',
|
||||
gulp.series('clean',
|
||||
'update-licenses',
|
||||
'copy-bootswatch',
|
||||
'copy-bootswatch5',
|
||||
'copy-bootstrap',
|
||||
|
||||
1710
package-lock.json
generated
1710
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
58
package.json
58
package.json
@@ -1,33 +1,34 @@
|
||||
{
|
||||
"name": "@opensourcepos/opensourcepos",
|
||||
"version": "3.4.2",
|
||||
"description": "Open Source Point of Sale is a web based point of sale system written in the PHP language. It uses MySQL as the data storage back-end and has a simple user interface.",
|
||||
"keywords": [
|
||||
"point-of-sale",
|
||||
"POS"
|
||||
],
|
||||
"homepage": "https://opensourcepos.org",
|
||||
"bugs": {
|
||||
"url": "https://github.com/opensourcepos/opensourcepos/issues"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/opensourcepos/opensourcepos.git"
|
||||
},
|
||||
"description": "pen Source Point of Sale is a web based point of sale system written in the PHP language. It uses MySQL as the data storage back-end and has a simple user interface.",
|
||||
"main": "index.php",
|
||||
"license": "MIT",
|
||||
"contributors": [
|
||||
"authors": [
|
||||
"jekkos <jekkos - at - opensourcepos.org>",
|
||||
"objecttothis <objecttothis - at - gmail.com>"
|
||||
"FrancescoUK <francesco.lodolo.uk - at - gmail.com>",
|
||||
"objecttothis <objecttothis - at - gmail.com>",
|
||||
"SteveIreland <stevei - at - ruledomain.com>"
|
||||
],
|
||||
"files": [
|
||||
"dist/opensourcepos.$version.tgz"
|
||||
],
|
||||
"type": "module",
|
||||
"main": "index.php",
|
||||
"publishConfig": {
|
||||
"registry": "https://npm.pkg.github.com/"
|
||||
},
|
||||
"keywords": [
|
||||
"point-of-sale",
|
||||
"POS"
|
||||
],
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/opensourcepos/opensourcepos"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "gulp default",
|
||||
"gulp": "gulp"
|
||||
},
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
"bootstrap": "^3.4.1",
|
||||
"bootstrap-daterangepicker": "^2.1.27",
|
||||
@@ -38,9 +39,9 @@
|
||||
"bootstrap-tagsinput-2021": "^0.8.6",
|
||||
"bootstrap-toggle": "^2.2.2",
|
||||
"bootstrap3-dialog": "github:nakupanda/bootstrap3-dialog#master",
|
||||
"bootstrap5": "npm:bootstrap@^5.3.8",
|
||||
"bootstrap5": "npm:bootstrap@^5.3.5",
|
||||
"bootswatch": "^3.4.1",
|
||||
"bootswatch5": "npm:bootswatch@^5.3.8",
|
||||
"bootswatch5": "npm:bootswatch@^5.3.5",
|
||||
"chartist": "^0.11.4",
|
||||
"chartist-plugin-axistitle": "^0.0.7",
|
||||
"chartist-plugin-barlabels": "^0.0.5",
|
||||
@@ -48,7 +49,7 @@
|
||||
"chartist-plugin-tooltips": "^0.0.17",
|
||||
"clipboard": "^2.0.11",
|
||||
"coffeescript": "^2.7.0",
|
||||
"dompurify": "^3.4.0",
|
||||
"dompurify": "^3.3.2",
|
||||
"elegant-circles": "github:opensourcepos/elegant-circles#minified",
|
||||
"es6-promise": "^4.2.8",
|
||||
"file-saver": "^2.0.5",
|
||||
@@ -63,26 +64,23 @@
|
||||
"tableexport.jquery.plugin": "^1.30.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"gulp": "^5.0.1",
|
||||
"gulp": "^5.0.0",
|
||||
"gulp-clean": "^0.4.0",
|
||||
"gulp-clean-css": "^4.3.0",
|
||||
"gulp-concat": "^2.6.1",
|
||||
"gulp-debug": "^5.0.1",
|
||||
"gulp-gzip": "^1.4.2",
|
||||
"gulp-header": "^2.0.12",
|
||||
"gulp-header": "^2.0.9",
|
||||
"gulp-inject": "^5.0.5",
|
||||
"gulp-rename": "^2.1.0",
|
||||
"gulp-rev": "^12.0.0",
|
||||
"gulp-rename": "^2.0.0",
|
||||
"gulp-rev": "^10.0.0",
|
||||
"gulp-run": "^1.7.1",
|
||||
"gulp-tar": "^5.0.0",
|
||||
"gulp-tar": "^4.0.0",
|
||||
"gulp-uglify": "^3.0.2",
|
||||
"gulp-zip": "^6.1.0",
|
||||
"license-report": "^6.8.2",
|
||||
"npm-check-updates": "^22.1.1",
|
||||
"license-report": "^6.7.2",
|
||||
"npm-check-updates": "^17.1.14",
|
||||
"readable-stream": "^4.4.2",
|
||||
"stream-series": "^0.1.1"
|
||||
},
|
||||
"publishConfig": {
|
||||
"registry": "https://npm.pkg.github.com/"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,15 +1,12 @@
|
||||
<?php
|
||||
|
||||
use CodeIgniter\Boot;
|
||||
use Config\Paths;
|
||||
|
||||
/*
|
||||
*---------------------------------------------------------------
|
||||
* CHECK PHP VERSION
|
||||
*---------------------------------------------------------------
|
||||
*/
|
||||
|
||||
$minPhpVersion = '8.2'; // If you update this, don't forget to update `spark`.
|
||||
$minPhpVersion = '8.1'; // If you update this, don't forget to update `spark`.
|
||||
if (version_compare(PHP_VERSION, $minPhpVersion, '<')) {
|
||||
$message = sprintf(
|
||||
'Your PHP version must be %s or higher to run CodeIgniter. Current version: %s',
|
||||
@@ -51,9 +48,9 @@ if (getcwd() . DIRECTORY_SEPARATOR !== FCPATH) {
|
||||
require FCPATH . '../app/Config/Paths.php';
|
||||
// ^^^ Change this line if you move your application folder
|
||||
|
||||
$paths = new Paths();
|
||||
$paths = new Config\Paths();
|
||||
|
||||
// LOAD THE FRAMEWORK BOOTSTRAP FILE
|
||||
require $paths->systemDirectory . '/Boot.php';
|
||||
|
||||
exit(Boot::bootWeb($paths));
|
||||
exit(CodeIgniter\Boot::bootWeb($paths));
|
||||
|
||||
9
spark
9
spark
@@ -10,9 +10,6 @@
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
use CodeIgniter\Boot;
|
||||
use Config\Paths;
|
||||
|
||||
/*
|
||||
* --------------------------------------------------------------------
|
||||
* CODEIGNITER COMMAND-LINE TOOLS
|
||||
@@ -38,7 +35,7 @@ if (str_starts_with(PHP_SAPI, 'cgi')) {
|
||||
*---------------------------------------------------------------
|
||||
*/
|
||||
|
||||
$minPhpVersion = '8.2'; // If you update this, don't forget to update `public/index.php`.
|
||||
$minPhpVersion = '8.1'; // If you update this, don't forget to update `public/index.php`.
|
||||
if (version_compare(PHP_VERSION, $minPhpVersion, '<')) {
|
||||
$message = sprintf(
|
||||
'Your PHP version must be %s or higher to run CodeIgniter. Current version: %s',
|
||||
@@ -79,9 +76,9 @@ chdir(FCPATH);
|
||||
require FCPATH . '../app/Config/Paths.php';
|
||||
// ^^^ Change this line if you move your application folder
|
||||
|
||||
$paths = new Paths();
|
||||
$paths = new Config\Paths();
|
||||
|
||||
// LOAD THE FRAMEWORK BOOTSTRAP FILE
|
||||
require $paths->systemDirectory . '/Boot.php';
|
||||
|
||||
exit(Boot::bootSpark($paths));
|
||||
exit(CodeIgniter\Boot::bootSpark($paths));
|
||||
|
||||
@@ -237,7 +237,7 @@ class ItemsCsvImportTest extends CIUnitTestCase
|
||||
'deleted' => 0
|
||||
];
|
||||
|
||||
$this->assertTrue($this->item->save_value($itemData));
|
||||
$this->assertTrue($this->item->saveValue($itemData));
|
||||
|
||||
$row = $this->db->table('items')
|
||||
->where('item_number', $itemData['item_number'])
|
||||
@@ -268,7 +268,7 @@ class ItemsCsvImportTest extends CIUnitTestCase
|
||||
'deleted' => 0
|
||||
];
|
||||
|
||||
$this->assertTrue($this->item->save_value($itemData));
|
||||
$this->assertTrue($this->item->saveValue($itemData));
|
||||
|
||||
$locationId = 1;
|
||||
$quantity = 100;
|
||||
@@ -298,7 +298,7 @@ class ItemsCsvImportTest extends CIUnitTestCase
|
||||
'deleted' => 0
|
||||
];
|
||||
|
||||
$this->assertTrue($this->item->save_value($itemData));
|
||||
$this->assertTrue($this->item->saveValue($itemData));
|
||||
|
||||
$inventoryData = [
|
||||
'trans_inventory' => 50,
|
||||
@@ -329,7 +329,7 @@ class ItemsCsvImportTest extends CIUnitTestCase
|
||||
'deleted' => 0
|
||||
];
|
||||
|
||||
$this->assertTrue($this->item->save_value($itemData));
|
||||
$this->assertTrue($this->item->saveValue($itemData));
|
||||
|
||||
$taxesData = [
|
||||
['name' => 'VAT', 'percent' => 20],
|
||||
@@ -406,7 +406,7 @@ class ItemsCsvImportTest extends CIUnitTestCase
|
||||
'deleted' => false
|
||||
];
|
||||
|
||||
$this->assertTrue($this->item->save_value($itemData));
|
||||
$this->assertTrue($this->item->saveValue($itemData));
|
||||
}
|
||||
|
||||
$item1 = $this->item->get_info_by_id_or_number('ITEM-A');
|
||||
@@ -430,7 +430,7 @@ class ItemsCsvImportTest extends CIUnitTestCase
|
||||
'deleted' => 0
|
||||
];
|
||||
|
||||
$this->assertTrue($this->item->save_value($originalData));
|
||||
$this->assertTrue($this->item->saveValue($originalData));
|
||||
|
||||
$updatedData = [
|
||||
'item_id' => $originalData['item_id'],
|
||||
@@ -443,7 +443,7 @@ class ItemsCsvImportTest extends CIUnitTestCase
|
||||
'deleted' => 0
|
||||
];
|
||||
|
||||
$this->assertTrue($this->item->save_value($updatedData, $updatedData['item_id']));
|
||||
$this->assertTrue($this->item->saveValue($updatedData));
|
||||
|
||||
$updatedItem = $this->item->get_info($updatedData['item_id']);
|
||||
$this->assertEquals('Updated Name', $updatedItem->name);
|
||||
@@ -464,7 +464,7 @@ class ItemsCsvImportTest extends CIUnitTestCase
|
||||
'deleted' => 0
|
||||
];
|
||||
|
||||
$this->assertTrue($this->item->save_value($originalData));
|
||||
$this->assertTrue($this->item->saveValue($originalData));
|
||||
|
||||
$definitionData = [
|
||||
'definition_name' => 'Color',
|
||||
@@ -510,7 +510,7 @@ class ItemsCsvImportTest extends CIUnitTestCase
|
||||
'deleted' => 0
|
||||
];
|
||||
|
||||
$this->assertTrue($this->item->save_value($itemData));
|
||||
$this->assertTrue($this->item->saveValue($itemData));
|
||||
|
||||
$definitionData = [
|
||||
'definition_name' => 'Color',
|
||||
@@ -553,7 +553,7 @@ class ItemsCsvImportTest extends CIUnitTestCase
|
||||
'deleted' => 0
|
||||
];
|
||||
|
||||
$this->assertTrue($this->item->save_value($itemData));
|
||||
$this->assertTrue($this->item->saveValue($itemData));
|
||||
|
||||
// Mock Attribute DROPDOWN
|
||||
$definitionData = [
|
||||
@@ -604,7 +604,7 @@ class ItemsCsvImportTest extends CIUnitTestCase
|
||||
'deleted' => 0
|
||||
];
|
||||
|
||||
$this->assertTrue($this->item->save_value($itemData));
|
||||
$this->assertTrue($this->item->saveValue($itemData));
|
||||
|
||||
$locationId = 1;
|
||||
|
||||
@@ -633,7 +633,7 @@ class ItemsCsvImportTest extends CIUnitTestCase
|
||||
'deleted' => 0
|
||||
];
|
||||
|
||||
$this->assertTrue($this->item->save_value($itemData));
|
||||
$this->assertTrue($this->item->saveValue($itemData));
|
||||
|
||||
$savedItem = $this->item->get_info($itemData['item_id']);
|
||||
$this->assertEquals(-1, (int)$savedItem->reorder_level);
|
||||
@@ -672,7 +672,7 @@ class ItemsCsvImportTest extends CIUnitTestCase
|
||||
'deleted' => 0
|
||||
];
|
||||
|
||||
$this->assertTrue($this->item->save_value($itemData));
|
||||
$this->assertTrue($this->item->saveValue($itemData));
|
||||
|
||||
$savedItem = $this->item->get_info($itemData['item_id']);
|
||||
|
||||
@@ -702,7 +702,7 @@ class ItemsCsvImportTest extends CIUnitTestCase
|
||||
'deleted' => 0
|
||||
];
|
||||
|
||||
$this->assertTrue($this->item->save_value($itemData));
|
||||
$this->assertTrue($this->item->saveValue($itemData));
|
||||
|
||||
$savedItem = $this->item->get_info($itemData['item_id']);
|
||||
$this->assertEquals('8471', $savedItem->hsn_code);
|
||||
@@ -719,7 +719,7 @@ class ItemsCsvImportTest extends CIUnitTestCase
|
||||
'deleted' => 0
|
||||
];
|
||||
|
||||
$this->assertTrue($this->item->save_value($itemData));
|
||||
$this->assertTrue($this->item->saveValue($itemData));
|
||||
|
||||
$locations = [
|
||||
'Warehouse' => 100,
|
||||
@@ -792,7 +792,7 @@ class ItemsCsvImportTest extends CIUnitTestCase
|
||||
'deleted' => 0
|
||||
];
|
||||
|
||||
$this->assertTrue($this->item->save_value($itemData));
|
||||
$this->assertTrue($this->item->saveValue($itemData));
|
||||
|
||||
$this->assertIsInt($itemData['item_id']);
|
||||
$this->assertGreaterThan(0, $itemData['item_id']);
|
||||
@@ -812,7 +812,7 @@ class ItemsCsvImportTest extends CIUnitTestCase
|
||||
'deleted' => 0
|
||||
];
|
||||
|
||||
$this->assertTrue($this->item->save_value($itemData));
|
||||
$this->assertTrue($this->item->saveValue($itemData));
|
||||
|
||||
$exists = $this->item->exists($itemData['item_id']);
|
||||
$this->assertTrue($exists);
|
||||
@@ -858,7 +858,7 @@ class ItemsCsvImportTest extends CIUnitTestCase
|
||||
'deleted' => 0
|
||||
];
|
||||
|
||||
$this->assertTrue($this->item->save_value($itemData));
|
||||
$this->assertTrue($this->item->saveValue($itemData));
|
||||
|
||||
$taxesData = [];
|
||||
if (is_numeric($csvRow['Tax 1 Percent']) && $csvRow['Tax 1 Name'] !== '') {
|
||||
@@ -1032,7 +1032,7 @@ class ItemsCsvImportTest extends CIUnitTestCase
|
||||
'deleted' => 0
|
||||
];
|
||||
|
||||
$this->assertTrue($this->item->save_value($itemData));
|
||||
$this->assertTrue($this->item->saveValue($itemData));
|
||||
|
||||
$uniqueId = uniqid();
|
||||
$locations = ['Warehouse' . $uniqueId, 'Store' . $uniqueId];
|
||||
|
||||
Reference in New Issue
Block a user