barcode_lib = new Barcode_lib(); $this->sale_lib = new Sale_lib(); $this->receiving_lib = new receiving_lib(); $this->tax_lib = new Tax_lib(); $this->appconfig = model(Appconfig::class); $this->attribute = model(Attribute::class); $this->customer_rewards = model(Customer_rewards::class); $this->dinner_table = model(Dinner_table::class); $this->module = model(Module::class); $this->stock_location = model(Stock_location::class); $this->tax = model(Tax::class); $this->config = config(OSPOS::class)->settings; $this->db = Database::connect(); helper('security'); if (check_encryption()) { $this->encrypter = Services::encrypter(); } else { log_message('alert', 'Error preparing encryption key'); } } /** * This function loads all the licenses starting with the first one being OSPOS one */ private function _licenses(): array // TODO: remove hungarian notation. Super long function. Perhaps we need to refactor out functions? { $i = 0; $composer = false; $npmProd = false; $npmDev = false; $license = []; $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); } else { $license[$i]['text'] = 'LICENSE file must be in OSPOS license directory. You are not allowed to use OSPOS application until the distribution copy of LICENSE file is present.'; } $dir = new DirectoryIterator('license'); // Read all the files in the dir license foreach ($dir as $fileinfo) { // TODO: $fileinfo doesn't match our variable naming convention // License files must be in couples: .version (name & version) & .license (license text) if ($fileinfo->isFile()) { if ($fileinfo->getExtension() == 'version') { ++$i; $basename = 'license/' . $fileinfo->getBasename('.version'); $license[$i]['title'] = file_get_contents($basename . '.version', false, null, 0, 100); $license_text_file = $basename . '.license'; if (file_exists($license_text_file)) { $license[$i]['text'] = file_get_contents($license_text_file, false, null, 0, 2000); } else { $license[$i]['text'] = $license_text_file . ' file is missing'; } } elseif ($fileinfo->getBasename() == 'composer.LICENSES') { // Set a flag to indicate that the composer.LICENSES file is available and needs to be attached at the end $composer = true; } elseif ($fileinfo->getBasename() == 'npm-prod.LICENSES') { // Set a flag to indicate that the npm-prod.LICENSES file is available and needs to be attached at the end $npmProd = true; } elseif ($fileinfo->getBasename() == 'npm-dev.LICENSES') { // Set a flag to indicate that the npm-dev.LICENSES file is available and needs to be attached at the end $npmDev = true; } } } // Attach the licenses from the LICENSES file generated by Composer if ($composer) { ++$i; $license[$i]['title'] = 'Composer Libraries'; $license[$i]['text'] = ''; $file = file_get_contents('license/composer.LICENSES'); $array = json_decode($file, true); if (isset($array['dependencies'])) { foreach ($array['dependencies'] as $dependency => $details) { $license[$i]['text'] .= "library: $dependency\n"; foreach ($details as $key => $value) { if (is_array($value)) { $license[$i]['text'] .= "$key: " . implode(' ', $value) . "\n"; } else { $license[$i]['text'] .= "$key: $value\n"; } } $license[$i]['text'] .= "\n"; } $license[$i]['text'] = rtrim($license[$i]['text'], "\n"); } } // Attach the licenses from the LICENSES file generated by license-report if ($npmProd) { ++$i; $license[$i]['title'] = 'NPM Production Libraries'; $license[$i]['text'] = ''; $file = file_get_contents('license/npm-prod.LICENSES'); $array = json_decode($file, true); foreach ($array as $dependency) { $license[$i]['text'] .= "library: {$dependency['name']}\n"; $license[$i]['text'] .= "authors: {$dependency['author']}\n"; $license[$i]['text'] .= "website: {$dependency['homepage']}\n"; $license[$i]['text'] .= "version: {$dependency['installedVersion']}\n"; $license[$i]['text'] .= "license: {$dependency['licenseType']}\n"; $license[$i]['text'] .= "\n"; } $license[$i]['text'] = rtrim($license[$i]['text'], "\n"); } if ($npmDev) { ++$i; $license[$i]['title'] = 'NPM Development Libraries'; $license[$i]['text'] = ''; $file = file_get_contents('license/npm-dev.LICENSES'); $array = json_decode($file, true); foreach ($array as $dependency) { $license[$i]['text'] .= "library: {$dependency['name']}\n"; $license[$i]['text'] .= "authors: {$dependency['author']}\n"; $license[$i]['text'] .= "website: {$dependency['homepage']}\n"; $license[$i]['text'] .= "version: {$dependency['installedVersion']}\n"; $license[$i]['text'] .= "license: {$dependency['licenseType']}\n"; $license[$i]['text'] .= "\n"; } $license[$i]['text'] = rtrim($license[$i]['text'], "\n"); } return $license; } /** * This function loads all the available themes in the dist/bootswatch directory * @return array */ private function _themes(): array // TODO: Hungarian notation { $themes = []; // Read all themes in the dist folder $dir = new DirectoryIterator('resources/bootswatch'); foreach ($dir as $dirinfo) { // TODO: $dirinfo doesn't follow naming convention if ($dirinfo->isDir() && !$dirinfo->isDot() && $dirinfo->getFileName() != 'fonts') { $file = $dirinfo->getFileName(); $themes[$file] = ucfirst($file); } } asort($themes); return $themes; } /** */ public function getIndex(): void { $data['stock_locations'] = $this->stock_location->get_all()->getResultArray(); $data['dinner_tables'] = $this->dinner_table->get_all()->getResultArray(); $data['customer_rewards'] = $this->customer_rewards->get_all()->getResultArray(); $data['support_barcode'] = $this->barcode_lib->get_list_barcodes(); $data['barcode_fonts'] = $this->barcode_lib->listfonts('fonts'); $data['logo_exists'] = $this->config['company_logo'] != ''; $data['line_sequence_options'] = $this->sale_lib->get_line_sequence_options(); $data['register_mode_options'] = $this->sale_lib->get_register_mode_options(); $data['invoice_type_options'] = $this->sale_lib->get_invoice_type_options(); $data['rounding_options'] = rounding_mode::get_rounding_options(); $data['tax_code_options'] = $this->tax_lib->get_tax_code_options(); $data['tax_category_options'] = $this->tax_lib->get_tax_category_options(); $data['tax_jurisdiction_options'] = $this->tax_lib->get_tax_jurisdiction_options(); $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()); // Load all the license statements, they are already XSS cleaned in the private function $data['licenses'] = $this->_licenses(); // Load all the themes, already XSS cleaned in the private function $data['themes'] = $this->_themes(); // General related fields $image_allowed_types = ['jpg', 'jpeg', 'gif', 'svg', 'webp', 'bmp', 'png', 'tif', 'tiff']; $data['image_allowed_types'] = array_combine($image_allowed_types, $image_allowed_types); $data['selected_image_allowed_types'] = explode(',', $this->config['image_allowed_types']); // Integrations Related fields $data['mailchimp'] = []; if (check_encryption()) { // TODO: Hungarian notation if (!isset($this->encrypter)) { helper('security'); $this->encrypter = Services::encrypter(); } $data['mailchimp']['api_key'] = (isset($this->config['mailchimp_api_key']) && !empty($this->config['mailchimp_api_key'])) ? $this->encrypter->decrypt($this->config['mailchimp_api_key']) : ''; $data['mailchimp']['list_id'] = (isset($this->config['mailchimp_list_id']) && !empty($this->config['mailchimp_list_id'])) ? $this->encrypter->decrypt($this->config['mailchimp_list_id']) : ''; // Remove any backup of .env created by check_encryption() remove_backup(); } else { $data['mailchimp']['api_key'] = ''; $data['mailchimp']['list_id'] = ''; } $data['mailchimp']['lists'] = $this->_mailchimp(); echo view('configs/manage', $data); } /** * Saves company information. Used in app/Views/configs/info_config.php * * @throws ReflectionException * @return void * @noinspection PhpUnused */ public function postSaveInfo(): void { $upload_data = $this->upload_logo(); $upload_success = empty($upload_data['error']); $batch_save_data = [ 'company' => $this->request->getPost('company'), 'address' => $this->request->getPost('address'), 'phone' => $this->request->getPost('phone'), 'email' => strtolower($this->request->getPost('email', FILTER_SANITIZE_EMAIL)), 'fax' => $this->request->getPost('fax'), 'website' => $this->request->getPost('website', FILTER_SANITIZE_URL), 'return_policy' => $this->request->getPost('return_policy') ]; if (!empty($upload_data['orig_name']) && $upload_data['raw_name']) { $batch_save_data['company_logo'] = $upload_data['raw_name'] . '.' . $upload_data['file_ext']; } $result = $this->appconfig->batch_save($batch_save_data); $success = $upload_success && $result; $message = lang('Config.saved_' . ($success ? '' : 'un') . 'successfully'); $message = $upload_success ? $message : strip_tags($upload_data['error']); echo json_encode(['success' => $success, 'message' => $message]); } /** * @return array */ private function upload_logo(): array { $file = $this->request->getFile('company_logo'); if (!$file) { return []; } helper(['form']); $validation_rule = [ 'company_logo' => [ 'label' => 'Company logo', 'rules' => [ 'uploaded[company_logo]', 'is_image[company_logo]', 'max_size[company_logo,1024]', 'mime_in[company_logo,image/png,image/jpg,image/jpeg,image/gif]', 'ext_in[company_logo,png,jpg,gif]', 'max_dims[company_logo,800,680]', ] ] ]; if (!$this->validate($validation_rule)) { return (['error' => $this->validator->getError('company_logo')]); } $filename = $file->getClientName(); $info = pathinfo($filename); $file_info = [ 'orig_name' => $filename, 'raw_name' => $info['filename'], 'file_ext' => $file->guessExtension() ]; $file->move(FCPATH . 'uploads/', $file_info['raw_name'] . '.' . $file_info['file_ext'], true); return ($file_info); } /** * Saves general configuration. Used in app/Views/configs/general_config.php * * @throws ReflectionException * @noinspection PhpUnused */ public function postSaveGeneral(): void { $batch_save_data = [ 'theme' => $this->request->getPost('theme'), 'login_form' => $this->request->getPost('login_form'), 'default_sales_discount_type' => $this->request->getPost('default_sales_discount_type') != null, 'default_sales_discount' => parse_decimals($this->request->getPost('default_sales_discount')), 'default_receivings_discount_type' => $this->request->getPost('default_receivings_discount_type') != null, 'default_receivings_discount' => parse_decimals($this->request->getPost('default_receivings_discount')), 'enforce_privacy' => $this->request->getPost('enforce_privacy') != null, 'receiving_calculate_average_price' => $this->request->getPost('receiving_calculate_average_price') != null, 'lines_per_page' => $this->request->getPost('lines_per_page', FILTER_SANITIZE_NUMBER_INT), 'notify_horizontal_position' => $this->request->getPost('notify_horizontal_position'), 'notify_vertical_position' => $this->request->getPost('notify_vertical_position'), 'image_max_width' => $this->request->getPost('image_max_width', FILTER_SANITIZE_NUMBER_INT), 'image_max_height' => $this->request->getPost('image_max_height', FILTER_SANITIZE_NUMBER_INT), 'image_max_size' => $this->request->getPost('image_max_size', FILTER_SANITIZE_NUMBER_INT), 'image_allowed_types' => implode(',', $this->request->getPost('image_allowed_types')), 'gcaptcha_enable' => $this->request->getPost('gcaptcha_enable') != null, 'gcaptcha_secret_key' => $this->request->getPost('gcaptcha_secret_key'), 'gcaptcha_site_key' => $this->request->getPost('gcaptcha_site_key'), 'suggestions_first_column' => $this->request->getPost('suggestions_first_column'), 'suggestions_second_column' => $this->request->getPost('suggestions_second_column'), 'suggestions_third_column' => $this->request->getPost('suggestions_third_column'), 'giftcard_number' => $this->request->getPost('giftcard_number'), 'derive_sale_quantity' => $this->request->getPost('derive_sale_quantity') != 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 ]; $this->module->set_show_office_group($this->request->getPost('show_office_group') != null); if ($batch_save_data['category_dropdown'] == 1) { $definition_data['definition_name'] = 'ospos_category'; $definition_data['definition_flags'] = 0; $definition_data['definition_type'] = 'DROPDOWN'; $definition_data['definition_id'] = CATEGORY_DEFINITION_ID; $definition_data['deleted'] = 0; $this->attribute->save_definition($definition_data, CATEGORY_DEFINITION_ID); } elseif ($batch_save_data['category_dropdown'] == NO_DEFINITION_ID) { $this->attribute->deleteDefinition(CATEGORY_DEFINITION_ID); } $success = $this->appconfig->batch_save($batch_save_data); echo json_encode(['success' => $success, 'message' => lang('Config.saved_' . ($success ? '' : 'un') . 'successfully')]); } /** * Checks a number against the currently selected locale. Used in app/Views/configs/locale_config.php * * @return void * @noinspection PhpUnused */ public function postCheckNumberLocale(): void { $number_locale = $this->request->getPost('number_locale'); $save_number_locale = $this->request->getPost('save_number_locale'); $fmt = new NumberFormatter($number_locale, NumberFormatter::CURRENCY); if ($number_locale != $save_number_locale) { $currency_symbol = $fmt->getSymbol(NumberFormatter::CURRENCY_SYMBOL); $currency_code = $fmt->getTextAttribute(NumberFormatter::CURRENCY_CODE); $save_number_locale = $number_locale; } else { $currency_symbol = empty($this->request->getPost('currency_symbol')) ? $fmt->getSymbol(NumberFormatter::CURRENCY_SYMBOL) : $this->request->getPost('currency_symbol'); $currency_code = empty($this->request->getPost('currency_code')) ? $fmt->getTextAttribute(NumberFormatter::CURRENCY_CODE) : $this->request->getPost('currency_code'); } if ($this->request->getPost('thousands_separator') == 'false') { $fmt->setTextAttribute(NumberFormatter::GROUPING_SEPARATOR_SYMBOL, ''); } $fmt->setSymbol(NumberFormatter::CURRENCY_SYMBOL, $currency_symbol); $number_local_example = $fmt->format(1234567890.12300); echo json_encode([ '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, ]); } /** * Saves locale configuration. Used in app/Views/configs/locale_config.php * * @throws ReflectionException * @return void * @noinspection PhpUnused */ public function postSaveLocale(): void { $exploded = explode(":", $this->request->getPost('language')); $batch_save_data = [ 'currency_symbol' => $this->request->getPost('currency_symbol'), 'currency_code' => $this->request->getPost('currency_code'), 'language_code' => $exploded[0], 'language' => $exploded[1], 'timezone' => $this->request->getPost('timezone'), 'dateformat' => $this->request->getPost('dateformat'), 'timeformat' => $this->request->getPost('timeformat'), 'thousands_separator' => $this->request->getPost('thousands_separator') != null, 'number_locale' => $this->request->getPost('number_locale'), 'currency_decimals' => $this->request->getPost('currency_decimals', FILTER_SANITIZE_NUMBER_INT), 'tax_decimals' => $this->request->getPost('tax_decimals', FILTER_SANITIZE_NUMBER_INT), 'quantity_decimals' => $this->request->getPost('quantity_decimals', FILTER_SANITIZE_NUMBER_INT), 'country_codes' => htmlspecialchars($this->request->getPost('country_codes')), 'payment_options_order' => $this->request->getPost('payment_options_order'), 'date_or_time_format' => $this->request->getPost('date_or_time_format') != null, 'cash_decimals' => $this->request->getPost('cash_decimals', FILTER_SANITIZE_NUMBER_INT), 'cash_rounding_code' => $this->request->getPost('cash_rounding_code'), 'financial_year' => $this->request->getPost('financial_year', FILTER_SANITIZE_NUMBER_INT) ]; $success = $this->appconfig->batch_save($batch_save_data); echo json_encode(['success' => $success, 'message' => lang('Config.saved_' . ($success ? '' : 'un') . 'successfully')]); } /** * Saves email configuration. Used in app/Views/configs/email_config.php * * @throws ReflectionException * @return void * @noinspection PhpUnused */ public function postSaveEmail(): void { $password = ''; if (check_encryption() && !empty($this->request->getPost('smtp_pass'))) { $password = $this->encrypter->encrypt($this->request->getPost('smtp_pass')); } $batch_save_data = [ 'protocol' => $this->request->getPost('protocol'), 'mailpath' => $this->request->getPost('mailpath'), 'smtp_host' => $this->request->getPost('smtp_host'), 'smtp_user' => $this->request->getPost('smtp_user'), 'smtp_pass' => $password, 'smtp_port' => $this->request->getPost('smtp_port', FILTER_SANITIZE_NUMBER_INT), 'smtp_timeout' => $this->request->getPost('smtp_timeout', FILTER_SANITIZE_NUMBER_INT), 'smtp_crypto' => $this->request->getPost('smtp_crypto') ]; $success = $this->appconfig->batch_save($batch_save_data); echo json_encode(['success' => $success, 'message' => lang('Config.saved_' . ($success ? '' : 'un') . 'successfully')]); } /** * Saves SMS message configuration. Used in app/Views/configs/message_config.php. * * @throws ReflectionException * @return void * @noinspection PhpUnused */ public function postSaveMessage(): void { $password = ''; if (check_encryption() && !empty($this->request->getPost('msg_pwd'))) { $password = $this->encrypter->encrypt($this->request->getPost('msg_pwd')); } $batch_save_data = [ 'msg_msg' => $this->request->getPost('msg_msg'), 'msg_uid' => $this->request->getPost('msg_uid'), 'msg_pwd' => $password, 'msg_src' => $this->request->getPost('msg_src') ]; $success = $this->appconfig->batch_save($batch_save_data); echo json_encode(['success' => $success, 'message' => lang('Config.saved_' . ($success ? '' : 'un') . 'successfully')]); } /** * This function fetches all the available lists from Mailchimp for the given API key */ private function _mailchimp(string $api_key = ''): array // TODO: Hungarian notation { $mailchimp_lib = new Mailchimp_lib(['api_key' => $api_key]); $result = []; $lists = $mailchimp_lib->getLists(); if ($lists !== false) { if (is_array($lists) && !empty($lists['lists']) && is_array($lists['lists'])) { foreach ($lists['lists'] as $list) { $result[$list['id']] = $list['name'] . ' [' . $list['stats']['member_count'] . ']'; } } } return $result; } /** * Gets Mailchimp lists when a valid API key is inserted. Used in app/Views/configs/integrations_config.php * * @return void * @noinspection PhpUnused */ public function postCheckMailchimpApiKey(): void { $lists = $this->_mailchimp($this->request->getPost('mailchimp_api_key')); $success = count($lists) > 0; echo json_encode([ 'success' => $success, 'message' => lang('Config.mailchimp_key_' . ($success ? '' : 'un') . 'successfully'), 'mailchimp_lists' => $lists ]); } /** * Saves Mailchimp configuration. Used in app/Views/configs/integrations_config.php * * @throws ReflectionException * @return void * @noinspection PhpUnused */ public function postSaveMailchimp(): void { $api_key = ''; $list_id = ''; if (check_encryption()) { $api_key_unencrypted = $this->request->getPost('mailchimp_api_key'); if (!empty($api_key_unencrypted)) { $api_key = $this->encrypter->encrypt($api_key_unencrypted); } $list_id_unencrypted = $this->request->getPost('mailchimp_list_id'); if (!empty($list_id_unencrypted)) { $list_id = $this->encrypter->encrypt($list_id_unencrypted); } } $batch_save_data = ['mailchimp_api_key' => $api_key, 'mailchimp_list_id' => $list_id]; $success = $this->appconfig->batch_save($batch_save_data); echo json_encode(['success' => $success, 'message' => lang('Config.saved_' . ($success ? '' : 'un') . 'successfully')]); } /** * Gets all stock locations. Used in app/Views/configs/stock_config.php * * @return void * @noinspection PhpUnused */ public function getStockLocations(): void { $stock_locations = $this->stock_location->get_all()->getResultArray(); echo view('partial/stock_locations', ['stock_locations' => $stock_locations]); } /** * @return void */ public function getDinnerTables(): void { $dinner_tables = $this->dinner_table->get_all()->getResultArray(); echo view('partial/dinner_tables', ['dinner_tables' => $dinner_tables]); } /** * Gets all tax categories. * * @return void */ public function ajax_tax_categories(): void // TODO: Is this function called anywhere in the code? { $tax_categories = $this->tax->get_all_tax_categories()->getResultArray(); echo view('partial/tax_categories', ['tax_categories' => $tax_categories]); } /** * Gets all customer rewards. Used in app/Views/configs/reward_config.php * * @return void * @noinspection PhpUnused */ public function getCustomerRewards(): void { $customer_rewards = $this->customer_rewards->get_all()->getResultArray(); echo view('partial/customer_rewards', ['customer_rewards' => $customer_rewards]); } /** * @return void */ private function _clear_session_state(): void // TODO: Hungarian notation { $this->sale_lib->clear_sale_location(); $this->sale_lib->clear_table(); $this->sale_lib->clear_all(); $this->receiving_lib = new Receiving_lib(); $this->receiving_lib->clear_stock_source(); $this->receiving_lib->clear_stock_destination(); $this->receiving_lib->clear_all(); } /** * Saves stock locations. Used in app/Views/configs/stock_config.php * * @return void * @noinspection PhpUnused */ public function postSaveLocations(): void { $this->db->transStart(); $not_to_delete = []; foreach ($this->request->getPost() as $key => $value) { if (str_contains($key, 'stock_location')) { // Save or update foreach ($value as $location_id => $location_name) { $location_data = ['location_name' => $location_name]; if ($this->stock_location->save_value($location_data, $location_id)) { $location_id = $this->stock_location->get_location_id($location_name); $not_to_delete[] = $location_id; $this->_clear_session_state(); } } } } // All locations not available in post will be deleted now $deleted_locations = $this->stock_location->get_all()->getResultArray(); foreach ($deleted_locations as $location => $location_data) { if (!in_array($location_data['location_id'], $not_to_delete)) { $this->stock_location->delete($location_data['location_id']); } } $this->db->transComplete(); $success = $this->db->transStatus(); echo json_encode(['success' => $success, 'message' => lang('Config.saved_' . ($success ? '' : 'un') . 'successfully')]); } /** * Saves all dinner tables. Used in app/Views/configs/table_config.php * * @throws ReflectionException * @return void * @noinspection PhpUnused */ public function postSaveTables(): void { $this->db->transStart(); $dinner_table_enable = $this->request->getPost('dinner_table_enable') != null; $this->appconfig->save(['dinner_table_enable' => $dinner_table_enable]); if ($dinner_table_enable) { $not_to_delete = []; foreach ($this->request->getPost() as $key => $value) { // TODO: Not sure if this is the best way to filter the array if (strstr($key, 'dinner_table') && $key != 'dinner_table_enable') { $dinner_table_id = preg_replace("/.*?_(\d+)$/", "$1", $key); $not_to_delete[] = $dinner_table_id; // Save or update $table_data = ['name' => $value]; if ($this->dinner_table->save_value($table_data, $dinner_table_id)) { $this->_clear_session_state(); // TODO: Remove hungarian notation. } } } // All tables not available in post will be deleted now $deleted_tables = $this->dinner_table->get_all()->getResultArray(); foreach ($deleted_tables as $dinner_tables => $table) { if (!in_array($table['dinner_table_id'], $not_to_delete)) { $this->dinner_table->delete($table['dinner_table_id']); } } } $this->db->transComplete(); $success = $this->db->transStatus(); echo json_encode(['success' => $success, 'message' => lang('Config.saved_' . ($success ? '' : 'un') . 'successfully')]); } /** * Saves tax configuration. Used in app/Views/configs/tax_config.php * * @throws ReflectionException * @return void * @noinspection PhpUnused */ public function postSaveTax(): void { $default_tax_1_rate = $this->request->getPost('default_tax_1_rate'); $default_tax_2_rate = $this->request->getPost('default_tax_2_rate'); $batch_save_data = [ 'default_tax_1_rate' => parse_tax(filter_var($default_tax_1_rate, FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION)), 'default_tax_1_name' => $this->request->getPost('default_tax_1_name'), 'default_tax_2_rate' => parse_tax(filter_var($default_tax_2_rate, FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION)), 'default_tax_2_name' => $this->request->getPost('default_tax_2_name'), 'tax_included' => $this->request->getPost('tax_included') != null, 'use_destination_based_tax' => $this->request->getPost('use_destination_based_tax') != null, 'default_tax_code' => $this->request->getPost('default_tax_code'), 'default_tax_category' => $this->request->getPost('default_tax_category'), 'default_tax_jurisdiction' => $this->request->getPost('default_tax_jurisdiction'), 'tax_id' => $this->request->getPost('tax_id', FILTER_SANITIZE_NUMBER_INT) ]; $success = $this->appconfig->batch_save($batch_save_data); $message = lang('Config.saved_' . ($success ? '' : 'un') . 'successfully'); echo json_encode(['success' => $success, 'message' => $message]); } /** * Saves customer rewards configuration. Used in app/Views/configs/reward_config.php * * @throws ReflectionException * @return void * @noinspection PhpUnused */ public function postSaveRewards(): void { $this->db->transStart(); $customer_reward_enable = $this->request->getPost('customer_reward_enable') != null; $this->appconfig->save(['customer_reward_enable' => $customer_reward_enable]); if ($customer_reward_enable) { $not_to_delete = []; $array_save = []; foreach ($this->request->getPost() as $key => $value) { if (strstr($key, 'customer_reward') && $key != 'customer_reward_enable') { $customer_reward_id = preg_replace("/.*?_(\d+)$/", "$1", $key); $not_to_delete[] = $customer_reward_id; $array_save[$customer_reward_id]['package_name'] = $value; } elseif (str_contains($key, 'reward_points')) { $customer_reward_id = preg_replace("/.*?_(\d+)$/", "$1", $key); $array_save[$customer_reward_id]['points_percent'] = $value; } } if (!empty($array_save)) { foreach ($array_save as $key => $value) { // Save or update $package_data = ['package_name' => $value['package_name'], 'points_percent' => $value['points_percent']]; $this->customer_rewards->save_value($package_data, $key); // TODO: reflection exception } } // All packages not available in post will be deleted now $deleted_packages = $this->customer_rewards->get_all()->getResultArray(); foreach ($deleted_packages as $customer_rewards => $reward_category) { if (!in_array($reward_category['package_id'], $not_to_delete)) { $this->customer_rewards->delete($reward_category['package_id']); } } } $this->db->transComplete(); $success = $this->db->transStatus(); echo json_encode(['success' => $success, 'message' => lang('Config.saved_' . ($success ? '' : 'un') . 'successfully')]); } /** * Saves barcode configuration. Used in app/Views/configs/barcode_config.php * * @throws ReflectionException * @return void * @noinspection PhpUnused */ public function postSaveBarcode(): void { $batch_save_data = [ 'barcode_type' => $this->request->getPost('barcode_type'), 'barcode_width' => $this->request->getPost('barcode_width', FILTER_SANITIZE_NUMBER_INT), 'barcode_height' => $this->request->getPost('barcode_height', FILTER_SANITIZE_NUMBER_INT), 'barcode_font' => $this->request->getPost('barcode_font'), 'barcode_font_size' => $this->request->getPost('barcode_font_size', FILTER_SANITIZE_NUMBER_INT), 'barcode_first_row' => $this->request->getPost('barcode_first_row'), 'barcode_second_row' => $this->request->getPost('barcode_second_row'), 'barcode_third_row' => $this->request->getPost('barcode_third_row'), 'barcode_num_in_row' => $this->request->getPost('barcode_num_in_row', FILTER_SANITIZE_NUMBER_INT), 'barcode_page_width' => $this->request->getPost('barcode_page_width', FILTER_SANITIZE_NUMBER_INT), 'barcode_page_cellspacing' => $this->request->getPost('barcode_page_cellspacing', FILTER_SANITIZE_NUMBER_INT), 'barcode_generate_if_empty' => $this->request->getPost('barcode_generate_if_empty') != null, 'allow_duplicate_barcodes' => $this->request->getPost('allow_duplicate_barcodes') != null, 'barcode_content' => $this->request->getPost('barcode_content'), 'barcode_formats' => json_encode($this->request->getPost('barcode_formats')) ]; $success = $this->appconfig->batch_save($batch_save_data); echo json_encode(['success' => $success, 'message' => lang('Config.saved_' . ($success ? '' : 'un') . 'successfully')]); } /** * Saves receipt configuration. Used in app/Views/configs/receipt_config.php. * * @throws ReflectionException * @return void * @noinspection PhpUnused */ public function postSaveReceipt(): void { $batch_save_data = [ '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'), 'print_receipt_check_behaviour' => $this->request->getPost('print_receipt_check_behaviour'), 'receipt_show_company_name' => $this->request->getPost('receipt_show_company_name') != null, 'receipt_show_taxes' => $this->request->getPost('receipt_show_taxes') != null, '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_serialnumber' => $this->request->getPost('receipt_show_serialnumber') != null, 'print_silently' => $this->request->getPost('print_silently') != null, 'print_header' => $this->request->getPost('print_header') != null, 'print_footer' => $this->request->getPost('print_footer') != null, 'print_top_margin' => $this->request->getPost('print_top_margin', FILTER_SANITIZE_NUMBER_INT), 'print_left_margin' => $this->request->getPost('print_left_margin', FILTER_SANITIZE_NUMBER_INT), 'print_bottom_margin' => $this->request->getPost('print_bottom_margin', FILTER_SANITIZE_NUMBER_INT), 'print_right_margin' => $this->request->getPost('print_right_margin', FILTER_SANITIZE_NUMBER_INT) ]; $success = $this->appconfig->batch_save($batch_save_data); echo json_encode(['success' => $success, 'message' => lang('Config.saved_' . ($success ? '' : 'un') . 'successfully')]); } /** * Saves invoice configuration. Used in app/Views/configs/invoice_config.php. * * @throws ReflectionException * @return void * @noinspection PhpUnused */ public function postSaveInvoice(): void { $batch_save_data = [ 'invoice_enable' => $this->request->getPost('invoice_enable') != null, 'sales_invoice_format' => $this->request->getPost('sales_invoice_format'), 'sales_quote_format' => $this->request->getPost('sales_quote_format'), 'recv_invoice_format' => $this->request->getPost('recv_invoice_format'), 'invoice_default_comments' => $this->request->getPost('invoice_default_comments'), 'invoice_email_message' => $this->request->getPost('invoice_email_message'), 'line_sequence' => $this->request->getPost('line_sequence'), 'last_used_invoice_number' => $this->request->getPost('last_used_invoice_number', FILTER_SANITIZE_NUMBER_INT), 'last_used_quote_number' => $this->request->getPost('last_used_quote_number', FILTER_SANITIZE_NUMBER_INT), 'quote_default_comments' => $this->request->getPost('quote_default_comments'), 'work_order_enable' => $this->request->getPost('work_order_enable') != null, 'work_order_format' => $this->request->getPost('work_order_format'), 'last_used_work_order_number' => $this->request->getPost('last_used_work_order_number', FILTER_SANITIZE_NUMBER_INT), 'invoice_type' => $this->request->getPost('invoice_type') ]; $success = $this->appconfig->batch_save($batch_save_data); // Update the register mode with the latest change so that if the user // switches immediately back to the register the mode reflects the change if ($success) { if ($this->config['invoice_enable']) { $this->sale_lib->set_mode($this->config['default_register_mode']); } else { $this->sale_lib->set_mode('sale'); } } echo json_encode(['success' => $success, 'message' => lang('Config.saved_' . ($success ? '' : 'un') . 'successfully')]); } /** * Removes the company logo from the database. Used in app/Views/configs/info_config.php. * * @return void * @throws ReflectionException * @noinspection PhpUnused */ public function postRemoveLogo(): void { $success = $this->appconfig->save(['company_logo' => '']); echo json_encode(['success' => $success]); } }