diff --git a/README.md b/README.md
index 56c47dd17..ecd695b8f 100644
--- a/README.md
+++ b/README.md
@@ -106,7 +106,7 @@ NOTE: If you're running non-release code, please make sure you always run the la
## 🏃 Keep the Machine Running
-If you like our project, please consider buying us a coffee through the button below so we can keep adding features.
+If you like our project, please consider buying us a coffee through the button below so we can keep adding features. Please star the project if you like it!
[](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=MUN6AEG7NY6H8)\
Or refer to the [FUNDING.yml](.github/FUNDING.yml) file.
diff --git a/app/Config/OSPOS.php b/app/Config/OSPOS.php
index d8b5b99d4..1f411394d 100644
--- a/app/Config/OSPOS.php
+++ b/app/Config/OSPOS.php
@@ -5,7 +5,6 @@ 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
@@ -41,9 +40,11 @@ class OSPOS extends BaseConfig
$this->settings[$app_config->key] = $app_config->value;
}
$this->cache->save('settings', encode_array($this->settings));
- } catch (DatabaseException $e) {
+ } catch (\Exception $e) {
// Database table doesn't exist yet (migrations haven't run)
- // Return empty settings to allow migration page to display
+ // or database connection failed. Return empty settings to
+ // allow migration page to display. Catches mysqli_sql_exception
+ // which is not a subclass of DatabaseException.
$this->settings = [
'language' => 'english',
'language_code' => 'en',
diff --git a/app/Config/Session.php b/app/Config/Session.php
index 7c83fc94f..3d78928f4 100644
--- a/app/Config/Session.php
+++ b/app/Config/Session.php
@@ -3,7 +3,6 @@
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;
@@ -139,7 +138,11 @@ class Session extends BaseConfig
$this->driver = FileHandler::class;
$this->savePath = WRITEPATH . 'session';
}
- } catch (DatabaseException $e) {
+ } 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.
$this->driver = FileHandler::class;
$this->savePath = WRITEPATH . 'session';
}
diff --git a/app/Controllers/Config.php b/app/Controllers/Config.php
index 2df8c3f38..3140e9baf 100644
--- a/app/Controllers/Config.php
+++ b/app/Controllers/Config.php
@@ -370,6 +370,9 @@ 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;
@@ -377,12 +380,16 @@ class Config extends Secure_Controller
$definitionData['definition_id'] = CATEGORY_DEFINITION_ID;
$definitionData['deleted'] = 0;
- $this->attribute->saveDefinition($definitionData, CATEGORY_DEFINITION_ID);
+ $attributeSuccess = $this->attribute->saveDefinition($definitionData, CATEGORY_DEFINITION_ID);
} elseif ($batchSaveData['category_dropdown'] == NO_DEFINITION_ID) {
- $this->attribute->deleteDefinition(CATEGORY_DEFINITION_ID);
+ $attributeSuccess = $this->attribute->deleteDefinition(CATEGORY_DEFINITION_ID);
}
- $success = $this->appconfig->batch_save($batchSaveData);
+ $success = $attributeSuccess && $this->appconfig->batch_save($batchSaveData);
+
+ $this->db->transComplete();
+
+ $success = $success && $this->db->transStatus();
return $this->response->setJSON(['success' => $success, 'message' => lang('Config.saved_' . ($success ? '' : 'un') . 'successfully')]);
}
@@ -395,32 +402,35 @@ class Config extends Secure_Controller
*/
public function postCheckNumberLocale(): ResponseInterface
{
- $number_locale = $this->request->getPost('number_locale');
- $save_number_locale = $this->request->getPost('save_number_locale');
+ $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');
- $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');
+ $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;
}
if ($this->request->getPost('thousands_separator') == 'false') {
$fmt->setTextAttribute(NumberFormatter::GROUPING_SEPARATOR_SYMBOL, '');
}
- $fmt->setSymbol(NumberFormatter::CURRENCY_SYMBOL, $currency_symbol);
- $number_local_example = $fmt->format(1234567890.12300);
+ $fmt->setSymbol(NumberFormatter::CURRENCY_SYMBOL, $currencySymbol);
+ $numberLocaleExample = $fmt->format(1234567890.12300);
return $this->response->setJSON([
- '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,
+ 'success' => $numberLocaleExample != false,
+ 'save_number_locale' => $saveNumberLocale,
+ 'number_locale_example' => $numberLocaleExample,
+ 'currency_symbol' => $currencySymbol,
+ 'currency_code' => $currencyCode,
]);
}
diff --git a/app/Controllers/Home.php b/app/Controllers/Home.php
index d98d8e3d5..9ae68e2df 100644
--- a/app/Controllers/Home.php
+++ b/app/Controllers/Home.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 = $loggedInEmployee->person_id;
+ $currentPersonId = (int) $loggedInEmployee->person_id;
$employeeId = $employeeId === NEW_ENTRY ? $currentPersonId : $employeeId;
@@ -68,10 +68,11 @@ 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 ? $currentUser->person_id : $employeeId;
+ $employeeId = $employeeId === NEW_ENTRY ? $currentPersonId : $employeeId;
- if (!$this->employee->isAdmin($currentUser->person_id) && $employeeId !== $currentUser->person_id) {
+ if (!$this->employee->isAdmin($currentPersonId) && $employeeId !== $currentPersonId) {
return $this->response->setStatusCode(403)->setJSON([
'success' => false,
'message' => lang('Employees.unauthorized_modify')
diff --git a/app/Controllers/Sales.php b/app/Controllers/Sales.php
index d44d61fe1..76b3a8bfe 100644
--- a/app/Controllers/Sales.php
+++ b/app/Controllers/Sales.php
@@ -796,7 +796,7 @@ class Sales extends Secure_Controller
if ($sale_id == NEW_ENTRY && $this->sale->check_invoice_number_exists($invoice_number)) {
$data['error'] = lang('Sales.invoice_number_duplicate', [$invoice_number]);
- $this->_reload($data);
+ return $this->_reload($data);
} else {
$data['invoice_number'] = $invoice_number;
$data['sale_status'] = COMPLETED;
@@ -817,6 +817,7 @@ class Sales extends Secure_Controller
if ($data['sale_id_num'] == NEW_ENTRY) {
$data['error_message'] = lang('Sales.transaction_failed');
+ return $this->_reload($data);
} else {
$data['barcode'] = $this->barcode_lib->generate_receipt_barcode($data['sale_id']);
$this->sale_lib->clear_all();
@@ -840,7 +841,7 @@ class Sales extends Secure_Controller
if ($sale_id == NEW_ENTRY && $this->sale->check_work_order_number_exists($work_order_number)) {
$data['error'] = lang('Sales.work_order_number_duplicate');
- $this->_reload($data);
+ return $this->_reload($data);
} else {
$data['work_order_number'] = $work_order_number;
$data['sale_status'] = SUSPENDED;
@@ -868,7 +869,7 @@ class Sales extends Secure_Controller
if ($sale_id == NEW_ENTRY && $this->sale->check_quote_number_exists($quote_number)) {
$data['error'] = lang('Sales.quote_number_duplicate');
- $this->_reload($data);
+ return $this->_reload($data);
} else {
$data['quote_number'] = $quote_number;
$data['sale_status'] = SUSPENDED;
@@ -900,6 +901,7 @@ class Sales extends Secure_Controller
if ($data['sale_id_num'] == NEW_ENTRY) {
$data['error_message'] = lang('Sales.transaction_failed');
+ return $this->_reload($data);
} else {
$data['barcode'] = $this->barcode_lib->generate_receipt_barcode($data['sale_id']);
$this->sale_lib->clear_all();
@@ -935,7 +937,10 @@ class Sales extends Secure_Controller
new Token_customer((array)$sale_data)
];
$text = $this->token_lib->render($text, $tokens);
- $sale_data['mimetype'] = mime_content_type(FCPATH . 'uploads/' . $this->config['company_logo']);
+ $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();
// Generate email attachment: invoice in PDF format
$view = Services::renderer();
@@ -972,13 +977,7 @@ 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'] = '';
-
- $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'] = '';
- }
+ $sale_data['img_tag'] = $this->email_lib->buildLogoImgTag();
$to = $sale_data['customer_email'];
$subject = lang('Sales.receipt');
@@ -1693,10 +1692,11 @@ class Sales extends Secure_Controller
$this->item->update_item_number($item_id, $item_number);
$cart = $this->sale_lib->get_cart();
$x = $this->search_cart_for_item_id($item_id, $cart);
- if ($x != null) {
+ if ($x !== null) {
$cart[$x]['item_number'] = $item_number;
}
$this->sale_lib->set_cart($cart);
+ return $this->response->setJSON(['success' => true]);
}
/**
@@ -1715,11 +1715,12 @@ class Sales extends Secure_Controller
$cart = $this->sale_lib->get_cart();
$x = $this->search_cart_for_item_id($item_id, $cart);
- if ($x != null) {
+ if ($x !== null) {
$cart[$x]['name'] = $name;
}
$this->sale_lib->set_cart($cart);
+ return $this->response->setJSON(['success' => true]);
}
/**
@@ -1738,11 +1739,12 @@ class Sales extends Secure_Controller
$cart = $this->sale_lib->get_cart();
$x = $this->search_cart_for_item_id($item_id, $cart);
- if ($x != null) {
+ if ($x !== null) {
$cart[$x]['description'] = $description;
}
$this->sale_lib->set_cart($cart);
+ return $this->response->setJSON(['success' => true]);
}
/**
diff --git a/app/Helpers/locale_helper.php b/app/Helpers/locale_helper.php
index ed21c9fa9..fb6024bc2 100644
--- a/app/Helpers/locale_helper.php
+++ b/app/Helpers/locale_helper.php
@@ -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_CODE;
+ return $config['language'] ?? DEFAULT_LANGUAGE;
}
/**
diff --git a/app/Language/es-ES/Items.php b/app/Language/es-ES/Items.php
index 47d087105..783686ef8 100644
--- a/app/Language/es-ES/Items.php
+++ b/app/Language/es-ES/Items.php
@@ -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" => "Ubicación(es) de stock inválida(s) encontrada(s): {0}. Solo ubicaciones de stock válidas son permitidas.",
+ "csv_import_invalid_location" => "Se encontraron ubicaciones de stock no válidas: {0}. Solo se permiten ubicaciones de stock válidas.",
"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.",
diff --git a/app/Language/ka/Calendar.php b/app/Language/ka/Calendar.php
index b3c9c5d15..3ca3c3825 100644
--- a/app/Language/ka/Calendar.php
+++ b/app/Language/ka/Calendar.php
@@ -38,7 +38,7 @@ return [
"february" => "",
"march" => "",
"april" => "",
- "mayl" => "",
+ "may" => "",
"june" => "",
"july" => "",
"august" => "",
@@ -46,4 +46,4 @@ return [
"october" => "",
"november" => "",
"december" => "",
-];
\ No newline at end of file
+];
diff --git a/app/Language/lo/Calendar.php b/app/Language/lo/Calendar.php
index b3c9c5d15..3ca3c3825 100644
--- a/app/Language/lo/Calendar.php
+++ b/app/Language/lo/Calendar.php
@@ -38,7 +38,7 @@ return [
"february" => "",
"march" => "",
"april" => "",
- "mayl" => "",
+ "may" => "",
"june" => "",
"july" => "",
"august" => "",
@@ -46,4 +46,4 @@ return [
"october" => "",
"november" => "",
"december" => "",
-];
\ No newline at end of file
+];
diff --git a/app/Language/ml/Calendar.php b/app/Language/ml/Calendar.php
index 1da89214d..34ac990a2 100644
--- a/app/Language/ml/Calendar.php
+++ b/app/Language/ml/Calendar.php
@@ -38,7 +38,7 @@ return [
"february" => "ഫെബ്രുവരി",
"march" => "മാർച്ച്",
"april" => "ഏപ്രിൽ",
- "mayl" => "മേയ്",
+ "may" => "മേയ്",
"june" => "ജൂൺ",
"july" => "ജൂലൈ",
"august" => "ആഗസ്റ്റ്",
@@ -46,4 +46,4 @@ return [
"october" => "ഒക്ടോബർ",
"november" => "നവംബർ",
"december" => "ഡിസംബർ",
-];
\ No newline at end of file
+];
diff --git a/app/Language/nb/Calendar.php b/app/Language/nb/Calendar.php
index bb7e706b2..5e9e48c7c 100644
--- a/app/Language/nb/Calendar.php
+++ b/app/Language/nb/Calendar.php
@@ -38,7 +38,7 @@ return [
"february" => "Februar",
"march" => "Mars",
"april" => "April",
- "mayl" => "Mai",
+ "may" => "Mai",
"june" => "Juni",
"july" => "Juli",
"august" => "August",
@@ -46,4 +46,4 @@ return [
"october" => "Oktober",
"november" => "November",
"december" => "Desember",
-];
\ No newline at end of file
+];
diff --git a/app/Language/th/Bootstrap_tables.php b/app/Language/th/Bootstrap_tables.php
index c384db69a..76c2f2574 100644
--- a/app/Language/th/Bootstrap_tables.php
+++ b/app/Language/th/Bootstrap_tables.php
@@ -1,12 +1,12 @@
"ทั้งหมด",
- "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' => "ซ่อน/แสดง",
];
diff --git a/app/Language/th/Login.php b/app/Language/th/Login.php
index e9b7b7cd1..8368a4fb2 100644
--- a/app/Language/th/Login.php
+++ b/app/Language/th/Login.php
@@ -9,7 +9,9 @@ return [
"login" => "ลงชื่อเข้าใช้",
"logout" => "ออกจากระบบ",
"migration_needed" => "การย้ายฐานข้อมูลไปยัง {0} จะเริ่มต้นหลังจากเข้าสู่ระบบ",
- "migration_required" => "",
+ "migration_required" => "จําเป็นต้องมีการปรับปรุงฐานข้อมูล",
+ "migration_auth_message" => "ผู้ดูแลระบบจำเป็นต้องมีสิทธิ์ในการปรับปรุงฐานข้อมูลเวอร์ชั่น {0} กรุณาเข้าระบบเพื่อดำเนินการต่อ",
+ "migration_complete_redirect" => "ทำการปรับปรุงฐานข้อมูลเรียบร้อย กำลังดำเนินการไปหน้าเข้าสู่ระบบ ...",
"migration_auth_message" => "",
"migration_initializing" => "",
"migration_running" => "",
@@ -17,7 +19,6 @@ return [
"migration_complete_login" => "",
"migration_failed" => "",
"migration_error_connection" => "",
- "migration_complete_redirect" => "",
"password" => "รหัสผ่าน",
"required_username" => "จำเป็นต้องระบุชื่อผู้ใช้งาน",
"username" => "ชื่อผู้ใช้",
diff --git a/app/Language/th/Sales.php b/app/Language/th/Sales.php
index 3ba4bf68e..dcbc849b5 100644
--- a/app/Language/th/Sales.php
+++ b/app/Language/th/Sales.php
@@ -1,231 +1,231 @@
"คะแนนที่มี",
- "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_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" => "ลูกค้าที่เลือก",
+ '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_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' => "ลูกค้าที่เลือก",
];
diff --git a/app/Libraries/Email_lib.php b/app/Libraries/Email_lib.php
index 914344567..eb8a9c24c 100644
--- a/app/Libraries/Email_lib.php
+++ b/app/Libraries/Email_lib.php
@@ -82,4 +82,40 @@ 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 '
';
+ }
}
diff --git a/app/Libraries/MY_Migration.php b/app/Libraries/MY_Migration.php
index b0187eb0a..c27954145 100644
--- a/app/Libraries/MY_Migration.php
+++ b/app/Libraries/MY_Migration.php
@@ -2,7 +2,6 @@
namespace App\Libraries;
-use CodeIgniter\Database\Exceptions\DatabaseException;
use CodeIgniter\Database\MigrationRunner;
use Config\Database;
use stdClass;
@@ -44,7 +43,9 @@ class MY_Migration extends MigrationRunner
$result = $builder->get()->getRow();
return $result ? $result->version : 0;
}
- } catch (DatabaseException $e) {
+ } catch (\Exception $e) {
+ // Database not available yet (e.g. fresh install before schema).
+ // Catches mysqli_sql_exception which is not a DatabaseException.
return 0;
}
@@ -76,8 +77,9 @@ class MY_Migration extends MigrationRunner
$result = $builder->get()->getRow();
return $result ? $result->version : false;
}
- } catch (DatabaseException $e) {
- // Database doesn't exist yet or connection failed
+ } catch (\Exception $e) {
+ // Database not available yet (e.g. fresh install before schema).
+ // Catches mysqli_sql_exception which is not a DatabaseException.
}
return false;
diff --git a/app/Models/Item.php b/app/Models/Item.php
index 3759810a0..efb8531d0 100644
--- a/app/Models/Item.php
+++ b/app/Models/Item.php
@@ -65,8 +65,10 @@ 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);
@@ -389,9 +391,10 @@ 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->join('suppliers', 'suppliers.person_id = items.supplier_id', 'left');
+ $builder->groupStart();
$builder->where('item_number', $item_number);
$builder->orWhere('item_id', $item_number);
+ $builder->groupEnd();
if (!$ignore_deleted) {
$builder->where('items.deleted', $deleted);
diff --git a/app/Views/barcodes/barcode_sheet.php b/app/Views/barcodes/barcode_sheet.php
index c6a13b831..3e27880f0 100644
--- a/app/Views/barcodes/barcode_sheet.php
+++ b/app/Views/barcodes/barcode_sheet.php
@@ -13,17 +13,17 @@ $barcode_lib = new Barcode_lib();