mirror of
https://github.com/opensourcepos/opensourcepos.git
synced 2026-05-25 16:54:58 -04:00
Compare commits
3 Commits
fix/4554-e
...
WebShells-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
19184b50c6 | ||
|
|
1a6cfffc27 | ||
|
|
5e0541c53e |
@@ -1,4 +1,4 @@
|
||||
<?php
|
||||
<?php
|
||||
|
||||
use CodeIgniter\Router\RouteCollection;
|
||||
|
||||
@@ -12,6 +12,40 @@ $routes->get('login', 'Login::index');
|
||||
$routes->post('login', 'Login::index');
|
||||
$routes->post('migrate', 'Login::migrate');
|
||||
|
||||
$routes->get('sales', 'Sales::getIndex');
|
||||
$routes->get('sales/customerDisplay', 'Sales::getCustomerDisplay');
|
||||
$routes->get('sales/itemSearch', 'Sales::getItemSearch');
|
||||
$routes->post('sales/selectCustomer', 'Sales::postSelectCustomer');
|
||||
$routes->post('sales/changeMode', 'Sales::postChangeMode');
|
||||
$routes->post('sales/setComment', 'Sales::postSetComment');
|
||||
$routes->post('sales/setInvoiceNumber', 'Sales::postSetInvoiceNumber');
|
||||
$routes->post('sales/setPaymentType', 'Sales::postSetPaymentType');
|
||||
$routes->post('sales/setPrintAfterSale', 'Sales::postSetPrintAfterSale');
|
||||
$routes->post('sales/setPriceWorkOrders', 'Sales::postSetPriceWorkOrders');
|
||||
$routes->post('sales/setEmailReceipt', 'Sales::postSetEmailReceipt');
|
||||
$routes->post('sales/addPayment', 'Sales::postAddPayment');
|
||||
$routes->post('sales/add', 'Sales::postAdd');
|
||||
$routes->post('sales/editItem/(:segment)', 'Sales::postEditItem/$1');
|
||||
$routes->post('sales/deleteItem/(:segment)', 'Sales::getDeleteItem/$1');
|
||||
$routes->post('sales/deletePayment/(:segment)', 'Sales::getDeletePayment/$1');
|
||||
$routes->post('sales/removeCustomer', 'Sales::getRemoveCustomer');
|
||||
$routes->post('sales/complete', 'Sales::postComplete');
|
||||
$routes->post('sales/cancel', 'Sales::postCancel');
|
||||
$routes->post('sales/suspend', 'Sales::postSuspend');
|
||||
$routes->post('sales/unsuspend', 'Sales::postUnsuspend');
|
||||
$routes->post('sales/checkInvoiceNumber', 'Sales::postCheckInvoiceNumber');
|
||||
$routes->post('sales/changeItemNumber', 'Sales::postChangeItemNumber');
|
||||
$routes->post('sales/changeItemName', 'Sales::postChangeItemName');
|
||||
$routes->post('sales/changeItemDescription', 'Sales::postChangeItemDescription');
|
||||
$routes->get('sales/suspended', 'Sales::getSuspended');
|
||||
$routes->get('sales/discardSuspendedSale', 'Sales::getDiscardSuspendedSale');
|
||||
$routes->get('sales/sales_keyboard_help', 'Sales::getSalesKeyboardHelp');
|
||||
$routes->get('sales/receipt/(:num)', 'Sales::getReceipt/$1');
|
||||
$routes->get('sales/invoice/(:num)', 'Sales::getInvoice/$1');
|
||||
$routes->get('sales/edit/(:num)', 'Sales::getEdit/$1');
|
||||
$routes->post('sales/delete/(:num)', 'Sales::postDelete/$1');
|
||||
$routes->post('sales/save/(:num)', 'Sales::postSave/$1');
|
||||
|
||||
$routes->add('no_access/index/(:segment)', 'No_access::index/$1');
|
||||
$routes->add('no_access/index/(:segment)/(:segment)', 'No_access::index/$1/$2');
|
||||
|
||||
|
||||
@@ -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);
|
||||
@@ -241,6 +241,28 @@ class Config extends Secure_Controller
|
||||
$data['show_office_group'] = $this->module->get_show_office_group();
|
||||
$data['currency_code'] = $this->config['currency_code'] ?? '';
|
||||
$data['dbVersion'] = mysqli_get_server_info($this->db->getConnection());
|
||||
$data['scale_export_formats'] = [
|
||||
'txt' => 'TXT',
|
||||
'csv' => 'CSV',
|
||||
];
|
||||
$data['scale_export_charsets'] = [
|
||||
'windows-1256' => 'Windows-1256',
|
||||
'utf-8' => 'UTF-8',
|
||||
'windows-1252' => 'Windows-1252',
|
||||
];
|
||||
$data['scale_export_delimiters'] = [
|
||||
';' => ';',
|
||||
',' => ',',
|
||||
"\t" => 'Tab',
|
||||
];
|
||||
$data['scale_export_fields_options'] = [
|
||||
'legacy_code' => lang('Items.item_number'),
|
||||
'item_number' => lang('Items.item_number'),
|
||||
'repeat_item_number' => lang('Items.item_number'),
|
||||
'name' => lang('Items.name'),
|
||||
'unit_price' => lang('Items.unit_price'),
|
||||
'legacy_tail' => lang('Items.item_number'),
|
||||
];
|
||||
|
||||
// Load all the license statements, they are already XSS cleaned in the private function
|
||||
$data['licenses'] = $this->_licenses();
|
||||
@@ -394,6 +416,7 @@ class Config extends Secure_Controller
|
||||
'suggestions_third_column' => $this->validateSuggestionsColumn($this->request->getPost('suggestions_third_column'), 'other'),
|
||||
'giftcard_number' => $this->request->getPost('giftcard_number'),
|
||||
'derive_sale_quantity' => $this->request->getPost('derive_sale_quantity') != null,
|
||||
'customer_display_enabled' => $this->request->getPost('customer_display_enabled') != null,
|
||||
'multi_pack_enabled' => $this->request->getPost('multi_pack_enabled') != null,
|
||||
'include_hsn' => $this->request->getPost('include_hsn') != null,
|
||||
'category_dropdown' => $this->request->getPost('category_dropdown') != null
|
||||
@@ -474,13 +497,36 @@ class Config extends Secure_Controller
|
||||
*/
|
||||
public function postSaveLocale(): ResponseInterface
|
||||
{
|
||||
$exploded = explode(":", $this->request->getPost('language'));
|
||||
$language = trim((string) $this->request->getPost('language'));
|
||||
$languageCode = 'en';
|
||||
$languageName = 'english';
|
||||
|
||||
if ($language !== '' && str_contains($language, ':')) {
|
||||
$exploded = array_map('trim', explode(':', $language, 2));
|
||||
|
||||
if (count($exploded) === 2) {
|
||||
$languageCode = htmlspecialchars($exploded[0]);
|
||||
$languageName = htmlspecialchars($exploded[1]);
|
||||
}
|
||||
}
|
||||
|
||||
$currency_symbol = $this->request->getPost('currency_symbol');
|
||||
$secondaryCurrencyCode = strtoupper(trim((string) $this->request->getPost('secondary_currency_code')));
|
||||
|
||||
if (!preg_match('/^[A-Z]{3}$/', $secondaryCurrencyCode)) {
|
||||
$secondaryCurrencyCode = '';
|
||||
}
|
||||
|
||||
$batch_save_data = [
|
||||
'currency_symbol' => htmlspecialchars($currency_symbol ?? ''),
|
||||
'currency_code' => $this->request->getPost('currency_code'),
|
||||
'language_code' => $exploded[0],
|
||||
'language' => $exploded[1],
|
||||
'secondary_currency_enabled' => $this->request->getPost('secondary_currency_enabled') != null,
|
||||
'secondary_currency_symbol' => htmlspecialchars($this->request->getPost('secondary_currency_symbol') ?? ''),
|
||||
'secondary_currency_code' => $secondaryCurrencyCode,
|
||||
'secondary_currency_rate' => $this->request->getPost('secondary_currency_rate', FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION),
|
||||
'secondary_currency_decimals' => $this->request->getPost('secondary_currency_decimals', FILTER_SANITIZE_NUMBER_INT),
|
||||
'language_code' => $languageCode,
|
||||
'language' => $languageName,
|
||||
'timezone' => $this->request->getPost('timezone'),
|
||||
'dateformat' => $this->request->getPost('dateformat'),
|
||||
'timeformat' => $this->request->getPost('timeformat'),
|
||||
@@ -924,9 +970,7 @@ class Config extends Secure_Controller
|
||||
public function postSaveReceipt(): ResponseInterface
|
||||
{
|
||||
$batch_save_data = [
|
||||
'receipt_template' => Sale_lib::isValidReceiptTemplate($this->request->getPost('receipt_template'))
|
||||
? $this->request->getPost('receipt_template')
|
||||
: 'receipt_default',
|
||||
'receipt_template' => $this->request->getPost('receipt_template'),
|
||||
'receipt_font_size' => $this->request->getPost('receipt_font_size', FILTER_SANITIZE_NUMBER_INT),
|
||||
'print_delay_autoreturn' => $this->request->getPost('print_delay_autoreturn', FILTER_SANITIZE_NUMBER_INT),
|
||||
'email_receipt_check_behaviour' => $this->request->getPost('email_receipt_check_behaviour'),
|
||||
@@ -936,6 +980,7 @@ class Config extends Secure_Controller
|
||||
'receipt_show_tax_ind' => $this->request->getPost('receipt_show_tax_ind') != null,
|
||||
'receipt_show_total_discount' => $this->request->getPost('receipt_show_total_discount') != null,
|
||||
'receipt_show_description' => $this->request->getPost('receipt_show_description') != null,
|
||||
'receipt_show_secondary_currency' => $this->request->getPost('receipt_show_secondary_currency') != null,
|
||||
'receipt_show_serialnumber' => $this->request->getPost('receipt_show_serialnumber') != null,
|
||||
'print_silently' => $this->request->getPost('print_silently') != null,
|
||||
'print_header' => $this->request->getPost('print_header') != null,
|
||||
@@ -964,7 +1009,7 @@ class Config extends Secure_Controller
|
||||
$batchSaveData = [];
|
||||
|
||||
foreach ($currentShortcuts as $name => $shortcut) {
|
||||
$postedValue = trim((string)$this->request->getPost('key_' . $name));
|
||||
$postedValue = trim((string) $this->request->getPost('key_' . $name));
|
||||
|
||||
if (!in_array($postedValue, $allowedShortcuts, true)) {
|
||||
$postedValue = $shortcut['value'];
|
||||
@@ -1068,3 +1113,6 @@ class Config extends Secure_Controller
|
||||
return in_array($column, $allowed, true) ? $column : $fallback;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -66,12 +66,168 @@ class Sales extends Secure_Controller
|
||||
$this->employee = model(Employee::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the shared secondary currency context to a view data array.
|
||||
*
|
||||
* @param array $data
|
||||
* @return void
|
||||
*/
|
||||
private function _append_secondary_currency(array &$data): void
|
||||
{
|
||||
$secondaryCurrency = secondary_currency_context($this->config);
|
||||
$data['secondaryCurrency'] = $secondaryCurrency;
|
||||
|
||||
if (!$secondaryCurrency['show']) {
|
||||
return;
|
||||
}
|
||||
|
||||
$displayFields = [
|
||||
'total' => 'secondaryTotalDisplay',
|
||||
'amount_due' => 'secondaryAmountDueDisplay',
|
||||
'cash_amount_due' => 'secondaryCashAmountDueDisplay',
|
||||
'non_cash_total' => 'secondaryNonCashTotalDisplay',
|
||||
'non_cash_amount_due' => 'secondaryNonCashAmountDueDisplay'
|
||||
];
|
||||
|
||||
foreach ($displayFields as $sourceField => $targetField) {
|
||||
if (array_key_exists($sourceField, $data)) {
|
||||
$data[$targetField] = to_secondary_currency((float) $data[$sourceField], $secondaryCurrency);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function getIndex(): ResponseInterface|string
|
||||
{
|
||||
$this->session->set('allow_temp_items', 1);
|
||||
return $this->_reload(); // TODO: Hungarian Notation
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the customer display popup.
|
||||
*
|
||||
* @return ResponseInterface|string
|
||||
* @noinspection PhpUnused
|
||||
*/
|
||||
public function getCustomerDisplay(): ResponseInterface|string
|
||||
{
|
||||
if (($this->config['customer_display_enabled'] ?? false) != 1) {
|
||||
return $this->response->setStatusCode(404)->setBody('');
|
||||
}
|
||||
|
||||
if ($this->session->get('sale_id') == '') {
|
||||
$this->session->set('sale_id', NEW_ENTRY);
|
||||
}
|
||||
|
||||
$secondaryCurrency = secondary_currency_context($this->config);
|
||||
$secondaryCurrencyEnabled = (($this->config['secondary_currency_enabled'] ?? false) == 1);
|
||||
$cashRounding = $this->sale_lib->reset_cash_rounding();
|
||||
$showCustomerDisplay = $secondaryCurrencyEnabled && !empty($secondaryCurrency['rate']) && (float) $secondaryCurrency['rate'] > 0;
|
||||
$companyLines = preg_split("/\r\n|\r|\n/", (string) ($this->config['company'] ?? '')) ?: [];
|
||||
$companyName = array_shift($companyLines) ?? '';
|
||||
$companyDetails = trim(implode("\n", $companyLines));
|
||||
$secondaryCurrencySymbol = trim((string) ($this->config['secondary_currency_symbol'] ?? ''));
|
||||
$secondaryCurrencyCode = trim((string) ($this->config['secondary_currency_code'] ?? ''));
|
||||
$originalCurrencySymbol = trim((string) ($this->config['currency_symbol'] ?? ''));
|
||||
$customerDisplayCurrencyLabel = $secondaryCurrencyCode !== '' ? $secondaryCurrencyCode : ($secondaryCurrencySymbol !== '' ? $secondaryCurrencySymbol : 'LBP');
|
||||
$originalCurrencyLabel = $originalCurrencySymbol !== '' ? $originalCurrencySymbol : '$';
|
||||
$cartHasCustomerDisplay = $showCustomerDisplay;
|
||||
$cartColspan = $cartHasCustomerDisplay ? 6 : 5;
|
||||
$cartItemWidth = $cartHasCustomerDisplay ? 32 : 44;
|
||||
$cartPriceWidth = $cartHasCustomerDisplay ? 18 : 0;
|
||||
$cartOriginalWidth = $cartHasCustomerDisplay ? 18 : 26;
|
||||
$cartQuantityWidth = $cartHasCustomerDisplay ? 12 : 10;
|
||||
$cartDiscountWidth = $cartHasCustomerDisplay ? 10 : 9;
|
||||
$cartTotalWidth = $cartHasCustomerDisplay ? 10 : 11;
|
||||
|
||||
$data = [
|
||||
'cash_rounding' => $cashRounding,
|
||||
'cart' => $this->sale_lib->get_cart()
|
||||
];
|
||||
$customer_info = $this->_load_customer_data($this->sale_lib->get_customer(), $data, true);
|
||||
$data += [
|
||||
'customer_name' => $data['customer'] ?? lang('Sales.walk_in_customer'),
|
||||
'customer_reward_points' => (int) ($data['customer_rewards']['points'] ?? 0),
|
||||
'customer_reward_package' => $data['customer_rewards']['package_name'] ?? '',
|
||||
'giftcard_remainder' => $this->sale_lib->get_giftcard_remainder(),
|
||||
'rewards_remainder' => $this->sale_lib->get_rewards_remainder(),
|
||||
'customerName' => $data['customer'] ?? lang('Sales.walk_in_customer'),
|
||||
'customerRewardPoints' => (int) ($data['customer_rewards']['points'] ?? 0),
|
||||
'giftcardRemainder' => $this->sale_lib->get_giftcard_remainder()
|
||||
];
|
||||
|
||||
$tax_details = $this->tax_lib->get_taxes($data['cart']);
|
||||
$data += [
|
||||
'tax_exclusive_subtotal' => $this->sale_lib->get_subtotal(true, true),
|
||||
'taxes' => $tax_details[0],
|
||||
'discount' => $this->sale_lib->get_discount(),
|
||||
'payments' => $this->sale_lib->get_payments()
|
||||
];
|
||||
|
||||
$totals = $this->sale_lib->get_totals($tax_details[0]);
|
||||
$data += [
|
||||
'item_count' => $totals['item_count'],
|
||||
'total_units' => $totals['total_units'],
|
||||
'subtotal' => $totals['subtotal'],
|
||||
'total' => $totals['total'],
|
||||
'payments_total' => $totals['payment_total'],
|
||||
'payments_cover_total' => $totals['payments_cover_total'],
|
||||
'prediscount_subtotal' => $totals['prediscount_subtotal'],
|
||||
'cash_total' => $totals['cash_total'],
|
||||
'non_cash_total' => $totals['total'],
|
||||
'cash_amount_due' => $totals['cash_amount_due'],
|
||||
'non_cash_amount_due' => $totals['amount_due'],
|
||||
'cash_mode' => $this->session->get('cash_mode'),
|
||||
'selected_payment_type' => $this->sale_lib->get_payment_type(),
|
||||
'comment' => $this->sale_lib->get_comment(),
|
||||
'email_receipt' => $this->sale_lib->is_email_receipt(),
|
||||
'config' => $this->config,
|
||||
'mode' => $this->sale_lib->get_mode(),
|
||||
'rate' => (float) ($secondaryCurrency['rate'] ?? $this->config['secondary_currency_rate'] ?? 0),
|
||||
'secondaryCurrency' => $secondaryCurrency,
|
||||
'secondaryCurrencyEnabled' => $secondaryCurrencyEnabled,
|
||||
'showCustomerDisplay' => $showCustomerDisplay,
|
||||
'companyName' => $companyName,
|
||||
'companyDetails' => $companyDetails,
|
||||
'secondaryCurrencySymbol' => $secondaryCurrencySymbol,
|
||||
'secondaryCurrencyCode' => $secondaryCurrencyCode,
|
||||
'originalCurrencySymbol' => $originalCurrencySymbol,
|
||||
'customerDisplayCurrencyLabel' => $customerDisplayCurrencyLabel,
|
||||
'originalCurrencyLabel' => $originalCurrencyLabel,
|
||||
'cartHasCustomerDisplay' => $cartHasCustomerDisplay,
|
||||
'cartColspan' => $cartColspan,
|
||||
'cartItemWidth' => $cartItemWidth,
|
||||
'cartPriceWidth' => $cartPriceWidth,
|
||||
'cartOriginalWidth' => $cartOriginalWidth,
|
||||
'cartQuantityWidth' => $cartQuantityWidth,
|
||||
'cartDiscountWidth' => $cartDiscountWidth,
|
||||
'cartTotalWidth' => $cartTotalWidth,
|
||||
'items_module_allowed' => $this->employee->has_grant('items', $this->employee->get_logged_in_employee_info()->person_id),
|
||||
'change_price' => $this->employee->has_grant('sales_change_price', $this->employee->get_logged_in_employee_info()->person_id)
|
||||
];
|
||||
|
||||
$invoice_number = $this->sale_lib->get_invoice_number();
|
||||
if ($invoice_number == null || $invoice_number == '') {
|
||||
$invoice_number = $this->token_lib->render($this->config['sales_invoice_format'], [], false);
|
||||
}
|
||||
|
||||
$data += [
|
||||
'invoice_number' => $invoice_number,
|
||||
'print_after_sale' => $this->sale_lib->is_print_after_sale(),
|
||||
'price_work_orders' => $this->sale_lib->is_price_work_orders(),
|
||||
'pos_mode' => $data['mode'] == 'sale' || $data['mode'] == 'return',
|
||||
'quote_number' => $this->sale_lib->get_quote_number(),
|
||||
'work_order_number' => $this->sale_lib->get_work_order_number(),
|
||||
'amount_due' => $data['cash_mode'] && ($data['selected_payment_type'] === lang('Sales.cash') || $data['payments_total'] > 0) ? $totals['cash_amount_due'] : $totals['amount_due']
|
||||
];
|
||||
$data['amount_change'] = $data['amount_due'] * -1;
|
||||
$data['payment_change_due'] = ((float) $data['amount_due'] < 0)
|
||||
? abs((float) $data['amount_due'])
|
||||
: max(((float) $data['payments_total']) - ((float) $data['amount_due']), 0);
|
||||
$data['paymentChangeDue'] = $data['payment_change_due'];
|
||||
|
||||
return view('sales/customer_display', $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the sale edit modal. Used in app/Views/sales/register.php.
|
||||
*
|
||||
@@ -93,8 +249,6 @@ class Sales extends Secure_Controller
|
||||
'only_check' => lang('Sales.check_filter'),
|
||||
'only_creditcard' => lang('Sales.credit_filter'),
|
||||
'only_debit' => lang('Sales.debit'),
|
||||
'only_bank_transfer'=> lang('Sales.bank_transfer'),
|
||||
'only_wallet' => lang('Sales.wallet'),
|
||||
'only_invoices' => lang('Sales.invoice_filter'),
|
||||
'selected_customer' => lang('Sales.selected_customer')
|
||||
];
|
||||
@@ -158,8 +312,6 @@ class Sales extends Secure_Controller
|
||||
'selected_customer' => false,
|
||||
'only_creditcard' => false,
|
||||
'only_debit' => false,
|
||||
'only_bank_transfer'=> false,
|
||||
'only_wallet' => false,
|
||||
'only_invoices' => $this->config['invoice_enable'] && $this->request->getGet('only_invoices', FILTER_SANITIZE_NUMBER_INT),
|
||||
'is_valid_receipt' => $this->sale->is_valid_receipt($search)
|
||||
];
|
||||
@@ -818,6 +970,7 @@ class Sales extends Secure_Controller
|
||||
|
||||
// Resort and filter cart lines for printing
|
||||
$data['cart'] = $this->sale_lib->sort_and_filter_cart($data['cart']);
|
||||
$this->_append_secondary_currency($data);
|
||||
|
||||
if ($data['sale_id_num'] == NEW_ENTRY) {
|
||||
$data['error_message'] = lang('Sales.transaction_failed');
|
||||
@@ -857,6 +1010,7 @@ class Sales extends Secure_Controller
|
||||
$data['cart'] = $this->sale_lib->sort_and_filter_cart($data['cart']);
|
||||
|
||||
$data['barcode'] = null;
|
||||
$this->_append_secondary_currency($data);
|
||||
|
||||
$this->sale_lib->clear_all();
|
||||
return view('sales/work_order', $data);
|
||||
@@ -884,6 +1038,7 @@ class Sales extends Secure_Controller
|
||||
|
||||
$data['cart'] = $this->sale_lib->sort_and_filter_cart($data['cart']);
|
||||
$data['barcode'] = null;
|
||||
$this->_append_secondary_currency($data);
|
||||
|
||||
$this->sale_lib->clear_all();
|
||||
return view('sales/quote', $data);
|
||||
@@ -902,20 +1057,13 @@ class Sales extends Secure_Controller
|
||||
$data['sale_id'] = 'POS ' . $data['sale_id_num'];
|
||||
|
||||
$data['cart'] = $this->sale_lib->sort_and_filter_cart($data['cart']);
|
||||
$this->_append_secondary_currency($data);
|
||||
|
||||
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']);
|
||||
|
||||
// Validate receipt template to prevent path traversal
|
||||
$receipt_template = $this->config['receipt_template'] ?? '';
|
||||
if (!Sale_lib::isValidReceiptTemplate($receipt_template)) {
|
||||
$receipt_template = 'receipt_default';
|
||||
}
|
||||
$data['receipt_template_view'] = $receipt_template;
|
||||
|
||||
$this->sale_lib->clear_all();
|
||||
return view('sales/receipt', $data);
|
||||
}
|
||||
@@ -1170,13 +1318,7 @@ class Sales extends Secure_Controller
|
||||
$invoice_type = 'invoice';
|
||||
}
|
||||
$data['invoice_view'] = $invoice_type;
|
||||
|
||||
// Validate receipt template to prevent path traversal
|
||||
$receipt_template = $this->config['receipt_template'] ?? '';
|
||||
if (!Sale_lib::isValidReceiptTemplate($receipt_template)) {
|
||||
$receipt_template = 'receipt_default';
|
||||
}
|
||||
$data['receipt_template_view'] = $receipt_template;
|
||||
$this->_append_secondary_currency($data);
|
||||
|
||||
return $data;
|
||||
}
|
||||
@@ -1243,6 +1385,7 @@ class Sales extends Secure_Controller
|
||||
}
|
||||
|
||||
$data['amount_change'] = $data['amount_due'] * -1;
|
||||
$this->_append_secondary_currency($data);
|
||||
|
||||
$data['comment'] = $this->sale_lib->get_comment();
|
||||
$data['email_receipt'] = $this->sale_lib->is_email_receipt();
|
||||
@@ -1272,7 +1415,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.
|
||||
@@ -1661,9 +1803,7 @@ class Sales extends Secure_Controller
|
||||
*/
|
||||
public function getSalesKeyboardHelp(): string
|
||||
{
|
||||
return view('sales/help', [
|
||||
'keyboardShortcuts' => $this->sale_lib->getKeyShortcuts()
|
||||
]);
|
||||
return view('sales/help');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1785,3 +1925,5 @@ class Sales extends Secure_Controller
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -272,9 +272,6 @@ function get_payment_options(): array
|
||||
$payments[lang('Sales.upi')] = lang('Sales.upi');
|
||||
}
|
||||
|
||||
$payments[lang('Sales.bank_transfer')] = lang('Sales.bank_transfer');
|
||||
$payments[lang('Sales.wallet')] = lang('Sales.wallet');
|
||||
|
||||
return $payments;
|
||||
}
|
||||
|
||||
@@ -368,6 +365,74 @@ function to_currency_no_money(?string $number): string
|
||||
return to_decimals($number, 'currency_decimals');
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the secondary currency rendering context from app config values.
|
||||
*
|
||||
* @param array $config
|
||||
* @return array{show:bool,rate:float,symbol:string,code:string,decimals:int}
|
||||
*/
|
||||
function secondary_currency_context(array $config): array
|
||||
{
|
||||
$rate = (float) ($config['secondary_currency_rate'] ?? 0);
|
||||
$symbol = trim((string) ($config['secondary_currency_symbol'] ?? ''));
|
||||
$code = trim((string) ($config['secondary_currency_code'] ?? ''));
|
||||
$decimals = (int) ($config['secondary_currency_decimals'] ?? ($config['currency_decimals'] ?? DEFAULT_PRECISION));
|
||||
|
||||
return [
|
||||
'show' => (($config['secondary_currency_enabled'] ?? false) == 1) && $rate > 0,
|
||||
'rate' => $rate,
|
||||
'symbol' => $symbol,
|
||||
'code' => $code,
|
||||
'decimals' => $decimals,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Render a value in the secondary currency.
|
||||
*
|
||||
* @param float|int|string|null $number
|
||||
* @param array{show:bool,rate:float,symbol:string,code:string,decimals:int} $secondaryCurrency
|
||||
* @return string
|
||||
*/
|
||||
function to_secondary_currency(float|int|string|null $number, array $secondaryCurrency): string
|
||||
{
|
||||
if (!isset($number) || !$secondaryCurrency['show']) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$config = config(OSPOS::class)->settings;
|
||||
$amount = (float) $number * (float) $secondaryCurrency['rate'];
|
||||
$fmt = new NumberFormatter($config['number_locale'], NumberFormatter::CURRENCY);
|
||||
$fmt->setAttribute(NumberFormatter::MIN_FRACTION_DIGITS, $secondaryCurrency['decimals']);
|
||||
$fmt->setAttribute(NumberFormatter::MAX_FRACTION_DIGITS, $secondaryCurrency['decimals']);
|
||||
|
||||
if (empty($config['thousands_separator'])) {
|
||||
$fmt->setTextAttribute(NumberFormatter::GROUPING_SEPARATOR_SYMBOL, '');
|
||||
}
|
||||
|
||||
$fmt->setSymbol(NumberFormatter::CURRENCY_SYMBOL, $secondaryCurrency['symbol'] !== '' ? $secondaryCurrency['symbol'] : ($secondaryCurrency['code'] !== '' ? $secondaryCurrency['code'] : ''));
|
||||
|
||||
return $fmt->format($amount);
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the secondary and primary currency amounts together.
|
||||
*
|
||||
* @param float|int|string|null $number
|
||||
* @param array{show:bool,rate:float,symbol:string,code:string,decimals:int} $secondaryCurrency
|
||||
* @return string
|
||||
*/
|
||||
function to_secondary_currency_dual(float|int|string|null $number, array $secondaryCurrency): string
|
||||
{
|
||||
$secondary = to_secondary_currency($number, $secondaryCurrency);
|
||||
|
||||
if ($secondary === '') {
|
||||
return to_currency((string) $number);
|
||||
}
|
||||
|
||||
return $secondary . '<br>' . to_currency((string) $number);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string|null $number
|
||||
* @return string
|
||||
|
||||
@@ -268,10 +268,19 @@ return [
|
||||
"receipt_show_company_name" => "Show Company Name",
|
||||
"receipt_show_description" => "Show Description",
|
||||
"receipt_show_serialnumber" => "Show Serial Number",
|
||||
"receipt_show_secondary_currency" => "Show Secondary Currency",
|
||||
"receipt_show_tax_ind" => "Show Tax Indicator",
|
||||
"receipt_show_taxes" => "Show Taxes",
|
||||
"receipt_show_total_discount" => "Show Total Discount",
|
||||
"receipt_template" => "Receipt Template",
|
||||
"secondary_currency" => "Secondary Currency",
|
||||
"secondary_currency_decimals" => "Secondary Currency Decimals",
|
||||
"secondary_currency_code" => "Secondary Currency Code",
|
||||
"secondary_currency_enable" => "Enable Secondary Currency",
|
||||
"secondary_currency_enable_tooltip" => "Show secondary currency fields and print/display values across the app.",
|
||||
"secondary_currency_rate" => "Secondary Currency Rate",
|
||||
"secondary_currency_settings" => "Secondary Currency Settings",
|
||||
"secondary_currency_symbol" => "Secondary Currency Symbol",
|
||||
"receiving_calculate_average_price" => "Calc avg. Price (Receiving)",
|
||||
"recv_invoice_format" => "Receivings Invoice Format",
|
||||
"register_mode_default" => "Default Register Mode",
|
||||
@@ -288,6 +297,7 @@ return [
|
||||
"security_issue" => "Security Vulnerability Warning",
|
||||
"server_notice" => "Please use the below info for issue reporting.",
|
||||
"service_charge" => "",
|
||||
"customer_display" => "Customer Display",
|
||||
"show_due_enable" => "",
|
||||
"show_office_group" => "Show office icon",
|
||||
"statistics" => "Send Statistics",
|
||||
@@ -302,10 +312,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",
|
||||
@@ -334,3 +340,5 @@ return [
|
||||
"work_order_enable" => "Work Order Support",
|
||||
"work_order_format" => "Work Order Format",
|
||||
];
|
||||
|
||||
|
||||
|
||||
@@ -7,9 +7,9 @@ return [
|
||||
"account_number" => "Account #",
|
||||
"add_payment" => "Add Payment",
|
||||
"amount_due" => "Amount Due",
|
||||
"amount_due_lbp" => "Amount Due LBP",
|
||||
"amount_tendered" => "Amount Tendered",
|
||||
"authorized_signature" => "Authorized Signature",
|
||||
"bank_transfer" => "Bank Transfer",
|
||||
"cancel_sale" => "Cancel",
|
||||
"cash" => "Cash",
|
||||
"cash_1" => "",
|
||||
@@ -20,6 +20,8 @@ return [
|
||||
"cash_deposit" => "Cash Deposit",
|
||||
"cash_filter" => "Cash",
|
||||
"change_due" => "Change Due",
|
||||
"change" => "Change",
|
||||
"currency_rate" => "Currency Rate",
|
||||
"change_price" => "Change Selling Price",
|
||||
"check" => "Check",
|
||||
"check_balance" => "Check remainder",
|
||||
@@ -41,6 +43,7 @@ return [
|
||||
"customer_address" => "Address",
|
||||
"customer_discount" => "Discount",
|
||||
"customer_email" => "Email",
|
||||
"customer_name" => "Customer Name",
|
||||
"customer_location" => "Location",
|
||||
"customer_mailchimp_status" => "MailChimp Status",
|
||||
"customer_optional" => "(Required for Due Payments)",
|
||||
@@ -74,12 +77,6 @@ return [
|
||||
"employee" => "Employee",
|
||||
"entry" => "Entry",
|
||||
"error_editing_item" => "Error editing item",
|
||||
"negative_price_invalid" => "Price cannot be negative.",
|
||||
"negative_quantity_invalid" => "Quantity cannot be negative.",
|
||||
"negative_discount_invalid" => "Discount cannot be negative.",
|
||||
"discount_percent_exceeds_100" => "Percentage discount cannot exceed 100%.",
|
||||
"discount_exceeds_item_total" => "Discount cannot exceed the item total.",
|
||||
"negative_total_invalid" => "Sale total cannot be negative. Check item discounts and quantities.",
|
||||
"find_or_scan_item" => "Find or Scan Item",
|
||||
"find_or_scan_item_or_receipt" => "Find or Scan Item or Receipt",
|
||||
"giftcard" => "Gift Card",
|
||||
@@ -110,6 +107,7 @@ return [
|
||||
"item_name" => "Item Name",
|
||||
"item_number" => "Item #",
|
||||
"item_out_of_stock" => "Item is out of stock.",
|
||||
"items" => "Items",
|
||||
"key_browser" => "Helpful Shortcuts",
|
||||
"key_cancel" => "Cancels Current Quote/Invoice/Sale",
|
||||
"key_customer_search" => "Customer Search",
|
||||
@@ -151,7 +149,9 @@ return [
|
||||
"payment_type" => "Type",
|
||||
"payments" => "",
|
||||
"payments_total" => "Payments Total",
|
||||
"loyalty_reward_points" => "Loyalty Reward Points",
|
||||
"price" => "Price",
|
||||
"price_with_currency" => "Price (%s)",
|
||||
"print_after_sale" => "Print after Sale",
|
||||
"quantity" => "Quantity",
|
||||
"quantity_less_than_reorder_level" => "Warning: Desired Quantity is below Reorder Level for that Item.",
|
||||
@@ -167,10 +167,13 @@ return [
|
||||
"receipt_number" => "Sale #",
|
||||
"receipt_sent" => "Receipt sent to",
|
||||
"receipt_unsent" => "Receipt failed to be sent to",
|
||||
"rate" => "Rate",
|
||||
"refund" => "Refund Type",
|
||||
"register" => "Sales Register",
|
||||
"remove_customer" => "Remove Customer",
|
||||
"remove_discount" => "",
|
||||
"customer_display" => "Customer Display",
|
||||
"summary" => "Summary",
|
||||
"return" => "Return",
|
||||
"rewards" => "Reward Points",
|
||||
"rewards_balance" => "Reward Points Balance",
|
||||
@@ -182,6 +185,7 @@ return [
|
||||
"sales_total" => "",
|
||||
"select_customer" => "Select Customer",
|
||||
"selected_customer" => "Selected Customer",
|
||||
"walk_in_customer" => "Walk-in Customer",
|
||||
"send_invoice" => "Send Invoice",
|
||||
"send_quote" => "Send Quote",
|
||||
"send_receipt" => "Send Receipt",
|
||||
@@ -212,6 +216,7 @@ return [
|
||||
"tax_percent" => "Tax %",
|
||||
"taxed_ind" => "T",
|
||||
"total" => "Total",
|
||||
"total_lbp" => "Total LBP",
|
||||
"total_tax_exclusive" => "Tax excluded",
|
||||
"transaction_failed" => "Sales Transaction failed.",
|
||||
"unable_to_add_item" => "Item add to Sale failed",
|
||||
@@ -224,7 +229,6 @@ return [
|
||||
"update" => "Update",
|
||||
"upi" => "UPI",
|
||||
"visa" => "",
|
||||
"wallet" => "Wallet",
|
||||
"wholesale" => "",
|
||||
"work_order" => "Work Order",
|
||||
"work_order_number" => "Work Order Number",
|
||||
@@ -232,3 +236,5 @@ return [
|
||||
"work_order_sent" => "Work Order sent to",
|
||||
"work_order_unsent" => "Work Order failed to be sent to",
|
||||
];
|
||||
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
) ?>
|
||||
</div>
|
||||
<div class="col-sm-7">
|
||||
<a href="<?= 'https://bootswatch.com/3/' . ('bootstrap' == ($config['theme']) ? 'default' : esc($config['theme'])) ?>" target="_blank" rel=”noopener”>
|
||||
<a href="<?= 'https://bootswatch.com/3/' . ('bootstrap' == ($config['theme']) ? 'default' : esc($config['theme'])) ?>" target="_blank" rel="noopener">
|
||||
<span><?= lang('Config.theme_preview') . ' ' . ucfirst(esc($config['theme'])) . ' ' ?></span>
|
||||
<span class="glyphicon glyphicon-new-window"></span>
|
||||
</a>
|
||||
@@ -130,14 +130,17 @@
|
||||
</div>
|
||||
|
||||
<div class="form-group form-group-sm">
|
||||
<?= form_label(lang('Config.receiving_calculate_average_price'), 'receiving_calculate_average_price', ['class' => 'control-label col-xs-2']) ?>
|
||||
<div class="col-xs-1">
|
||||
<?= form_checkbox([
|
||||
'name' => 'receiving_calculate_average_price',
|
||||
'id' => 'receiving_calculate_average_price',
|
||||
'value' => 'receiving_calculate_average_price',
|
||||
'checked' => $config['receiving_calculate_average_price'] == 1
|
||||
]) ?>
|
||||
<?= form_label(lang('Config.receiving_cost_price_method'), 'receiving_cost_price_method', ['class' => 'control-label col-xs-2']) ?>
|
||||
<div class="col-xs-3">
|
||||
<?= form_dropdown(
|
||||
'receiving_cost_price_method',
|
||||
[
|
||||
'average' => lang('Config.receiving_cost_price_method_average'),
|
||||
'new' => lang('Config.receiving_cost_price_method_new'),
|
||||
],
|
||||
(($config['receiving_cost_price_method'] ?? (($config['receiving_calculate_average_price'] ?? 1) ? 'average' : 'new'))),
|
||||
['id' => 'receiving_cost_price_method', 'class' => 'form-control']
|
||||
) ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -278,7 +281,7 @@
|
||||
'checked' => $config['gcaptcha_enable'] == 1
|
||||
]) ?>
|
||||
<label class="control-label">
|
||||
<a href="https://www.google.com/recaptcha/admin" target="_blank">
|
||||
<a href="https://www.google.com/recaptcha/admin" target="_blank" rel="noopener noreferrer">
|
||||
<span class="glyphicon glyphicon-info-sign" data-toggle="tooltip" data-placement="right" title="<?= lang('Config.gcaptcha_tooltip') ?>"></span>
|
||||
</a>
|
||||
</label>
|
||||
@@ -405,6 +408,18 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group form-group-sm">
|
||||
<?= form_label(lang('Config.customer_display'), 'customer_display_enabled', ['class' => 'control-label col-xs-2']) ?>
|
||||
<div class="col-xs-1">
|
||||
<?= form_checkbox([
|
||||
'name' => 'customer_display_enabled',
|
||||
'id' => 'customer_display_enabled',
|
||||
'value' => 'customer_display_enabled',
|
||||
'checked' => ($config['customer_display_enabled'] ?? 1) == 1
|
||||
]) ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group form-group-sm">
|
||||
<?= form_label(lang('Config.show_office_group'), 'show_office_group', ['class' => 'control-label col-xs-2']) ?>
|
||||
<div class="col-xs-1">
|
||||
@@ -441,6 +456,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="form-group form-group-sm">
|
||||
<?= form_label(lang('Config.category_dropdown'), 'category_dropdown', ['class' => 'control-label col-xs-2']) ?>
|
||||
<div class="col-xs-1">
|
||||
@@ -541,3 +557,6 @@
|
||||
}));
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
|
||||
|
||||
249
app/Views/partial/customer_display_header.php
Normal file
249
app/Views/partial/customer_display_header.php
Normal file
@@ -0,0 +1,249 @@
|
||||
<?php
|
||||
/**
|
||||
* @var array $config
|
||||
* @var string $companyName
|
||||
* @var string $companyDetails
|
||||
*/
|
||||
|
||||
helper('url');
|
||||
?>
|
||||
|
||||
<!doctype html>
|
||||
<html lang="<?= esc(service('request')->getLocale()) ?>">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title><?= lang('Sales.customer_display') ?></title>
|
||||
<link rel="shortcut icon" type="image/x-icon" href="<?= base_url('images/favicon.ico') ?>">
|
||||
<link rel="stylesheet" href="<?= base_url('resources/bootswatch/' . (empty($config['theme']) ? 'flatly' : esc($config['theme'])) . '/bootstrap.min.css') ?>">
|
||||
<link rel="stylesheet" href="<?= base_url('resources/opensourcepos-8e34d6a398.min.css') ?>">
|
||||
<style>
|
||||
html, body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
background: #f8f8f8;
|
||||
color: #333;
|
||||
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||
}
|
||||
|
||||
body {
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.customer-display-header {
|
||||
background: #1f3143;
|
||||
color: #fff;
|
||||
text-align: center;
|
||||
font-size: 15px;
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.02em;
|
||||
padding: 6px 12px;
|
||||
border-bottom: 1px solid #102131;
|
||||
}
|
||||
|
||||
.customer-display-shell {
|
||||
width: 100%;
|
||||
max-width: 1280px;
|
||||
margin: 0 auto;
|
||||
padding: 12px 18px 18px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.customer-display-company {
|
||||
text-align: center;
|
||||
margin-bottom: 18px;
|
||||
}
|
||||
|
||||
.customer-display-company img {
|
||||
display: block;
|
||||
margin: 0 auto 6px;
|
||||
max-height: 84px;
|
||||
max-width: 240px;
|
||||
}
|
||||
|
||||
.customer-display-company .company-name {
|
||||
font-size: 20px;
|
||||
font-weight: 600;
|
||||
line-height: 1.2;
|
||||
margin-top: 12px;
|
||||
}
|
||||
|
||||
.customer-display-company .company-details {
|
||||
font-size: 13px;
|
||||
line-height: 1.35;
|
||||
white-space: pre-line;
|
||||
}
|
||||
|
||||
.customer-display-company .company-phone {
|
||||
font-size: 13px;
|
||||
line-height: 1.35;
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
.customer-display-main-row {
|
||||
display: flex;
|
||||
gap: 14px;
|
||||
align-items: flex-start;
|
||||
margin-top: 6px;
|
||||
}
|
||||
|
||||
.customer-display-cart-column {
|
||||
flex: 1 1 auto;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.customer-display-summary-column {
|
||||
flex: 0 0 320px;
|
||||
width: 320px;
|
||||
}
|
||||
|
||||
.customer-display-summary-panel,
|
||||
.customer-display-info-panel,
|
||||
.customer-display-items-panel {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.customer-display-summary-panel .panel-heading,
|
||||
.customer-display-info-panel .panel-heading,
|
||||
.customer-display-items-panel .panel-heading {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.customer-display-summary-panel .table,
|
||||
.customer-display-info-table {
|
||||
margin-bottom: 0;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.customer-display-summary-panel .table > tbody > tr > th,
|
||||
.customer-display-info-table > tbody > tr > th {
|
||||
background: #f8fbfd;
|
||||
width: 56%;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.customer-display-summary-panel .table > tbody > tr > td,
|
||||
.customer-display-info-table > tbody > tr > td {
|
||||
width: 44%;
|
||||
text-align: right;
|
||||
white-space: nowrap;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.customer-display-summary-panel .rate-row th,
|
||||
.customer-display-summary-panel .rate-row td {
|
||||
color: #c00000;
|
||||
}
|
||||
|
||||
.customer-display-summary-panel .summary-section-row th {
|
||||
background: #eaf2f8;
|
||||
color: #1f3b5b;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.customer-display-summary-panel .summary-subtable {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.customer-display-summary-panel .summary-subtable > tbody > tr > th {
|
||||
background: #fdfefe;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.customer-display-summary-panel .summary-subtable > tbody > tr > td {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.register-wrap {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#register {
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
table-layout: fixed;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
#register th,
|
||||
#register td {
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
padding: 6px 5px;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
||||
#register thead th {
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
#register tbody td {
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
#register tbody td.item-name-cell {
|
||||
font-size: 16px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
#register tbody td.price-cell {
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
#register tbody td.serial-cell {
|
||||
font-size: 12px;
|
||||
color: #2F4F4F;
|
||||
}
|
||||
|
||||
.customer-display-summary-panel .table > tbody > tr > th,
|
||||
.customer-display-info-table > tbody > tr > th {
|
||||
border-top: 1px solid #e5e5e5;
|
||||
}
|
||||
|
||||
.customer-display-summary-panel .table > tbody > tr > td,
|
||||
.customer-display-info-table > tbody > tr > td {
|
||||
border-top: 1px solid #e5e5e5;
|
||||
}
|
||||
|
||||
.customer-display-summary-panel .panel-body,
|
||||
.customer-display-info-panel .panel-body,
|
||||
.customer-display-items-panel .panel-body {
|
||||
padding: 12px 15px;
|
||||
}
|
||||
|
||||
.customer-display-summary-column .panel-body {
|
||||
padding-top: 8px;
|
||||
}
|
||||
|
||||
.customer-display-summary-column .customer-name-value,
|
||||
.customer-display-summary-column .giftcard-value,
|
||||
.customer-display-summary-column .reward-value {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.customer-display-footer {
|
||||
margin-top: 14px;
|
||||
text-align: center;
|
||||
font-size: 12px;
|
||||
color: #777;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="customer-display-header">Open Source Point of Sale</div>
|
||||
<div class="customer-display-shell">
|
||||
<div class="customer-display-company">
|
||||
<?php if (!empty($config['company_logo'])) { ?>
|
||||
<img src="<?= base_url('uploads/' . esc($config['company_logo'], 'url')) ?>" alt="company_logo">
|
||||
<?php } ?>
|
||||
<div class="company-name"><?= esc($companyName) ?></div>
|
||||
<div class="company-phone">Phone: <?= esc((string)($config['phone'] ?? '')) ?></div>
|
||||
<?php if ($companyDetails !== '') { ?>
|
||||
<div class="company-details"><?= nl2br(esc($companyDetails)) ?></div>
|
||||
<?php } ?>
|
||||
</div>
|
||||
|
||||
<div class="customer-display-main-row">
|
||||
|
||||
224
app/Views/sales/customer_display.php
Normal file
224
app/Views/sales/customer_display.php
Normal file
@@ -0,0 +1,224 @@
|
||||
<?php
|
||||
/**
|
||||
* @var array $cart
|
||||
* @var array $config
|
||||
* @var float $rate
|
||||
* @var float $total
|
||||
* @var float $subtotal
|
||||
* @var float $prediscount_subtotal
|
||||
* @var array $taxes
|
||||
* @var array $payments
|
||||
* @var float $amount_change
|
||||
*/
|
||||
|
||||
$priceWithCurrencyLabel = lang('Sales.price_with_currency');
|
||||
|
||||
?>
|
||||
|
||||
<?= view('partial/customer_display_header') ?>
|
||||
|
||||
<div class="customer-display-cart-column">
|
||||
<div class="register-wrap">
|
||||
<div class="panel panel-default customer-display-items-panel">
|
||||
<div class="panel-heading"><?= lang('Sales.items') ?></div>
|
||||
<div class="panel-body table-responsive">
|
||||
<table class="table table-striped table-condensed" id="register">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="width: <?= (int) $cartItemWidth ?>%;"><?= lang('Sales.item_name') ?></th>
|
||||
<?php if ($cartHasCustomerDisplay) { ?>
|
||||
<th style="width: <?= (int) $cartPriceWidth ?>%;"><?= sprintf($priceWithCurrencyLabel, esc($customerDisplayCurrencyLabel)) ?></th>
|
||||
<?php } ?>
|
||||
<th style="width: <?= (int) $cartOriginalWidth ?>%;"><?= sprintf($priceWithCurrencyLabel, esc($originalCurrencyLabel)) ?></th>
|
||||
<th style="width: <?= (int) $cartQuantityWidth ?>%;"><?= lang('Sales.quantity') ?></th>
|
||||
<th style="width: <?= (int) $cartDiscountWidth ?>%;"><?= lang('Sales.discount') ?></th>
|
||||
<th style="width: <?= (int) $cartTotalWidth ?>%;"><?= lang('Sales.total') ?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="cart_contents">
|
||||
<?php if (count($cart) == 0) { ?>
|
||||
<tr>
|
||||
<td colspan="<?= (int) $cartColspan ?>">
|
||||
<div class="alert alert-dismissible alert-info"><?= lang('Sales.no_items_in_cart') ?></div>
|
||||
</td>
|
||||
</tr>
|
||||
<?php } else { ?>
|
||||
<?php foreach (array_reverse($cart, true) as $line => $item) { ?>
|
||||
<tr>
|
||||
<td class="item-name-cell">
|
||||
<?= esc($item['name']) ?><br>
|
||||
<?= !empty($item['attribute_values']) ? esc($item['attribute_values']) : '' ?>
|
||||
</td>
|
||||
<?php if ($cartHasCustomerDisplay) { ?>
|
||||
<td class="price-cell">
|
||||
<?= to_secondary_currency((float)$item['price'], $secondaryCurrency) ?>
|
||||
</td>
|
||||
<?php } ?>
|
||||
<td class="price-cell">
|
||||
<?= to_currency($item['price']) ?>
|
||||
</td>
|
||||
<td class="price-cell">
|
||||
<?= to_quantity_decimals($item['quantity']) ?>
|
||||
</td>
|
||||
<td class="price-cell">
|
||||
<?= to_decimals($item['discount'], 0) ?>
|
||||
</td>
|
||||
<td class="price-cell">
|
||||
<?= $item['item_type'] == ITEM_AMOUNT_ENTRY ? to_currency_no_money($item['discounted_total']) : to_currency($item['discounted_total']) ?>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="<?= $cartHasCustomerDisplay ? 3 : 2 ?>"></td>
|
||||
<td class="serial-cell">
|
||||
<?= $item['is_serialized'] == 1 ? lang('Sales.serial') : '' ?>
|
||||
</td>
|
||||
<td colspan="2" class="serial-cell">
|
||||
<?php if ($item['is_serialized'] == 1) {
|
||||
echo esc($item['serialnumber']);
|
||||
} ?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php } ?>
|
||||
<?php } ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="customer-display-summary-column">
|
||||
<div class="panel panel-primary customer-display-summary-panel">
|
||||
<div class="panel-heading"><?= lang('Sales.summary') ?></div>
|
||||
<div class="panel-body">
|
||||
<table class="table table-condensed summary-subtable">
|
||||
<tbody>
|
||||
<tr>
|
||||
<th><?= lang('Sales.total') ?></th>
|
||||
<td><?= to_currency($total) ?></td>
|
||||
</tr>
|
||||
<?php if ($showCustomerDisplay): ?>
|
||||
<tr>
|
||||
<th><?= lang('Sales.total') ?> <?= esc($customerDisplayCurrencyLabel) ?></th>
|
||||
<td><?= to_secondary_currency((float)$total, $secondaryCurrency) ?></td>
|
||||
</tr>
|
||||
<tr class="rate-row">
|
||||
<th><?= lang('Sales.rate') ?></th>
|
||||
<td><?= number_format((float) $rate, 2) ?></td>
|
||||
</tr>
|
||||
<?php endif; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<table class="table table-condensed summary-subtable" style="margin-top: 10px;">
|
||||
<tbody>
|
||||
<tr class="summary-section-row">
|
||||
<th colspan="2"><?= lang('Sales.customer') ?></th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><?= lang('Sales.customer_name') ?></th>
|
||||
<td class="customer-name-value"><?= esc($customerName ?? lang('Sales.walk_in_customer')) ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><?= lang('Sales.giftcard_balance') ?></th>
|
||||
<td class="giftcard-value"><?= to_currency((float) ($giftcardRemainder ?? 0)) ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><?= lang('Sales.loyalty_reward_points') ?></th>
|
||||
<td class="reward-value"><?= esc((string)($customerRewardPoints ?? 0)) ?></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<table class="table table-condensed summary-subtable" style="margin-top: 10px;">
|
||||
<tbody>
|
||||
<tr class="summary-section-row">
|
||||
<th colspan="2"><?= lang('Sales.change') ?></th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><?= lang('Sales.payments_total') ?></th>
|
||||
<td><?= to_currency($payments_total) ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th><?= lang('Sales.amount_due') ?></th>
|
||||
<td><?= to_currency($amount_due) ?></td>
|
||||
</tr>
|
||||
<?php if ($showCustomerDisplay): ?>
|
||||
<tr>
|
||||
<th><?= lang('Sales.amount_due') ?> <?= esc($customerDisplayCurrencyLabel) ?></th>
|
||||
<td><?= to_secondary_currency((float)$amount_due, $secondaryCurrency) ?></td>
|
||||
</tr>
|
||||
<?php endif; ?>
|
||||
<tr>
|
||||
<th><?= lang('Sales.change_due') ?></th>
|
||||
<td><?= to_currency($paymentChangeDue ?? 0) ?></td>
|
||||
</tr>
|
||||
<?php if ($showCustomerDisplay): ?>
|
||||
<tr>
|
||||
<th><?= lang('Sales.change_due') ?> <?= esc($customerDisplayCurrencyLabel) ?></th>
|
||||
<td><?= to_secondary_currency((float)($paymentChangeDue ?? 0), $secondaryCurrency) ?></td>
|
||||
</tr>
|
||||
<?php endif; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="customer-display-footer"></div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const customerDisplayId = new URLSearchParams(window.location.search).get('displayId') || '';
|
||||
const customerDisplayStorageSuffix = customerDisplayId !== '' ? '_' + customerDisplayId : '';
|
||||
const customerDisplayStorageKeys = {
|
||||
open: 'customerDisplayOpen' + customerDisplayStorageSuffix,
|
||||
dirtyAt: 'customerDisplayDirtyAt' + customerDisplayStorageSuffix
|
||||
};
|
||||
|
||||
localStorage.setItem(customerDisplayStorageKeys.open, '1');
|
||||
|
||||
let lastDirtyAt = localStorage.getItem(customerDisplayStorageKeys.dirtyAt) || '';
|
||||
let refreshTimer = null;
|
||||
|
||||
const scheduleRefresh = function(dirtyAt) {
|
||||
if (refreshTimer !== null) {
|
||||
clearTimeout(refreshTimer);
|
||||
}
|
||||
|
||||
refreshTimer = setTimeout(function() {
|
||||
if (localStorage.getItem(customerDisplayStorageKeys.open) !== '1') {
|
||||
return;
|
||||
}
|
||||
|
||||
if (localStorage.getItem(customerDisplayStorageKeys.dirtyAt) === dirtyAt) {
|
||||
window.location.reload();
|
||||
}
|
||||
}, 700);
|
||||
};
|
||||
|
||||
const checkForRefresh = function() {
|
||||
const dirtyAt = localStorage.getItem(customerDisplayStorageKeys.dirtyAt) || '';
|
||||
if (dirtyAt !== '' && dirtyAt !== lastDirtyAt) {
|
||||
lastDirtyAt = dirtyAt;
|
||||
scheduleRefresh(dirtyAt);
|
||||
}
|
||||
};
|
||||
|
||||
window.addEventListener('storage', function(event) {
|
||||
if (event.key === customerDisplayStorageKeys.dirtyAt) {
|
||||
checkForRefresh();
|
||||
}
|
||||
});
|
||||
|
||||
setInterval(checkForRefresh, 500);
|
||||
|
||||
window.addEventListener('beforeunload', function() {
|
||||
localStorage.removeItem(customerDisplayStorageKeys.open);
|
||||
});
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
|
||||
@@ -61,6 +61,20 @@ if (isset($success)) {
|
||||
helper('url');
|
||||
?>
|
||||
|
||||
<?php if ($secondaryCurrency['show']): ?>
|
||||
<?php $secondaryCurrencyLabel = $secondaryCurrency['symbol'] ?: $secondaryCurrency['code']; ?>
|
||||
<table align="center" style="font-size: 22px; font-weight: 600; background-color: rgb(221, 221, 221); width: 25%; margin: 0 auto 0.5em; border: dashed 1px;">
|
||||
<tr>
|
||||
<td style="text-align: center; padding-right: 5%;"><?= lang(ucfirst($controller_name) . '.total') ?>:</td>
|
||||
<td style="text-align: center;"><?= to_currency($total) ?></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="text-align: center; padding-right: 5%;"><?= lang(ucfirst($controller_name) . '.total') ?> <?= esc($secondaryCurrencyLabel) ?>:</td>
|
||||
<td style="text-align: center;"><?= $secondaryTotalDisplay ?? to_secondary_currency((float) $total, $secondaryCurrency) ?></td>
|
||||
</tr>
|
||||
</table>
|
||||
<?php endif; ?>
|
||||
|
||||
<div id="register_wrapper">
|
||||
|
||||
<!-- Top register controls -->
|
||||
@@ -90,6 +104,16 @@ helper('url');
|
||||
</li>
|
||||
<?php } ?>
|
||||
|
||||
<?php if (($config['customer_display_enabled'] ?? true) == 1) { ?>
|
||||
<li class="pull-right">
|
||||
<?= anchor(
|
||||
"$controller_name/customerDisplay",
|
||||
'<span class="glyphicon glyphicon-blackboard"> </span>' . lang(ucfirst($controller_name) . '.customer_display'),
|
||||
['class' => 'btn btn-success btn-sm', 'id' => 'show_customer_display', 'title' => lang(ucfirst($controller_name) . '.customer_display'), 'onclick' => 'return openCustomerDisplay(this.href);']
|
||||
) ?>
|
||||
</li>
|
||||
<?php } ?>
|
||||
|
||||
<li class="pull-right">
|
||||
<button class="btn btn-default btn-sm modal-dlg" id="show_suspended_sales_button" data-href="<?= esc("$controller_name/suspended") ?>"
|
||||
title="<?= lang(ucfirst($controller_name) . '.suspended_sales') ?>">
|
||||
@@ -191,7 +215,7 @@ helper('url');
|
||||
if ($items_module_allowed && $change_price) {
|
||||
echo form_input(['name' => 'price', 'class' => 'form-control input-sm', 'value' => to_currency_no_money($item['price']), 'tabindex' => ++$tabindex, 'onClick' => 'this.select();']);
|
||||
} else {
|
||||
echo to_currency($item['price']);
|
||||
echo $secondaryCurrency['show'] ? to_secondary_currency_dual((float) $item['price'], $secondaryCurrency) : to_currency($item['price']);
|
||||
echo form_hidden('price', to_currency_no_money($item['price']));
|
||||
}
|
||||
?>
|
||||
@@ -362,9 +386,6 @@ helper('url');
|
||||
<button class="btn btn-info btn-sm modal-dlg" data-btn-submit="<?= lang('Common.submit') ?>" data-href="<?= "customers/view" ?>" title="<?= lang(ucfirst($controller_name) . ".new_customer") ?>">
|
||||
<span class="glyphicon glyphicon-user"> </span><?= lang(ucfirst($controller_name) . ".new_customer") ?>
|
||||
</button>
|
||||
<button class="btn btn-default btn-sm modal-dlg" id="show_keyboard_help" data-href="<?= esc("$controller_name/salesKeyboardHelp") ?>" title="<?= lang(ucfirst($controller_name) . '.key_title') ?>">
|
||||
<span class="glyphicon glyphicon-share-alt"> </span><?= lang(ucfirst($controller_name) . '.key_help') ?>
|
||||
</button>
|
||||
</div>
|
||||
<?php } ?>
|
||||
<?= form_close() ?>
|
||||
@@ -380,7 +401,7 @@ helper('url');
|
||||
</tr>
|
||||
<?php foreach ($taxes as $tax_group_index => $tax) { ?>
|
||||
<tr>
|
||||
<th style="width: 55%;"><?= (float)$tax['tax_rate'] . '% ' . $tax['tax_group'] ?></th>
|
||||
<th style="width: 55%;"><?= (float)$tax['tax_rate'] . '% ' . esc($tax['tax_group']) ?></th>
|
||||
<th style="width: 45%; text-align: right;"><?= to_currency_tax($tax['sale_tax_amount']) ?></th>
|
||||
</tr>
|
||||
<?php } ?>
|
||||
@@ -388,6 +409,12 @@ helper('url');
|
||||
<th style="width: 55%; font-size: 150%"><?= lang(ucfirst($controller_name) . '.total') ?></th>
|
||||
<th style="width: 45%; font-size: 150%; text-align: right;"><span id="sale_total"><?= to_currency($total) ?></span></th>
|
||||
</tr>
|
||||
<?php if ($secondaryCurrency['show']) { ?>
|
||||
<tr>
|
||||
<th style="width: 55%; font-size: 120%"><?= lang(ucfirst($controller_name) . '.total') ?> <?= esc($secondaryCurrencyLabel) ?></th>
|
||||
<th style="width: 45%; font-size: 120%; text-align: right;"><span id="sale_total_secondary_currency"><?= $secondaryTotalDisplay ?? to_secondary_currency((float) $total, $secondaryCurrency) ?></span></th>
|
||||
</tr>
|
||||
<?php } ?>
|
||||
</table>
|
||||
|
||||
<?php if (count($cart) > 0) { // Only show this part if there are Items already in the register ?>
|
||||
@@ -396,16 +423,21 @@ helper('url');
|
||||
<th style="width: 55%;"><?= lang(ucfirst($controller_name) . '.payments_total') ?></th>
|
||||
<th style="width: 45%; text-align: right;"><?= to_currency($payments_total) ?></th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th style="width: 55%; font-size: 120%"><?= lang(ucfirst($controller_name) . '.amount_due') ?></th>
|
||||
<th style="width: 45%; font-size: 120%; text-align: right;"><span id="sale_amount_due"><?= to_currency($amount_due) ?></span></th>
|
||||
</tr>
|
||||
<?php if ($secondaryCurrency['show']) { ?>
|
||||
<tr>
|
||||
<th style="width: 55%; font-size: 120%"><?= lang(ucfirst($controller_name) . '.amount_due') ?></th>
|
||||
<th style="width: 45%; font-size: 120%; text-align: right;"><span id="sale_amount_due"><?= to_currency($amount_due) ?></span></th>
|
||||
<th style="width: 55%; font-size: 120%"><?= lang(ucfirst($controller_name) . '.amount_due') ?> <?= esc($secondaryCurrencyLabel) ?></th>
|
||||
<th style="width: 45%; font-size: 120%; text-align: right;"><span id="sale_amount_due_secondary_currency"><?= $secondaryAmountDueDisplay ?? to_secondary_currency((float) $amount_due, $secondaryCurrency) ?></span></th>
|
||||
</tr>
|
||||
</table>
|
||||
<?php } ?>
|
||||
</table>
|
||||
|
||||
<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>
|
||||
@@ -582,8 +614,76 @@ helper('url');
|
||||
cancel: keyboardShortcuts?.cancel?.code ?? null
|
||||
};
|
||||
|
||||
window.customerDisplayWindow = window.customerDisplayWindow || null;
|
||||
window.customerDisplayDisplayId = window.customerDisplayDisplayId || sessionStorage.getItem('customerDisplayId') || localStorage.getItem('customerDisplayId') || '';
|
||||
|
||||
window.customerDisplayStorageSuffix = function() {
|
||||
return window.customerDisplayDisplayId ? '_' + window.customerDisplayDisplayId : '';
|
||||
};
|
||||
|
||||
window.customerDisplayStorageKeys = function() {
|
||||
const suffix = window.customerDisplayStorageSuffix();
|
||||
|
||||
return {
|
||||
open: 'customerDisplayOpen' + suffix,
|
||||
dirtyAt: 'customerDisplayDirtyAt' + suffix
|
||||
};
|
||||
};
|
||||
|
||||
window.openCustomerDisplay = function(url) {
|
||||
if (window.customerDisplayDisplayId === '') {
|
||||
window.customerDisplayDisplayId = String(Date.now()) + Math.random().toString(36).slice(2);
|
||||
}
|
||||
|
||||
const keys = window.customerDisplayStorageKeys();
|
||||
const displayUrl = new URL(url, window.location.href);
|
||||
displayUrl.searchParams.set('displayId', window.customerDisplayDisplayId);
|
||||
|
||||
sessionStorage.setItem('customerDisplayId', window.customerDisplayDisplayId);
|
||||
localStorage.setItem('customerDisplayId', window.customerDisplayDisplayId);
|
||||
localStorage.setItem(keys.open, '1');
|
||||
localStorage.setItem(keys.dirtyAt, String(Date.now()));
|
||||
window.customerDisplayWindow = window.open(displayUrl.toString(), 'customer_display_' + window.customerDisplayDisplayId, 'width=1280,height=720,resizable=yes,scrollbars=yes');
|
||||
if (window.customerDisplayWindow && !window.customerDisplayWindow.closed) {
|
||||
window.customerDisplayWindow.focus();
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
window.refreshCustomerDisplay = function() {
|
||||
const keys = window.customerDisplayStorageKeys();
|
||||
|
||||
if (localStorage.getItem(keys.open) !== '1') {
|
||||
return;
|
||||
}
|
||||
|
||||
localStorage.setItem(keys.dirtyAt, String(Date.now()));
|
||||
if (window.customerDisplayWindow && !window.customerDisplayWindow.closed) {
|
||||
window.customerDisplayWindow.location.reload();
|
||||
window.customerDisplayWindow.focus();
|
||||
}
|
||||
};
|
||||
|
||||
window.notifyCustomerDisplay = function() {
|
||||
window.refreshCustomerDisplay();
|
||||
};
|
||||
|
||||
const secondaryAmounts = <?= json_encode([
|
||||
'total' => $secondaryTotalDisplay ?? null,
|
||||
'amountDue' => $secondaryAmountDueDisplay ?? null,
|
||||
'cashAmountDue' => $secondaryCashAmountDueDisplay ?? null,
|
||||
'nonCashTotal' => $secondaryNonCashTotalDisplay ?? null,
|
||||
'nonCashAmountDue' => $secondaryNonCashAmountDueDisplay ?? null
|
||||
], JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP) ?>;
|
||||
|
||||
$(document).ready(function() {
|
||||
setTimeout(function() {
|
||||
window.notifyCustomerDisplay();
|
||||
}, 300);
|
||||
|
||||
const redirect = function() {
|
||||
window.notifyCustomerDisplay();
|
||||
window.location.href = "<?= site_url('sales'); ?>";
|
||||
};
|
||||
|
||||
@@ -611,7 +711,10 @@ helper('url');
|
||||
'item_id': item_id,
|
||||
'item_number': item_number,
|
||||
},
|
||||
dataType: 'json'
|
||||
dataType: 'json',
|
||||
success: function() {
|
||||
window.notifyCustomerDisplay();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -625,7 +728,10 @@ helper('url');
|
||||
'item_id': item_id,
|
||||
'item_name': item_name,
|
||||
},
|
||||
dataType: 'json'
|
||||
dataType: 'json',
|
||||
success: function() {
|
||||
window.notifyCustomerDisplay();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -639,7 +745,10 @@ helper('url');
|
||||
'item_id': item_id,
|
||||
'item_description': item_description,
|
||||
},
|
||||
dataType: 'json'
|
||||
dataType: 'json',
|
||||
success: function() {
|
||||
window.notifyCustomerDisplay();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -688,6 +797,7 @@ helper('url');
|
||||
delay: 10,
|
||||
select: function(a, ui) {
|
||||
$(this).val(ui.item.value);
|
||||
window.notifyCustomerDisplay();
|
||||
$('#select_customer_form').submit();
|
||||
return false;
|
||||
}
|
||||
@@ -706,6 +816,7 @@ helper('url');
|
||||
delay: 10,
|
||||
select: function(a, ui) {
|
||||
$(this).val(ui.item.value);
|
||||
window.notifyCustomerDisplay();
|
||||
$('#add_payment_form').submit();
|
||||
return false;
|
||||
}
|
||||
@@ -745,28 +856,33 @@ helper('url');
|
||||
});
|
||||
|
||||
$('#finish_sale_button').click(function() {
|
||||
window.notifyCustomerDisplay();
|
||||
$('#buttons_form').attr('action', "<?= "$controller_name/complete" ?>");
|
||||
$('#buttons_form').submit();
|
||||
});
|
||||
|
||||
$('#finish_invoice_quote_button').click(function() {
|
||||
window.notifyCustomerDisplay();
|
||||
$('#buttons_form').attr('action', "<?= "$controller_name/complete" ?>");
|
||||
$('#buttons_form').submit();
|
||||
});
|
||||
|
||||
$('#suspend_sale_button').click(function() {
|
||||
window.notifyCustomerDisplay();
|
||||
$('#buttons_form').attr('action', "<?= site_url("$controller_name/suspend") ?>");
|
||||
$('#buttons_form').submit();
|
||||
});
|
||||
|
||||
$('#cancel_sale_button').click(function() {
|
||||
if (confirm("<?= lang(ucfirst($controller_name) . '.confirm_cancel_sale') ?>")) {
|
||||
window.notifyCustomerDisplay();
|
||||
$('#buttons_form').attr('action', "<?= site_url("$controller_name/cancel") ?>");
|
||||
$('#buttons_form').submit();
|
||||
}
|
||||
});
|
||||
|
||||
$('#add_payment_button').click(function() {
|
||||
window.notifyCustomerDisplay();
|
||||
$('#add_payment_form').find('input[name="complete_after_payment"]').val('0');
|
||||
$('#add_payment_form').submit();
|
||||
});
|
||||
@@ -803,11 +919,13 @@ helper('url');
|
||||
if (response.success) {
|
||||
if (resource.match(/customers$/)) {
|
||||
$('#customer').val(response.id);
|
||||
window.notifyCustomerDisplay();
|
||||
$('#select_customer_form').submit();
|
||||
} else {
|
||||
var $stock_location = $("select[name='stock_location']").val();
|
||||
$('#item_location').val($stock_location);
|
||||
$('#item').val(response.id);
|
||||
window.notifyCustomerDisplay();
|
||||
if (stay_open) {
|
||||
$('#add_item_form').ajaxSubmit();
|
||||
} else {
|
||||
@@ -830,10 +948,17 @@ helper('url');
|
||||
|
||||
function check_payment_type() {
|
||||
var cash_mode = <?= json_encode($cash_mode) ?>;
|
||||
const updateSecondaryRows = function(totalDisplay, amountDueDisplay) {
|
||||
if (totalDisplay !== null && amountDueDisplay !== null) {
|
||||
$("#sale_total_secondary_currency").html(totalDisplay);
|
||||
$("#sale_amount_due_secondary_currency").html(amountDueDisplay);
|
||||
}
|
||||
};
|
||||
|
||||
if ($("#payment_types").val() == "<?= lang(ucfirst($controller_name) . '.giftcard') ?>") {
|
||||
$("#sale_total").html("<?= to_currency($total) ?>");
|
||||
$("#sale_amount_due").html("<?= to_currency($amount_due) ?>");
|
||||
updateSecondaryRows(secondaryAmounts.total, secondaryAmounts.amountDue);
|
||||
$("#amount_tendered_label").html("<?= lang(ucfirst($controller_name) . '.giftcard_number') ?>");
|
||||
$("#amount_tendered:enabled").val('').focus();
|
||||
$(".giftcard-input").attr('disabled', false);
|
||||
@@ -842,6 +967,7 @@ helper('url');
|
||||
} else if (($("#payment_types").val() == "<?= lang(ucfirst($controller_name) . '.cash') ?>" && cash_mode == '1')) {
|
||||
$("#sale_total").html("<?= to_currency($non_cash_total) ?>");
|
||||
$("#sale_amount_due").html("<?= to_currency($cash_amount_due) ?>");
|
||||
updateSecondaryRows(secondaryAmounts.nonCashTotal, secondaryAmounts.cashAmountDue);
|
||||
$("#amount_tendered_label").html("<?= lang(ucfirst($controller_name) . '.amount_tendered') ?>");
|
||||
$("#amount_tendered:enabled").val("<?= to_currency_no_money($cash_amount_due) ?>");
|
||||
$(".giftcard-input").attr('disabled', true);
|
||||
@@ -849,6 +975,7 @@ helper('url');
|
||||
} else {
|
||||
$("#sale_total").html("<?= to_currency($non_cash_total) ?>");
|
||||
$("#sale_amount_due").html("<?= to_currency($amount_due) ?>");
|
||||
updateSecondaryRows(secondaryAmounts.nonCashTotal, secondaryAmounts.nonCashAmountDue);
|
||||
$("#amount_tendered_label").html("<?= lang(ucfirst($controller_name) . '.amount_tendered') ?>");
|
||||
$("#amount_tendered:enabled").val("<?= to_currency_no_money($amount_due) ?>");
|
||||
$(".giftcard-input").attr('disabled', true);
|
||||
@@ -861,6 +988,7 @@ helper('url');
|
||||
if ($(event.target).closest('.modal').length || $('.modal.in').length) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.altKey) {
|
||||
switch (event.keyCode) {
|
||||
case shortcutCodes.items:
|
||||
@@ -909,3 +1037,6 @@ helper('url');
|
||||
</script>
|
||||
|
||||
<?= view('partial/footer') ?>
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user